ARMアセンブリ

ARM は RISC でありながら、個々の命令が複雑な機能を持っています。特にほとんどの命令が条件に従って実行されたり、されなかったりする条件実行の機能を持っている
スタックが使いやすく、比較的高機能な命令が多いため、アセンブラでプログラムしやすいCPUである
ARM系のCPUの場合、システムコールの方法やスタックの使い方を規定した Application Binary Interface (ABI) に 2種類ある

LR(リンクレジスタ)は、分岐命令(サブルーチン呼び出し)が行われたときに、サブルーチン終了後に呼び出し元に戻ってこられるよう、現在の PC 値(正確には、現在の PC 値の次の命令のアドレス)を覚えておくためのもの
プログラムの実行とともに「プログラムカウンタ(PC)」が更新されます。プログラムカウンタとは、CPU内にあるアドレス(番地)を収める場所で、そのCPUが次に実行する命令が置かれている番地が書かれている
Pentium系のCPUと比べて命令数は少ないのですが、 条件実行が可能なことや演算命令でフラグレジスタへの反映の有無を指定できることから、 それらの組み合わせでニーモニック(命令の表現)が多い

PowerPCアセンブリ

PowerPCと他のCPU(x86, MIPS, ARM)との最も異なる点は、条件比較命令で変化する条件レジスタが 8 セットあり、比較命令でフラグを設定する条件レジスタを指定することができ、各セット間の論理演算が可能な点と分岐命令の分岐条件に条件レジスタの 8セットのうちの1つを指定できる点
読み書きの対象となるメモリアドレスの指定方法(アドレッシングモード)が単純である一方、ネイティブなニーモニックが複雑(人間向きでない)
MIPS, ARMと同様に命令が32ビット固定長、ARMと同じくMIPSやSHので採用されている遅延スロット(慣性:分岐する場合でも1命令余分に実行)がない、 MIPSと同じくx86やARMが持つようなレジスタをスタック退避する便利な命令がない (MIPSよりは便利)といった、MIPSとARMの中間の性質がある

### 汎用レジスタ
32本の汎用レジスタ(General Purpose Register)があり、演算命令、比較命令、メモリ転送命令など多くの命令のオペランドとして使い、数値、アドレスを格納

[Arm64] 浮動小数点型命令

ARM64は32bit の ARMと異なり、浮動小数点数演算用の命令がオプションではなく、ARMv8 の標準として組み込まれている。
浮動小数点数の正負を表す符号(sign)、浮動小数点数の数値自体(有効数字)を表す仮数部(fraction)とべき乗を示す指数部(exponent) に分けて考える。
ARMv8は、浮動小数点数レジスタとして128ビットを使って複数のベクトル の要素を同時に演算する事ができる Vn レジスタを32本持っている。
浮動小数点数レジスタとメモリ間の読み書きは、汎用レジスタとメモリ間と 同じように簡単に行なえる。
浮動小数点数を複数格納できるベクトルレジスタ (Vn) は、 データのサイズと数をレジスタ名の後ろに指定することができる。
ベクトルレジスタ (Vn) に格納された複数の浮動小数点数の1つを指定するには、 ゼロから始まるインデックスを付けて配列形式で行う。
行列 M の16個の要素をメモリ中に { m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15 } の順に格納

  1.2345678987654321        3ff-3c0ca44de3938
  -1.2345678987654321       bff-3c0ca44de3938
  -9.87654E33               c6f-e6f375e71abf3
   9.87654E33               46f-e6f375e71abf3
   5.87654E33               46f-21bc5cd4e4725
  -1.87654E-33              b92-37cb2f215b389
   1.2345678987654321E299   7e0-798ba335bafbd
  -1.2345678987654321E-299  81e-0891ed3843971
  123.8987654E1             409-35bf35b91f70e
  1.2345678987653           3ff-3c0ca44de36e5
  0.12345678987652          3fb-f9add3afd21d2
  -123456789876543          c2d-c122186c3cfc0
  -123456789876542          c2d-c122186c3cf80
  -123456789876541          c2d-c122186c3cf40
  1.000                     3ff-0000000000000
  0.1                       3fb-999999999999a
  0                         000-0000000000000 

浮動小数点数の演算は、基本的にメモリに格納されている数値をレジスタに読み込んで、演算し、メモリに書き戻すという動きになる
ARM64 (ARMv8) では浮動小数点数を1つずつ扱うスカラー型と、複数の浮動小数点数をまとめて扱うベクトル型のレジスタを扱う命令が別に存在

[Arm64] 分岐命令

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

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

    B     label

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

    BR    Xn

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

    BL    label

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

    BLR   Xn

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

    RET   { Xn }

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

    // 呼び出し元
    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

    CBZ     Wt, label
    CBZ     Xt, label

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

    CBNZ    Wt, label
    CBNZ    Xt, label

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

    TBZ     Wt, #imm, label
    TBZ     Xt, #imm, label

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

    TBNZ    Wt, #imm, label
    TBNZ    Xt, #imm, label

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

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

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

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

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

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

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

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

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

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

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

    // 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)を条件フラグに設定

    // 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)を条件フラグに設定

    // 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)を条件フラグに設定

    // 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) 命令はシステムコール用の命令

    SVC     #0
.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"

[Arm64] シフト演算命令

シフト演算とは論理演算と同じようにビット列を操作する演算
単純な左右へのシフトの他に、複雑な動作をするビットフィールド移動命令がある

### シフト演算

.include        "debug.s"
.text
.global _start

num:    .quad   0x876543210fedcba9

_start:
        ldr     x2, num
        mov     x0, x2
        bl      PrintHex16
        bl      NewLine
        mov     x1, #22
        bl      PrintRight
        bl      NewLine
        
        lsl     x0, x2, #8

        bl      PrintHex16
        bl      NewLine
        mov     x1, #22
        bl      PrintRight
        bl      NewLine
        bl      Exit

