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

汇编scanf函数读取最后一个数字时触发段错误的问题求助

汇编代码中scanf读取最后一个数字触发段错误的问题

我尝试用汇编的scanf函数接收两组字符串及其长度,再接收一个数字,输入格式示例为:5 hello 2 hi 8。目前能成功接收两组字符串及其长度,但读取最后一个数字时触发错误:Program received signal SIGSEGV, Segmentation fault.(分配大栈空间是因为假设字符串最大长度为255)。相关汇编代码如下:

.data

.section    .rodata         #read only data section
_scanf_check:   .string "%d" #in order to check output
_scanf_length1: .string "%d"
_scanf_length2: .string "%d"    
_scanf_str1:    .string "%s"    
_scanf_str2:    .string "%s"    
_scanf_option:  .string "%d"


.text
.global main
.type   main, @function
main:
    movq %rsp, %rbp #for correct debugging
    pushq %rbp      #save the old frame pointer
    movq    %rsp, %rbp  #create the new frame pointer
    #########################################################
    #receiving the length of first pstring.
    leaq -524(%rbp),%rsi    #allocate 524 bytes on the stack.
    movq $_scanf_length1,%rdi
    xor %rax,%rax
    call scanf
    #########################################################
    #receiving the string of first pstring.
    leaq -520(%rbp),%rsi
    movq $_scanf_str1,%rdi
    xor %rax,%rax
    call scanf
    #########################################################
    #receiving the length of second pstring.
    leaq -264(%rbp),%rsi
    movq $_scanf_length2,%rdi
    xor %rax,%rax
    call scanf
    #########################################################
    #receiving the string of first pstring.
    leaq -260(%rbp),%rsi
    movq $_scanf_str2,%rdi
    xor %rax,%rax
    call scanf
    #########################################################
    #receiving the option from the menu.
    leaq -4(%rbp),%rsi
    movq $_scanf_option,%rdi
    xor %rax,%rax
    call scanf
    #########################################################
    #move back the %rdi-first arg to point on the length of first pstring
    #and %rsi-second arg to point on the length of second pstring also
    #move back the %rdx-third arg to point on the number of option.
    leaq -524(%rbp),%rdi
    leaq -264(%rbp),%rsi
    leaq -4(%rbp),%rdx
    .char_pstrlength:
   movq %rdx,%rsi #reload the address of the last number to %rsi
    movq (%rsi),%rsi #insert the value to rsi.
    movq $_scanf_check,%rdi
    xor %rax,%rax
    call printf
    movq    %rbp, %rsp  #restore the old stack pointer - release all used memory.
    popq    %rbp        #restore old frame pointer (the caller function frame)
    ret

错误原因

  1. 栈帧初始化顺序错误:main函数开头先执行movq %rsp, %rbp再pushq %rbp,这会破坏旧栈帧指针的保存,导致栈帧结构混乱。
  2. printf参数传递错误:调用printf时,movq (%rsi),%rsi把整数数值直接存入rsi,但printf("%d")需要的是存储该整数的内存地址,直接传数值会让printf读取非法内存,触发段错误。
  3. 栈空间未对齐:x86-64平台要求函数调用时栈保持16字节对齐,原代码的栈空间分配未遵循此规则,可能导致函数调用异常。

修复方案

  • 修正栈帧初始化顺序:先push旧rbp,再将rsp赋值给rbp。
  • 调整printf参数:传递存储最后一个数字的内存地址给rsi,而非直接传数值。
  • 调整栈空间分配,确保16字节对齐。

修复后的汇编代码

.data

.section    .rodata         #只读数据段
_scanf_check:   .string "%d\n" #用于输出检查
_scanf_length1: .string "%d"
_scanf_length2: .string "%d"    
_scanf_str1:    .string "%s"    
_scanf_str2:    .string "%s"    
_scanf_option:  .string "%d"


.text
.global main
.type   main, @function
main:
    pushq %rbp      #保存旧栈帧指针
    movq    %rsp, %rbp  #创建新栈帧指针
    subq    $544, %rsp  #分配544字节栈空间(16的倍数,确保对齐)
    #########################################################
    #接收第一个pstring的长度
    leaq -544(%rbp),%rsi    
    movq $_scanf_length1,%rdi
    xor %rax,%rax
    call scanf
    #########################################################
    #接收第一个pstring的字符串
    leaq -540(%rbp),%rsi
    movq $_scanf_str1,%rdi
    xor %rax,%rax
    call scanf
    #########################################################
    #接收第二个pstring的长度
    leaq -280(%rbp),%rsi
    movq $_scanf_length2,%rdi
    xor %rax,%rax
    call scanf
    #########################################################
    #接收第二个pstring的字符串
    leaq -276(%rbp),%rsi
    movq $_scanf_str2,%rdi
    xor %rax,%rax
    call scanf
    #########################################################
    #接收菜单选项数字
    leaq -4(%rbp),%rsi
    movq $_scanf_option,%rdi
    xor %rax,%rax
    call scanf
    #########################################################
    #输出检查最后一个数字
    movq $_scanf_check,%rdi
    leaq -4(%rbp),%rsi  #传递存储选项的内存地址给printf
    xor %rax,%rax
    call printf
    #########################################################
    movq    %rbp, %rsp  #恢复栈指针,释放内存
    popq    %rbp        #恢复旧栈帧指针
    ret

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 06:00:47