Arm汇编指令汇总
本文最后更新于:2023年2月3日 晚上
Arm汇编指令汇总
本指令汇总主要由此文章总结得出,故若有对指令细节不理解的地方,可将文章作为参考。
需要说明的是,和AT&T风格的x86汇编相比,arm汇编的源操作数在右边,目的操作数在左边,而且运算指令基本上是需要指定目的地址的。(本文使用的是GUN风格的arm汇编,除此之外还有armasm风格的)
寄存器汇总
在AArch64架构下,有31个通用寄存器。这些通用寄存器可以作为大部分指令的操作数参与运算。
r0 ~ r7 : 传递参数或者返回值(第一个参数/返回值对应于r0,以此类推)
r8 : 用来存储多于的参数/返回值,并将其立即存入栈中
r16 : 用来存储系统调用编号(MacOS特有)
r18 : 平台保留的寄存器(Apple Silicon规定,我们不应该使用)
r19 ~ r28 : 被调用者保留的寄存器
r29 : FP寄存器
r30 : LR寄存器
还有一种寄存器比较特殊,叫做零寄存器:
wzr : 读取该寄存器的值,永远为0;向该寄存器写入数值将无效,也就是说无法向该寄存器写入数值
赋值指令
指令名 | 英文联想 | 指令作用 |
---|---|---|
mov | move | 将后一个变量值赋值给前一个 |
内存交互指令
指令名 | 英文联想 | 指令作用 |
---|---|---|
ldr | load register | 将源地址中的值存储到目的寄存器中 |
str | store register | 将寄存器中的值赋值给指定地址中 |
扩展指令
指令名 | 英文联想 | 指令作用 |
---|---|---|
sxtb | signed extense with byte | 有符号扩展一字节 |
sxth | signed extense with halfword | 有符号扩展两字节 |
sxtw | signed extense with word | 有符号扩展四个字节 |
uxtb | unsigned extense with byte | 无符号扩展一字节 |
uxth | unsigned extense with halfword | 无符号扩展两字节 |
uxtw | unsigned extense with word | 无符号扩展四个字节 |
运算指令
指令名 | 英文联想 | 指令作用 |
---|---|---|
add | add | 将第一个源操作数的值加上第二个源操作数的值返回给目的操作数 |
sub | substract | 将第一个源操作数的值减去第二个源操作数的值返回给目的操作数 |
and | and | 将第一个源操作数的值与上第二个源操作数的值返回给目的操作数 |
orr | or | 将第一个源操作数的值或上第二个源操作数的值返回给目的操作数 |
mvn | move not | 将源操作数的值取非返回给目的操作数 |
eor | exclusive or | 将第一个源操作数的值异或第二个源操作数的值返回给目的操作数 |
mul | multiply | 将第一个源操作数的值乘上第二个源操作数的值返回给目的操作数 |
smull | signed multiply | 将第一个源操作数的值乘上第二个源操作数的值返回给目的操作数(有符号) |
umull | unsigned multiply | 将第一个源操作数的值乘上第二个源操作数的值返回给目的操作数(无符号) |
sdiv | signed divide | 将第一个源操作数的值除以第二个源操作数的值返回给目的操作数(有符号) |
udiv | unsigned divide | 将第一个源操作数的值除以第二个源操作数的值返回给目的操作数(无符号) |
lsl | logical shift left | 将第一个源操作数的值左移第二个源寄存器的值返回给目的寄存器 |
比较指令
指令名 | 英文联想 | 指令作用 |
---|---|---|
cmp | compare | 将两数相减,并设置PSTATE |
tst | test | 将两数相与,并设置PSTATE |
跳转指令
指令名 | 英文联想 | 指令作用 |
---|---|---|
b | branch | 跳转到指定标签处 |
br | branch refer to register | 跳转到寄存器内的地址处 |
b.eq | branch if equal | 如果相等则跳转 |
b.ne | branch if not equal | 如果不相等则跳转 |
b.hi | branch if higher | 如果大于则跳转(无符号比较) |
b.hs | branch if higher or same | 如果大于等于则跳转(无符号比较) |
b.lo | branch if lower | 如果小于则跳转(无符号比较) |
b.ls | branch if lower or same | 如果小于等于则跳转(无符号比较) |
b.gt | branch if greater | 如果大于则跳转(有符号比较) |
b.ge | branch if greater or equal | 如果大于等于则跳转(有符号比较) |
b.lt | branch if less | 如果小于则跳转(有符号比较) |
b.le | branch if less or equal | 如果小于等于则跳转(有符号比较) |
bl | branch and link | 跳转至指定函数并将其返回地址写入r30 |
条件选择指令
指令名 | 英文联想 | 指令作用 |
---|---|---|
csel | conditional select | 根据condition将两个源操作数比较,以此来选择哪个原操作数给到目的操作数 |
LR、FP寄存器与栈交互
指令名 | 英文联想 | 指令作用 |
---|---|---|
stp | store pair of registers | 比如stp x29, x30, [sp] 表示将x29存储到sp,x30存储到sp + 8 |
ldp | load pair of registers | 比如ldp x29, x30, [sp] 表示将sp读取8字节至x29,sp + 8 读取8字节至x30 |
系统调用指令
指令名 | 英文联想 | 指令作用 |
---|---|---|
svc | supervisor call | 调用系统调用 |
参考代码
Fibonacci function:
.p2align 2
fibonacci:
sub sp, sp, #32
stp x29, x30, [sp, #16]
add x29, sp, #16
str w0, [x29, #-4]
cmp w0, #2
b.lt init_val
sub w0, w0, #1
bl fibonacci
str w0, [x29, #-8]
ldr w0, [x29, #-4]
sub w0, w0, #2
bl fibonacci
ldr w1, [x29, #-8]
add w0, w0, w1
ldp x29, x30, [sp, #16]
add sp, sp, #32
ret
init_val:
mov w0, #1
ldp x29, x30, [sp, #16]
add sp, sp, #32
ret
# hello.s
.section __TEXT,__text
.globl _main
.p2align 2
_main:
sub sp, sp, #16
stp x29, x30, [sp]
mov w0, #0 ; fd: STDOUT
adrp x1, _hello@PAGE
add x1, x1, _hello@PAGEOFF ; cbuf: "hello, world"
mov w2, #13 ; nbyte: 13
mov w16, #4 ; Syscall number: write
svc #0x80 ; write(STDOUT_FILENO, "hello, world", 13);
ldp x29, x30, [sp]
add sp, sp, #16
ret
.data
.p2align 2
_hello:
.asciz "hello, world"
需要注意的是,在macOS中,大部分的系统调用都是可以通过0x80这个数来调用,所以使用svc #0x80
即可。如果你想知道XNU内核所有的系统调用号,可以参考这里。
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!