.section __DATA,__data
.p2align 2
buffer:
.zero 4096
.section __TEXT,__text
.global _main
.build_version macos, 13, 0
.p2align 2
_main:
// x9: buf ptr
// x10: file descriptor storage
// x11: file size in bytes
//init ptr to buf
adrp x9, buffer@PAGE
add x9, x9, buffer@PAGEOFF
// open file
adr x0, file_path
mov x1, #0
mov x2, #444
mov x16, #5
svc 0
// copy file descriptor to x10
mov x10, x0
.p2align 2
stream_buffer:
// make syscall read, file descriptor is in x10
mov x0, x10
mov x1, x9
mov x2, #4096
mov x16, #3
svc 0
// if x0 == 0, exit, no bytes were read
cmp x0, #0
beq exit
blt error
// store number of bytes read
mov x11, x0
// write to stdout from buffer
mov x0, #1
mov x1, x9
mov x2, x11
mov x16, #4
svc 0
b stream_buffer
.p2align 2
exit:
// exit with status code 0
mov x0, #0
mov x16, #1
svc 0
.p2align 2
error:
mov x0, #1
adr x1, file_not_found_error_string
mov x2, #20
mov x16, #4
svc 0
b exit
.p2align 2
file_path:
.asciz "/test.txt"
.p2align 2
file_not_found_error_string:
.asciz "file was not found.\n"
字符串
我试图通过编写一个简单的程序来学习汇编语言,该程序模拟了“cat”Linux命令。我使用的是带有M1芯片的macbook air 2020。我的程序编译得很好,但是当执行二进制文件时,我遇到了我的程序期望输入,然后它会返回任何输入。我相信我滥用了我的文件描述符。感谢任何帮助。
1条答案
按热度按时间iszxjhcz1#
噢,这太搞笑了。
事实上,您的代码最终从stdin阅读是代码中错误的顶峰,并伴有一些意外的操作系统行为。
让我们先从一个高层次的Angular 来看:
1.打开
/test.txt
进行阅读。1.你可以从中读取多达4096个字节。
1.将这些字节写入标准输出。
但是你在arm 64 macOS上,这意味着除非你花了很大的力气去弄乱操作系统,否则系统卷是只读的,
/test.txt
不存在。所以你的
open
系统调用失败了,但是你没有检测到,因为你没有在那里做错误检查。现在,在这种情况下,你可能会假设
x0
是-1
,因为如果从C调用open()
,这就是open()
所做的,但这不是系统调用ABI。如果你看/usr/lib/system/libsystem_kernel.dylib
是一个反汇编程序,并查找___open
,你会看到:字符串
这里的关键部分是
b.lo
。系统调用使用进位标志(NZCV中的“C”)来表示是否有错误。这意味着:b.lo
->x0
保存文件描述符b.hs
->x0
保存errno
值所以你的系统调用失败并返回一个错误值
x0
。特别是ENOENT
,因为它找不到你要求的文件。而ENOENT
恰好是2
,所以当你把这个错误值传递给你的下一个系统调用时,你最终会从文件描述符2
中阅读,也就是stderr。但是现在,因为你从命令行调用了你的二进制文件,文件描述符0,1和2恰好都是同一个文件描述符,所以在这种情况下从stderr阅读的行为就像从stdin阅读一样。那么如何解决这个问题呢?在第一个
svc
之后放一个b.hs error
。然后选择一个实际存在的文件路径。