【问题标题】:Calling C function fgetc from NASM, it always returns a -1从 NASM 调用 C 函数 fgetc,它总是返回 -1
【发布时间】:2015-11-10 04:03:42
【问题描述】:

使用 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

【问题讨论】:

  • 首先,你确定你系统上的调用约定是cdecl,你还记得sub esp, 8,然后再把参数放到堆栈上吗?
  • 1.是的。我正在使用 ubuntu 32 位。 2.是的,这里是完整的代码:hastebin.com/ijuyuvipay.avrasm
  • 你是编译成32位还是64位?这些指令对 64 位系统完全有效,但您不会为 x86-64 调用约定生成正确的指令。
  • 我将其编译为 32 位我相信:nasm -f elf test.asmgcc test.o -masm=intel -o test
  • cmp ebx, 0 在检查是否还有剩余字符时看起来很可疑。 ASCII 0 (nul) 仍然是有效字符。当遇到 EOF 时,libc 通常会从 fgetc 返回 -1(在 Linux 上)。

标签: assembly x86 std nasm calling-convention


【解决方案1】:

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

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

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

    push    file_mode
    push    file_name
    call    fopen
    add     esp, 8

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

    cmp ebx, 0
    je no_characters_left

到:

    cmp ebx, -1
    je no_characters_left

【讨论】:

  • 好的,谢谢。我已经进行了适当的更改。所以,我刚醒来,发现文本文件中没有任何文本......我不知道这是怎么回事。 :(。感谢 Olipro 和 Michael 抽出时间帮助我。
  • 也许当我将文件模式更改为w+ 时,它会擦除​​文本文件。
  • 有什么东西把它抹掉了。很高兴你发现它是空的;)
【解决方案2】:

好的,所以根据 cmets,我认为这将是我们可能的答案:

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

【讨论】:

  • 该死,我现在正在做nasm -f elf32 test.asm gcc -m32 test.o -masm=intel -o test ./test 但它仍在连续打印-1。
  • 好的,所以将文件模式从r 更改为w+,看看是不是因为文件实际上不存在而导致失败。
  • 没用。我还将代码中的文件名更改为晦涩难懂的内容,然后程序确实崩溃了。所以它知道它的存在。
猜你喜欢
  • 2013-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-26
相关资源
最近更新 更多