汇编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
错误原因
- 栈帧初始化顺序错误:main函数开头先执行
movq %rsp, %rbp再pushq %rbp,这会破坏旧栈帧指针的保存,导致栈帧结构混乱。 - printf参数传递错误:调用printf时,
movq (%rsi),%rsi把整数数值直接存入rsi,但printf("%d")需要的是存储该整数的内存地址,直接传数值会让printf读取非法内存,触发段错误。 - 栈空间未对齐: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
相关产品推荐
相关产品推荐

