科软Linux | lab4.以time/gettimeofday系统调用为例分析ARM64 Linux 5.4.34

用户态内嵌汇编触发系统调用

配置ARM64环境:

sudo apt-get install gcc-aarch64-linux-gnu
sudo apt-get install libncurses5-dev  build-essential git bison flex libssl-dev
sudo apt install gdb-multiarch
# 为arm64配置内核编译选项:
make defconfig ARCH=arm64
make menuconfig ARCH=arm64

触发系统调用的方法

time 系统调用为例,分别使用C库函数和 int $0x80/syscallsvc 指令汇编代码触发系统调用。
C库函数 time_t time(time_t *seconds) 返回自 1970-01-01 00:00:00(UTC国际时区)起经过的时间,以秒为单位。如果 seconds 不为空,则返回值也存储在变量 seconds 中。
C库函数 struct tm *localtime(const time_t *timer) 使用 timer 的值来填充 stuct tm 结构体。timer 的值被分解到 stuct tm 结构体中,并用本地时区表示。

使用C库函数触发time系统调用

#include <stdio.h>
#include <time.h>
int main()
{
	time_t tt;
	struct tm *t;
	tt = time (NULL);
	t = localtime(&tt);
	printf("time: %d/%d/%d %d:%d:%d\n",
	t一>tm_year + 1900,
	t一>tm_mon,
	t一>tm_mday,t->tm_hour,t一>tm_min,t一>tm_sec);
	return 0;
}

gcc -o time time.c -static
objdump -S time > time64.S
64位机器上编出32位代码需加-m32
sudo apt-get install gcc-multilib
gcc -o time time.c -static -m32
objdump -S time > time32.S

系统调用的参数传递和系统调用号

系统调用表

Linux源代码中的 arch/x86/entry/syscalls/syscall_32.tblarch/x86/entry/syscalls/syscall_64.tbl 分别定义了32位 x86x86-64 的系统调用内核处理函数,它们最终通过脚本转换按照系统调用号依次存入ia32_sys_call_tablesys_call_table 数组中。而系统调用内核处理函数则是由系统调用入口 entry_INT80_32entry_SYSCALL_64 分别调用的do_int80_syscall_32do_syscall_64 来调用执行。do_int80_syscall_32do_syscall_64 的代码如 arch/x86/entry/common.c

start_kernel 函数开始执行之前是用汇编代码初始化 CPU ,其中非常重要的就是将异常向量表的基地址(vectors)配置到 VBAR_EL1 寄存器中,从arch\arm64\kernel\head.S 中可以找到代码,这段代码配置了不仅配置了异常向量表,还配置了0号进程的内核堆栈和进程描述符。

在这里插入图片描述

异常向量表分为4组,每组有4个向量入口地址,分别处理4种不同类型的异常。每个向量入口空间128字节,也就是说,在这个异常向量空间里可以放入32条指令(每条指令4字节)。举个例子,如果用户态程序执行了 svc 指令,这时CPU自动把 VBAR_EL1 寄存器的值(vectors),和第3组Synchronous 的偏移量 0x400 相加,即 vectors + 0x400 ,得出该异常向量空间的入口地址,然后跳转到那里,执行里面的第一条指令。

在这里插入图片描述

ARM64处理保存现场和恢复现场

保存现场

在Linux系统中系统调用发生时,CPU会把当前程序指针寄存器PC放入ELR_EL1 寄存器里,把 PSTATE 放入SPSR_EL1 寄存器里,同时Linux系统从用户态切换到内核态(从EL0切换到EL1),这时SP指的是SP_EL1 寄存器,用户态堆栈的栈顶地址依然保存在 SP_EL0 寄存器中。也就是说异常(这里是指系统调用)发生时CPU的关键状态sppcpstate 分别保存在SP_EL0ELR_EL1SPSR_EL1 寄存器中。保存现场的主要工作如上代码所示,是保存 x0-x30sppcpstate ,这和 struct pt_regs 数据结构的起始部分正好一一对应。
在这里插入图片描述

恢复现场

kernel_exit 0 负责恢复现场的代码和 kernel_entry 0 负责保存现场的代码相对应
在这里插入图片描述

内核堆栈pt_regs等

pt_regs 的数据结构如下:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_之桐_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值