【Linux】系统调用

编译配置安装Linux内核

sudo apt install axel
axel -n 20 https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/linux-5.4.34.tar.xz
xz -d linux-5.4.34.tar.xz 
tar -xvf linux-5.4.34.tar
cd linux-5.4.34
sudo apt install build-essential gcc-multilib  libncurses5-dev bison flex libssl-dev libelf-dev
sudo apt install qemu 
sudo apt install make  
make defconfig 
make menuconfig

#####################在界面内这样设置
Kernel hacking ---> 
Compile-time checks and compiler options ---> 
[*] Compile the kernel with debug info 
[*] Provide GDB scripts for kernel debugging
Processor type and features ----> 
[] Randomize the address of the kernel image (KASLR)
################################

make -j$(nproc)
qemu-system-x86_64 -kernel arch/x86/boot/bzImage #没有⽂件系统最终会kernel panic

制作根文件系统

#利用BusyBox构造根文件系统
axel -n 20 https://busybox.net/downloads/busybox-1.31.1.tar.bz2
tar -jxvf busybox-1.31.1.tar.bz2
cd busybox-1.31.1
make menuconfig
############勾选静态链接编译
Settings  --->
    [*] Build static binary (no shared libs) 
####################
make -j$(nproc) && make install
cd ..
mkdir rootfs
cd rootfs
cp ../busybox-1.31.1/_install/* ./ -rf
mkdir dev proc sys home
sudo cp -a /dev/{null,console,tty,tty1,tty2,tty3,tty4} dev/
#准备放在根⽂件系统跟⽬录的init脚本
touch init
chmod +x init

init.c脚本内容如下

 #!/bin/sh
 mount -t proc none /proc 
 mount -t sysfs none /sys
 echo "Wellcome MyOS!"
 echo "--------------------" 
 cd home
 /bin/sh 
#打包成内存根⽂件系统镜像 
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../ rootfs.cpio.gz 
#测试挂载根⽂件系统,看内核启动完成后是否执⾏init脚本 
cd ..
qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz

lseek为例,尝试通过汇编指令触发该系统调用

 通过查阅/linux-5.4.34/arch/x86/entry/syscalls/syscall_64.tbl文件,能够找到8号系统调用为lseek

lseek是一个用于改变读写一个文件时读写指针位置的一个系统调用:

off_t  lseek(int fd, off_t offset, int whence);

编写一个程序调用lseek:

结果:      

#查看调用过程的汇编形式
gcc -S -o mylseek.s mylseek.c -static

通过汇编代码调用lseek

 

 再次打包根目录,再次执行内核

cd roofs
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../ rootfs.cpio.gz 
cd ..
qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz -S -s -nographic -append "console=ttyS0"
#另外一个终端运行gdb进行调试
gdb vmlinux   #target remote:1234

再输入b __x64_sys_lseek打断点

输入c使内核进行执行

通过gdb跟踪lseek的内核处理过程

在内核端执行根文件下的mylseek,由于gdb的调试断点,程序停了下来

此时通过bt可以看到此时的堆栈信息

 连续输入n可以查看lseek的执行过程

总结

当⽤户态进程调⽤⼀个系统调⽤时,CPU切换到内核态并执⾏entry_SYSCALL_64以及do_syscall_64,根据系统调⽤号调⽤对应的内核处理函数。

在执行do_syscall_64之前会上保存⼀些上下文信息,如当前执⾏程序的栈顶地址(ESPRSP)、状态字(EFlagsRFlags)、CS:EIP 的值等,并且将CS:EIP寄存器的值指向系统调⽤处理的⼊⼝。

在系统调用执行完成后,调用iret或者sysret进行对应的出栈操作恢复现场、回到用户态,系统调用过程便完成了。

 

posted @ 2020-05-27 19:42  Gyzarus  阅读(266)  评论(0编辑  收藏  举报