从 NASM 调用 C 函数 fgetc,它总是 returns a -1

Calling C function fgetc from NASM, it always returns a -1

使用 NASM,我试图打开一个文本文件并打印文本文件的每个字符。问题是,fgetc 不断返回 -1

    extern  printf
    extern  fopen
    extern  fgetc
    extern  fclose

SECTION .data           ; Data section, initialized variables

    p1_fmt:   db   0xA, "blah", 0xA, 0xA, 0
    p2_fmt:   db   0xA, "Opening: stuff.txt", 0xA, 0xA, 0
    p3_fmt:   db   0xA, "Closing.", 0xA, 0xA, 0
    result_fmt:   db   0xA, "search results: a=%d, e=%d, i=%d, o=%d, u=%d", 0
    p5_fmt:   db   0xA, "debug", 0
    p6_fmt:   db   0xA, "character: %d", 0xA, 0
    file_name:  db  "stuff.txt", 0
    file_mode:  db  "r", 0

SECTION .bss            ; Data section, uninitialized variables

    num_a   resd 0
    num_e   resd 0
    num_i   resd 0
    num_o   resd 0
    num_u   resd 0


SECTION .text           ; Code section.

    global main         ; the standard gcc entry point

main:               ; the program label for the entry point
    push    p1_fmt
    call    printf
    add     esp, 4

    push    p2_fmt
    call    printf
    add     esp, 4

    ;push    file_mode
    ;push    file_name

    mov     DWORD [esp], file_name
    mov     DWORD [esp + 4], file_mode
    call    fopen
    add     esp, 8

    push   eax ; push file pointer on stack.

    character:
        call    fgetc ; an int is in eax now
        mov     ebx, eax ; ebx holds this int too

        ; this continuously print a -1...
        push    ebx
        push    p6_fmt
        call    printf
        add     esp, 8

        cmp ebx, 0
        je no_characters_left

        ; need to loop thru all the characters.
        cmp     ebx, 97
        je vowel_a

        cmp     ebx, 101
        je vowel_e

        cmp     ebx, 105
        je vowel_i

        cmp     ebx, 111
        je vowel_o

        cmp     ebx, 117
        je vowel_u
        jne character

        vowel_a:
            mov eax, num_a
            inc eax
            mov [num_a], eax
            jmp character
        vowel_e:
            mov eax, num_e
            inc eax
            mov [num_e], eax
            jmp character
        vowel_i:
            mov eax, num_i
            inc eax
            mov [num_i], eax
            jmp character
        vowel_o:
            mov eax, num_o
            inc eax
            mov [num_o], eax
            jmp character
        vowel_u:
            mov eax, num_u
            inc eax
            mov [num_u], eax
            jmp character

    no_characters_left:
        call fclose
        add esp, 4 ; remove file pointer off the stack

        push    p5_fmt
        call    printf
        add     esp, 4

    mov     eax, 0      ; normal, no error, return value
    ret                 ; return

好的,根据评论,我认为这将是我们可能的答案:

  1. 使用 nasm
  2. 编译时使用 -f elf32
  3. 与 GCC 链接时使用 -m32

您的代码有几个问题。一个与 fgetc 无关。你像这样进行 fopen 调用:

    mov     DWORD [esp], file_name
    mov     DWORD [esp + 4], file_mode
    call    fopen
    add     esp, 8

两条MOV指令破坏了调用函数的return地址。当您从函数 main 中 return 时,这可能会导致段错误。我相信它应该是这样的:

    push    file_mode
    push    file_name
    call    fopen
    add     esp, 8

fgetc returns EOF (在 Linux EOF 通常映射到 -1 ).相反,您正在检查 ASCII 值 0 (nul) 以检测流的结尾。 ASCII 0(nul) 是可从流中读取的有效字符。您应该更改此检查:

    cmp ebx, 0
    je no_characters_left

至:

    cmp ebx, -1
    je no_characters_left