はじめに
ARMアセンブラの勉強のメモ書きです。ARMアセンブラと機械語の変換や仕組みについて記述してあります。間違った情報があるかもしれませんがご了承ください。
機械語
ARMは32bit命令を使用している。 命令はデータ処理命令、メモリ命令、分岐命令とその他の命令に分類される。
基本形
※上段:ビット数。下段:内容。
| 31:28 | 27:26 | 25:20 | 19:0 |
|---|---|---|---|
| cond | op | funct | - |
各内容
- cond:命令の発動タイミング cond=1110:Always発動
- op:オペレーションコード ←ここを見てまず何の命令かを判断する。
- op=00:データ処理命令
- op=01:メモリ命令
- op=10:分岐命令
- funct:ファンクション データ処理、メモリ、分岐でそれぞれ形が変わる。
- -:命令によって形が変わる。
データ処理命令
op=00のときに実行される命令
基本形
※上段:ビット数。下段:内容。
| 31:28 | 27:26 | 25 | 24:21 | 20 | 19:16 | 15:12 | 11:0 |
|---|---|---|---|---|---|---|---|
| cond | op | I | cmd | S | Rn | Rd | Src2 |
各内容
- I:直値orレジスタの判断。これによりSrc2の形が変わる。
- I=1:直値
- I=0:レジスタorシフト数レジスタ
- cmd:データ処理命令 ここで、データ処理の内容が決まる。
- S:条件フラグ更新
- S=1:更新する
- S=0:更新しない
- Rd:レジスタ1
- Rn:レジスタ2
- Src2:ソース2
cmdの内容
| cmd | フォーマット | 説明 | 動作 |
|---|---|---|---|
| 0000 | AND Rd,Rn,Src2 | ビット毎のAND | Rd ← Rn & Src2 |
| 0001 | EOR Rd,Rn,Src2 | ビット毎のXOR | Rd ← Rn ^ Src2 |
| 0010 | SUB Rd,Rn,Src2 | 減算 | Rd ← Rn - Src2 |
| 0011 | RSB Rd,Rn,Src2 | 逆方向減算 | Rd ← Src2 - Rn |
| 0100 | ADD Rd,Rn,Src2 | 加算 | Rd ← Rn + Src2 |
| 0101 | ADC Rd,Rn,Src2 | キャリー付加算 | Rd ← Rn + Src2 + C |
| 0110 | SBC Rd,Rn,Src2 | キャリー付減算 | Rd ← Rn - Src2 - C |
| 0111 | RSC Rd,Rn,Src2 | キャリー付き逆方向減算 | Rd ← Src2 - Rn - C |
| 1000 | TST Rn,Src2 | テスト | Rn & Src2に基づきフラグをセット |
| 1001 | TEQ Rn,Src2 | 等しいかテスト | Rn ^ Src2に基づきフラグをセット |
| 1010 | CMP Rn,Src2 | 比較 | Rn -Src2に基づきフラグをセット |
| 1011 | CMN Rn,Rd,Src2 | 負の比較 | Rn + src2に基づきフラグをセット |
| 1100 | ORR Rd,Rn,Src2 | ビット毎のOR | Rd ← Rn ∧ Src2 |
| 1101 | シフト | 下表参照 | |
| 1110 | BIC Rd,Rn,Src2 | ビット毎のクリア | Rd ← Rn & ~Src2 |
| 1111 | MVN Rd,Rn,Src2 | ビット毎の否定 | Rd ← ~Rn |
- フォーマット例 この場合、R1=Rd、R2=Rn、#12=Src2に相当する。
ADD R1,R2,#12
シフトの内容
I=1のときは移動命令、I=0のときはシフトor回転命令となる。 I=0のときは、shを見て命令を判断する。 ※例外1:I=0かつsh=00かつshmat5=00000の場合、移動命令(MOV)となる。 ※例外2:I=0かつsh=11かつshmat5=00000の場合、拡張右回転命令(RRX)となる。
I=1のときのシフト内訳
| フォーマット | 説明 | 動作 |
|---|---|---|
| MOV Rd,Src2 | 移動 | Rd ← Src2 |
I=0のときのシフト内訳
| sh | フォーマット | 説明 | 動作 |
|---|---|---|---|
| 00 | LSL Rd,Rm,Rs/shmat5 | 論理左シフト | Rd ← Rm << Src2 |
| 01 | LSR Rd,Rm,Rs/shmat5 | 論理右シフト | Rd ← Rm >> Src2 |
| 10 | ASR Rd,Rm,Rs/shmat5 | 算術右シフト | Rd ← Rm >> Src2 |
| 11 | ROR Rd,Rm,Rs/shmat5 | 右回転 | Rd ← Rn ror Src2 |
条件フラグが更新される命令
S=1になる命令
- ADDS
- SUBS
- ASRS,LSLS,LSRS,RORS
- ANDS,ORRS,EORS,BICS
- MOVS,MVNS
- MULS,SMULLS,UMULLS
- CMP,CMN
- TEQ,TST
Src2の内容
大きく分けてデータ処理命令(ADD、SUB)とシフト命令に分けられる
データ処理命令の場合
2パターン存在する
I=1:直値を扱う場合
Src2の中身が以下のように変形する
※上段:ビット数。下段:内容。
| 11:8 | 7:0 |
|---|---|
| rot | imm8 |
- rot:回転数
- imm8:8bitの値
直値を扱う場合、基本8bitでしか値を扱えない。しかし、バレルシフタという工夫を行うことで、32bit(制限付き)までの値を扱うことができる。
- 計算方法 imm8の値をrot x 2の値分右回転させる。 例:imm8=1111 1111 rot=1110 rot=1110は10進数に直すと、14である。よって、14 x 2 = 28bit分、右回転を行えば良い。 32bit回転前 0000 0000 0000 0000 0000 0000 1111 1111 32bit回転後 0000 0000 0000 0000 0000 1111 1111 0000
回転後の値は10進数で4080である。この値は8bitでは扱えないがこのようにバレルシフトを行うことで扱うことができる。当たり前だが、8bit以内で表現できる値の場合はrot=0000を指定する。
例:ADD R0,R1,#42
| cond | op | I | cmd | S | Rn | Rd | rot | imm8 |
|---|---|---|---|---|---|---|---|---|
| 1110 | 00 | 1 | 0100 | 0 | 0001 | 0000 | 0000 | 0010 1010 |
cmd=ADD、Rd=R0、Rn=R1、rot/imm8=#42となっている。 この機械語を4bitずつに区切ると
1110 0010 1000 0001 0000 0000 0010 1010
となり、これを16進数に直すと
0xE281002A
となる。
I=0:レジスタを扱う場合
Src2の中身が以下のように変形する
※上段:ビット数。下段:内容。
| 11:7 | 6:5 | 4 | 3:0 |
|---|---|---|---|
| shmat5 | sh | 0 | Rm |
- shmat5:共有メモリ ※データ処理命令かつレジスタを扱う場合はshmat5=00000になる。
- sh:シフト命令 ※データ処理命令かつレジスタを扱う場合はsh=00になる。
- 0:0が格納されている
- Rm:レジスタ 3つ目のレジスタに該当する
例:SUB R8,R9,R10
| cond | op | I | cmd | S | Rn | Rd | shmat5 | sh | 0 | Rm |
|---|---|---|---|---|---|---|---|---|---|---|
| 1110 | 00 | 0 | 0010 | 0 | 0110 | 0101 | 00000 | 00 | 0 | 1010 |
cmd=SUB、Rd=R9、Rn=R8、Rm=R10となっている。 この機械語を4bitずつに区切ると
1110 0000 0100 0110 0101 0000 0000 1010
となり、これを16進数に直すと
0xE049800A
となる。
シフト命令の場合
3パターン存在する
I=1:移動命令の場合
Src2の中身が以下のように変形する
※上段:ビット数。下段:内容。
| 11:8 | 7:0 |
|---|---|
| rot | imm8 |
- rot:回転数
- imm8:8bitの値
前述したとおり、シフト命令でI=1の場合は移動命令(MOV)となる。 例:MOV R0,#7
| cond | op | I | cmd | S | Rn | Rd | rot | imm8 |
|---|---|---|---|---|---|---|---|---|
| 1110 | 00 | 1 | 1101 | 0 | 0000 | 0000 | 0000 | 0000 0111 |
cmd=シフト命令、Rd=R0、rot/imm8=#7となっている。 この機械語を4bitずつに区切ると
1110 0011 1010 0000 0000 0000 0000 0111
となり、これを16進数に直すと
0xE3A00007
となる。
I=0:シフト量が直値の場合
Src2の中身は以下のように変形する
※上段:ビット数。下段:内容。
| 11:7 | 6:5 | 4 | 3:0 |
|---|---|---|---|
| shmat5 | sh | 0 | Rm |
- shmat5:共有メモリ ※直値が入る。
- sh:シフト命令
- 0:0が格納されている
- Rm:レジスタ ※シフト命令の場合、Rnは使用せず2つ目のレジスタはRmとなる。
例:LSL R0,R9,#7
| cond | op | I | cmd | S | Rn | Rd | shmat5 | sh | 0 | Rm |
|---|---|---|---|---|---|---|---|---|---|---|
| 1110 | 00 | 0 | 1101 | 0 | 0000 | 0000 | 00111 | 00 | 0 | 1001 |
cmd=シフト命令、Rd=R0、Rm=R9、shmat5=#7、sh=LSLとなっている。 この機械語を4bitずつに区切ると
1110 0001 1010 0000 0000 0011 1000 1001
となり、これを16進数に直すと
0xE1A00309
となる。
I=0:シフト量がレジスタの場合
Src2の中身は以下のように変形する
※上段:ビット数。下段:内容。
| 11:8 | 7 | 6:5 | 4 | 3:0 |
|---|---|---|---|---|
| Rs | 0 | sh | 1 | Rm |
- Rs:レジスタ 3つ目のレジスタに該当する
- 0:0が格納されている
- sh:シフト命令
- 1:1が格納されている
- Rm:レジスタ 2つ目のレジスタに該当する
例:ASR R5,R1,R12
| cond | op | I | cmd | S | Rn | Rd | Rs | 0 | sh | 1 | Rm |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1110 | 00 | 0 | 1101 | 0 | 0000 | 0101 | 1100 | 0 | 10 | 1 | 0001 |
cmd=シフト命令、Rd=R5、Rm=R、Rs=R12、sh=ASLとなっている。 この機械語を4bitずつに区切ると
1110 0001 1010 0000 0101 1100 0101 0001
となり、これを16進数に直すと
0xE1A05C51
となる。
メモリ命令
op=01のときに実行される命令
基本形
※上段:ビット数。下段:内容。
| 31:28 | 27:26 | 25 | 24 | 23 | 22 | 21 | 20 | 19:16 | 15:12 | 11:0 |
|---|---|---|---|---|---|---|---|---|---|---|
| cond | op | I | P | U | B | W | L | Rn | Rd | Src2 |
各内容
- I:直値orレジスタの判断。これによりSrc2の形が変わる。
- I=0:直値オフセット
- I=1:レジスタオフセット
- U:足し算or引き算
- U=1:オフセットを足す
- U=0:オフセットを引く
- P W:インデックスモード ←PとWの2値を使って判断する。
- L B:メモリ命令 ←LとBの2値を使って判断する。
- Rd:レジスタ1
- Rn:レジスタ2
- Src2:ソース2
P W:インデックスモードの内容
| P W | インデックスモード | 例 | 見分け方 |
|---|---|---|---|
| 0 0 | ポストインデックス | LDR R0,[R1],R2 | 真ん中に括弧 |
| 0 1 | サポート外 | - | |
| 1 0 | オフセット | LDR R0,[R1,R2] | 右二個に括弧 |
| 1 1 | プレインデックス | LDR R0,[R1,R2]! | ビックリマーク |
L B:メモリ命令の内容
| L B | 命令 |
|---|---|
| 0 0 | STR |
| 0 1 | STRB |
| 1 0 | LDR |
| 1 1 | LDRB |
Src2の内容
I=0:直値を扱う場合
Src2の中身が以下のように変形する
※上段:ビット数。下段:内容。
| 11:0 |
|---|
| imm12 |
- imm12:12bitの値を格納 直値を扱う
例:STR R11,[R5],#-26
| cond | op | I | P | U | B | W | L | Rn | Rd | imm12 |
|---|---|---|---|---|---|---|---|---|---|---|
| 1110 | 01 | 0 | 0 | 0 | 0 | 0 | 0 | 0101 | 1011 | 0000 0001 1010 |
U=引き算、P W=ポストインデックス、L B=STR、imm12=#26 この機械語を4bitずつに区切ると
1110 0100 0000 0101 1011 0000 0001 1010
となり、これを16進数に直すと
0xE405B01A
となる。
I=1:レジスタを扱う場合
Src2の中身は以下のように変形する
※上段:ビット数。下段:内容。
| 11:7 | 6:5 | 4 | 3:0 |
|---|---|---|---|
| shmat5 | sh | 0 | Rm |
- shmat5:共有メモリ
- sh:シフト命令
- 0:0が格納されている
- Rm:レジスタ
例:省略
分岐命令
OP=10のときに実行される命令
基本形
※上段:ビット数。下段:内容。
| 31:28 | 27:26 | 25 | 24 | 23:0 |
|---|---|---|---|---|
| cond | op | 1 | L | imm24 |
- 1:1が格納されている
- L:分岐命令
- imm24:24bit値を格納 ←分岐先アドレスを格納
L:分岐命令
| L | 命令 |
|---|---|
| 0 | B |
| 1 | BL |
分岐先のアドレス計算
- 分岐命令を探す
- 分岐命令+2の命令を基準として考える
- 分岐先のアドレスが基準から何個離れているかを計算する
- アドレスの値をimm24に格納する ※値がマイナスの場合は2の歩数表現を使う
例:
1 TEST LDRB R5,[R0,R3] ←分岐先アドレス
2 STRB R5,[R1,R3]
3 ADD R3,R3,#1
4 MOV PC,LR
5 BL TEST ←分岐命令
6 LDR R3,[R1],#4
7 SUB R4,R3,#9 ←基準
この場合、基準から分岐先アドレスは“-6“となる。 つまり、機械語で表すと
| cond | op | 1 | L | imm24 |
|---|---|---|---|---|
| 1110 | 10 | 1 | 1 | 1111 1111 1111 1111 1111 1010 |
この機械語を4bitずつに区切ると
1110 1011 1111 1111 1111 1111 1111 1010
となり、これを16進数に直すと
0xEBFFFFFA
となる。