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

为何我的极简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

关键修正说明

  1. 替换movq为leaq:leaq专门用于计算内存地址并加载到寄存器,不会访问地址对应的内存内容,能正确拿到静态内存区域的起始地址/标签地址。
  2. 整理段定义:将所有静态数据标签集中放在同一个.data段内,代码结构更简洁清晰。
  3. 调整栈帧顺序:先执行pushq %rbp; movq %rsp, %rbp建立函数栈帧,再进行其他操作,符合x86_64函数的常规执行流程。

补充说明

  • .skip仅预留内存空间,不初始化内容;.zero会把预留空间全部初始化为0。
  • 原代码中movq加载的是a.codata地址处的随机垃圾值(.skip未初始化),之后尝试向这个随机值指向的内存地址写入,必然触发无效内存访问,导致SIGSEGV段错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 07:15:31