分析Linux内核5.0系统调用处理过程

学号后三位098
原创作品转载请注明出处 + https://github.com/mengning/linuxkernel/

1.实验目标

1.编译内核5.0
2.选择系统调用进行跟踪分析

2.实验环境

VM14pro虚拟机

ubuntu系统(ubuntu-18.04.2-desktop-amd64)

3.实验步骤

1.编译内核

打开shell命令行。

输入 wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.0.tar.xz,载压缩包。

使用xz -d linux-5.0.tar.xz转化格式

使用tar -xvf linux-5.0.tar解压

解压后的文件目录如下:

使用cd linux-5.0定位到源文件夹

使用make i386_defconfig进行编译

出现错误:

使用sudo apt-get install flex安装flex

使用sudo apt-get install bison安装bison

再次make i386_defconfig

使用make编译

出现问题;

使用sudo apt-get install libssl-dev来解决

再次编译。

建立根文件系统


sudo apt-get install gcc-multilib//这一步是必要的,不然会报错,需要安装gcc编译器

cd ..
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

2.系统调用

学号为:098,使用98系统调用号,转化为16进制即0X62.

该系统调用号的作用为#define __NR_getrusage

功能描述:

    获得进程的相关资源信息。如:用户开销时间,系统开销时间,接收的信号量等等;

用法:

   #include <sys/types.h>

   #include <sys/time.h>

   #include <sys/resource.h>

   #define   RUSAGE_SELF     0

   #define   RUSAGE_CHILDREN     -1

   int getrusage(int who, struct rusage *usage); 

    当调用成功后,返回0,否则-1; 

参数:

    who:可能选择有

    RUSAGE_SELF:获取当前进程的资源使用信息。以当前进程的相关信息来填充rusage(数据)结构

    RUSAGE_CHILDREN:获取子进程的资源使用信息。rusage结构中的数据都将是当前进程的子进程的信息

    usage:指向存放资源使用信息的结构指针。

rusage(数据)结构定义在/usr/include/sys/resource.h中,下面是rusage的结构:

struct rusage {

        struct timeval ru_utime; // user time used 

        struct timeval ru_stime; // system time used 

        long ru_maxrss; // maximum resident set size 

        long ru_ixrss; // integral shared memory size

        long ru_idrss; // integral unshared data size 

        long ru_isrss; // integral unshared stack size 

        long ru_minflt; // page reclaims 

        long ru_majflt; // page faults 

        long ru_nswap;// swaps

        long ru_inblock; // block input operations 

        long ru_oublock; // block output operations 

        long ru_msgsnd; // messages sent 

        long ru_msgrcv; //messages received 

        long ru_nsignals; // signals received 

        long ru_nvcsw; // voluntary context switches 

        long ru_nivcsw; // involuntary context switches 

};

定义两个c文件:rusage.c,rusageASM.c

分别使用c语言和汇编语言进行系统调用.

rusage.c

   #include <stdio.h>
   #include <sys/types.h>
   #include <sys/time.h>
   #include <sys/resource.h>
int main(void){
   struct rusage rup;
   getrusage(RUSAGE_SELF, &rup);
   printf("integral shared memory size is:%lu\r\n",(unsigned long)rup.ru_ixrss);
   printf("integral unshared memory size is:%lu\r\n",(unsigned long)rup.ru_isrss);
   printf("maximum resident set size  is:%lu\r\n",(unsigned long)rup.ru_maxrss);
   printf("User Time:%lu\n",rup.ru_utime.tv_usec);
   printf("System Time:%lu\n",rup.ru_stime.tv_usec);

}

rusageASM.c

   #include <stdio.h>
   #include <sys/types.h>
   #include <sys/time.h>
   #include <sys/resource.h>
int main(void){
   struct rusage rup;
   getrusage(RUSAGE_SELF, &rup);
   printf("integral shared memory size is:%lu\r\n",(unsigned long)rup.ru_ixrss);
   printf("integral unshared memory size is:%lu\r\n",(unsigned long)rup.ru_isrss);
   printf("maximum resident set size  is:%lu\r\n",(unsigned long)rup.ru_maxrss);
   printf("User Time:%lu\n",rup.ru_utime.tv_usec);
   printf("System Time:%lu\n",rup.ru_stime.tv_usec);

分别编译运行,结果如下:

3.总结

1)系统调用可以通过编程语言的API和汇编代码实现

