X86 寄存器及寻址方式
X86 寄存器及寻址方式
絮絮叨叨:之前看的汇编都是 ARM Cotex M 系列,在调试任务切换时,不得不学习一下 x86 的汇编。
x86 寄存器列表
inter i386 平台下寄存器包括 8 个 32 位的通用寄存器、8 个调试寄存器、6 个 16 位的段寄存器、4 个 32 位的控制寄存器等寄存器。
使用最多的时 8 个通用寄存器,EAX、ECX、EDX、EBX、ESI、EDI、ESP、EBP 和一个程序指针寄存器 EIP。
8 个通用寄存器可以作为 16 位(字)或者 32 位(双字)进行访问,同时可以独立访问前四个寄存器(EAX、ECX、EDX、EBX)的低两字节。
x86 寄存器功能
x86 寄存器功能列表如下:
寄存器 | 功能 | 函数调用时 | 保护者 |
---|---|---|---|
eax | 累加器 | 作为返回值 | 调用者保护 |
ebx | 基地址寄存器 | 临时参数 | 被调用者保护 |
ecx | 计数器 | 第 4 个参数 | 调用者保护 |
edx | 中间数据寄存器 | 第 3 个参数 | 调用者保护 |
esi | 源变址寄存器 | 第 2 个参数 | 被调用者保护 |
edi | 目标变址寄存器 | 第 1 个参数 | 被调用者保护 |
ebp | 栈底指针 | - | 被调用者保存 |
esp | 栈顶指针 | - | - |
注:在 main 函数中调用函数 add ,main 为调用者,add 为被调用者。
在 main 函数调用 add 之前,应该将【EAX, ECX, EDX】保存到栈中。
在 add 函数中应该将【EBX, ESI, EDI, EBP】保存到栈中,在函数执行完成后,恢复原始数据。
操作数类型
在 x86 指令中,包括三类操作数:立即数、寄存器和存储器引用。
立即数:即常数,任何可以用 32 位寄存器表示的数,都可以作为立即数。
立即数使用前缀$
进行表示,后面可跟十进制或者十六进制。使用 $I_{mm}$ 代表任意立即数。
例如:$0x10
或者 $16
,都表示数字 16。
寄存器:用符号 $E_a$ 表示任意寄存器 a , 使用 $R[E_a]$ 表示寄存器 a 的值。
存储器引用:存储器引用表示存储器某个地址的数据。
用 $M[Addr]$ 表示地址 Addr 的值。
寻址方式
x86 包括 7 种寻址方式,分别为:_立即数寻址_、_寄存器寻址_、_绝对寻址_、_间接寻址_、_基址+偏移寻址_、_变址寻址_、_比例变址寻址_。
前三种寻址方式的表示即上面立即数的表示方式。
间接寻址:通过访问寄存器 $E_a$ 的值($R[E_a]$),访问对应地址的值。
使用符号 $M[R[E_a]]$ 表示。
例如:EAX
寄存器为 0x0001
,地址 0x0001
的值为0x1234
。
则 $M[R[E_{eax}]]$ 的值为0x1234
基址+偏移寻址:通过寄存器 $E_a$ 和立即数 $I_{mm}$ ,访问地址:$R[E_a]+I_{MM}$ 处的值。
使用符号 $M[I_{MM}+R[E_a]]$ 表示。
完整寻址方式见下表:
类型 |AT&T 语法格式| 操作数值| 名称|
|—|—|—|—|—|
|立即数| $$Imm$ |$Imm$ |立即数寻址|
|寄存器| $E_a$| $R[E_a]$ |寄存器寻址|
|存储器| $Imm$| $M[Imm]$ |绝对寻址|
|存储器| $(E_a)$| $M[R[E_a]] $|间接寻址|
|存储器| $Imm(E_b)$| $M[Imm+R[E_b]]$ |(基址+偏移量)寻址|
|存储器| $(E_b,E_i)$| $M[R[E_b]+R[E_i]]$ |变址寻址|
|存储器| $Imm(E_b,E_i)$|$ M[Imm+R[E_b]+R[E_i]]$ |变址寻址|
|存储器| $(,E_i,s)$ |$M[R[E_i]*s]$ |比例变址寻址|
|存储器| $Imm(,E_i,s)$| $M[Imm+R[E_i]*s]$ |比例变址寻址|
|存储器| $(E_b,E_i,s)$| $M[R[E_b]+R[E_i]*s] $|比例变址寻址|
|存储器| $Imm(E_b,E_i,s)$| $M[Imm+R[E_b]+R[E_i]*s]$ |比例变址寻址|
立即数 $Imm$、基址寄存器 $E_b$、变址寄存器 $E_i$、比例因子 $s$(其值为 1、2、4、8)。