Linux NASM检测EOF

7

我正在尝试学习Linux上汇编语言的基础知识,但是我找不到一个很好的参考资料。NASM文档似乎假定你已经知道MASM...文档中没有cmp(除了英特尔指令参考)的示例。

我写了一个从stdin读取单个字节并将其写入stdout的程序。下面是我的修改,以尝试检测stdin上的EOF并在到达EOF时退出。问题是它永远不会退出。它只是一直打印从stdin读取的最后一个字符。我认为问题要么在于我的EOF检测(cmp ecx, EOF),要么在于跳转到的代码(je _exit)。

我做错了什么?

%define EOF     -1

section .bss
        char:   resb    1

section .text
        global  _start

_exit:
        mov     eax,    1       ; exit
        mov     ebx,    0       ; exit status
        int     80h

_start:
        mov     eax,    3       ; sys_read
        mov     ebx,    0       ; stdin
        mov     ecx,    char    ; buffer
        cmp     ecx,    EOF     ; EOF?
        je      _exit
        mov     edx,    1       ; read byte count
        int     80h

        mov     eax,    4       ; sys_write
        mov     ebx,    1       ; stdout
        mov     ecx,    char    ; buffer
        mov     edx,    1       ; write byte count
        int     80h

        jmp     _start

为了方便起见,我用以下C代码验证EOF是否为-1:

#include <stdio.h>
int main() { printf("%d\n", EOF); }

1
我不太熟悉 NASM,但 'char' 是指向单个字符的指针吗?看起来你可能正在比较字符的指针地址和 EOF 值。如果是这样,你需要取消引用指针,然后再进行比较。'read' 和 'write' 系统调用将缓冲区指针作为参数,而不是单个字符。此外,我会将 'char' 重命名为除了基本 C 类型名称以外的其他名称。 - Mr. Shickadance
1个回答

6
您正在将缓冲区的地址与EOF(-1)进行比较,而不是与缓冲区中存储的字符进行比较。
话虽如此,当到达文件末尾时,read系统调用并不返回EOF的值,而是返回零,并且不会将任何东西粘贴到缓冲区中(请参见man 2 read)。要识别文件末尾,请在调用read后检查eax的值。
section .bss
    buf:   resb    1

section .text
    global  _start

_exit:
    mov     eax,    1       ; exit
    mov     ebx,    0       ; exit status
    int     80h

_start:
    mov     eax,    3       ; sys_read
    mov     ebx,    0       ; stdin
    mov     ecx,    buf    ; buffer
    mov     edx,    1       ; read byte count
    int     80h

    cmp     eax, 0
    je      _exit

    mov     eax,    4       ; sys_write
    mov     ebx,    1       ; stdout
    mov     ecx,    buf    ; buffer
    mov     edx,    1       ; write byte count
    int     80h

    jmp     _start

如果你想要将字符与某个值进行比较,请使用以下代码:

cmp byte [buf], VALUE

另外,我将char重命名为bufchar是C语言的基本数据类型,作为变量名称选择不当。


我尝试通过 gdb 逐步执行程序,但是 ecx 中的内容似乎从未改变。它似乎保持不变(0x80490c0)。 - tMC
2
我在意识到一些事情后更新了我的答案。然而,这是正确的,因为您将缓冲区的地址存储在ecx中,在这种情况下存储在内存中的0x80490c0。由sys_read调用读取的值被存储在该内存位置。即使更改了缓冲区的内容,其在内存中的位置仍然相同。要取消引用指针并将其与另一个字节进行比较,请使用cmp byte [buf],VALUE - Mr. Shickadance

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接