Linux环境下运行GAS汇编时,如何让STDIN正常工作?
问题分析与解决
你的程序卡在输入后无响应,核心是两个关键错误导致的:
1. exponent函数的汇编语法错误
看你的exponent代码里这行:
.section .textexponent:
这是完全错误的语法,正确写法应该分开声明代码段和函数标签:
.section .text exponent:
原来的写法会把代码段命名搞乱,汇编器无法正确识别函数入口,执行流会出现异常。
2. scanf格式符与数据宽度不匹配
你用%d(对应32位int)读取输入,但却用64位的栈位置(LOCAL_NUMBER=-8、LOCAL_EXPONENT=-16,都是qword偏移)存储,并且用movq读取整个64位数据。fscanf只会往内存里写32位的int值,高32位会保留栈上的随机垃圾值,导致读取到的指数变成一个极大的数(比如垃圾值是0xffffffff时,实际读取的64位值就是0xffffffff000000xx,是个超大负数),exponent里的循环会一直执行,永远跳不出来,程序就卡死了。
修正后的完整代码
主程序(exponentscanf.s)
.globl main .section .data promptformat: .ascii "Enter two numbers separated by spaces, then press RETURN.\n\0" scanformat: .ascii "%d %d\0" resultformat: .ascii "The result is %d.\n\0" .section .text .equ LOCAL_NUMBER, -4 # 32位int的栈位置 .equ LOCAL_EXPONENT, -8 # 32位int的栈位置 main: enter $8, $0 # 只需要8字节栈空间存两个32位int # 输出提示 movq stdout, %rdi movq $promptformat, %rsi movq $0, %rax call fprintf # 读取输入 movq stdin, %rdi movq $scanformat, %rsi leaq LOCAL_NUMBER(%rbp), %rdx leaq LOCAL_EXPONENT(%rbp), %rcx movq $0, %rax call fscanf # 准备调用exponent:把32位int零扩展到64位寄存器 movl LOCAL_NUMBER(%rbp), %edi movl LOCAL_EXPONENT(%rbp), %esi movslq %edi, %rdi movslq %esi, %rsi call exponent # 输出结果 movq stdout, %rdi movq $resultformat, %rsi movq %rax, %rdx movq $0, %rax call fprintf leave ret
exponent函数(exponentfunc.s)
.globl exponent .type exponent, @function .section .text exponent: enter $16, $0 # 16字节栈对齐 movq $1, %rax # 初始化结果为1 movq %rsi, -8(%rbp) # 保存指数到栈上 # 先判断指数是否为0,直接返回1 cmpq $0, -8(%rbp) jz complete mainloop: mulq %rdi # 结果 *= 底数 decq -8(%rbp) # 指数减1 jnz mainloop # 指数不为0继续循环 complete: leave ret
编译与测试
用你原来的命令编译即可:
gcc -static exponentscanf.s exponentfunc.s -o exponentscanf
运行后输入两个整数(比如2 3),就能得到正确结果The result is 8.
内容的提问来源于stack exchange,提问作者Digital Samizdat
相关产品推荐
相关产品推荐

