在程序集中使用fgets进行分段错误

时间:2016-04-23 23:32:35

标签: c assembly x86 nasm

我尝试用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.

我的代码出了什么问题?

1 个答案:

答案 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/)。