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

在WSL-Ubuntu(VS Code环境)运行汇编代码时为何出现段错误?

问题分析与解决

你的段错误并不是push rcx/pop rcx本身的逻辑问题,而是违反了x86-64 System V调用约定的栈对齐要求导致的。

核心原因

在x86-64 Linux(包括WSL-Ubuntu)的调用约定中,要求执行call指令调用函数前,栈指针rsp必须是16字节对齐的。因为call会将8字节的返回地址压入栈,进入被调用函数时rsp会偏移8字节,此时被调用函数的栈帧才能保持16字节对齐——很多标准库函数比如putchar的实现依赖这个对齐要求(比如使用SSE指令或分配对齐的栈空间),一旦对齐被破坏就会触发段错误。

看你的代码流程:

  1. 调用print_row时,call指令压入8字节返回地址,此时rsp是8字节偏移(未对齐)。
  2. 执行push rbx后,rsp恢复16字节对齐。
  3. 进入循环后执行push rcx,rsp再次偏移8字节(回到未对齐状态),此时直接call putchar就违反了栈对齐要求,触发段错误。

修复方案

有两种简单的修复方式:

方案1:调整栈对齐后再调用putchar

在push rcx后额外压入一个临时寄存器(比如rax)让栈重新对齐,调用完成后再弹出:

; print_row(10, '<')     重复打印指定字符N次——此例为打印10次'<'
print_row:
    mov ecx, edi     ; 传入的重复次数num
    push rbx         ; 保存被调用者保存寄存器的值
    mov ebx, esi     ; 使用被调用者保存寄存器存储字符值
    sub ecx, 1
loop_print:
    mov edi, ebx
    push rcx         ; 保存rcx寄存器的值
    push rax         ; 临时压入,让栈恢复16字节对齐
    call putchar     ; 调用putchar函数
    pop rax          ; 弹出临时值
    pop rcx          ; 恢复rcx的值
    sub ecx, 1       
    jns loop_print   ; 当ecx非负时继续循环
    
    mov edi, 10      ; 末尾打印换行符'\n'
    push rax         ; 同样需要对齐栈
    call putchar     
    pop rax
    pop rbx          ; 恢复rbx调用前的原始值
    ret

方案2:使用被调用者保存寄存器存储循环计数

x86-64中r12-r15属于被调用者保存寄存器,标准库函数不会修改它们,因此可以用这些寄存器存储循环次数,避免频繁的栈操作,同时天然满足栈对齐要求:

; print_row(10, '<')     重复打印指定字符N次——此例为打印10次'<'
print_row:
    push rbx         ; 保存被调用者保存寄存器
    push r12
    mov r12d, edi    ; 用r12d存储循环次数(32位足够)
    mov ebx, esi
    dec r12d         ; 初始减1,匹配原逻辑
loop_print:
    mov edi, ebx
    call putchar     ; 调用前栈是对齐的,无需额外操作
    dec r12d
    jns loop_print   ; 非负则继续循环
    
    mov edi, 10      ; 打印换行
    call putchar
    pop r12          ; 恢复寄存器
    pop rbx
    ret

额外说明

  • 你代码中mov al, 0是多余的:putchar不是可变参数函数,调用前不需要设置rax(只有可变参数函数才需要用al传递浮点参数个数)。
  • 原循环逻辑是正确的:初始ecx = num-1,循环中每次减1直到ecx为-1,刚好执行num次打印。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 15:15:27