x86-64 汇编学习笔记
一、Win64 汇编基础(hello, world 示例)
1. 核心代码解析
$SG2989 DB 'hello, world', 00H ; 定义字符串(C风格以0结尾) main PROC sub rsp, 40 ; 分配40字节:32字节影子空间 + 8字节对齐 lea rcx, OFFSET$SG2989 ; 传递字符串地址到rcx(Win64第1参数寄存器) call printf ; 调用printf输出字符串 xor eax, eax ; 设置main返回值为0 add rsp, 40 ; 释放栈空间 ret 0 main ENDP
2. 关键概念
影子空间(Shadow Space):Win64 调用约定要求调用者提前分配 32 字节,用于被调用函数备份寄存器参数,保证参数安全。
栈对齐:x86-64 要求
call执行后栈指针rsp保持 16 字节对齐,因此需要额外分配 8 字节,总分配 40 字节。寄存器用途:
rcx传递第 1 个参数,rax传递返回值,xor eax, eax是高效清零写法。
二、Win64 栈变化完整流程
| 操作 | 栈指针变化 | 说明 |
|---|---|---|
进入 main | rsp = 0x10000000(16 字节对齐) | 系统启动代码保证初始对齐 |
sub rsp, 40 | rsp = 0xFFFFFFD8 | 分配影子空间 + 对齐空间 |
call printf | 压入返回地址,rsp = 0xFFFFFFD0 | 保持 16 字节对齐 |
printf 执行 ret | 弹出返回地址,rsp = 0xFFFFFFD8 | 回到调用前栈位置 |
add rsp, 40 | rsp = 0x10000000 | 恢复初始栈状态 |
三、32 位 Windows 汇编示例(MessageBeep)
main: push 0xFFFFFFFF ; 传递错误提示音参数 call MessageBeep ; 播放错误提示音 xor eax, eax ; 返回值0 retn
四、Linux x86-64 AT&T 汇编示例(sleep)
main:
pushq %rbp ; 保存旧栈帧基址
movq %rsp, %rbp ; 建立新栈帧
movl$2, %edi ; 传递参数2到edi(Linux第1参数寄存器)
call sleep ; 休眠2秒
popq %rbp ; 恢复旧栈帧
ret
功能:让程序休眠 2 秒后退出。
五、常用寄存器速查表
| 64 位寄存器 | 32 位低半部分 | 主要用途 |
|---|---|---|
rax | eax | 返回值、临时存储 |
rcx | ecx | Win64 第 1 参数、循环计数器 |
rdi | edi | Linux 第 1 参数、目的变址 |
rsp | esp | 栈指针 |
rbp | ebp | 栈基址指针 |
附录
通用寄存器(64 位 / 32 位 / 16 位 / 8 位)
| 64 位寄存器 | 32 位低半部分 | 16 位低半部分 | 8 位低半部分 | 主要用途 |
|---|---|---|---|---|
rax | eax | ax | al | 函数返回值;临时存储 |
rbx | ebx | bx | bl | 基址寄存器;全局变量指针 |
rcx | ecx | cx | cl | Win64 第 1 个函数参数;循环计数器 |
rdx | edx | dx | dl | Win64 第 2 个函数参数;乘除法结果 |
rsi | esi | si | sil | 源变址寄存器;字符串 / 数组源指针 |
rdi | edi | di | dil | 目的变址寄存器;字符串 / 数组目标指针 |
rbp | ebp | bp | bpl | 栈基址指针;保存栈帧起始地址 |
rsp | esp | sp | spl | 栈指针;指向栈顶 |
r8 | r8d | r8w | r8b | Win64 第 3 个函数参数 |
r9 | r9d | r9w | r9b | Win64 第 4 个函数参数 |
r10 | r10d | r10w | r10b | 临时存储;函数调用前的参数传递 |
r11 | r11d | r11w | r11b | 临时存储;系统调用 scratch 寄存器 |
r12-r15 | r12d-r15d | r12w-r15w | r12b-r15b | 被调用者保存寄存器;需要手动保存恢复 |
专用寄存器
| 寄存器 | 用途 |
|---|---|
rip | 指令指针;指向当前要执行的指令地址 |
rflags | 标志寄存器;存储运算结果状态(如零标志、进位标志) |
xmm0-xmm15 | 128 位浮点 / 向量寄存器;传递浮点参数和返回值 |
调用约定相关要点(Win64)
参数传递:前 4 个整数 / 指针参数用
rcx,rdx,r8,r9;前 4 个浮点参数用xmm0-xmm3;剩余参数压栈。返回值:整数 / 指针返回值存在
rax;浮点返回值存在xmm0。被调用者保存寄存器:
rbx,rbp,r12-r15—— 如果函数修改了这些寄存器,必须在退出前恢复。调用者责任:必须为被调用函数分配 32 字节的影子空间;调用变参函数时,需要将
rax清零。