1. 寄存器、内存和寻址
1.寄存器和内存
寄存器(Register)是 CPU的组成部分,是有限存储容量的告诉存储部件,用来暂存指令、数据和地址。一般的IA-32即x86架构的处理器中包含以下几个寄存器:
- 通用寄存器:EAX、EBX、ECX、EDX、ESI、EDI。
- 栈顶指针寄存器:ESP、栈底指针寄存器:EBP。
- 指令计数器:EIP(保存下一条即将执行的指令的地址)。
- 段寄存器:CS、DS、SS、ES、FS、GS。
对于x86-64架构,在以上寄存器基础上,将前缀的E改成R,以标记64位,同时增加了R8~R15这八个通用寄存器。
除此之外,CPU中还存在一个标志寄存器,其中的每位表示对于标志位的值,常用标志位如下:
- AF:辅助进位标志,当运算结果在第3位时置1;
- PF:奇偶校验标志,当运算结果的最低有效字节有偶数个时置1;
- SF:符号标志,有符号整型的符号位为1时置1,代表是负数;
- ZF:零标志,当运算结果为全0时置1;
- OF:溢出标志,当运算结果在被操作数是有符号数且溢出时置1;
- CF:进位标志,运算结果向最高位以上进位时置1,用来判断无符号数的溢出。
2.CPU的寻址方式
寻址方式 | 示例 | 操作对象 |
立即寻址 | 1000h | 1000h这个数字 |
直接寻址 | [1000h] | 内存地址1000h的单元 |
寄存器寻址 | RAX | RAX这个寄存器 |
寄存器间接寻址 | [RAX] | 以RAX中存的数作为地址的内存单元 |
基址寻址 | [RBP+10h] | 将RBP中数作为基址,加10h,访问这个地址的内存单元 |
变址寻址 | [RDI+10h] | RDI中数字为基址+10h,访问这个地址的内存单元 |
基址加变址寻址 | [RBX+RSI+10h] | …… |
2.x86/x64汇编语言
x86和x64汇编指令的基本格式:操作码 [操作数1] [操作数2]
3. 反汇编
汇编语言中的条件跳转指令:
反汇编的两种算法:线性扫描反汇编算法和递归下降反汇编算法。线性扫描法从代码起始片段开始一个接一个地解析指令,直到结束;缺点是一旦有新数据插入到代码段中,后续的反汇编结果均为错误的。递归下降法则会尝试推测每条代码的执行结果。
4. 调用约定
x86 32位调用约定
- __cdecl:参数从右向左依次入栈,调用完毕,由调用者负责将这些压入栈的参数清理,返回值置于EAX中。
- __stdcall:参数从右向左依次入栈。同上。
- __thiscall:为类方法专门优化的调用约定,将类方法的this指针放在ECX寄存器中,然后将其他参数压栈。
- __fastcall:为加速调用而生的调用约定,将第一个参数放在ECX中,第二个放在EDX中,然后将后续参数从右至左入栈。
x86 64位调用约定
- Windows中:依次从左至右将前四个参数放入RCX、RDX、R8、R9这四个寄存器,然后将其余参数从右至左压入栈中。
- Linux和MacOS:使用RDI、RSI、RDX、RCX、R8、R9这六个寄存器传递前6个参数,其余从右至左入栈。
5.局部变量
局部变量在函数调用时一同临时存储在栈中,每个函数存在的一片栈区域叫做栈帧,一个函数中每个局部变量相对于该函数栈帧的偏移都是固定的,所以引入一个寄存器专门存储栈帧的位置,即EBP。