举例跟踪分析Linux内核5.0系统调用处理过程

427+原创作品转载请注明出处 + https://github.com/mengning/linuxkernel/

实验要求

题目自拟,内容围绕系统调用进行;
博客中需要使用实验截图
博客内容中需要仔细分析系统调用、保护现场与恢复现场、系统调用号及参数传递过程
总结部分需要阐明自己对系统调用工作机制的理解。

实验环境

ubuntu 14 32位

1.编译linux5.0.1内核

1.下载linux5.0.1内核源码,使用make menuconfig 配置编译,使内核带调试信息。

步骤顺序如下:
举例跟踪分析Linux内核5.0系统调用处理过程举例跟踪分析Linux内核5.0系统调用处理过程举例跟踪分析Linux内核5.0系统调用处理过程举例跟踪分析Linux内核5.0系统调用处理过程配置好后保存退出,使用make bzImage 命令编译内核。
举例跟踪分析Linux内核5.0系统调用处理过程

2.制作根文件系统

使用如下命令

  • cd linux-expriment
  • mkdir rootfs
  • git clone https://github.com/mengning/menu.git
  • cd menu
  • gcc -pthread -o init linktable.c menu.c test.c -m32 -static
  • cd …/rootfs
  • cp …/menu/init ./
  • find . | cpio -o -Hnewc |gzip -9 > …/rootfs.img

举例跟踪分析Linux内核5.0系统调用处理过程## 3.使用qemu启动系统
使用命令:

qemu-system-i386 -kernel linux-5.0.1/arch/x86/boot/bzImage -initrd rootfs.img

举例跟踪分析Linux内核5.0系统调用处理过程使用gdb 插入断点start_kernel 可以分析内核启动过程
举例跟踪分析Linux内核5.0系统调用处理过程

2.系统调用

选择27号系统调用。

#include <unistd.h>
unsigned int alarm(unsigned int seconds)
系统调用alarm安排内核为调用进程在指定的seconds秒后发出一个SIGALRM的信号。如果指定的参数seconds为0,则不再发送 SIGALRM信号。后一次设定将取消前一次的设定。该调用返回值为上次定时调用到发送之间剩余的时间,或者因为没有前一次定时调用而返回0。

系统调用查询文件 linux-5.0.1/arch/x86/entry/syscalls.tbl
举例跟踪分析Linux内核5.0系统调用处理过程
查询可知,27号系统调用为alarm。
修改menu/test.c文件
举例跟踪分析Linux内核5.0系统调用处理过程
分别添加关于alarm的API调用和系统调用函数(asm)。

重新生成根系统文件,再调试。添加断点 sys_alarm
举例跟踪分析Linux内核5.0系统调用处理过程
举例跟踪分析Linux内核5.0系统调用处理过程
举例跟踪分析Linux内核5.0系统调用处理过程

分析

  1. 当⽤户态进程调⽤⼀个系统调⽤时,CPU切换到内核态并开始执⾏⼀个内核函数。在Linux中是通过执⾏int $0x80来执⾏系统调⽤的,这条汇编指令产⽣向量为128的编程异常。
  2. 传参:
    内核实现了很多不同的系统调⽤,进程必须指明需要哪个系统调⽤,这需要传递⼀个名为系统调⽤号的参数。
    使用eax寄存器。
  3. 系统调⽤也需要输⼊输出参数,例如
    • 实际的值
    • ⽤户态进程地址空间的变量的地址
    • 甚⾄是包含指向⽤户态函数的指针的数据结构的地址
  4. system_call是linux中所有系统调⽤的⼊⼜点,每个系统调⽤⾄少有⼀个参数,即由eax传
    递的系统调⽤号
    • ⼀个应⽤程序调⽤fork()封装例程,那么在执⾏int $0x80之前就把eax寄存器的值置为2(即
      __NR_fork)。
    • 这个寄存器的设置是libc库中的封装例程进⾏的,因此⽤户⼀般不关⼼系统调⽤号
    • 进⼊sys_call之后,⽴即将eax的值压⼊内核堆栈