[Arm64] 分岐命令

CPU はメモリに格納されている32ビット (4バイト) の命令をメモリアドレスの 小さい方から大きい方に向かって順に実行する。
この命令の実行順を変更する 命令が分岐命令。 実行中の命令のメモリアドレスはプログラムカウンタ (PC) が保持していますが、分岐命令はプログラムカウンタの値を書き換える命令と 考えられる。
実行するメモリアドレスに無条件にジャンプする 「B」と「BR」、呼び出し元(ジャンプした次の命令)に戻る準備をして分岐する 「BL」と「BLR」、呼び出し元へジャンプして 戻る「RET」、条件フラグの値によって分岐したり、直後の命令を順に実行したりする 条件分岐命令(B.EQ、B.GTなど) がある。

## 無条件分岐命令
### B
分岐命令の B は、プログラムカウンタの値にオフセットを加えたメモリアドレスに 分岐(ジャンプ)。 分岐先の命令に付けたラベルを分岐先として指定しますが、 アセンブラが「B」命令の アドレスとラベルのアドレスから、プログラムカウンタ相対オフセットを計算

1
B     label

### BR
分岐命令の BR は、分岐先のメモリアドレスを汎用レジスタに格納して実行することで 、汎用レジスタが格納しているメモリアドレスへの無条件分岐

1
BR    Xn

### BL
リンク付分岐命令の BL は、プログラムカウンタの値にオフセットを加えた メモリアドレスに分岐(ジャンプ)。 分岐先の命令に付けたラベルを分岐先として指定しますが、 アセンブラが「BL」命令のアドレスとラベルのアドレスから、 プログラムカウンタ相対オフセットを計算

1
BL    label

### BLR
リンク付分岐命令の BLR は、分岐先のメモリアドレスを汎用レジスタに格納して 実行することで、汎用レジスタが格納しているメモリアドレスへの無条件分岐

1
BLR   Xn

### RET
RET (Return) 命令は、指定したレジスタのアドレスに無条件分岐。 レジスタを指定しない場合はリンクレジスタ(X30) を指定したことになる

1
RET   { Xn }

### サブルーチン呼び出し

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 呼び出し元
Main:
 
    
 
    bl      Sub                   // サブルーチン呼び出し
    mov     x0, xzr               // X30に格納される戻り先
 
    
 
// サブルーチン
Sub:                              // このラベルにジャンプ
    stp     x0, x30, [sp, #-16]!  // リンクレジスタ(X30)の退避
    stp     x1, x2,  [sp, #-16]!  // レジスタの PUSH の例
 
    // 何か処理
 
    ldp     x1, x2,  [sp], #16    // レジスタの POP の例
    ldp     x0, x30, [sp], #16    // リンクレジスタ(X30)の復帰
    ret                           // 呼び出し元の次の命令に戻る

### 条件分岐命令
EQ, NE, CS, CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL, NV

### CBZ

1
2
CBZ     Wt, label
CBZ     Xt, label

### CBNZ
汎用レジスタ(Rt)の値が 0 でなければ、ラベルに分岐

1
2
CBNZ    Wt, label
CBNZ    Xt, label

### TBZ
TBZ(Test bit and Branch if Zero)命令は汎用レジスタ(Rt)の imm で指定した ビット(0..63) が 0 ならばラベルに分岐

1
2
TBZ     Wt, #imm, label
TBZ     Xt, #imm, label

### TBNZ
TBNZ (Test bit and Branch if Nonero) 命令は汎用レジスタ(Rt)の imm で指定した ビット(0..63) が 1 ならばラベルに分岐

1
2
TBNZ    Wt, #imm, label
TBNZ    Xt, #imm, label

## 条件実行命令
### CSEL
条件が真ならば Rd に Rn を返します。条件が偽ならば Rd に Rm を返します。 条件はサフィックスで指定します。

1
2
CSEL   Wd, Wn, Wm, 条件
CSEL   Xd, Xn, Xm, 条件

### CSET
条件が真ならば Rd に 1 を返し、偽ならば Rd に 0

1
2
CSET   Wd, 条件          //  CSINC Wd, WZR, WZR, 逆条件
CSET   Xd, 条件          //  CSINC Xd, XZR, XZR, 逆条件

### CSINC
条件が真ならば Xd に Rn

1
2
CSINC  Wd, Wn, Wm, 条件
CSINC  Xd, Xn, Xm, 条件

### CSINV
条件が真ならば Rd に Rn を返します。 条件が偽ならば Rm のビット毎の反転(1の補数)を Rd に

1
2
CSINV  Wd, Wn, Wm, 条件
CSINV  Xd, Xn, Xm, 条件

### CSNEG
条件が真ならば Rd に Rn を返します。 条件が偽ならば Rm が符号付整数として2の補数(正負反転)を Rd に

1
2
CSINV  Wd, Wn, Wm, 条件
CSINV  Xd, Xn, Xm, 条件

## 条件比較
### CCMP (イミディエート)
指定した条件(サフィックス)が真の場合は、 汎用レジスタと5ビットの符号なし整数 (0..31) を比較した結果で 条件フラグを設定し、指定した条件(サフィックス)が 偽の場合は、4ビットのNZCV定数(0..15)を条件フラグに設定

1
2
3
4
// NZCV = if cond then CMP(Wn, uimm) else nzcv.
 
CCMP Wn, #imm, #nzcv, cond
CCMP Xn, #imm, #nzcv, cond

### CCMP (レジスタ)
指定した条件(サフィックス)が真の場合は、 汎用レジスタ Rn と Rm を比較した結果で条件フラグを設定し、 指定した条件(サフィックス)が偽の場合は、 4ビットのNZCV定数(0..15)を条件フラグに設定

1
2
3
4
// NZCV = if cond then CMP(Rn,Rm) else uimm4.
 
CCMP    Wn, Wm, #nzcv, cond
CCMP    Xn, Xm, #nzcv, cond

### CCMN (イミディエート)
指定した条件(サフィックス)が真の場合は、 汎用レジスタと、5ビットの符号なし整数 (0..31) に -1 を乗じた数を比較した結果で 条件フラグを設定し、指定した条件(サフィックス)が 偽の場合は、4ビットのNZCV定数(0..15)を条件フラグに設定

1
2
3
4
// NZCV = if cond then CMP(Xn,-uimm5) else uimm4.
 
CCMN   Wn, #imm, #nzcv, cond
CCMN   Xn, #imm, #nzcv, cond

### CCMN (レジスタ)
指定した条件(サフィックス)が真の場合は、 汎用レジスタ Rn と、Rm に-1を乗じた数を比較した結果で条件フラグを設定し、 指定した条件(サフィックス)が偽の場合は、 4ビットのNZCV定数(0..15)を条件フラグに設定

1
2
3
4
// NZCV = if cond then CMP(Rn,-Rm) else uimm4.
 
CCMN   Wn, Wm, #nzcv, cond
CCMN   Xn, Xm, #nzcv, cond

### ビット操作
REV, REV16, REV32, RBIT, CLS, CLZ

### ステータスレジスタの操作
MRS, MSR

### システムコール
SVC (Supervisor Call) 命令はシステムコール用の命令

1
SVC     #0
1
2
3
4
5
6
7
8
9
10
11
12
13
.text
        .global _start
_start:
        mov     x2,  #13    // x2  length
        adr     x1,  msg    // x1  string address
        mov     x0,  #1     // x0  stdout
        mov     x8,  #64    // sys_write
        svc     #0
        mov     x0,  xzr
        mov     x8,  #93    // sys_exit
        svc     #0
msg:
        .asciz  "hello, world\n"