深入理解系统调用

一、配置实验环境

1、安装实验工具

1 sudo apt install build-essential
2 sudo apt install qemu
3 sudo apt install libncurses5-dev bison flex libssl-dev libelf-dev

2、下载并解压内核

1 sudo apt install axel 
2 axel -n 20 https://mirrors.edge.kernel.org/pub/linux/kernel/v5.x/ linux-5.4.34.tar.xz 
3 xz -d linux-5.4.34.tar.xz 
4 tar -xvf linux-5.4.34.tar 
5 cd linux-5.4.34

3、配置内核环境

1 make defconfig 
2 make menuconfig 
3 Kernel hacking  ---> 
4     Compile-time checks and compiler options  ---> 
5         [*] Compile the kernel with debug info 
6         [*]   Provide GDB scripts for kernel debugging 
7 [*] Kernel debugging 
8 Processor type and features ----> 
9         [] Randomize the address of the kernel image (KASLR)

部分步骤如下图所示:

深入理解系统调用_第1张图片

深入理解系统调用_第2张图片

 

 

 4、编译运行内核

1 make -j$(nproc)
2 qemu-system-x86_64 -kernel arch/x86/boot/bzImage

5、制作根文件系统

1)下载安装并编译busybox

1 axel -n 20 https://busybox.net/downloads/busybox-1.31.1.tar.bz2 
2 tar -jxvf busybox-1.31.1.tar.bz2 
3 cd busybox-1.31.1
4 make menuconfig 
5  Settings  ---> 
6      [*] Build static binary (no shared libs) 
7 make -j$(nproc) && make install

部分操作如下图所示:

深入理解系统调用_第3张图片

 

2)制作根文件系统镜像

1 mkdir rootfs 
2 cd rootfs 
3 cp ../busybox-1.31.1/_install/* ./ -rf
4 mkdir dev proc sys home 
5 sudo cp -a /dev/{null,console,tty,tty1,tty2,tty3,tty4} dev/

3)新建init脚本⽂件放在根⽂件系统根⽬录下(rootfs/init)

1 touch init
2 vim init

编写如下内容:

 

 深入理解系统调用_第4张图片

4)给init添加可执行权限并打包成内存根⽂件系统镜像,之后测试挂载根⽂件系统,看内核启动完成后是否执⾏init脚本。

1 chmod +x init
2 find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../ rootfs.cpio.gz 
3 qemu-system-x86_64 -kernel linux-5.4.34/arch/x86/boot/bzImage -initrd rootfs.cpio.gz

执行结果如下:

深入理解系统调用_第5张图片

二、编写系统调用程序

1、查找系统调用

我的学号后三位为391,故寻找91号系统调用,查找方法如下:

1 cd ~/linux-5.4.34/arch/x86/entry/syscalls
2 vim syscall_64.tbl

查找结果如下:

深入理解系统调用_第6张图片

2、fchmod函数

深入理解系统调用_第7张图片

 深入理解系统调用_第8张图片

Fchmod函数出错信息:

EBADF:非法的文件描述符。

EIO:发生I/O错误。

EPERM:有效用户ID与文件拥有者不同,进程无权访问、修改文件。

EROFS:文件位于只读文件系统。

3、编写测试程序

1)编写fchmod.c测试文件

 深入理解系统调用_第9张图片

 2)编译并执行该程序

1 gcc -o fchmod fchmod.c -static
2 ./fchmod fchmod.c

将测试文件本身作为测试对象,测试结果如下:

 

3)反汇编该文件

1 objdump -S fchmod > fchmod.S

部分汇编代码如下所示:

 

 深入理解系统调用_第10张图片

4)移动fchmod、fchmod.c文件至根目录的home文件夹下后,重新打包镜像文件

1 find . -print0 | cpio --null -ov --format=newc | gzip -9 > ../ rootfs.cpio.gz 

4、使用gdb跟踪该系统调用

1)启动qemu

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

此时启动不会弹出QEMU虚拟机窗⼝,终端界面会显示停止状态;

2)这时,重新打开一个终端,设置断点并调试

1 cd linux-5.4.34/ 
2 gdb vmlinux 
3 (gdb) target remote:1234
4 (gdb) b start_kernel 
5 (gdb) n

结果如下:

深入理解系统调用_第11张图片

 

 三、总结

linux内核中设置了一组用于实现系统功能的子程序,称为系统调用。系统调用和普通库函数调用非常相似,只是系统调用由操作系统核心提供,运行于内核态,而普通的函数调用由函数库或用户自己提供,运行于用户态。一般的,进程是不能访问内核的。它不能访问内核所占内存空间也不能调用内核函数。为了和用户空间上运行的进程进行交互,内核提供了一组接口。透过该接口,应用程序可以访问硬件设备和其他操作系统资源。

系统调用在用户空间进程和硬件设备之间添加了一个中间层。该层主要作用有三个:

  • 它为用户空间提供了一种统一的硬件的抽象接口。比如当需要读些文件的时候,应用程序就可以不去管磁盘类型和介质,甚至不用去管文件所在的文件系统到底是哪种类型。

  • 系统调用保证了系统的稳定和安全。作为硬件设备和应用程序之间的中间人,内核可以基于权限和其他一些规则对需要进行的访问进行裁决。举例来说,这样可以避免应用程序不正确地使用硬件设备,窃取其他进程的资源,或做出其他什么危害系统的事情。

  • 每个进程都运行在虚拟系统中,而在用户空间和系统的其余部分提供这样一层公共接口,也是出于这种考虑。如果应用程序可以随意访问硬件而内核又对此一无所知的话,几乎就没法实现多任务和虚拟内存,当然也不可能实现良好的稳定性和安全性。在Linux中,系统调用是用户空间访问内核的惟一手段;除异常和中断外,它们是内核惟一的合法入口。

 

你可能感兴趣的:(深入理解系统调用)