学号后三位098
原创作品转载请注明出处 + https://github.com/mengning/linuxkernel/
1.编译内核5.0
2.选择系统调用进行跟踪分析
VM14pro虚拟机
ubuntu系统(ubuntu-18.04.2-desktop-amd64)
打开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
学号为:098,使用98系统调用号,转化为16进制即0X62.
该系统调用号的作用为#define __NR_getrusage
功能描述:
获得进程的相关资源信息。如:用户开销时间,系统开销时间,接收的信号量等等;
用法:
#include
#include
#include
#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
#include
#include
#include
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
#include
#include
#include
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);
分别编译运行,结果如下:
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()。