Linux实验(二):跟踪分析LINUX内核5.0系统调用处理过程

学号478原创作品转载请注明出处
本实验来源 https://github.com/mengning/linuxkernel/
一.编译Linux5.0内核
1.从官网下载最新的Linux5.0内核源码
2.需要安装的依赖库
sudo apt-get install libncurses5-dev libssl-dev
sudo apt-get install build-essential openssl
sudo apt-get install libidn11-dev libidn11
sudo apt-get install bison
3.配置内核编译参数
sudo make menuconfig
Linux实验(二):跟踪分析LINUX内核5.0系统调用处理过程
Linux实验(二):跟踪分析LINUX内核5.0系统调用处理过程
4.编译内核
make
编译后输出信息如下所示:
Linux实验(二):跟踪分析LINUX内核5.0系统调用处理过程
5.准备根文件系统
mkdir ~/LinuxKernel
cd ~/LinuxKernel/
mkdir rootfs
git clone https://github.com/mengning/menu.git
cd menu/
gcc -o init linktable.c menu.c test.c -m32 -static -pthread
cd …/rootfs/
cp …/menu/init ./
find . | cpio -o -Hnewc |gzip -9 > …/rootfs.img
6.运行MenuOS:
sudo ln -s /usr/bin/qemu-system-i386 /usr/bin/qemu
qemu -kernel /usr/src/linux-5.0.1/arch/x86/boot/bzImage -initrd …/rootfs.img
Linux实验(二):跟踪分析LINUX内核5.0系统调用处理过程
二.跟踪调试
1.执行以下命令
qemu-system-x86_64 -kernel linux-5.0.1/arch/x86/boot/bzImage -initrd rootfs.img -S -s -append nokaslr

cd linux-5.0.1
gdb
(gdb)file vmlinux
(gdb)target remote:1234
(gdb)break start_kernel
(gdb) c
Linux实验(二):跟踪分析LINUX内核5.0系统调用处理过程
2.选择系统调用号后两位与您的学号后两位相同的系统调用进行跟踪分析
Linux实验(二):跟踪分析LINUX内核5.0系统调用处理过程
3.学号478,所以选择系统调用为gettimeofday
函数说明:
int gettimeofday(struct timeval*tv,struct timezone *tz )
gettimeofday()函数会把目前的时间用tv 结构体返回,当地时区的信息放到tz所指的结构中。
4.函数分析
(1)timeval

struct  timeval{
       long  tv_sec;/*秒*/

       long  tv_usec;/*微妙*/
}

(2)timezone 结构定义为:

struct  timezone{

int tz_minuteswest;/*时间差了多少分钟*/

int tz_dsttime;/*type of DST correction*/

}

(3)在gettimeofday()函数中tv或者tz都可以为空。如果为空则就不返回其对应的结构体。

(4)函数执行成功后返回0,失败后返回-1,错误代码存于errno中。
采用系统API和汇编两种方式调用该函数,在桌面上建立两个程序:78.c和78asm.c,指令如下:
gcc -g gettime.c -o gettime -m32

(5)
Linux实验(二):跟踪分析LINUX内核5.0系统调用处理过程

78.c

    #include<stdio.h>
    #include<sys/time.h>
    #include<unistd.h>
    
    int main(){
    struct timeval tv;
    struct timezone tz;
    gettimeofday(&tv,&tz);
    
    printf("tv_sec:%ld\n", tv.tv_sec);
    printf("tv_usec:%ld\n", tv.tv_usec);
    printf("tz_minuteswest:%d\n",tz.tz_minuteswest);
    printf("tz_dsttime:%d\n",tz.tz_dsttime);
    }

(6)gdbd断点调试
gdb -q
file gettime     //运行gettime
list
b gettimeofday   //设置断点处为gettimeofday函数调用处
Linux实验(二):跟踪分析LINUX内核5.0系统调用处理过程
Linux实验(二):跟踪分析LINUX内核5.0系统调用处理过程
分析:箭头处为运行处。当函数跳转至call时,函数跳转。调用寄存器exa 存储 78 即 gettimeofday。
三.总结
Linux系统就是通过内核发出的系统调用(system call)实现了用户态进程和硬件设备之间的大部分接口。计算机系统资源的访问都必须有操作系统控制。也就是说操作系统是使用这些资源的唯一入口,而这个入口就是操作系统提供的系统调用(System Call)。在linux中系统调用是用户空间访问内核的唯一手段,除异常和陷入外,他们是内核唯一的合法入口。
普通情况下应用程序通过应用编程接口API,而不是直接通过系统调用来编程。操作系统通常是通过中断从用户态切换到内核态。中断就是一个硬件或软件请求,要求CPU暂停当前的工作,去处理更重要的事情。比如在x86机器上能够通过int指令进行软件中断。而在磁盘完毕读写操作后会向CPU发起硬件中断。中断有两个重要的属性,中断号和中断处理程序。中断号用来标识不同的中断,不同的中断具有不同的中断处理程序。在操作系统内核中维护着一个中断向量表(Interrupt Vector Table)。这个数组存储了全部中断处理程序的地址,而中断号就是对应中断在中断向量表中的偏移量。一般地,系统调用都是通过软件中断实现的,x86系统上的软件中断由int $0x80指令产生,而128号异常处理程序就是系统调用处理程序system_call()。