$ ./test
876543210FEDCBA9
-8690466096661279831
6543210FEDCBA900
7296712173568108800

算術右シフトはASR x0, x2, #8
論理右シフトはLSR x0, x2, #8
右ローテートはROR x0, x2, #8
左ローテートは右ローテート(ROR)のシフト量を (64 – ビット数) とすることで左ローテートを実現

### アドレッシングモード
シフト演算命令には、シフト量を定数で指定するイミディエートとレジスタで指定するモードの2種類のアドレッシングモードがある

    LSR    Wd, Wn, #imm6
    LSR    Xd, Xn, #imm6

    LSR    Wd, Wn, Wm
    LSR    Xd, Xn, Xm

### ASR
ASR命令 (Arithmetic Shift Right) は算術右シフトを実行。算術右シフトはRn レジスタの内容を Rm レジスタで指定したビット数だけ右にシフト。

    ASR     Wd, Wn, Wm        // ASRV Wd, Wn, Wm と同じ
    ASR     Xd, Xn, Xm        // ASRV Xd, Xn, Xm と同じ

### LSR
LSR命令 (Logical Shift Right)は論理右シフトを実行。論理右シフトはレジスタ Rn の内容をレジスタ Rm で指定したビット数だけ右にシフトしてレジスタ Rd に返却。

    LSR    Wd, Wn, Wm          // LSRV Wd, Wn, Wm と同じ
    LSR    Xd, Xn, Xm          // LSRV Xd, Xn, Xm と同じ

    LSR    Wd, Wn, #shift      // UBFM Wd, Wn, #shift, #31
    LSR    Xd, Xn, #shift      // UBFM Xd, Xn, #shift, #63

### LSL
LSL命令 (Logical Shift Left)は論理左シフトを実行。論理左シフトはレジスタ Rn の内容をレジスタ Rm で指定したビット数だけ左にシフトしてレジスタ Rd に返却

    LSL    Wd, Wn, Wm          // LSLV   Wd, Wn, Wm と同じ
    LSL    Xd, Xn, Xm          // LSLV   Xd, Xn, Xm と同じ

    LSL     Wd, Wn, #shift     // UBFM Wd, Wn, #(-shift MOD 32), #(31-shift)
    LSL     Xd, Xn, #shift     // UBFM Xd, Xn, #(-shift MOD 64), #(63 - shift)

### ROR
レジスタ Rn の内容をレジスタ Rm で指定したビット数(レジスタのビット数で除算した剰余)でローテイトした値をレジスタ Rd に返却

    ROR    Wd, Wn, Wm          // RORV Wd, Wn, Wm と同じ
    ROR    Xd, Xn, Xm          // RORV Xd, Xn, Xm と同じ

    ROR    Wd, Ws, #shift      // EXTR Wd, Ws, Ws, #shift
    ROR    Xd, Xs, #shift      // EXTR Xd, Xs, Xs, #shift

### EXTR
レジスタ Wn とレジスタ Wm のペアを連結してデータのビット列を抽出。定数には抽出する最下位のビット位置を指定

    EXTR    Wd, Wn, Wm, #lsb
    EXTR    Xd, Xn, Xm, #lsb

実装例

num0:      .quad   0xabcdefabcdefabcd
num1:      .quad   0x1234567890123456
//
    ldr     x11, num0
    ldr     x12, num1
//
    extr    x0, X11, x12, #8    // CD12345678901234
    extr    x0, X11, x12, #16   // ABCD123456789012
    extr    x0, X11, x12, #24   // EFABCD1234567890

### ビットフィールドムーブ命令
レジスタ内の最下位のビットを含む連続したビット列(最も右側のビット列)を移動する命令。 移動先レジスタをゼロクリアして 移動するビット列の最上位を符号フラグとして移動先レジスタの 上位ビットに符号をコピーする SBFM 命令、 移動先のレジスタの内容の対応するビット列だけ上書きして元の内容を保持する BFM 命令、移動先レジスタをゼロクリアしてビット列だけ を書き込む UBFM 命令がある。

                            x2    : 923486789ABCDEF0
                            x3    : 0123456789ABCDEF (使われない)
 SBFM X3, X2, #40, #23 -->  x3    : FFFFBCDEF0000000

                            x2    : 923486789ABCDEF0
                            x3    : BBBBBBBBBBBBBBBB (保持される)
 BFM  X3, X2, #40, #23 -->  x3    : BBBBBCDEF0BBBBBB

                            x2    : 923486789ABCDEF0
                            x3    : 0123456789ABCDEF (使われない)
 UBFM X3, X2, #40, #23 -->  x3    : 0000BCDEF0000000

### SBFM
Signed Bitfield Move の略で、ソースレジスタ(Wn、Xn)の 下位ビット側の任意の桁数 (imms+1) を、転送先レジスタの右シフト (immr)するビット位置にコピー

  SBFM Wd, Wn, #immr, #imms
  SBFM Xd, Xn, #immr, #imms
 x2    : 823456789ABCDEF0
 x5    : 5555555555555555
 SBFM X5, X2, #60, #23 --> FFFFFFFFFBCDEF00
 SBFM X5, X2, #56, #23 --> FFFFFFFFBCDEF000
 SBFM X5, X2, #60, #47 --> 00056789ABCDEF00
 SBFM X5, X2, #56, #47 --> 0056789ABCDEF000
 SBFM X5, X2, #24, #47 --> 000000000056789A
 SBFM X5, X2, #16, #23 --> FFFFFFFFFFFFFFBC
 SBFM X5, X2,  #8, #23 --> FFFFFFFFFFFFBCDE

