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 栈变化完整流程

操作栈指针变化说明
进入 mainrsp = 0x10000000(16 字节对齐)系统启动代码保证初始对齐
sub rsp, 40rsp = 0xFFFFFFD8分配影子空间 + 对齐空间
call printf压入返回地址,rsp = 0xFFFFFFD0保持 16 字节对齐
printf 执行 ret弹出返回地址,rsp = 0xFFFFFFD8回到调用前栈位置
add rsp, 40rsp = 0x10000000恢复初始栈状态

三、32 位 Windows 汇编示例(MessageBeep)

main:
    push 0xFFFFFFFF  ; 传递错误提示音参数
    call MessageBeep ; 播放错误提示音
    xor eax, eax     ; 返回值0
    retn
功能:调用 Windows API 播放错误提示音,然后正常退出。

四、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 位低半部分主要用途
raxeax返回值、临时存储
rcxecxWin64 第 1 参数、循环计数器
rdiediLinux 第 1 参数、目的变址
rspesp栈指针
rbpebp栈基址指针

附录


通用寄存器(64 位 / 32 位 / 16 位 / 8 位)

64 位寄存器32 位低半部分16 位低半部分8 位低半部分主要用途
raxeaxaxal函数返回值;临时存储
rbxebxbxbl基址寄存器;全局变量指针
rcxecxcxclWin64 第 1 个函数参数;循环计数器
rdxedxdxdlWin64 第 2 个函数参数;乘除法结果
rsiesisisil源变址寄存器;字符串 / 数组源指针
rdiedididil目的变址寄存器;字符串 / 数组目标指针
rbpebpbpbpl栈基址指针;保存栈帧起始地址
rspespspspl栈指针;指向栈顶
r8r8dr8wr8bWin64 第 3 个函数参数
r9r9dr9wr9bWin64 第 4 个函数参数
r10r10dr10wr10b临时存储;函数调用前的参数传递
r11r11dr11wr11b临时存储;系统调用 scratch 寄存器
r12-r15r12d-r15dr12w-r15wr12b-r15b被调用者保存寄存器;需要手动保存恢复

专用寄存器

寄存器用途
rip指令指针;指向当前要执行的指令地址
rflags标志寄存器;存储运算结果状态(如零标志、进位标志)
xmm0-xmm15128 位浮点 / 向量寄存器;传递浮点参数和返回值

调用约定相关要点(Win64)

  1. 参数传递:前 4 个整数 / 指针参数用 rcx, rdx, r8, r9;前 4 个浮点参数用 xmm0-xmm3;剩余参数压栈。

  2. 返回值:整数 / 指针返回值存在 rax;浮点返回值存在 xmm0

  3. 被调用者保存寄存器rbx, rbp, r12-r15 —— 如果函数修改了这些寄存器,必须在退出前恢复。

  4. 调用者责任:必须为被调用函数分配 32 字节的影子空间;调用变参函数时,需要将 rax 清零。