我尝试用fgets读取缓冲区的输入。我推了3个参数,但得到了分段错误。我试图看到GDB的问题,但我不明白我到那里的信息 这是代码:
section .rodata
buffer: db 10
section .text
align 16
global main
extern fgets
extern stdin
main:
push ebp
mov ebp, esp
pushad
push dword[stdin]
push 10;
push buffer;
call fgets;
add esp, 12
popad
mov esp, ebp
pop ebp
ret
这是我得到的信息:
Program received signal SIGSEGV, Segmentation fault.
__GI__IO_getline_info (fp=fp@entry=0xf7fb1c20 <_IO_2_1_stdin_>,
buf=buf@entry=0x80484f0 "\n", n=8, n@entry=9, delim=delim@entry=10,
extract_delim=extract_delim@entry=1, eof=eof@entry=0x0) at iogetline.c:86
86 iogetline.c: No such file or directory.
我的代码出了什么问题?
答案 0 :(得分:1)
您是段错误,因为您要求fgets
写入.rodata
部分中的地址。它当然是只读的。
将缓冲区放在.bss
部分,并使用resb 10
保留10个字节。您当前的版本是一个字节,初始化为{ 10 }
。您不希望无缘无故地在可执行文件中存储一堆零;这就是bss的用途。
section .bss
buffer: resb 10
buffer_length equ $ - buffer
section .text
align 16
global main
extern fgets
extern stdin
main:
push dword [stdin]
push buffer_length
push buffer ; 3 pushes gets the stack back to 16B-alignment
call fgets
add esp, 12
ret
此函数中不需要pusha
或堆栈框架(带有ebp的东西)。通常,您只保存/恢复要使用的呼叫保留寄存器,而不是每次都保存/恢复。
正如Michael Petch所指出的,最好在堆栈上为缓冲区保留空间,而不是使用静态存储。查看使用本地数组的等效C函数的编译器输出。 (例如http://gcc.godbolt.org/)。