点击查看系列文章 =》 Interrupt Pipeline系列文章大纲-优快云博客
原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!
5.1. ARM64 Linux系统调用
5.1.1 用户层:用hello world演示系统调用
从何说起?从最简单的hello world实例说起!
root@u20:~# cat hello.c
#include <stdio.h>
int main()
{
printf("Hello World!\n");
return 0;
}
root@u20:~# gcc -g -o hello hello.c
一个最简单的hello world程序,会涉及多少系统调用?使用strace -c来统计一下涉及了哪些syscall,如下图:
接下来使用gdb来找出系统调用write对应的汇编指令:
(1)通过(gdb) catch syscall write定义一个断点。
(2)执行(gdb) run,走到write断点。
(3)通过(gdb) disassemble打印出当前上下文的汇编代码。
上述汇编代码片段是 __GI___libc_write 函数的一部分,这是 GNU C 库(glibc)中实现的 write 系统调用的包装函数。这个函数的作用是准备参数并通过系统调用write来与内核交互,以完成实际的数据写入操作。在hello world代码中,所谓数据写入对应的就是printf操作。
其中的关键代码片段如下:
0x0000fffff7f08c7c <+44>: mov x8, #0x40 // #64
0x0000fffff7f08c80 <+48>: svc #0x0
在发起 SVC 指令之前,应用程序需要将系统调用号以及任何必要的参数放置在特定的寄存器中。对于 AArch64 来说:系统调用号通常放在 x8 寄存器。参数依次放在 x0 到 x7 寄存器中(最多 6 个参数通过寄存器传递,更多参数可以通过内存传递)。
在当前的例子中,x8 被设置为 0x40,这是 write 系统调用的编号,对应的十进制是64。
当程序在用户层(EL0)执行 SVC 指令时,它会触发一个同步异常(即软件中断),导致处理器进入更高的特权级别(通常是 EL1,即操作系统运行的级别)。
那么Linux内核如何处理这个EL0 同步异常呢?在下一章节揭晓。
5.1.2 内核层:ARM64 Linux系统调用的流程与定义
点击查看系列文章 =》 Interrupt Pipeline系列文章大纲-优快云博客
原创不易,需要大家多多鼓励!您的关注、点赞、收藏就是我的创作动力!