ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

深入理解系统调用

2020-05-27 22:57:00  阅读:245  来源: 互联网

标签:kernel 调用 5.4 系统 理解 深入 linux 64


 

 

一、实验目标

(1)、找一个系统调用,系统调用号为学号最后2位相同的系统调用

(2)、通过汇编指令触发该系统调用

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

(4)、重点阅读分析系统调用入口的保存现场、恢复现场和系统调用返回,以及重点关注系统调用过程中内核堆栈状态的变化

 

二、实验过程

(1).内核源码下载及编译

采用的linux内核为5.4.34版本:

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
make defconfig # Default configuration is based on 'x86_64_defconfig'

使用文本菜单进行选项设置

make menuconfig

此时可能出现以下错误:

 

 

此时需要调整窗口终端大小即可,或者直接将其最大化,如下图所示:

 

 

按下述指令对窗口进行配置:

# 打开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) # nproc gives the number of CPU cores/threads available
# 测试⼀下内核能不能正常加载运⾏,因为没有⽂件系统终会kernel panic 
qemu-system-x86_64 -kernel arch/x86/boot/bzImage  #  不能正常运行

 

 

(2).制作根文件系统

相关代码如下:

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) 
#然后编译安装,默认会安装到源码⽬录下的 _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 "Welcome My OS!"
echo "-------------------"
cd home
/bin/sh

 

 给init脚本增加可执行权限

chmod +x init

 

输入下面代码查看qemu运行情况:

#打包成内存根⽂件系统镜像 (rootfs下运行)
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 

 如下图所示:

 

 

(3).触发系统调用

本人学号后两位为:16,故通过查看打开/linux-5.4.34/arch/x86/entry/syscalls/syscall_64.tbl可知16号调用为ioctl,代码入口为:_64_sys_iotcl,

 

使用下面的代码触发系统调用:

//sys16.c
int main()
{
  asm volatile(
     //使⽤EAX传递系统调⽤号16
  "movl $0x10,%eax\n\t"
    //触发系统调用
  "syscall\n\t" 
   );
  return 0;
} 

 对该程序进行静态编译

gcc sys16.c -o syscaall16 -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 -S -s

在linux-5.4.34目录下启动gdb调试

 

gdb vmlinux
target remote:1234
b __64x_sys_msgrcv
c

获取16号系统调用的返回信息

使用bt命令查看栈信息

(4).系统调用的保存和恢复现场

syscall指令触发系统调用,通过MSR寄存器找到了中断函数入口,系统调用入口为entry_SYSCALL_64,其中使用了swapgs这一方法来快照式的保存现场,加快了系统调用,随后对一些相关寄存器进行压栈操作。

在do_syscall_64函数中,在ax寄存器中获取到系统调用号所对应的入口,跳转执行。

随后便执行16号系统调用相关内容,调用结束后准备恢复现场

 

三、总结

从系统调用的整个过程来看,主要有以下几个阶段:

(1)用户态程序,发生syscall,触发系统调用;

(2)进入内核态,完成内核初始化后,调用entry_SYSCALL_64 ()

(3)完成现场的保存,将关键寄存器压栈,并从CPU内部的MSR寄存器来查找系统调⽤处理⼊⼝,更改CPU的指令指针(eip/rip)到系统调⽤处理⼊⼝ ,调用do_syscall_64()

(4)do_syscall_64()函数中得到系统调用号,调用相关的函数gettimeofday()

(5)调用结束后,保存现场和恢复现场时的CPU寄存器也通过CPU内部的存储器快速保存和恢复 

(6)系统调用返回,回到用户态程序

 

 

 

 

 

 

 

标签:kernel,调用,5.4,系统,理解,深入,linux,64
来源: https://www.cnblogs.com/ustcsselee/p/12956874.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有