码迷,mamicode.com
首页 > 其他好文 > 详细

深入理解系统调用

时间:2020-05-27 20:11:03      阅读:58      评论:0      收藏:0      [点我收藏+]

标签:启动   type   base   div   highlight   内容   zip   idt   find   

一、实验要求

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

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

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

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

二、实验环境准备

(1)安装工具:

sudo apt install build-essential
sudo apt install qemu # install QEMU
sudo apt install libncurses5-dev bison ?ex libssl-dev libelf-dev

(2)下载内核源码:

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

(3)配置内核编译选项

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)

(4)编辑内核

make -j$(nproc) # nproc gives the number of CPU cores/threads available
# 测试?下内核能不能正常加载运?,因为没有?件系统终会kernel panic
qemu-system-x86_64 -kernel arch/x86/boot/bzImage  #  此时应该不能正常运行

(5)制作根文件系统

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

(6)制作内核文件系统镜像

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/

(7)准备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

(8)给init脚本增加可执行权限

chmod +x init

(9)输入下面代码查看qemu运行情况

#打包成内存根?件系统镜像
?nd . -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 

技术图片

 

 

三、查找系统调用

  我的学号后两位是36,对应系统调用为getitimer

     技术图片

查阅资料知,getitimer系统调用的功能是:获取间歇计时器的值。系统为进程提供三种类型的计时器,每一类以不同的时间域递减其值。当计时器超时,信号被发送到进程,之后计时器重启动。

 用法:

#include

int getitimer(int which, struct itimerval *value);

参数:
which:间歇计时器类型,有三种选择

ITIMER_REAL //数值为0,计时器的值实时递减,发送的信号是SIGALRM。
ITIMER_VIRTUAL //数值为1,进程执行时递减计时器的值,发送的信号是SIGVTALRM。
ITIMER_PROF //数值为2,进程和系统执行时都递减计时器的值,发送的信号是SIGPROF。

value,ovalue:时间参数,原型如下

struct itimerval {
    struct timeval it_interval; /* 计时器重启动的间歇值 */
    struct timeval it_value;    /* 计时器安装后首先启动的初始值 */
};

struct timeval {
    long tv_sec;                /* 秒 */
    long tv_usec;               /* 微妙(1/1000000) */
};

getitimer()用计时器的当前值填写value指向的结构体。

返回说明:
成功执行时,返回0。失败返回-1,errno被设为以下的某个值
EFAULT:value或ovalue是不有效的指针
EINVAL:其值不是ITIMER_REAL,ITIMER_VIRTUAL 或 ITIMER_PROF之一

 四、触发系统调用

编写程序getitimer.c,使用getitimer来触发系统调用

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <sys/time.h>
#include <errno.h>

void PrintMsg(int Num)
{
    printf("%s\n", "Hello World");

    return;
}

int main(int argc, char* argv[])
{
    signal(SIGALRM, PrintMsg);

    struct itimerval tick;
    tick.it_value.tv_sec = 10;  //十秒钟后将启动定时器
    tick.it_value.tv_usec = 0;
    tick.it_interval.tv_sec  =1; //定时器启动后,每隔1秒将执行相应的函数
    tick.it_interval.tv_usec = 0;

    //setitimer将触发SIGALRM信号
    int ret = setitimer(ITIMER_REAL, &tick, NULL);

    if ( ret != 0)
    {
        printf("Set timer error. %s \n", strerror(errno) );

        return -1;
    }

    printf("Wait!\n");

    getchar();

    return 0;
}

 将测试文件放在rootfs/home 目录下,进行静态编译,再在rootfs目录下重新打包。

gcc -o testge testge.c -static
find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../rootfs.cpio.gz

 使用gdb系统跟踪调用

技术图片

   启动qemu

qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz -S -s -nographic -append "console=ttyS0"

  再重新打开一个终端,运行以下命令:

cd linux-5.4.34/
gdb vmlinux
target remote:1234
b __x64_sys_getitimer
c

  

在运行qemu的终端中,输入./getitimer即可开始单步调试。

 

总结:

系统调用的执行,是用户程序触发系统调用之后,CPU以及内核执行调用的过程。本次实验从调试源码的角度,调试了linux内核系统调用的过程,深刻理解了入口的保存现场、恢复现场和系统调用返回的过程,以及系统调用过程中内核堆栈状态的变化。

深入理解系统调用

标签:启动   type   base   div   highlight   内容   zip   idt   find   

原文地址:https://www.cnblogs.com/yxud/p/12972381.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!