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 寄存器功能

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)。


X86 寄存器及寻址方式
https://gary-hobson.github.io/2022/09/04/X86寄存器寻址方式/
作者
非典型技术宅
发布于
2022年9月4日
许可协议