常见汇编指令
0x0. 引言
好记性不如烂笔头,本文旨在记录一些日常工作中经常会遇到的汇编指令,并会不断更新。目前只包含ARM和AT&T两种格式,以ARM64为主。
0x1. ARM64
mov
传送指令:将立即数传送到寄存器/内存单元,或互传内存单元和寄存器两者中的数据。
例如:mov x0, #0x1
/ mov $0x1, %rdi
将立即数0x1移动到寄存器x0/rdi中
mvn
该指令与mov唯一不同的是:需要对操作数进行按位取反。
str
store register. 将寄存器中的数据存到内存单元中。
例如:str x0, [sp, #0x28]
将寄存器x0中的数据存到地址sp+0x28处
stp
store pair of registers.
例如:stp x29, x30, [sp, #0x70]
先将x29存到地址sp+0x70处,再将x30存到sp+0x78处 (Tip1)。
Tip1: 64位下,寄存器大小为8bytes
ldr
load register. 从内存中读取数据,存到寄存器中。
例如:ldr x1, [sp, #0x30]
将内存地址sp+0x30处的数据加载到x1中。
ldp
load pair of registers.
例如:ldp x29, x30, [sp, #0x70]
将内存地址sp+0x70处的数据加载到x29中,再将sp+0x78(Tip1)处的数据加载到x30中。
b
branch. 无条件跳转。
例如:b 0x1b6b79cf8
跳转到0x1b6b79cf8
处继续执行。
bl
branch with link. 将下一条指令地址copy到lr中,然后跳转。由于保存了下一条指令地址(相对于pc),所以可实现子程序的返回,而b只能单纯的实现跳转,不能实现子程序返回。
例如:
0x102b7d8a4 <+160>: bl 0x102bda450 ; symbol stub for: objc_msgSend
-> 0x102b7d8a8 <+164>: adrp x0, 107
2
当程序执行完bl指令时,lr中的内容应该是是bl下一条指令的地址,即0x102b7d8a8
。通过控制台查看lr中的内容如下:
fp = 0x000000016d2853c0
lr = 0x0000000102b7d8a8 `-[AppDelegate application:didFinishLaunchingWithOptions:] + 164 at AppDelegate.m:41:5
sp = 0x000000016d285350
2
3
cbz
compare and branch on zero. 比较操作数是否为0,若为0则跳转。
例如:cbz w24, 0x1b6b798f4
若w24 (x24寄存器低32位) 中的数据为0,则跳转到0x1b6b798f4
处执行 (Note1)。
Note1: 跳转地址需要在cbz/cbnz指令之后的4~130字节内。
cbnz
compare and branch on non-zero. 操作数不为0,则跳转。
例如:cbnz w27, 0x1b73c9e2c
若w27中的数据不为0,则跳转到0x1b73c9e2c
处执行 (Note1)。
lsl
logical shift left. 左移位。
例如:str x0, [x1, x2, lsl #2]
将x2中的值左移两位,再加上x1中的值,得到的结果为一个内存地址,最后将x0中的数据存到该内存中。
lsr
logical shift right. 右移位。
cmp
compare. 比较两个数是否相等,首先将两个数相减,若差为0,则ZF (Tip2) 为1,即两者相等。
cmp w8, #0x3
通过判断w8中的值与0x3的差值是否为0,即ZF (Tip2) 是否为1,来比较两者是否相等。
Tip2: ZF是零标志位寄存器。它记录相关指令执行后,其结果是否为0。若结果为0,则ZF=1;若结果为1,则ZF=0。
adrp
form pc-relative address to 4KB page. 先将操作数左移12位,再将pc的低12位清零 (即3个十六进制位清零,得到一个页对齐地址),最后两者相加,赋值给寄存器。
例如:
0x1b703f074 <+44>: adrp x20, 270332
-> 0x1b703f078 <+48>: ldr x0, [x20, #0x7a0]
2
执行adrp时,先将操作数270332 (十六进制为0x41ffc
) 左移12位得到0x41ffc000
,再将pc (0x1b703f074
) 低12清零得到 0x1b703f000
,最后两者相加得到0x1f903b000
赋值给x20。通过控制台查看x20中的内容:
x19 = 0x000000016ef25fb0
x20 = 0x00000001f903b000
x21 = 0x0000000281454380
2
3
adr
load a program-relative or register-relative address into a register. 是一条伪指令,遇到该指令时汇编器会生成一条add或sub指令,来计算pc和操作数的和或者差,最后将得到的结果,放在寄存器中。
例如:
; 生成加法指令,即x0 = 0x1022c3b08 + 0x2fc48 = 0x1022f3750
0x1022c3b08 <+108>: adr x0, #0x2fc48 ; _MergedGlobals + 16
-> 0x1022c3b0c <+112>: nop
; 生成减法指令,即x2 = 0x1022c3b10 - 0x390 = 0x1022c3780
0x1022c3b10 <+116>: adr x2, #-0x390 ; initializeAvailabilityCheck
-> 0x1022c3b14 <+120>: nop
2
3
4
5
6
7
brk
breakpoint instruction. 用于生成断点指令异常。
tbz
test branch zero. 测试位为0,则跳转。
tbz w24, #0x6, 0x19307005c ; 即w24第6位,若为0,则跳转到0x19307005c执行
w24 二级制数为:0b00000111000000000000100000000110
tbnz
test branch no zero. 测试位不为0,则跳转。
tbnz w24, #0x6, 0x19307005c ; 即w24第6位,若不为0,则跳转到0x19307005c执行
w24 二级制数为:0b00000111000000000000100000000110
0x2. AT&T
test
将指令后的两个数进行按位与操作,其结果影响ZF。通常用来判断某个数是否为0/nil。
例如:
testq %rax, %rax ; 若%rax中的值为0,则ZF=1;反之,ZF=0,q表示四字长
sete
取ZF中的值,放入目标寄存器中。
例如:
testq %rax, %rax ; 两个寄存器中的值按位与,结果影响ZF
sete %r12 ; 若%rax和%rbx相等,即ZF=1,则将%r12设为1,反之设为0
2
setne
取ZF中的值,然后取反,再放入目标寄存器中。
例如:setne %rax
若ZF=1,则%rax设为0;反之设为1
je / jz
je 和 jz这两条指令虽然名字不同,但做的事情都是一样的。即ZF=1,则跳转。
例如:
libobjc.A.dylib`objc_retain:
0x7fff50bad350 <+0>: testq %rdi, %rdi ; 判断%rdi中的值(第一个参数)是否为nil
0x7fff50bad353 <+3>: je 0x7fff50bad371 ; <+33> 若%rdi为nil,则跳转到0x7fff50bad371执行
0x7fff50bad355 <+5>: js 0x7fff50bad373 ; <+35>
-> 0x7fff50bad357 <+7>: movq (%rdi), %rax
2
3
4
5
jne / jnz
jne 和 jnz这两条指令做的事情也都是一样的。即ZF=0,则跳转。
js
jump if sign. 若结果为负数,即SF=1,则进行跳转。
SF: 符号标志位
它记录相关指令执行后,其结果是否为负。若结果为负,则SF=1;若为非负,则SF=0。
nop
no operation. 不执行任何操作。是一条单字节指令。
Opcode 90
ud2
undefined instruction.
该指令用于生成一个无效操作码。当CPU试图执行无效或未定义的操作码时,将发生无效的操作码异常。UD2
指令除了引发无效的操作码异常外,与NOP
指令相同。
这里的异常是指CPU在发生“错误”时生成的。大多数情况下,有些异常并不是真正的错误,而是中断的一种类型。比如: Page Fault。异常分类如下:
- Faults (错误):这些错误可以被纠正,程序可以像什么都没有发生一样继续运行。
- Traps (陷阱):陷阱指令执行后会立即被报告。
- Aborts (终止):一些严重的不可恢复的错误。
ret
该指令用于子程序的返回。将栈顶数据(返回地址)弹出,赋值给 ip 寄存器,此时 sp 会增加一个内存单元大小,来释放栈空间。
栈底 [ ... | ... , parameters, return address | previous frame pointer, %rbp
] 栈顶
pop %rbp
👇
栈底 [ ... | ... , parameters, return address ] 栈顶
ret
👇
栈底 [ ... | ... , parameters ] 栈顶
caller release parameters
👇
栈底 [ ... | ... ] 栈顶
← 汇编入门必备