lab4:以time/gettimeofday系统调用为例分析ARM64 Linux 5.4.34

本文详细介绍了如何在Ubuntu上安装交叉编译工具链,制作ARM64的根文件系统,以及利用BusyBox构建基础环境。接着,讨论了Linux系统的启动配置,包括创建必要的系统文件和目录。文章重点在于分析time/gettimeofday系统调用在ARM64架构下的执行流程,涉及系统调用参数、异常处理和内核态转换。通过对调用堆栈的观察,解释了ARM64中系统调用的执行机制。
摘要由CSDN通过智能技术生成

1.

安装编译工具链

由于Ubuntu是X86架构,为了编译arm64的文件,需要安装交叉编译工具链

sudo apt install gcc-aarch64-linux-gnu

sudo apt install libncurses5-dev  build-essential git bison flex libssl-dev

 2.第二步是制作根文件系统

linux的启动需要配合根文件系统,和实验三一样我们利用busybox来制作一个简单的根文件系统

我们在实验三的时候利用了busybox制作简单的根文件系统,在本次实验和上次相同,也是制作一个简单的根文件系统

cd ~/linux_lab/lab4

wget  https://busybox.net/downloads/busybox-1.33.1.tar.bz2

 tar   -jxvf busybox-1.33.1.tar.bz2

cd busybox-1.33.1

3. 类似lab3 我们打开静态库编译选项

make menuconfig

 接着,我们指定编译工具

export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-

然后进行编译

make -j$(nproc) && make install

这样我们就做完了准备工作

4.为了实现正常启动,我们还需要额外的配置

我们编译完成后有_intstall目录

进入_install目录

根目录添加etc、dev和lib目录

我们在etc目录下创建文件profile、inittab、fstab、init.d/rcS

vim profile
#!/bin/sh
export HOSTNAME=imingz
export USER=root
export HOME=/home
export PS1="[$USER@$HOSTNAME \W]\# "
PATH=/bin:/sbin:/usr/bin:/usr/sbin
LD_LIBRARY_PATH=/lib:/usr/lib:$LD_LIBRARY_PATH
export PATH LD_LIBRARY_PATH

vim inittab
::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
::askfirst:-/bin/sh
::ctrlaltdel:/bin/umount -a -r

vim fstab
#device  mount-point    type     options   dump   fsck order
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
debugfs /sys/kernel/debug debugfs defaults 0 0
kmod_mount /mnt 9p trans=virtio 0 0

mkdir -p init.d

vim init.d/rcS

mkdir -p /sys
mkdir -p /tmp
mkdir -p /proc
mkdir -p /mnt
/bin/mount -a
mkdir -p /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s

如下图所示: 

对其他文件夹的操作如下图所示:

 我们像实验三一样,制作linux

因为本次实验是在arm64的情况下进行编译的

所以要求如下所示:

我们将之前制作好的根文件系统cp到root目录下

cp -r ../busybox-1.33.1/_install root
sudo mknod root/dev/console c 5 1

执行编译

启动qemu

下载qemu

使用 4.2.1 版本的 qemu

sudo apt install build-essential zlib1g-dev pkg-config libglib2.0-dev binutils-dev libboost-all-dev autoconf libtool libssl-dev libpixman-1-dev libpython-dev python-pip python-capstone virtualenv
./configure --target-list=x86_64-softmmu,x86_64-linux-user,arm-softmmu,arm-linux-user,aarch64-softmmu,aarch64-linux-user --enable-kvm
make 
sudo make install

执行命令:

 执行命令:

/usr/local/bin/qemu-system-aarch64 -m 512M -smp 4 -cpu cortex-a57 -machine virt -kernel /home/hanjiajun/linux/lab4/linux-5.4.34/arch/arm64/boot/Image -append "rdinit=/linuxrc nokaslr console=ttyAMA0 loglevel=8" -nographic -s

进行编译

接下来就是本次实验的重点了:

分析 time/gettimeofday 系统调用在 ARM64 Linux 中的执行过程 

 在VSCODE中调试:

 分析:

通过查看调用堆栈,我们能很容易地分析出 ARM64 下系统调用的执行过程。ARM64 架构下 Linux 系统调用由同步异常 svc 指令触发,当用户态(EL0 级)程序调用库函数 gettimeofday() 从而触发系统调用的时候,先把系统调用的参数依次放入 X0-X5 这 6 个寄存器(Linux 系统调用最多有 6 个参数,ARM64 函数调用参数可以使用 X0-X7 这 8 个寄存器),然后把系统调用号放在 X8 寄存器里,最后执行 svc 指令,CPU 即进入内核态(EL1 级)。本文使用内嵌汇编触发系统调用,我们也编写相应的汇编代码完成了上述过程。

ARM64 架构的 CPU 中,Linux 系统调用(同步异常)和其他异常的处理过程大致相同。异常发生时,CPU 首先把异常的原因(比如执行 svc 指令触发系统调用)放在 ESR_EL1 寄存器里;把当前的处理器状态(PSTATE)放入 SPSR_EL1 寄存器里;把当前程序指针寄存器 PC 的值存入 ELR_EL1 寄存器里(保存断点),然后 CPU 通过异常向量表(vectors)基地址和异常的类型计算出异常处理程序的入口地址,即 VBAR_EL1 寄存器加上偏移量取得异常处理的入口地址,接着开始执行异常处理入口的第一行代码。这一过程是 CPU 硬件自动完成的,不需要程序干预。

随后,以 svc 指令对应的 el0_sync 为例,el0_sync 处的内核汇编代码首先做的就是保存异常发生时程序的执行现场(保存现场,即用户栈、通用寄存器等),然后根据异常发生的原因(ESR_EL1 寄存器中的内容)跳转到 el0_svc,el0_svc 会调用 el0_svc_handler、el0_svc_common 函数,将 X8 寄存器(regs->regs[8])中存放的系统调用号传递给 invoke_syscall 函数。

 

 系统调用内核处理函数执行完成后,会将系统调用的返回值存放在 X0 寄存器中。

我们可以看到 被存放在了X0寄存器中

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值