首页 > 其他 > 详细

深入理解系统调用

时间:2020-05-25 21:16:55      阅读:44      评论:0      收藏:0      [点我收藏+]

一、实验要求

1.学号末尾为27,故采用27号系统调用mincore,内核处理函数为__x64_sys_mincore。
技术分享图片

 

 

 

2.通过汇编指令触发系统调用

3.通过gdb跟踪该系统调用的内核处理过程

4.重点阅读分析系统调用入口的保存现场和恢复现场

二、理解基本系统调用流程

基本的系统调用流程可以大致分为以下四步:
1、应用程序代码调用a(),该函数是包装系统调用的库函数;
2、库函数a()负责准备向内核传递的参数,并触发软中断以切换到内核;
3、CPU被软中断打断后,执行中断处理函数,即系统调用处理函数(system_call);
4、系统调用处理函数调用系统调用服务例程(sys_a),开始真正系统调用

三、实验环境准备

在上次实验的基础上,配置内核选项

make defcon?g # Default con?guration is based on ‘x86_64_defcon?g‘
make menucon?g  
# 打开debug相关选项
Kernel hacking  ---> 
    Compile-time checks and compiler options  ---> 
       [*] Compile the kernel with debug info 
       [*]   Provide GDB scripts for kernel debugging
 [*] Kernel debugging 
# 关闭KASLR,否则会导致打断点失败
Processor type and features ----> 
   [] Randomize the address of the kernel image (KASLR)

 编译内核

make -j$(nproc)
# 测试一下内核能不能正常加载运行,因为没有文件系统最终会kernel panic
qemu-system-x86_64 -kernel arch/x86/boot/bzImage

  在这一步中的make -j$(nproc)中,如果遇到了internal compiler error: 已杀死 (program cc1)错误信息,需要增加虚拟机的虚拟内存。

  制作根文件系统

#下载
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 menucon?g 
#记得要编译成静态链接,不?动态链接库。
Settings  --->
    [*] Build static binary (no shared libs) 
#然后编译安装,默认会安装到源码?录下的 _install ?录中。 
make -j$(nproc) && make install
制作内存根文件系统镜像
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脚本文件放在根文件系统跟目录下(rootfs/init),添加如下内容到init文件。#!/bin/sh mount -t proc none /proc mount -t sysfs none /sys echo "Wellcome SJZOS!" echo "--------------------" cd home /bin/sh #给init脚本添加可执行权限 chmod +x init #打包成内存根文件系统镜像 find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../rootfs.cpio.gz #测试挂载根文件系统,看内核启动完成后是否执行init脚本 qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz 

  正常打印,执行成功

技术分享图片

 

 

 四、编写系统调用程序

在/rootfs/home/路径下编写test_mincore.c程序,调用27号系统调用。

int main() {
        asm volatile(
                "movl $0x1B,%eax\n\t"
                "syscall\n\t"
        );
        printf("Hello mincore");
        return 0;
}

 然后采用gcc静态编译,生成可执行文件

gcc -o test_mincore test_mincore.c -static

技术分享图片

 

 

重新执行

find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../rootfs.cpio.gz

qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz

  在qemu中 可以查看到系统中已经有了可执行程序test_mincore

技术分享图片

 

 五、GDB调试

1、采用如下命令启动qemu

 

qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz -s -S

  然后重新开启一个命令行,启动gdb

cd linux-5.4.34/
gdb vmlinux
(gdb) target remote:1234
(gdb) b __x64_sys_mincore

  在mincore调用处打了一个断点,然后输入c继续,qemu开始执行

技术分享图片

 

 在qemu中执行test_mincore,在gdb中捕获到断点

技术分享图片

 

 在gdb中采用bt命令可以查看堆栈信息,l命令查看对应代码。由下图可知,mincore是通过syscall来进行的系统调用,entry_SYSCALL_64是系统调用的入口

技术分享图片

 

 然后使用n命令进行单步执行,可以在gdb中查看保存现场信息的步骤

技术分享图片

 

 技术分享图片

 

 技术分享图片

 

 其中,swapgs指令的作用适用于保存现场,高效的保存上下文的快照。popq %rdi和popq %rsp的作用是恢复寄存器和堆栈现场。最后通过USERGS_SYSRET64宏恢复现场(swapgs)并返回(sysretq)。

六、实验总结

系统调用通过entry_SYSCALL_64入口进行系统调用,其中 执行swapgs来进行保存现场。并通过rax寄存器保存系统调用号,找到对应的mincore系统调用。在系统调用表sys_call_table中找到相应的函数进行调用并将寄存器中保存的参数取出来,作为函数参数,然后陷入内核。系统调用函数执行完毕后,通过popq %rdi 、popq %rsp和宏USERGS_SYSRET64恢复现场并返回。

深入理解系统调用

原文:https://www.cnblogs.com/bryanmelody/p/12960592.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!