assembly 如何在程序集nasm中检测EOF?

i86rm4rw  于 2022-12-04  发布在  其他
关注(0)|答案(1)|浏览(123)

我试图检测一个EOF字符,或只是任何字符,但它不工作,也没有错误。

section .data
    file db "text.txt", 0

section .bss
    char resb 1

section .text
    global _start

_start:
    mov rax, 2
    mov rdi, file
    syscall
    mov rbx, rax

    mov rdi, rbx
    mov rax, 0
    mov rsi, char
    mov rdx, 1
    syscall

    mov rcx, char
    cmp rcx, -1
    je _endOfFile

    call _end

_endOfFile:
    print 1, file, 0
    ret

_end:
    mov rax, 3
    mov rdi, rbx
    syscall

    mov rax, 60
    mov rdi, 0
    syscall

我希望它能打印文件名,但是它什么也没做。当我删除cmp,让它跳转时,它打印得很好。我也尝试过它打印其他字符,它也不工作。我真的是汇编新手,所以我不知道该怎么做。

m3eecexj

m3eecexj1#

好吧,这里有几层问题。
最基本的是没有“EOF字符”。与ISO C的getc()不同,Unix read系统调用并不通过阅读回特定字符来发出文件结束信号,而是通过返回0作为其返回值来发出信号。因此,在读取syscall之后,您需要检查rax中的值。如果它是零,那么你已经到达了文件结尾。如果它是1,那么你成功地将一个字符读入到了内存位置char。如果它是一个小的负数,那么发生了一个错误,这个值的否定是一个errno代码。
比较代码也有一些错误。首先,mov rcx, char不从char加载字符,它加载char的地址,当然不等于-1。如果你看,这与你用来设置系统调用的mov rsi, char完全相似,它同样将char的地址放入rsi。
要指定char位置的内存内容,请使用方括号:mov rcx, [char]。然而,这也不对。在x86-64上,大多数指令可以操作8、16、32或64位操作数。当至少一个操作数是寄存器时,指定寄存器的大小决定操作数的大小。因此mov rcx, [char]将加载8个字节,其中最低的字节是来自char的字节。而另外7个则是内存中紧随其后的垃圾。
要加载一个字节,使用一个8位寄存器,比如cl,然后你需要同样地只与8位寄存器进行比较,否则你就在与不是你的字符的东西进行比较。

mov cl, [char]
cmp cl, -1
je got_ff

但实际上,在大多数情况下,与mov cl, [char]相比,执行movzx ecx, byte [char]会更好,它会将rcx的高位清零。mov cl, [byte]被定义为保留这些位,这会带来轻微的性能代价。
但实际上,你根本不需要把字符载入寄存器; cmp与内存操作数一起工作正常。

cmp byte [char], -1
je it_was_ff

相关问题