我试图检测一个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,让它跳转时,它打印得很好。我也尝试过它打印其他字符,它也不工作。我真的是汇编新手,所以我不知道该怎么做。
1条答案
按热度按时间m3eecexj1#
好吧,这里有几层问题。
最基本的是没有“EOF字符”。与ISO C的
getc()
不同,Unixread
系统调用并不通过阅读回特定字符来发出文件结束信号,而是通过返回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]
相比,执行movzx ecx, byte [char]
会更好,它会将rcx
的高位清零。mov cl, [byte]
被定义为保留这些位,这会带来轻微的性能代价。但实际上,你根本不需要把字符载入寄存器;
cmp
与内存操作数一起工作正常。