2)调用是一个用户态->内核态->用户态的过程

3)当调用一个系统调用时,CPU从用户态切换到内核态并开始执行一个system_call和系统调用内核函数。在Linux中通过执行int 0x80来触发系统调用,内核为每个系统调用分配一个系统调用号,用户态进程必须明确指明系统调用号,需要使用EAX寄存器来传递。

4)系统调用可能需要参数,但是不能通过像用户态进程函数中将参数压栈的方式传递,因为用户态和内核态有不同的堆栈,必须通过寄存器的方式传递参数。

5)普通情况下应用程序通过应用编程接口API,而不是直接通过系统调用来编程。

6)操作系统通常是通过中断从用户态切换到内核态。中断就是一个硬件或软件请求,要求CPU暂停当前的工作,去处理更重要的事情。

比方。在x86机器上能够通过int指令进行软件中断。而在磁盘完毕读写操作后会向CPU发起硬件中断。

中断有两个重要的属性,中断号和中断处理程序。中断号用来标识不同的中断,不同的中断具有不同的中断处理程序。在操作系统内核中维护着一个中断向量表(Interrupt Vector Table)。这个数组存储了全部中断处理程序的地址,而中断号就是对应中断在中断向量表中的偏移量。

一般地,系统调用都是通过软件中断实现的,x86系统上的软件中断由int $0x80指令产生,而128号异常处理程序就是系统调用处理程序system_call()。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要在Linux内核中添加系统调用,需要进行以下步骤: 1. 编写系统调用函数:首先需要编写一个新的系统调用函数,这个函数需要实现你想要的功能。这个函数需要遵循Linux内核的规范,并且需要在内核中注册。 2. 修改系统调用系统调用是一个数组,其中包含了所有系统调用的函数指针。要添加一个新的系统调用,需要将其函数指针添加到系统调用中。 3. 更新系统调用号:每个系统调用都有一个唯一的系统调用号,这个号码用于在用户空间中调用系统调用。要添加一个新的系统调用,需要为其分配一个唯一的系统调用号。 4. 编译内核:完成以上步骤后,需要重新编译内核,以便将新的系统调用添加到内核中。 5. 测试系统调用:最后,需要编写一个测试程序来测试新的系统调用是否正常工作。这个测试程序需要在用户空间中调用新的系统调用,并检查其返回值是否正确。 总之,添加一个新的系统调用需要进行一系列的步骤,需要仔细考虑每个步骤的细节,以确保新的系统调用能够正常工作。 ### 回答2: ### 回答3: 系统调用是操作系统核心的一部分,是一组接口函数,用于在用户空间和内核空间之间提供通信和交互。在Linux内核中添加新的系统调用可以增强其功能和性能,同时也方便了应用程序开发者的使用。下面是Linux内核添加系统调用的基本步骤: 1. 编写新的系统调用函数,即定义一个新的C语言函数,并将其添加到内核源代码中。这个新函数必须满足一定的要求,比如返回值类型必须为long类型,参数列也必须符合规范。 2. 修改内核系统调用,将新的系统调用添加到系统调用中。系统调用可以用一个数组来示,由于其是一个全局变量,因此该修改需要在内核源代码中进行。 3. 重新编译内核,生成新的内核映像文件。在重新编译内核之前,你需要确认编译环境是否安装好,包括gcc,binutils,make等。 4. 更新bootloader,将新的内核映像文件加载到系统中。一般情况下,先拷贝内核映像文件到/boot目录下,然后更新bootloader配置文件,使其能够正确地加载新的内核映像文件。 5. 重启系统,验证新系统调用的正确性。在重启系统后,可以使用任何支持该系统调用的应用程序测试其正确性。如果系统调用的实现存在问题,可以通过反复测试迭代来调试和修复该系统调用。 总的来说,添加新的系统调用需要对Linux内核有一定的了解,并且需要对内核的源代码进行修改和编译。同时,添加新的系统调用需要小心谨慎,避免对系统造成不必要的损伤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值