寄存器
早期的 x86 CPU 只有 8 个寄存器(eax 、ebx、ecx、edx、esi、edi、ebp、esp),而且每个都有不同的用途。
| 寄存器名称 | 含义 | 用途 | 包含寄存器 |
|---|---|---|---|
eax |
累加(Accumulator)寄存器 |
常用于乘除法和函数返回值 |
ax(ah、al) |
ebx |
基址(Base)寄存器 |
常以它为基址来访问内存 |
bx(bh、bl) |
ecx |
计数器(Counter)寄存器 |
常做字符串和循环操作中的计数器 |
cx(ch、cl) |
edx |
数据(Data)寄存器 |
常用于乘除法和 I/O 指针 |
dx(dh、dl) |
esi |
来源索引(Source Index)寄存器 |
常用于内存数据指针和源字符串指针 | si |
edi |
目的索引(Destination Index)寄存器 |
常用于内存数据指针和源字符串指针 | di |
ebp |
基址指针(Base Pointer)寄存器 |
只做堆栈指针,可以访问堆栈内任意地址,经常用于中转 ESP 中的数据,也常以它为基址来访问堆栈;不能用于算术运算与数据传送 |
bp |
esp |
堆栈指针(Stack Pointer)寄存器 |
只做堆栈的栈顶指针,不能用于算术运算与数据传送 | sp |
栈帧中,最重要的是帧指针
ebp和栈指针esp,有了这两个指针,我们就可以刻画一个完整的栈帧。
x86-64 中,所有寄存器都是 64 位,相对 32 位的 x86 来说,标识符发生了变化,比如:从原来的 eax 变成了 rax。为了向后兼容性,eax 依然可以使用,不过指向了 rax 的低 32 位。
比如在 64 位 CPU 上:
-
rax是 64 位的寄存器 -
rax是rax的低 32 位 -
ax是rax的低 16 位 -
ah是ax的高 8 位。 -
al是ax的低 8 位。
它们的对照关系如下:
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
|=================================RAX=================================|---8个字节
|===============EAX===============|---4个字节
|======AX=======|---2个字节
|==AH===|-----------1个字节
|===AL==|---1个字节
通过 gdb 的 p /x $reg 命令打印寄存器的值。
(gdb) p /x $rax
$16 = 0x555555554870
(gdb) p /x $eax
$12 = 0x55554870
(gdb) p /x $ax
$13 = 0x4870
(gdb) p /x $ah
$14 = 0x48
(gdb) p /x $al
$15 = 0x70
汇编指令
1. 数据传送指令
| 指令 | 名称 | 语法 | 描述 |
|---|---|---|---|
mov |
数据传送指令 | mov dest, src |
将数据从 src 移动到 dest
|
push |
入栈指令 | push src |
将源操作数 src 压入堆栈 |
pop |
入栈指令 | pop dest |
从栈顶弹出数据到 dest
|
1.1 mov 指令
mov 指令是最常见的数据传送指令,类似于高级语言中的赋值语句。
mov 指令可以实现寄存器与寄存器之间、寄存器与内存之间、寄存器与立即数、内存与立即数的数据传递。
需要注意的是,内存与内存无法直接传递数据,目的操作数不能为立即数。
mov 指令的用法示例如下:
mov eax, 12345678h
mov eax, [00401000h]
mov eax, ebx
mov [00401000h], 12345678h
mov [00401000h], eax
1.2 push 和 pop 指令
push 指令和 pop 指令互为相反的操作指令。
-
push指令的功能是将操作数压入堆栈。 -
pop指令的功能是将栈顶的操作数弹出。
push 指令把一个 32 位的操作数送入堆栈,该操作致使 esp 寄存器的值减 4。
esp 寄存器始终指向栈顶。堆栈的方向是由高地址向低地址进行延伸,也就是执行的 push 次数越多,esp 寄存器指向的地址越小。
在 32 位平台上,每执行一次 push 指令,esp 指向的地址都减小 4 字节。
pop 指令把 esp 指向地址(栈顶)中的值送入寄存器或内存中,然后 esp 指向的地址加 4 字节。
执行的 pop 指令越多,esp 寄存器指向的地址越大。
(2)算术运算指令
| 指令 | 名称 | 语法 | 描述 |
|---|---|---|---|
add |
加法指令 | add dest, src |
在 dest 基础上加 src
|
sub |
减法指令 | sub dest, src |
在 dest 基础上减 src
|
inc |
加 1 指令 | inc dest |
在 dest 基础上加 1 |
dec |
减 1 指令 | dec dest |
在 dest 基础上减 1 |
(3)逻辑运算指令
| 指令 | 名称 | 语法 | 描述 |
|---|---|---|---|
not |
取反运算指令 | not dest |
把操作数 dest 按位取反 |
and |
与运算指令 | and dest, src |
把 dest 和 src 进行与预算之后送回 dest
|
or |
与运算指令 | or dest, src |
把 dest 和 src 进行或预算之后送回 dest
|
xor |
与运算指令 | xor dest, src |
把 dest 和 src 进行异或预算之后送回 dest
|
(4)循环控制指令
| 指令 | 名称 | 语法 | 描述 |
|---|---|---|---|
loop |
计数循环指令 | loop label |
使 ecx 寄存器的值减 1,当 ecx 寄存器的值不为 0 的时候跳转至 lable,否则执行 loop 之后的语句 |
(5)转移指令
| 指令 | 名称 | 语法 | 描述 |
|---|---|---|---|
jmp |
无条件转移指令 | jmp label |
无条件跳转至标号为 lable 的位置 |
call |
过程调用指令 | call label |
直接调用 lable
|
je |
条件转移指令 | je label |
zf = 1 时跳转至标号为 lable 的位置 |
jne |
条件转移指令 | jne label |
zf = 0 时跳转至标号为 lable 的位置 |













网友评论