---恢复内容开始---
学号178原创作品转载请注明出处
本实验来源 https://github.com/mengning/linuxkernel/
实验要求
举例跟踪分析Linux内核5.0系统调用处理过程
编译内核5.0
qemu -kernel linux-5.0.1/arch/x86/boot/bzImage -initrd rootfs.img
选择系统调用号后两位与您的学号后两位相同的系统调用进行跟踪分析
https://github.com/mengning/menu
给出相关关键源代码及实验截图,撰写一篇博客(署真实姓名或学号最后3位编号),并在博客文章中注明“原创作品转载请注明出处 + https://github.com/mengning/linuxkernel/ ”,博客内容的具体要求如下:
题目自拟,内容围绕系统调用进行;
博客中需要使用实验截图
博客内容中需要仔细分析系统调用、保护现场与恢复现场、系统调用号及参数传递过程
总结部分需要阐明自己对系统调用工作机制的理解。
实验环境
- Ubuntu
- gcc 7.3.0
编译环境
下载内核5.0内核代码,配置编译Linux内核,使之携带调试信息
下载内核源码 Linux内核5.0 source code
解压到目录中
安装编译内核需要的依赖:sudo apt install bison flex
make menuconfig,并找到kernel hacking,->Compile-time checks and compiler options,选择 [*]compile the kernel with debug info
make -j4 (4线程加速编译过程)
---恢复内容结束---
学号178原创作品转载请注明出处
本实验来源 https://github.com/mengning/linuxkernel/
实验要求
举例跟踪分析Linux内核5.0系统调用处理过程
编译内核5.0
qemu -kernel linux-5.0.1/arch/x86/boot/bzImage -initrd rootfs.img
选择系统调用号后两位与您的学号后两位相同的系统调用进行跟踪分析
https://github.com/mengning/menu
给出相关关键源代码及实验截图,撰写一篇博客(署真实姓名或学号最后3位编号),并在博客文章中注明“原创作品转载请注明出处 + https://github.com/mengning/linuxkernel/ ”,博客内容的具体要求如下:
题目自拟,内容围绕系统调用进行;
博客中需要使用实验截图
博客内容中需要仔细分析系统调用、保护现场与恢复现场、系统调用号及参数传递过程
总结部分需要阐明自己对系统调用工作机制的理解。
实验环境
- Ubuntu
- gcc 7.3.0
编译环境
下载内核5.0内核代码,配置编译Linux内核,使之携带调试信息
下载内核源码 Linux内核5.0 source code
解压到目录中
安装编译内核需要的依赖:sudo apt install bison flex
make menuconfig,并找到kernel hacking,->Compile-time checks and compiler options,选择 [*]compile the kernel with debug info
make -j4 (4线程加速编译过程)
将git上的一个根文件系统下载下来打包成img文件
cd ~/Lkernel/
mkdir rootfs
git clone https://github.com/mengning/menu.git
cd menu
cd ../rootfs cp ../menu/init ./ find . | cpio -o -Hnewc |gzip -9 > ../rootfs.img
启动Menu os
cd ~/Lkernel/
qemu-system-x86_64 -kernel linux-5.0.1/arch/x86/boot/bzImage -initrd rootfs.img
跟踪调试
执行以下命令
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
选择系统调用号后两位与您的学号后两位相同的系统调用进行跟踪分析
我的学号为178,因此找到78对应的系统调用为gettimeofday
函数原型:
#include<sys/time.h>
int gettimeofday(struct timeval*tv,struct timezone *tz )
说明:
gettimeofday()会把目前的时间用tv 结构体返回,当地时区的信息则放到tz所指的结构中
结构体:
1>timeval
struct timeval{
long tv_sec;/*秒*/
long tv_usec;/*微妙*/
};
2>timezone 结构定义为:
struct timezone{
int tz_minuteswest;/*和greenwich 时间差了多少分钟*/
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
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);
}
使用gdb断点,分析系统调用
gdb -q
file gettime //运行gettime
list
b gettimeofday //设置断点处为gettimeofday函数调用处
箭头处为运行处。
当函数跳转至call时,函数跳转。
调用寄存器exa 存储 78 即 gettimeofday。
三、总结
API、中断向量对应的system_call、中断服务程序system_service
当用户态进程调用一个系统调用时,CPU切换到内核态并开始执行一个内核函数,在Linux中是通过执行int $0x80来执行系统调用的,这条汇编指令产生向量为128的编程异常。内核实现了很多不同的系统调用,进程必须指明需要哪个系统调用,这需要传递一个名为系统调用号的参数,使用eax寄存器
系统调用的参数传递方法:
system_call是linux中所有系统调用的入口点,每个系统调用至少有一个参数,即由eax传递的系统调用号
进入sys_call之后,立即将eax的值压入内核堆栈
寄存器在传递参数时的限制:
1)每个参数的长度不能超过寄存器的长度,即32位。
2)在系统调用号(eax)之外,参数的个数不能超过6个(ebx,ecx,edx,esi,edi,ebp),若超过6个,就将某一个寄存器作为指针,指向一块内存,在进入内核态之后,可以访问所有的地址空间,通过内存来传递参数。
从实验中我们可以发现
通过eax传递系统调用号,然后由system_call交给system_service完成工作;system_service完成工作后,结果又由eax传递给用户态堆栈。