### ASR
ASR 命令 (Arithmetic Shift Right) は転送元レジスタの内容を定数で指定したビット数だけ右にシフトして転送先レジスタにコピー

    ASR Wd, Wn, #shift               // SBFM Wd, Wn, #shift, #31
    ASR Xd, Xn, #shift               // SBFM Xd, Xn, #shift, #63

### SBFIZ
SBFIZ (Signed Bitfield Insert in Zero) 命令は、転送元レジスタの最下位ビットのビット番号が lsb、幅 が width のビット列を転送先レジスタの下位にコピー

    SBFIZ    Xd, Xn, #lsb, #width    // SBFM Wd, Wn, #(-lsb MOD 32), #(width-1)
    SBFIZ    Wd, Wn, #lsb, #width    // SBFM Xd, Xn, #(-lsb MOD 64), #(width-1)

### SBFX
SBFX (Signed Bitfield Extract) 命令は、転送元レジスタの最下位ビットのビット番号が lsb、幅 が width のビット列を取り出して符号拡張して転送先レジスタにコピー

    SBFX     Wd, Wn, #lsb, #width    // SBFM Wd, Wn, #lsb, #(lsb+width-1)
    SBFX     Xd, Xn, #lsb, #width    // SBFM Xd, Xn, #lsb, #(lsb+width-1)

### SXTB
SXTB (Signed Extend Byte) 命令は転送元レジスタの下位8ビットを符号拡張して転送先レジスタにコピー

    SXTB     Wd, Wn                  // SBFM Wd, Wn, #0, #7
    SXTB     Xd, Wn                  // SBFM Xd, Xn, #0, #7

### SXTH
SXTH (Sign Extend Halfword) 命令は転送元レジスタの下位16ビットを符号拡張して転送先レジスタにコピー

    SXTH     Wd, Wn                  // SBFM Wd, Wn, #0, #15 
    SXTH     Xd, Wn                  // SBFM Xd, Xn, #0, #15

### SXTW
SXTW (Sign Extend Word) 命令は転送元レジスタの下位32ビットを符号拡張して転送先レジスタにコピー

    SXTW     Xd, Wn                  // SBFM Xd, Xn, #0, #31

### BFM
この命令は Bitfield Move の略で、ソースレジスタ(Wn、Xn)の 下位ビット側の任意の桁数 (imms+1) を、転送先レジスタの 右シフト(immr)したビット位置にコピー

    BFM     Wd, Wn, #imm6r, #imm6s    // sf = 0 && N = 0
    BFM     Xd, Xn, #imm6r, #imm6s    // sf = 1 && N = 1
 x2    : 823456789ABCDEF0
 x5    : 5555555555555555
 BFM  X5, X2, #60, #23 --> 555555555BCDEF05
 BFM  X5, X2, #56, #23 --> 55555555BCDEF055
 BFM  X5, X2, #60, #47 --> 55556789ABCDEF05
 BFM  X5, X2, #56, #47 --> 5556789ABCDEF055
 BFM  X5, X2, #24, #47 --> 555555555556789A
 BFM  X5, X2, #16, #23 --> 55555555555555BC
 BFM  X5, X2,  #8, #23 --> 555555555555BCDE

### BFI

                            <--- width --->
before     -----------------bbbbbbbbbbbbbbb
 
                       <--- width --->
                                     lsb
after      ------------bbbbbbbbbbbbbbb-----

    BFI    Wd, Wn, #lsb, #width    // BFM Wd, Wn, #(-lsb MOD 32), #(width-1)
    BFI    Xd, Xn, #lsb, #width    // BFM Xd, Xn, #(-lsb MOD 64), #(width-1)

### BFXIL
BFXIL命令 (Bitfield eXtract and Insert at Low end) は、転送元レジスタの最下位ビットのビット番号が lsb 幅 が width のビット列を転送先レジスタの下位にコピー

                        <--- width --->
                                      lsb
before      ------------bbbbbbbbbbbbbbb-----

                             <--- width --->
after       -----------------bbbbbbbbbbbbbbb

    BFXIL  Wd, Wn, #lsb, #width    // BFM Wd, Wn, #lsb, #(lsb+width-1)
    BFXIL  Xd, Xn, #lsb, #width    // BFM Xd, Xn, #lsb, #(lsb+width-1)

### UBFM

    UBFM Wd, Wn, #imm6r, #imm6s     // sf = 0 && N = 0
    UBFM Xd, Xn, #imm6r, #imm6s     // sf = 1 && N = 1

 x2    : 823456789ABCDEF0
 x5    : 5555555555555555
 UBFM X5, X2, #60, #23 --> 000000000BCDEF00
 UBFM X5, X2, #56, #23 --> 00000000BCDEF000
 UBFM X5, X2, #60, #47 --> 00056789ABCDEF00
 UBFM X5, X2, #56, #47 --> 0056789ABCDEF000
 UBFM X5, X2, #24, #47 --> 000000000056789A
 UBFM X5, X2, #16, #23 --> 00000000000000BC
 UBFM X5, X2,  #8, #23 --> 000000000000BCDE

### LSL

    LSL     Wd, Wn, #shift         // UBFM Wd, Wn, #(-shift MOD 32), #(31-shift)
    LSL     Xd, Xn, #shift         // UBFM Xd, Xn, #(-shift MOD 64), #(63-shift)

### LSR

    LSR     Wd, Wn, #shift         // UBFM Wd, Wn, #shift, #31
    LSR     Xd, Xn, #shift         // UBFM Xd, Xn, #shift, #63

