X86 汇编语言学习笔记

以 intel 上世纪推出的 8088/8086 处理器为切入点学习 X86 汇编语言

处理器与总线

X86 系列 CPU 的寄存器

在最初的 8086 系列 CPU 中仅有 14 个 16 位的寄存器,按功能可分为:8 个通用寄存器、4 个段寄存器和 2 个控制寄存器;通用寄存器又可以分为数据寄存器(AX, BX, CX, DX)、地址指针寄存器(BP, SP)、变址寄存器(SI, DI

1985年,intel 推出了 80386 处理器,这是 x86 系列的第一款 32 位处理器,主寄存器被扩展到了 32-bit。所有 32 位主寄存器的命名方式就是在原先寄存器名基础上加了一个 E。后来随着 AMD 在 2003 年推出第一款 x86-64 架构的 64 位处理器,主寄存器又被扩展到了 64-bit,也是在原先的基础上把 E 改成了 R,即 Register(如上图所示)。

此外,x86-64 架构也新增了 R8 ~ R15 寄存器,如同先前已有的寄存器那样,也可以访问其低位,分别用 \(\mathrm{R}x\mathrm{B}\)\(\mathrm{R}x\mathrm{W}\)\(\mathrm{R}x\mathrm{D}\) 来表示(Byte, Word, Double-word)

寻址方式

flowchart LR;
a(寻址方式) --- ima(立即寻址) & bva(基址变址寻址) & ta(隐含寻址)
bva --- da(直接寻址) & ia(间接寻址)
ia --- ra(寄存器间接寻址) & ma(存储器间接寻址)

立即寻址

由指令直接给出运算的数据(操作数是立即数),为常数形式或字符形式:

1
mov ax, 1200h ; 往 AX 寄存器写入 16 进制的 1200 这个立即数

基址变址寻址

方括号内表示偏移地址,由至多三个部分组成:基址寄存器内容 + 变址寄存器内容 + 位移量

  • 只有一个常数就是直接寻址:

    方括号里就是操作数的偏移地址,也就是被操作的数据在距某一段(默认为数据段)段首的偏移多少距离的内存单元里面

    1
    mov ax, [1200h] ; 操作的数据被存放在距 DS 1200 远的地方

    如果要人为指定逻辑段,可以用段重设

    1
    mov ax, es: [1200h] ; 操作的数据被存放在距 ES 1200 远的地方
  • 只有一个寄存器名就是寄存器间接寻址:

    需要注意的是,仅4个通用寄存器可用于存数据的偏移地址,即 BX, BP, SI, DI

    1
    mov ax, [bx] ; 把由 BX 存着的偏移地址上的内存单元数据送给 AX
  • 寄存器名 + 一个常数就是寄存器相对寻址:

    操作数的段地址(数据处于哪个段)取决于选择哪一个间址寄存器

    • BX, SI, DI : 默认在数据段
    • BP : 默认在堆栈段
  • 两个寄存器就是基址变址寻址:

    1
    2
    3
    mov al, [bx]5
    mov al, [bx + 5] ; 和上个语句完全一样
    mov ax, [bx][si] ; 相当于 BX + SI

隐含寻址

1
mul bl ; 隐含寻址,AL 和 BL 相乘送入 AX

指令系统

数据传送指令

flowchart TB;
cat(数据传送类指令) --- gm(通用数据传送指令) & io(输入输出指令) & am(地址传送指令) & fm(标志传送指令)

通用数据传送指令

一般数据传送指令

格式: \[\operatorname{mov}\;dest,\,src\]

将 src 中的数据传送给 dest,作个不太恰当的比方就是 C++ 中的

1
2
register int dest, src;
dest = src; // 把 src 赋值给 dest

但是需要注意几点:

  • 两操作数字长必须相同
  • 两操作数不允许同时为存储器操作数;
  • 两操作数不允许同时为段寄存器;
  • 在源操作数是立即数时,目标操作数不能是段寄存器;
  • IPCS 不作为目标操作数,FLAGS 一般也不作为操作数在指令中出现。

堆栈操作指令

格式: \[\operatorname{push}\;operand\qquad\operatorname{pop}\;operand\]

1
2
3
4
5
6
7
int* sp;

void push(byte[] operand) {
sp -= 2;
sp + 1 = operand[1];
sp = operand[0];
}

注意:

  • 操作数可以是寄存器或存储器两单元,但不能是立即数

交换指令

格式: \[\operatorname{xchg}\;reg,\,mem/reg\]

1
reg, mem = mem, reg

查表转换指令

格式: \[\operatorname{xlat}\]

所做操作是用 BX 的内容代表表格首地址,AL 内容为表内位移量,BX + AL 得到要查找元素的偏移地址

字位扩展指令

此类指令将符号数的符号位扩展到高位

算术运算指令

加法

普通加法指令 ADD

格式: \[\operatorname{add}\;operand_1,\,operand_2\]

operand1operand2 相加后,结果送入 operand1

1
2
register int operand1, operand2;
operand1 += operand2;

带进位的加法指令 ADC

和 ADD 指令一样,只不过还加了 CF 标志位;ADC 指令多用于多字节数相加,使用前要先将 CF 清零

自增指令 INC

格式: \[\operatorname{inc}\;operand\]

1
2
register int operand;
operand++;
未完待续
To be continued...

减法

乘法

除法

逻辑运算指令

串操作指令

程序控制指令

处理器控制指令


X86 汇编语言学习笔记
https://devexzh.github.io/2023/Note_Of_X86_Assembly_Language/
作者
Ryker Zhu
发布于
2023年8月15日
许可协议