为何我的极简amd64 x86_64汇编代码会触发段错误?
x86_64汇编静态内存操作段错误问题解决
核心问题
触发段错误的根本原因是错误使用movq指令获取静态内存地址:
movq a.codata(%rip), %rcx的作用是读取a.codata地址处的8字节数据到rcx,而非加载a.codata本身的内存地址。要获取这块内存的起始地址,必须用leaq(加载有效地址)指令。- 同理,
movq a.end_data_stack(%rip),%rdx也是错误用法,同样需要替换为leaq。
另外,代码中多次重复.data指令属于冗余操作,所有静态数据可以集中放在同一个.data段内。
修正后的完整代码
.global main .data a.codata: .skip 40 # 预留40字节未初始化静态内存 data_stack: .zero 400 # 预留400字节并初始化为0的静态内存 a.end_data_stack: # 标记data_stack的末尾位置 .LC0: .string "It worked: %p\n" .text .globl main .type main, @function main: pushq %rbp movq %rsp, %rbp # 正确获取内存标签的地址 leaq a.end_data_stack(%rip), %rdx leaq a.codata(%rip), %rcx # 打印a.codata的地址 leaq .LC0(%rip), %rax movq %rcx, %rsi movq %rax, %rdi movl $0, %eax call printf@PLT # 打印a.end_data_stack的地址 leaq .LC0(%rip), %rax movq %rdx, %rsi movq %rax, %rdi movl $0, %eax call printf@PLT # 现在可以安全向a.codata区域写入数据 movq %rdx, (%rcx) popq %rbp ret
关键修正说明
- 替换
movq为leaq:leaq专门用于计算内存地址并加载到寄存器,不会访问地址对应的内存内容,能正确拿到静态内存区域的起始地址/标签地址。 - 整理段定义:将所有静态数据标签集中放在同一个
.data段内,代码结构更简洁清晰。 - 调整栈帧顺序:先执行
pushq %rbp; movq %rsp, %rbp建立函数栈帧,再进行其他操作,符合x86_64函数的常规执行流程。
补充说明
.skip仅预留内存空间,不初始化内容;.zero会把预留空间全部初始化为0。- 原代码中
movq加载的是a.codata地址处的随机垃圾值(.skip未初始化),之后尝试向这个随机值指向的内存地址写入,必然触发无效内存访问,导致SIGSEGV段错误。
内容的提问来源于stack exchange,提问作者Samuel Squire
相关产品推荐
相关产品推荐