### UBFIZ
UBFIZ (Unsigned Bitfield Insert in Zero) 命令は転送先レジスタを0にした後、転送元レジスタの最下位ビットのビット番号が lsb、幅 が width のビット列を転送先レジスタの下位にコピー

    UBFIZ   Wd, Wn, #lsb, #width   // UBFM Wd, Wn, #(-lsb MOD 32), #(width-1)
    UBFIZ   Xd, Xn, #lsb, #width   // UBFM Xd, Xn, #(-lsb MOD 64), #(width-1)

### UBFX
UBFX (Unsigned Bitfield Extract) 命令は転送先レジスタを0にした後、、転送元レジスタの最下位ビットのビット番号が lsb、幅 が width のビット列を転送先レジスタの下位にコピー。コピーするビット列をゼロ拡張して転送する動作となる

    UBFX    Wd, Wn, #lsb, #width   // UBFM Wd, Wn, #lsb, #(lsb+width-1)
    UBFX    Xd, Xn, #lsb, #width   // UBFM Xd, Xn, #lsb, #(lsb+width-1)

### UXTB
UXTB (Unsigned Extend Byte) 命令は転送元レジスタの下位8ビットをゼロ拡張して転送先レジスタにコピー

    UXTB    Wd, Wn                 // UBFM Wd, Wn, #0, #7

### UXTH
UXTH (Sign Extend Halfword) 命令は転送元レジスタの下位16ビットをゼロ拡張して転送先レジスタにコピー

    UXTH    Wd, Wn                 // UBFM Wd, Wn, #0, #15

[Arm64] 演算命令

演算命令は四則演算、論理演算、比較などを行う命令群
ARM64では演算命令に3つのレジスタを指定することができる

add  x1, x2, x3           // x1 = x2 + x3
add  x1, x1, x1           // x1 = x1 + x1 = x1 * 2
add  x1, x2, x3 LSL #20   // x1 = x2 + (x3 << 20)

加減算の命令のアドレッシングモードには、単純なレジスタ指定、シフトレジスタ、イミディエート(定数指定)、 拡張レジスタの4種類があり、命令によって使えるアドレッシングが異なる

イミディエート(定数指定)

    ADD   Xd, Xn, #uimm12 {, LSL #12}
    ADD   Wd, Wn, #uimm12 {, LSL #12}

