提问人:Jake Snell 提问时间:11/1/2023 最后编辑:FrantJake Snell 更新时间:11/5/2023 访问量:41
在 Apple Mac M64 CPU 上的 ARM1 程序集中打开和读取文件时出现问题
Trouble opening and reading file in ARM64 assembly on apple mac M1 cpu
问:
.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命令来学习汇编。我使用的是带有 M2020 芯片的 macbook air 1。我的程序编译良好,但是在执行二进制文件时,我遇到了我的程序期望输入,然后它会回显输入的任何内容。我认为我滥用了我的文件描述符。任何帮助表示赞赏。
答:
哦,这很搞笑。
您的代码最终从 stdin 读取的事实是代码中错误的高潮,以及一些意想不到的操作系统行为。
让我们先从高层次的角度来看一下:
- 你打开阅读。
/test.txt
- 您最多可以从中读取 4096 个字节。
- 将这些字节写入 stdout。
但是你使用的是 arm64 macOS,这意味着除非你竭尽全力弄乱操作系统,否则系统卷是只读的,不存在。/test.txt
因此,您的系统调用失败了,但您没有检测到这一点,因为您没有在那里进行错误检查。坏!
现在,您可能会假设在这种情况下,因为如果从 C 调用,这就是这样做的,但这不是系统调用 ABI。如果你看是一个反汇编器并寻求,你会看到这个:open
x0
-1
open()
/usr/lib/system/libsystem_kernel.dylib
___open
;-- ___open:
;-- func.00002308:
0x00002308 b00080d2 mov x16, 5
0x0000230c 011000d4 svc 0x80
0x00002310 03010054 b.lo 0x2330
0x00002314 7f2303d5 pacibsp
0x00002318 fd7bbfa9 stp x29, x30, [sp, -0x10]!
0x0000231c fd030091 mov x29, sp
0x00002320 8a030094 bl sym._cerror
0x00002324 bf030091 mov sp, x29
0x00002328 fd7bc1a8 ldp x29, x30, [sp], 0x10
0x0000232c ff0f5fd6 retab
0x00002330 c0035fd6 ret
这里的关键部分是 .系统调用使用进位标志(NZCV 中的“C”)来指示是否存在错误。这意味着:b.lo
b.lo
->x0
保存文件描述符b.hs
->x0
保持值errno
因此,您的系统调用失败并返回错误值。具体来说,因为它找不到您要求的文件。碰巧是 ,所以当你将该错误值传递给下一个系统调用时,你最终会从文件描述符中读取,即 stderr。但是现在,由于您从命令行调用了二进制文件,因此文件描述符 0、1 和 2 恰好都是同一个文件描述符,因此在这种情况下,从 stderr 读取的行为就像从 stdin 读取一样。x0
ENOENT
ENOENT
2
2
那么你如何解决这个问题呢?在第一个 .
然后选择一个实际存在的文件路径。b.hs error
svc
评论