You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

x86-64编译指令与栈偏移选择的技术疑问咨询

x86-64汇编相关问题解答

原始C代码

char *name[2];  
name[0] = "Name";
name[1] = "null";

编译器生成的汇编代码(函数序言后)

mov    %fs:0x28,%rax
mov    %rax,-0x8(%rbp)
xor    %eax,%eax
lea    0x9689d(%rip),%rax
mov    %rax,-0x20(%rbp)
lea    0x9689a(%rip),%rax
mov    %rax,-0x18(%rbp)

问题解答

  1. 你对LEA指令的推测不正确。LEA(Load Effective Address)的作用是计算内存有效地址并写入目标寄存器,这里是通过RIP相对寻址获取静态字符串的地址:0x9689d(%rip) 指当前RIP的值加上偏移量0x9689d,得到的就是字符串"Name"在数据段的地址,再将该地址存入RAX。编译器选择LEA是为了生成位置无关代码(PIC),这样程序可以在内存任意地址加载,无需修改指令中的绝对地址,这是现代操作系统程序加载的标准要求。

  2. 第一条指令mov %fs:0x28,%rax和字符串地址复制无关——这是栈金丝雀(Stack Canary)的初始化操作,用于检测栈溢出:%fs段寄存器指向线程本地存储,0x28位置存储随机金丝雀值,将其存入栈上的-0x8(%rbp)位置,函数结束时会对比该值是否被篡改,以此判断栈是否溢出。而静态字符串的地址在数据段,必须通过RIP相对寻址获取(LEA是实现该寻址的合适指令),无法用访问FS段的方式获取字符串地址。

  3. 你混淆了栈上的存储位置:-0x8(%rbp)存储的是栈金丝雀值,并非第一个字符串的地址。第一个字符串的地址存在-0x20(%rbp),第二个在-0x18(%rbp),两者间隔正好是8字节(x86-64架构下指针的大小),完全符合char*数组的存储规则。这里存储的是指向字符串的指针,而非字符串内容本身,因此栈上不存在'\0'——字符串"Name"和"null"的内容(包括末尾的'\0')都存储在程序的数据段中,栈上仅保存指向这些数据的指针。

内容的提问来源于stack exchange,提问作者clancy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 10:15:28