シフトレジスタ(シフト済みレジスタ指定)

    ADD   Xd, Xn, Xm {, shift #amount}
    ADD   Wd, Wn, Wm {, shift #amount}

拡張レジスタ

    ADD   Xd, Xn, Wm {,extend {#amount}}
    ADD   Xd, Xn, Xm {,extend {#amount}}

拡張するデータはbyte, halfword, word, doublewordが可能

### 加減算
Add

    ADD    Xd, Xn, Xm {,shift #amount}
    ADD    Wd, Wn, Wm {,shift #amount}

    ADD    Xd|SP,  Xn|SP,  #uimm12 {, LSL #12}
    ADD    Wd|WSP, Wn|WSP, #uimm12 {, LSL #12}

    ADD    Xd|SP,  Xn|SP,  Rm {,extend {#amount}}
    ADD    Wd|WSP, Wn|WSP, Rm {,extend {#amount}}

ADDS

    ADDS   Xd, Xn, Xm {,shift #amount}
    ADDS   Wd, Wn, Wm {,shift #amount}

    ADDS   Xd|SP,  Xn|SP,  #uimm12 {,LSL #12}
    ADDS   Wd|WSP, Wn|WSP, #uimm12 {,LSL #12}

    ADDS   Xd|SP,  Xn|SP,  Rm {,extend {#amount}}
    ADDS   Wd|WSP, Wn|WSP, Rm {,extend {#amount}}

SUB

    SUB    Xd, Xn, Xm {,shift #amount}
    SUB    Wd, Wn, Wm {,shift #amount}

    SUB    Xd|SP,  Xn|SP,  #uimm12 {,LSL #12}
    SUB    Wd|WSP, Wn|WSP, #uimm12 {,LSL #12}

    SUB    Xd|SP,  Xn|SP,  Rm {,extend {#amount}}
    SUB    Wd|WSP, Wn|WSP, Rm {,extend {#amount}}

NEG

    NEG    Xd, Xm {,shift #amount}      // SUB   Xd, XZR, Xm {,shift #amount} と同じ
    NEG    Wd, Wm {,shift #amount}      // SUB   Xd, WZR, Xm {,shift #amount} と同じ

SUBS

    SUBS   Xd, Xn, Xm {,shift #amount}
    SUBS   Wd, Wn, Wm {,shift #amount}

    SUBS   Xd|SP,  Xn|SP,  #uimm12 {, LSL #12}
    SUBS   Wd|WSP, Wn|WSP, #uimm12 {, LSL #12}

    SUBS   Xd|SP,  Xn|SP,  Rm {,extend {#amount}}
    SUBS   Wd|WSP, Wn|WSP, Rm {,extend {#amount}}

NEGS

    NEGS   Xd, Xm {,shift #amount}      // SUBS Xd, XZR, Xm {,shift #amount} と同じ 
    NEGS   Wd, Wm {,shift #amount}      // SUBS Wd, WZR, Wm {,shift #amount} と同じ 

CMP

    CMP  Wn|WSP, #imm {,shift}           // SUBS WZR, Wn|WSP, #imm {,shift} と同じ
    CMP  Xn|SP, #imm {,shift}            // SUBS XZR, Xn|SP, #imm {,shift} と同じ

    CMP  Wn|WSP, Wm {,extend {#amount}}  // SUBS WZR, Wn|WSP, Wm {,extend {#amount}} と同じ
    CMP  Xn|SP, R m {,extend {#amount}}  // SUBS XZR, Xn|SP, R m {,extend {#amount}} と同じ

    CMP  Wn, Wm {,shift #amount}         // SUBS WZR, Wn, Wm {,shift #amount} と同じ
    CMP  Xn, Xm {,shift #amount}         // SUBS XZR, Xn, Xm {,shift #amount} と同じ

CMN

  CMN   Wn|WSP, #imm {,shift}            // ADDS WZR, Wn|WSP, #imm {,shift}と同じ
  CMN   Xn|SP, #imm {,shift}             // ADDS XZR, Xn|SP, #imm {,shift}と同じ

  CMN   Wn|WSP, Wm {,extend {#amount}}   // ADDS WZR, Wn|WSP, Wm {,extend {#amount}}と同じ
  CMN   Xn|SP,  Rm {,extend {#amount}}   // ADDS XZR, Xn|SP, Rm {,extend {#amount}}と同じ

  CMN   Wn, Wm {,shift #amount}          // ADDS WZR, Wn, Wm {,shift #amount}と同じ
  CMN   Xn, Xm {,shift #amount}          // ADDS XZR, Xn, Xm {,shift #amount}と同じ

### キャリー込みの加減算
加減算でオーバーフロー (キャリー、桁あふれ) やアンダーフロー (ボロー、桁借り) のために NZCV レジスタの C ビットがキャリーとして使用される

キャリーを含めて加算。 キャリーフラグが 1 のときに 1 が余分に加算される

    ADC     Rd, Rn, Rm
    ADCS    Rd, Rn, Rm

キャリーフラグとキャリー込の減算例

.include        "debug.s"
.text
.global _start
_start:
        mov     x1, #0x8000000000000000
        adds    x0, x1, x1
        PRINTFLAGS
        adc     x0, xzr, xzr

        bl      PrintLeft
        bl      NewLine
        bl      Exit

$ ld -o test test.o
$ ./test
nZCV
1

キャリー込みの減算

    SBC     Rd, Rn, Rm
    SBCS    Rd, Rn, Rm
.include        "debug.s"
.text
.global _start

_start:
        mov     x1, #1
        subs    x0, xzr, x1
        PRINTFLAGS
        sbc     x0, xzr, xzr

        bl      PrintLeft
        bl      NewLine
        bl      Exit

$ ./test
Nzcv
-1

### 乗算命令
32または64ビットの乗算
MADD/MUL : 2つのレジスタの積 (Rn * Rm) をレジスタ Ra に加算して、結果をレジスタ Rd に格納

    MADD   Wd, Wn, Wm, Wa  // Wd = Wa + (Wn * Wm)
    MADD   Xd, Xn, Xm, Xa  // Xd = Xa + (Xn * Xm)

    MUL    Wd, Wn, Wm      // MADD Wd, Wn, Wm, WZR の別名
    MUL    Xd, Xn, Xm      // MADD Xd, Xn, Xm, XZR の別名

MSUB/MNEG : 積差(Multiply-Subtract)演算は2つのレジスタの積 (Rn * Rm) をレジスタ Ra から減算して、結果をレジスタ Rd に格納

    MSUB   Wd, Wn, Wm, Wa  // Wd = Wa - (Wn * Wm)
    MSUB   Xd, Xn, Xm, Xa  // Xd = Xa - (Xn * Xm)

    MNEG   Wd, Wn, Wm      // MSUB Wd, Wn, Wm, WZR の別名
    MNEG   Xd, Xn, Xm      // MSUB Xd, Xn, Xm, XZR の別名

SMULH : 符号付上位乗算 (Signed Multiply High) は 2 つの 64 ビットレジスタ Xn と Xm を乗算し、その 128 ビットの乗算結果の上位 64 ビットをレジスタ (Xd) に書き込み

SMULH  Xd, Xn, Xm

UMULH : 符号なし上位乗算 (Unsigned Multiply High) は 2 つの 64 ビットレジスタを乗算し、その 128 ビットの乗算結果の上位 64 ビットをレジスタに書き込み

UMULH  Xd, Xn, Xm

SMADDL/SMUL : 2 つの 32 ビットのレジスタ Wn とWm の積を 64 ビットのレジスタ Xa と加算し、その結果を 64 ビットのレジスタ Xd に書き込み

    SMADDL Xd, Wn, Wm, Xa
    SMULL  Xd, Wn, Wm      // SMADDL Xd, Wn, Wm, XZR の別名

UMADDL/UMULL : 2 つの 32 ビットのレジスタ Wn とWm の積を 64 ビットのレジスタ Xa と加算し、その結果を 64 ビットのレジスタ Xd に書き込み

    UMADDL Xd, Wn, Wm, Xa
    UMULL  Xd, Wn, Wm      // UMADDL Xd, Wn, Wm, XZR の別名

SMSUBL/SMNEGL : 64 ビットのレジスタ Xa から 32ビットレジスタWn とWm の積を減算し、その結果を 64 ビットのレジスタ Xd に書き込み

    SMSUBL Xd, Wn, Wm, Xa  // Xd = Xa - (Wn * Wm)
    SMNEGL Xd, Wn, Wm      // SMSUBL Xd, Wn, Wm, XZR の別名

UMSUBL/UMNEGL : 64 ビットのレジスタ Xa から 32ビットレジスタWn とWm の積を減算し、その結果を 64 ビットのレジスタ Xd に書き込み

    UMSUBL Xd, Wn, Wm, Xa
    UMNEGL Xd, Wn, Wm      // UMSUBL Xd, Wn, Wm, XZR の別名

### 除算命令

    Rd = Rn / Rm

    mov     x2, #37
    mov     x3, #10
    sdiv    x0, x2, x3     // x0 = 37 / 10     --> 3
    msub    x4, x0, x3, x2 // x4 = 37 - 3 * 10 --> 7

SDIV

    SDIV  Wd, Wn, Wm
    SDIV  Xd, Xn, Xm

    mov     x5, #0x8000000000000000  // -9223372036854775808
    mov     x6, #-1                  // -1
    sdiv    x0, x5, x6               // x0 = -9223372036854775808

UDIV

    UDIV  Wd, Wn, Wm
    UDIV  Xd, Xn, Xm

論理演算
論理演算命令のアドレッシングモードには、シフトレジスタ、イミディエート(定数指定)、 拡張レジスタの3種類がある。命令によって使えるアドレッシングモードが異なる。

AND

    AND Wd|WSP, Wn, #imm
    AND Xd|SP,  Xn, #imm

    AND    Wd, Wn, Wm {,shift #amount}
    AND    Xd, Xn, Xm {,shift #amount}

ANDS

    ANDS  Wd|WSP, Wn, #imm
    ANDS  Wd, Wn, Wm {,shift #amount}

    ANDS  Xd|SP, Xn, #imm
    ANDS  Xd, Xn, Xm {,shift #amount}

TST

    TST    Wn, #imm                 // ANDS   WZR, Xn, #imm と同じ
    TST    Wn, Wm {,shift #amount}  // ANDS  WZR, Wn, Wm {,shift #amount} と同じ

    TST    Xn, #imm                 // ANDS   XZR, Xn, #imm と同じ
    TST    Xn, Xm {,shift #amount}  // ANDS  XZR, Xn, Xm {,shift #amount} と同じ

ORR : レジスタとレジスタ、またはレジスタと定数のビット単位の論理和を実行

    ORR  Wd|WSP, Wn, #imm
    ORR  Wd, Wn, Wm {,shift #amount}

    ORR  Xd|SP, Xn, #imm
    ORR  Xd, Xn, Xm {,shift #amount}

ORN: Rn レジスタの値と、 Rm レジスタを反転した値との間で論理和を求め、 結果を Rd レジスタに書き込み

    ORN  Xd, Xn, Xm {,shift #amount}
    ORN  Wd, Wn, Wm {,shift #amount}

EOR: レジスタとレジスタ、またはレジスタと定数のビット単位の排他的論理和を実行

    EOR  Wd|WSP, Wn, #imm
    EOR  Wd, Wn, Wm {,shift #amount}

    EOR  Xd|SP, Xn, #imm
    EOR  Xd, Xn, Xm {,shift #amount}

EON: Rn レジスタの値と、 Rm レジスタを反転した値との間で論理和

    EON  Xd, Xn, Xm {,shift #amount}
    EON  Wd, Wn, Wm {,shift #amount}

BIC: BIC命令は、ビット単位で指定したビットをクリア

    BIC  Wd, Wn, Wm {,shift #amount}
    BIC  Xd, Xn, Xm {,shift #amount}

BICS: Rn レジスタの値と、 Rm レジスタを反転した値との間で論理積を求め、結果を Rd レジスタに書き込み

    BICS Wd, Wn, Wm {,shift #amount}
    BICS Xd, Xn, Xm {,shift #amount}

[Arm64] MOV命令

レジスタに格納されているデータを別のレジスタに格納

SP-汎用レジスタ間

    MOV     Wd|WSP, Wn|WSP  // ADD Wd|WSP, Wn|WSP, #0 の別名
    MOV     Xd|SP, Xn|SP    // ADD Xd|SP, Xn|SP, #0 の別名

汎用レジスタ間

    MOV     Wd, Wm          // ORR Wd, WZR, Wm の別名
    MOV     Xd, Xm          // ORR Xd, XZR, Xm の別名

定数

    // x0  <-- 0x0123456789ABCDEF
    movz    x0, #0xCDEF
    movk    x0, #0x89AB, LSL #16
    movk    x0, #0x4567, LSL #32
    movk    x0, #0x0123, LSL #48

ビットマスクイミディエート

    MOV     Wd|WSP, #imm   // ORR Wd|WSP, WZR, #imm の別名
    MOV     Xd|SP, #imm    // ORR Xd|SP, XZR, #imm の別名

MOVK

    MOVK  Wd, #imm16 {,LSL #shift}
    MOVK  Xd, #imm16 {,LSL #shift}

16 ビットの定数をビット反転してレジスタに設定

  MOVN Wd, #uimm16 {,LSL #shift}
  MOVN Xd, #uimm16 {,LSL #shift} 

16 ビットの定数をビット反転してレジスタに設定
命令エンコードはzが1ならば64ビットレジスタ、sft は 0, 16, 32, 48 のシフト量に対応

レジスタに定数を設定する MOV命令は、定数値によりアセンブラが ORR、MOVZ、MOVN、MOVK を選択して使う

[Arm64] ストア命令

ストア命令(STR)はレジスタに格納されている値をメモリに書き込む
転送元 Wt, Xt
命令 STR, STR, STRH, STRB

### (1)STR ダブルワード(64ビット) → 64ビット
64ビットレジスタのデータをメモリにコピー

  STR   Xt, [base], #simm9      // ポストインデックス
  STR   Xt, [base, #simm9]!     // プレインデックス
  STUR  Xt, [base {,#simm9}]    
  STR   Xt, [base {,#uimm12}]  
  STR   Xt, [base, Wm {,SXTW|UXTW {#0 | #3}} ]  // レジスタオフセット
  STR   Xt, [base, Xm {,LSL|SXTX {#0 | #3}} ]   // レジスタオフセット

### (2)STR ワード(32ビット) → 32ビット

  STR   Wt, [base], #simm9       // ポストインデックス
  STR   Wt, [base, #simm9]!      // プレインデックス
  STUR  Wt, [base {,#simm9} ]    
  STR   Wt, [base {,#imm12} ]    
  STR   Wt, [base, Wm {,SXTW|UXTW {#0 | #2}} ]  // レジスタオフセット
  STR   Wt, [base, Xm {,LSL|SXTX {#0 | #2}} ]   // レジスタオフセット

### (3)STRH ハーフワード(32ビット) → 16ビット

  STRH  Wt, [base], #simm9      // ポストインデックス
  STRH  Wt, [base, #simm9]!     // プレインデックス
  STURH Wt, [base {,#simm9}]
  STRH  Wt, [base {,#uimm12}]   // 符号なしオフセット
  STRH  Wt, [base, Wm {,SXTW|UXTW {#0 | #1}} ]  // レジスタオフセット
  STRH  Wt, [base, Xm {,LSL|SXTX {#0 | #1}} ]   // レジスタオフセット

### (4)STRB バイト(32ビット) → 8ビット

  STRB  Wt, [base], #simm9        // ポストインデックス
  STRB  Wt, [base, #simm9]!       // プレインデックス
  STURB Wt, [base {,#simm9}]
  STRB  Wt, [base {,#uimm12}]     // 符号なしオフセット
  STRB  Wt, [base, Wm {,SXTW|UXTW {#0}} ]  // レジスタオフセット
  STRB  Wt, [base, Xm {,LSL|SXTX {#0}} ]   // レジスタオフセット

### PC相対アドレス計算
ラベル位置のアドレスをレジスタに設定

ADR, ADRP

    ADR     Xd, label
    ADRP    Xd, label

### レジスタペアのロード/ストア命令

    LDP   Xt1, Xt2, [base,  #simm7]!     // プレインデックス
    LDP   Wt1, Wt2, [base,  #simm7]!     // プレインデックス

      // プレインデックス
      base = base + simm7;
      Rt1 = memory[base];
      Rt2 = memory[base + 4|8];

    LDP   Xt1, Xt2, [base], #simm7      // ポストインデックス
    LDP   Wt1, Wt2, [base], #simm7      // ポストインデックス

      // ポストインデックス
      Rt1 = memory[base];
      Rt2 = memory[base + 4|8];
      base = base + simm7;

    LDP   Xt1, Xt2, [base, #simm7]      // base への書き戻しなし
    LDP   Wt1, Wt2, [base, #simm7]      // base への書き戻しなし

      Rt1 = memory[base];
      Rt2 = memory[base + simm7];

LDPは連続したメモリから2つのレジスタに読み込む命令

    LDP   Xt1, Xt2, [base], #simm7
    LDP   Wt1, Wt2, [base], #simm7

    LDP     Xt1, Xt2, [base, #simm7]!
    LDP     Wt1, Wt2, [base, #simm7]!

    LDP     Xt1, Xt2, [Xn {, #simm7}]
    LDP     Wt1, Wt2, [Xn {, #simm7}]

STP命令は二つのレジスタの内容(Xt1, Xt2)をメモリアドレスを保持するレジスタ (Xn) にオフセットの値を加えたアドレスを先頭とするメモリに書き込み、レジスタをスタックに退避する場合によく使う

    STP     Xt1, Xt2, [base], #simm7
    STP     Wt1, Wt2, [base], #simm7
    STP     Xt1, Xt2, [base, #simm7]!
    STP     Wt1, Wt2, [base, #simm7]!
    STP     Xt1, Xt2, [base {, #simm7}]
    STP     Wt1, Wt2, [base {, #simm7}]

[Arm64] ロード命令

ロード命令(LDR)はメモリに格納されている値をレジスタに読み込み、ストア命令はレジスタに入っている値をメモリに書き出す

LDR : メモリからレジスタ
STR : レジスタからストア
MOV : レジスタからレジスタ

ロード/ストア命令は読み書きするメモリの位置を指定する必要があり、アドレッシングという
x86, x64, ARM, PowerPCによってアドレッシングの方法が異なる
ARM64ではイミディエートオフセットと レジスターオフセットなどがある。
ベースレジスタのオフセット(加算)を使用する
イミディエートオフセットは定数、レジスターオフセットはレジスタの格納された値

LDR Xt, [base, #simm9]

	base = base + simm9;
	Xt = memory[base];
LDR Xt, [base, #uimm12]
	Xt = [base + uimm12 * scale];

### レジスタオフセット
ベースレジスタ(Xn または SP)が保持しているメモリアドレスにインデックス用のレジスタが格納しているオフセット値を加えたメモリアドレスをXtにコピー

LDR Xt, [base, Wm {, SXTW|UXTW {#0|#3}}]
LDR Xt, [base, Xm {, LSL|SXTX {#0|#3}}]

	Xt = memory[base + {* 8}];

### ロード命令
メモリが64, 32, 16, 8ビットあり、レジスタが32ビット(Wt)と64ビット(Xt)があるため、ビットに応じてそれぞれ命令がある
ビット幅を増やすには符号拡張とするか、ゼロ拡張を行う

### ロード命令の詳細
6種類のアドレッシング
9ビット符号付即値+ポストインデックス
9ビット符号付即値+プレインデックス
9ビット符号付即値
12ビット符号なし即値
32ビットレジスタオフセット
64ビットレジスタオフセット

### (1)LDR ダブルワード(64ビット) → 64ビット

  LDR   Xt, [base], #simm9       // ポストインデックス
  LDR   Xt, [base,  #simm9]!     // プレインデックス
  LDUR  Xt, [base,  #simm9]
  LDR   Xt, [base {,#uimm12} ]   // 符号なしオフセット(8の倍数) [0 - 32760] 
  LDR   Xt, [base, Wm {,SXTW|UXTW {#0 | #3}} ]  // レジスタオフセット
  LDR   Xt, [base, Xm {,LSL|SXTX {#0 | #3}} ]  // レジスタオフセット

### (2)LDR ワード(32ビット) → 32ビット

  LDR   Wt, [base], #simm9     // ポストインデックス
  LDR   Wt, [base,  #simm9]!   // プレインデックス
  LDUR  Wt, [base,  #simm9]
  LDR   Wt, [base {,#uimm12} ]  // 符号なしオフセット(4の倍数) [0 - 16380] 
  LDR   Wt, [base, Wm {,SXTW|UXTW {#0 | #2}} ] 
  LDR   Wt, [base, Xm {,LSL|SXTX {#0 | #2}} ] 

### (3)LDRSW 符号付きワード(32ビット) → 64ビット

  LDRSW  Xt, [base], #simm9     // ポストインデックス
  LDRSW  Xt, [base,  #simm9]!    // プレインデックス
  LDURSW Xt, [base,  #simm9]
  LDRSW  Xt, [base {,#uimm12} ]  // 符号なしオフセット(4の倍数) [0 - 16380]
  LDRSW  Xt, [base, Wm {,SXTW|UXTW {#0 | #2}} ]
  LDRSW  Xt, [base, Xm {,LSL|SXTX {#0 | #2}} ]

### (4)LDRH ハーフワード(16ビット) → 32ビット

  LDRH  Wt, [base], #simm9      // ポストインデックス
  LDRH  Wt, [base,  #simm9]!     // プレインデックス
  LDURH Wt, [base,  #simm9]
  LDRH  Wt, [base {,#uimm12} ]   // 符号なしオフセット(2の倍数) [0 - 8190]
  LDRH  Wt, [base, Wm {,SXTW|UXTW {#0 | #1}} ]
  LDRH  Wt, [base, Xm {,LSL|SXTX  {#0 | #1}} ]

### (5) LDRSH 符号付きハーフワード(16ビット) → 32ビット

  LDRSH  Wt, [base], #simm9     // ポストインデックス
  LDRSH  Wt, [base,  #simm9]!   // プレインデックス
  LDURSH Wt, [base,  #simm9]
  LDRSH  Wt, [base {,#uimm12} ]  // 符号なしオフセット(2の倍数) [0 - 8190]
  LDRSH  Wt, [base, Wm {,SXTW|UXTW {#0 | #1}} ] 
  LDRSH  Wt, [base, Xm {,LSL|SXTX  {#0 | #1}} ] 

### (6) LDRSH 符号付きハーフワード(16ビット) → 64ビット

  LDRSH  Xt, [base], #simm9     // ポストインデックス
  LDRSH  Xt, [base,  #simm9]!   // プレインデックス
  LDURSH Xt, [base,  #simm9]
  LDRSH  Xt, [base {,#uimm12} ]  // 符号なしオフセット(2の倍数) [0 - 8190]
  LDRSH  Xt, [base, Wm {,SXTW|UXTW {#0 | #1}} ] 
  LDRSH  Xt, [base, Xm {,LSL|SXTX {#0 | #1}} ] 

### (7)LDRB バイト(8ビット) → 32ビット

  LDRB  Wt, [base], #simm9     // ポストインデックス
  LDRB  Wt, [base,  #simm9]!    // プレインデックス
  LDURB Wt, [base,  #simm9]
  LDRB  Wt, [base {,#uimm12} ]  // 符号なしオフセット [0 - 4095]
  LDRB  Wt, [base, Wm {,SXTW|UXTW {#0}} ]
  LDRB  Wt, [base, Xm {,LSL|SXTX  {#0}} ]

### (8)LDRSB 符号付きバイト(8ビット) → 32ビット

  LDRSB  Wt, [base], #simm9     // ポストインデックス
  LDRSB  Wt, [base,  #simm9]!   // プレインデックス
  LDURSB Wt, [base,  #simm9]
  LDRSB  Wt, [base {,#uimm12} ]  // 符号なしオフセット [0 - 4095]
  LDRSB  Wt, [base, Wm {,SXTW|UXTW {#0}} ] 
  LDRSB  Wt, [base, Xm {,LSL|SXTX {#0}} ] 

### (9)LDRSB 符号付きバイト(8ビット) → 64ビット

  LDRSB  Xt, [base], #simm9     // ポストインデックス
  LDRSB  Xt, [base,  #simm9]!   // プレインデックス
  LDURSB Xt, [base,#simm9]
  LDRSB  Xt, [base {,#uimm12} ]  // 符号なしオフセット [0 - 4095]
  LDRSB  Xt, [base, Wm {,SXTW|UXTW {#0}} ] 
  LDRSB  Xt, [base, Xm {,LSL|SXTX  {#0}} ] 

### PC相対リテラルアドレッシング
ラベルの位置にあるデータをレジスタに読み込む

LDR     Xt, label
LDRSW   Xt, label
LDR     Wt, label

[Arm64] レジスタ

31本の汎用レジスタ、スタックポインタ、ゼロレジスタ、プログラムカウンタ、フラグレジスタ、32本のVectorレジスタ、浮動小数点を制御するFPCRレジスタ、FPSRレジスタを持っている

### 汎用レジスタ
x0からx30となっている
wで指定すると32ビットレジスタとして使用できる

### スタックポインタ、ゼロレジスタ、プログラムカウンタ
スタックトップのアドレスを保持するスタックポインタ、常にビットが0になっているゼロレジスタ、実行中のメモリアドレスを保持するプログラムカウンタがある

### NZCV レジスタ (フラグレジスタ)
演算命令の結果を保持するフラグはNZCVレジスタに保持される
条件分岐命令は、レジスタの各ビットの状態で分岐するかしないかを決定する
EQ, NE, CS, CC, MI, PL, VS, VC, HI, LS, GE, LT, GT, LE, AL

### Vectorレジスタ
複数のベクトル要素を同時演算するためにある 0~31の値

### FPCRレジスタ、FPSRレジスタ

レジスタとはマイクロプロセッサ(MPU/CPU)内部にある演算や実行状態の保持に用いる記憶素子