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

x86_64汇编中scanf执行两次的问题排查与修复

分析与修复x86_64汇编中scanf重复执行的问题

看起来你遇到的是x86_64汇编里调用标准库函数时的栈平衡与参数传递错误,直接导致了控制流混乱和函数重复执行的问题。我来拆解原因和修复方法:

核心原因分析

你的异常流程本质是程序的栈结构被破坏,导致函数返回后跳转到了错误的指令地址(比如回到之前的scanf调用处),主要可能是以下几点:

  1. 未遵循栈对齐要求:x86_64 System V ABI规定,调用外部函数(比如scanf、printf)前,栈指针rsp必须是16字节对齐。而main函数入口时,rsp是8字节对齐的(因为call main会压入8字节的返回地址),如果不提前调整,会触发未定义行为。
  2. 参数传递错误:
    • 对于scanf的%lf格式,你需要传递double变量的地址(指针),而非变量值;如果传错了,会导致scanf写入错误内存区域,破坏栈数据。
    • 对于printf的%lf格式,浮点参数需要放到xmm0寄存器(而非栈上),错误的传递方式会打乱栈结构,让后续函数调用读取到错误的参数或返回地址。
  3. 栈指针未正确恢复:如果在函数中压栈了数据(比如保存寄存器),退出前没有恢复rsp到初始状态,ret指令会读取到错误的返回地址,让程序跳回之前的scanf调用。

修复方案(附示例代码)

下面是符合ABI规范的代码示例,解决你的问题:

global main
extern printf
extern scanf

section .data
    ; 输入格式字符串(必须以0结尾)
    prompt_epsilon db "epsilon = %lf", 0
    prompt_order   db "order = %d", 0
    ; 输出格式字符串
    print_epsilon  db "epsilon: %lf", 10, 0  ; 10是换行符ASCII码
    print_order    db "order: %d", 10, 0

section .bss
    epsilon resq 1  ; double类型占8字节,用resq分配
    order   resd 1  ; int类型占4字节,用resd分配

section .text
main:
    ; 调整栈到16字节对齐:main入口时rsp是8字节对齐,sub rsp,8后满足要求
    sub rsp, 8

    ; 读取epsilon
    mov rdi, prompt_epsilon  ; 第一个参数:格式字符串地址
    mov rsi, epsilon         ; 第二个参数:epsilon变量的地址
    call scanf

    ; 打印epsilon
    mov rdi, print_epsilon   ; 第一个参数:格式字符串地址
    movsd xmm0, [epsilon]    ; 浮点参数放到xmm0(%lf对应xmm0)
    call printf

    ; 读取order
    mov rdi, prompt_order    ; 第一个参数:格式字符串地址
    mov rsi, order           ; 第二个参数:order变量的地址
    call scanf

    ; 打印order
    mov rdi, print_order     ; 第一个参数:格式字符串地址
    mov esi, [order]         ; 整数参数放到esi(rsi的低32位,%d对应32位整数)
    call printf

    ; 恢复栈指针,准备返回
    add rsp, 8
    ret

关键修复点说明

  • 栈对齐:进入main后先执行sub rsp,8,确保调用外部函数前rsp是16字节对齐;退出前用add rsp,8恢复。
  • scanf参数传递:所有输入格式的参数都是变量的地址,用rdi、rsi传递前两个参数(符合ABI的寄存器传递规则)。
  • printf参数传递:浮点参数epsilon用movsd加载到xmm0,整数参数order加载到esi,严格对应格式字符串的类型要求。

按照这个规范修改你的代码,就能解决scanf重复执行、输出顺序混乱的问题了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:08:29