我正在为 Aarch64 arm bit cpu 开发一个系统调用处理函数,我正在研究它是如何在 x86 汇编中完成的,但我无法弄清楚它是如何在 Aarch64 汇编中完成的。
我在 github 上看这个例子:https://github.com/rockytriton/LLD/blob/main/linux_os/part1/src/start.S这是用 x86 汇编语言编写的。
.globl _syscall
_syscall:
movq %rdi, %rax
movq %rsi, %rdi
movq %rdx, %rsi
movq %rcx, %rdx
movq %r8, %r10
movq %r9, %r8
movq 8(%rsp), %r9
syscall
ret
还有一些在线等价物,如本 answer 所示不满足相同的函数调用设计。这是用 Aarch64 程序集编写的。
/* Generated by gensyscalls.py. Do not edit. */
#include <private/bionic_asm.h>
.hidden __set_errno
ENTRY(write)
mov x8, __NR_write
svc #0
cmn x0, #(MAX_ERRNO + 1)
cneg x0, x0, hi
b.hi __set_errno
ret
END(write)
到目前为止,我有这段代码(从 x86 移植到 Aarch64 的效果很差):
.globl _syscall
_syscall:
mov x8, r7
svc #0
cmn x0, #(4095 + 1)
cneg x0, x0, hi
ret
它确实不起作用,但我还是试过了,具有讽刺意味的是,当我组装它时,它似乎不喜欢 r7
的寄存器名称,我不太明白为什么,因为它应该是函数调用的参数(见下文)。
我的 C 程序的头文件中有一个函数布局,如下所示:unsigned long _syscall(int num, void *a0, void *a1, void *a2, void *a3, void *a4, void *a5)
, 有没有人对如何在 Aarch64 程序集中重新创建相同的系统调用处理程序功能有任何想法 - 我在移植方面的尝试没有成功。我对此很迷茫,因为汇编不是我的强项 - 具有讽刺意味的是,这是我项目中唯一需要的汇编。
非常感谢!
最佳答案
如另一个答案所示,当您使用 svc
发出系统调用时,您应该在 x8
中有系统调用号,在 中有参数x0-x5
.
然而,根据ARM ABI ,参数从左到右传递给寄存器 x0-x7
中的 C 函数。 (文档使用 r0-r7
混淆;根据它们是 64 位值还是 32 位值,这意味着 x0-x7
或 w0-w7
。 AArch64 没有名为 r7
或类似名称的寄存器,但 ARM32 有。)
因此系统调用号在 w0
中,而它应该在 x8
中(或等同于 w8
,因为它总是正数32位数字);第一个参数 a0
在需要在 x0
中时在 x1
中;等等。因此,您需要一些代码来随机播放它们。
mov w8, w0
mov x0, x1
mov x1, x2
mov x2, x3
mov x3, x4
mov x4, x5
mov x5, x6
svc #0
(如果你把 num
参数放在参数列表的末尾而不是开头,你可以省去一些麻烦,如果你不想改变现有的,也许可以借助宏代码。那么你只需要 mov w8, w6 ; svc#0
。)
在另一端,svc#0
在x0
中留下一个返回值。但是,如果系统调用失败,则 x0
不包含 -1
而是应返回的 errno
代码的负值(在 -1 和 -4095 之间(含)。此测试与检查作为无符号值的返回值是否高于 -4096
相同。当发生这种情况时,通常您希望将 errno
设置为 -x0
,然后将 x0
设置为 -1
(以便系统调用函数返回 -1
。
不清楚您希望 syscall
函数在出现错误时如何运行。按照您的代码,它将否定负错误代码,然后通过将其保留在 x0
中返回它,这可能不是您想要的。例如,如果您尝试使用 syscall
打开文件,但由于文件不存在而失败并返回 ENOENT
,则 x0
从系统调用返回时将包含 -2
。您的测试将否定它并且您的 syscall
函数将返回 2
,这与 open 成功并在 fd 2 上打开文件没有区别。您可能想提出一些其他机制,但我不知道你是否想要一个全局变量,如 errno
或其他东西。
关于c - Aarch64 程序集中的系统调用调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68711164/