GAS (GNU Assembler) 是一款基于 Linux 的汇编器,主要供 GNU 项目使用,用于对 Linux 内核及其他软件进行进行汇编。
MASM (Microsoft Macro Assembler) 是微软操作系统的专属汇编器,于 1981 年随 Visual Studio 一起发布。
大学本科教育中有两门课可能涉及汇编语言的讲解,一门是《微机原理与接口技术》,一门是《计算机组成原理与汇编》,但它们讲解的往往是16位或32位指令集架构,分别以 Intel 8086 芯片和 80386 芯片为代表。随着64位系统的广泛应用,目前的主流架构转向了 x86_64,同时基于 Linux 系统的汇编环境与微软的汇编环境也不完全相同,因此有必要在大学课程基础上做一定扩展。
参考书籍:汇编程序设计与计算机体系结构:软件工程师教程
一、64位的寄存器
xx位 指的是 CPU 的通用寄存器(General Purpose Register)的数据宽度为 xx 位比特。
Note: 尽管当前的 x86_64 处理器是64位的,但只用到了低48位,因此理论上可以寻址 264 比特的地址空间,实际上只支持 248 比特。
64位 | 32位 | 64位 | 32位 | ||
---|---|---|---|---|---|
通用寄存器 | RAX | EAX | 段寄存器 | / | CS |
RBX | EBX | / | DS | ||
RCX | ECX | / | ES | ||
RDX | EDX | / | SS | ||
RSI | ESI | / | FS | ||
RDI | EDI | / | GS | ||
RBP | EBP | 指令指针寄存器 | RIP | EIP | |
RSP | ESP | 标志寄存器 | RFLAGS | EFLAGS | |
R8~R15 | / | / | / |
由上表可以看出共有四类寄存器:通用寄存器(64位有16个,32位有8个),段寄存器(64位没有段寄存器),指令指针寄存器和标志寄存器。汇编程序操作的一般都是通用寄存器。从16位发展到32位,再到64位,各个体系都做到向前兼容。因此在64位架构下,依然可以操作如 EAX 这样的32位寄存器,它对应的是 RAX 寄存器的低32位。当使用小位数寄存器的名义操作大位数寄存器时,实际上操作的是大位数寄存器中与小位数相对应那部分寄存器。
例如,以 AX 的名义操作 EAX,实际上操作的就是 EAX 的低16位,因此会破坏原本 EAX 中的部分数据。
1.1 部分寄存器有特殊用途
- rax/eax 通常是累加寄存器,一般数据不要保存在这类寄存器中。调用函数时的返回值应保存在 rax/eax 中。
- rcx/ecx 在循环过程中记录循环计数器的值,因此在循环内部不应使用这类寄存器保存一般数据。
- rbp/ebp 栈帧中的帧指针,用于指向栈中的数据。
- rsp/esp 栈帧中的栈指针,通常指向活动栈帧的顶部。
- rip/eip 是指令指针寄存器,指向接下来应获取、解码并执行的指令的内存地址,不应手动修改。
- rdi/edi 和 rsi/esi 是索引寄存器,用于字符串操作。
- rflags/eflags 是状态与控制寄存器,与 LAHF 以及 SAHF 指令配合使用,除此以外不可直接修改该寄存器。
rflags 中可用的只有低32位,因此 x86 与 x86_64 共用一套状态标志。