
寄存器基础16 位时代8086通用寄存器就是 16 位——AX、BX、CX、DX、SI、DI、BP、SP外加指令指针 IP。32 位时代80386加前缀EExtended扩展→ EAX、EBX、ECX、EDX、ESI、EDI、EBP、ESP、EIP。64 位时代AMD64 / Intel 64前缀换成RRegister→ RAX、RBX……RSP、RIP并新增 R8–R15。命名是层层包含的RAX 的低 32 位就叫 EAXEAX 的低 16 位就叫 AXAX 再拆成高字节 AHHighbit 15–8和低字节 ALLowbit 7–0。ESPStack Pointer栈指针指向当前栈顶——也就是栈上已使用的最低地址。x86 的栈向低地址方向增长所以push做esp - 4pop做esp 4。EBPBase Pointer帧指针指向当前栈帧的基址是访问局部变量和参数的锚点。标准函数序言是push ebp/mov ebp, esp之后局部变量用[ebp-4]、[ebp-8]访问参数用[ebp8]访问尾声再mov esp, ebp/pop ebp/ret。EIPInstruction Pointer指令指针等价于其他架构的 PC程序计数器指向下一条将要执行的指令地址。关键区别它不能用MOV直接读写只能被JMP、CALL、RET、中断/异常改变。CALL会把下一条指令的地址即 EIP 的当前值压栈RET再把它弹回 EIP核心指令MOV —— 数据搬运语法mov 目的, 源把源操作数复制一份到目的操作数源本身不变。可以是寄存器 ↔ 寄存器mov eax, ebx立即数 → 寄存器/内存mov eax, 123寄存器 ↔ 内存mov eax, [ebx]/mov [ebx], eax硬性限制不能两个操作数都是内存——mov [eax], [ebx]非法必须经过一个寄存器中转。不能直接改 CS / EIP——改它们只能靠跳转/调用指令。目的操作数的宽度必须明确——mov [eax], 1有歧义写 1 字节还是 4 字节要写mov byte [eax], 1或mov dword [eax], 1。LEA —— 算地址不读内存语法lea 目的, [地址表达式]leaLoad Effective Address直译加载有效地址mov eax, [ebx]把ebx指向的内存里的值读到 eax。lea eax, [ebx]把ebx这个地址本身算出来放进 eax根本不访问内存。JMP —— 无条件跳转语法jmp 目标直接把 EIP 改成目标地址不保存返回地址也不碰栈。近跳转段内jmp label或jmp eax间接跳转远跳转段间jmp far cs:ip改 CS 和 EIP用户态代码基本遇不到PUSH / POP —— 栈的入和出x86 栈向低地址增长ESP 始终指向栈顶最后一个压入的元素。push src做两件事esp - 432 位下栈以 4 字节为单位把 src 的值写入[esp]pop dst做两件事把[esp]的值读进 dstesp 4可以 push/pop 的操作数寄存器、内存、立即数立即数只能 push 不能 pop。CALL / RET —— 函数调用和返回这是一对配套指令本质上就是带返回地址的跳转。call 目标做三件事把 call 后面那条指令的地址也就是返回地址压入栈push eip_next跳转到目标地址jmp 目标注意EIP 不能直接赋值这是硬件内部操作。ret做一件事从栈顶弹出一个值放进 EIPpop eip所以call和ret必须配对——call压了什么ret就弹什么。如果栈上数据被改乱了ret会跳到错误的地址程序就崩了。