みなさんこんにちは!
私は職業別のJavaプログラマーです。 最後の数ヶ月の作業で、Android NDKの開発に慣れることを余儀なくされ、それに応じてネイティブアプリケーションをCで記述しました。その後、Linuxライブラリの最適化の問題に遭遇しました。 多くはARM向けに完全に最適化されておらず、プロセッサに大きな負荷がかかりました。 以前は、実際にはアセンブラーでプログラミングしなかったため、最初はこの言語の学習を開始することは困難でしたが、まだ試してみることにしました。 この記事は、いわば初心者から初心者まで書かれています。 私はすでに学んだ基本を説明しようとします。誰かがこれに興味を持ってくれることを願っています。 さらに、私は専門家から建設的な批判を受けることを嬉しく思います。
はじめに
まず、ARMについて理解しましょう。 ウィキペディアには次の定義があります。
ARMアーキテクチャ(アドバンストRISCマシン、Acorn RISCマシン、アドバンストRISCマシン)-ARM Limitedが開発した、ライセンス供与された32ビットおよび64ビットマイクロプロセッサコアのファミリ。 同社は、カーネルとそのツール(コンパイラ、デバッグツールなど)の開発に専念しており、サードパーティのメーカーにライセンスアーキテクチャを提供しています。
誰も知らない場合、現在、ほとんどのモバイルデバイスとタブレットは、このプロセッサアーキテクチャ専用に設計されています。 このファミリの主な利点は低消費電力であるため、さまざまな組み込みシステムでよく使用されます。 時間の経過とともに開発され、ARMv7以降、3つのプロファイルが定義されました。「A」(アプリケーション)-アプリケーション、「R」(リアルタイム)-リアルタイム、「M」(マイクロコントローラー)-マイクロコントローラー。 この技術の開発の歴史やその他の興味深いデータは、ウィキペディアまたはインターネット上のグーグルで読むことができます。 ARMはさまざまな動作モードをサポートしています(ThumbとARMに加えて、最近、ARMとThumbの混合であるThumb-2が登場しました)。 この記事では、32ビット命令セットが実行される実際のARMモードについて検討します。
各ARMプロセッサは、次のブロックから作成されます。
- 37個のレジスタ(開発中に表示されるのは17個のみ)
- 算術論理デバイス(ALU)-算術および論理タスクを実行します
- バレルシフター-データブロックを特定のビット数だけ移動するように設計されたデバイス
- CP15-ARMコプロセッサーを制御する特別なシステム
- 命令デコーダー-命令を一連のマイクロ操作に変換します
これらはすべてARMのコンポーネントではありませんが、プロセッサの構築の範囲を深く掘り下げることはこの記事のトピックには含まれていません。
パイプライン実行
ARMプロセッサは3ステージパイプラインを使用します(ARM8以降、5ステージパイプラインが実装されました)。 例としてARM7TDMIプロセッサを使用した単純なパイプラインを考えてみましょう。 各命令の実行は、3つのステップで構成されています。
1.サンプリングステージ(F)
この時点で、命令はRAMからプロセッサパイプラインに送られます。
2.デコード手順(D)
命令がデコードされ、そのタイプが認識されます。
3.実行の段階(E)
データがALUに送信されて実行され、結果の値が指定されたレジスタに書き込まれます。
ただし、開発時には、ロード(LDR)やストアなど、複数の実行サイクルを使用する命令があることを考慮する必要があります。 この場合、実行ステージ(E)はステージ(E1、E2、E3 ...)に分割されます。
条件付き実行
ARMアセンブラの最も重要な機能の1つは、条件付き実行です。 各命令は条件付きで実行でき、これには接尾辞が使用されます。 命令の名前に接尾辞が追加されている場合、実行する前にパラメータがチェックされます。 パラメータが条件を満たさない場合、命令は実行されません。 接尾辞:
MIは負の数です
PL-正またはゼロ
AL-常に指示に従う
条件付き実行サフィックスははるかに大きくなります。 残りの接尾辞と例は、公式ドキュメントで読みます:
ARMドキュメントそして今、検討する時間です...
ARMアセンブラーの構文の基本
アセンブラで作業していた人は、この点をスキップできます。 他の皆のために、私はこの言語で作業する基本を説明します。 したがって、すべてのアセンブラープログラムは命令で構成されています。 命令は次の方法で作成されます。
{ラベル} {命令|オペランド} {@コメント}
ラベルはオプションのパラメーターです。 命令は、プロセッサへの命令のニーモニックです。 基本的な手順とその使用方法については、後で説明します。 オペランド-定数、レジスタアドレス、RAM内のアドレス。 コメントは、プログラムの実行に影響しないオプションのパラメーターです。
登録名
次のレジスタ名が許可されます。
1.r0-r15
2.a1-a4
3.v1-v8(可変レジスタ、r4からr11)
4.sbおよびSB(静的レジスタ、r9)
5.slおよびSL(r10)
6.fpおよびFP(r11)
7.ipおよびIP(r12)
8.spおよびSP(r13)
9.lrおよびLR(r14)
10.pcおよびPC(ソフトウェアカウンター、r15)。
変数と共助
ARMアセンブラでは、(実際には)他のプログラミング言語と同様に、変数と定数を使用できます。 それらは次のタイプに分けられます:
数値変数は次のように初期化されます。
SETA 100; 値が100の数値変数「a」が作成されます。
文字列変数:
improb SETS "literal"; 「リテラル」の値でimprob変数が作成されます。 注意! 変数の値は5120文字を超えることはできません。
ブール変数は、それぞれTRUEとFALSEを使用します。
ARMアセンブラー命令の例
この表では、さらなる開発に必要な基本的な手順を集めました(最も基本的な段階で:):
役職 | 構文 | 申込み |
ADD(追加) | r0、r1、r2を追加
| r0 = r1 + r2 |
SUB(減算) | SUB r0、r1、r2
| r0 = r1-r2 |
RSB(逆引き) | RSB r0、r1、#10
| r0 = 10-r1 |
MUL(乗算) | MUL r0、r1、r2
| r0 = r1 * r2 |
Mov | Mov r0、r1
| r0 = r1 |
ORR(論理演算) | ORR r0、r1、r2
| r0 = r1 | r2 |
TEQ | TEQ r0、r1
| r0 == r1 |
LDR(ダウンロード) | LDR r4、[r5]
| r4 = * r5 |
STR | STR r4、[r5]
| * r5 = r4 |
ADR | ADR r3、a
| aは変数です。 r3 =&a |
基本的な指示の使用を統合するために、いくつかの簡単な例を書いてみましょうが、最初にアームツールチェーンが必要です。 Linuxで作業しているので、
frank.harvard.edu /
〜coldwell /
toolchain (arm-unknown-linux-gnuツールチェーン)を選択しました。 他のLinuxプログラムと同様に簡単に設定できます。 私の場合(ロシアのFedora)では、サイトからrpmパッケージをインストールするだけで済みました。
次に、簡単な例を作成します。 プログラムは絶対に役に立たないでしょうが、動作する主なもの:)ここに私があなたに提供するコードがあります:
start: @ , mov r0, #3 @ r0 3 mov r1, #2 @ r1, 2 add r2, r1, r0 @ r0 r1, r2 mul r3, r1, r0 @ r1 r0, r3 stop: b stop @
.binファイルを受け取る前にプログラムをコンパイルします。
/usr/arm/bin/arm-unknown-linux-gnu-as -o arm.o arm.s /usr/arm/bin/arm-unknown-linux-gnu-ld -Ttext=0x0 -o arm.elf arm.o /usr/arm/bin/arm-unknown-linux-gnu-objcopy -O binary arm.elf arm.bin
(コードはarm.sファイルにあり、私の場合のツールチェーンは/ usr / arm / bin /ディレクトリにあります)
すべてがうまくいけば、3つのファイルがあります:arm.s(コード自体)、arm.o、arm.elf、arm.bin(実行可能プログラム自体)。 プログラムの動作を確認するために、独自のアームデバイスを用意する必要はありません。 QEMUをインストールするだけです。 参照用:
QEMUは、さまざまなプラットフォームのハードウェアをエミュレートするための無料のオープンソースプログラムです。
Intel x86プロセッサと入出力デバイスのエミュレーションが含まれます。 80386、80486、Pentium、Pentium Pro、AMD64、およびその他のx86互換プロセッサーをエミュレートできます。 PowerPC、ARM、MIPS、SPARC、SPARC64、m68k-部分的にのみ。
音節、FreeBSD、FreeDOS、Linux、Windows 9x、Windows 2000、Mac OS X、QNX、Androidなどで動作します。
したがって、armをエミュレートするには、qemu-system-armが必要になります。 このパッケージはyumに含まれているため、Fedoraを使用している場合は、次のコマンドを実行するだけで済みます。
yum install qemu-system-arm
次に、ARMエミュレーターを実行して、プログラムarm.binを実行する必要があります。 これを行うには、flash.binファイルを作成します。このファイルはQEMUのフラッシュメモリになります。 とても簡単です:
dd if=/dev/zero of=flash.bin bs=4096 count=4096 dd if=arm.bin of=flash.bin bs=4096 conv=notrunc
次に、受信したフラッシュメモリでQEMUをロードします。
qemu-system-arm -M connex -pflash flash.bin -nographic -serial /dev/null
出力では、次のようなものが得られます。
[anton @ localhost〜] $ qemu-system-arm -M connex -pflash flash.bin -nographic -serial / dev / null
QEMU 0.15.1モニター-詳細については「help」と入力してください
(ケム)
プログラムarm.binは4つのレジスタの値を変更することになっていたため、正しい動作を確認するために、これらのレジスタを見てみましょう。 これは非常に簡単なコマンドで行われます:info register
出力では、15個すべてのARMレジスタが表示され、そのうち4個の値が変更されます。 チェック:)レジスタ値は、プログラム実行後に予想される値と一致します。
(qemu) info registers R00=00000003 R01=00000002 R02=00000005 R03=00000006 R04=00000000 R05=00000000 R06=00000000 R07=00000000 R08=00000000 R09=00000000 R10=00000000 R11=00000000 R12=00000000 R13=00000000 R14=00000000 R15=00000010 PSR=400001d3 -Z
PSこの記事では、ARMアセンブラーでのプログラミングの基本を説明しようとしました。 楽しんでいただけましたでしょうか! これは、この言語のジャングルをさらに掘り下げてプログラムを作成するのに十分です。 すべてがうまくいったら、自分で見つけたものについてさらに書きます。 エラーがある場合は、アセンブラーが初めてなので、キックしないでください。