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

深入理解系统调用

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

标签:png   dom   管理   ddr   编译   com   pts   creat   gdbserver   

 

一、实验要求

  • 找一个系统调用,系统调用号为学号最后2位相同的系统调用 (这里我的系统调用号就是73)
  • 通过汇编指令触发该系统调用
  • 通过gdb跟踪该系统调用的内核处理过程
  • 重点阅读分析系统调用入口的保存现场、恢复现场和系统调用返回,以及重点关注系统调用过程中内核堆栈状态的变化

 

二、环境配置

1 下载内核源代码

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

2 配置内核选项

make defconfig # Default configuration is based on ‘x86_64_defconfig‘
make menuconfig
# 打开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)

 技术图片

 

 技术图片

 

 技术图片

 

3 编译和运行内核

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

技术图片

 

4 制作根文件系统

电脑加电启动?先由bootloader加载内核,内核紧接着需要挂载内存根?件系统,其中包含必要的设备驱动和?具,bootloader加载根?件系统到内存中,内核会将其挂载到根?录/下,然后运?根?件系统中init脚本执??些启动任务,最后才挂载真正的磁盘根?件系统。

我们这?为了简化实验环境,仅制作内存根?件系统。这?借助BusyBox 构建极简内存根?件系统,提供基本的?户态可执?程序

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

技术图片

 

 然后制作内存根?件系统镜像,?致过程如下:

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/
准备init脚本?件放在根?件系统跟?录下(rootfs/init),添加如下内容到init?件。
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
echo "Wellcome MengningOS!"
echo "--------------------"
cd home
/bin/sh
给init脚本添加可执?权限
chmod +x init
打包成内存根?件系统镜像
find . -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

技术图片

 

 

 

环境配置成功!

 

三、查看系统调用

系统调?是?种特殊的中断,中断分外部中断(硬件中断)和内部中断(软件中断),内部中断?称为异常(Exception),异常?分为故障(fault)和陷阱(trap)。系统调?就是利?陷阱(trap)这种软件中断?式主动从?户态进?内核态的。

?般来说,从?户态进?内核态是由中断触发的,可能是硬件中断,在?户态进程执?时,硬件中断信号到来,进?内核态,就会执?这个中断对应的中断服务例程。也可能是?户态程序执?过程中,调?了?个系统调?,陷?了内核态,叫作陷阱(trap)(系统调?是特殊的中断)。



技术图片

 

 系统调?具有以下功能和特性:

把?户从底层的硬件编程中解放出来。操作系统为我们管理硬件,?户态进程不?直接与硬件设备打交道。

极?地提?系统的安全性。如果?户态进程直接与硬件设备打交道,会产?安全隐患,可能引起系统崩溃。

使?户程序具有可移植性。?户程序与具体的硬件已经解耦合并?接?代替了,不会有紧密的关系,便于在不同系统间移植。

 

我的学号后三位是73,73号系统调用是:flock

技术图片

flock简介:
在多个进程同时操作同一份文件的过程中,很容易导致文件中的数据混乱,需要锁操作来保证数据的完整性,这里介绍的针对文件的锁,称之为“文件锁”-flock。
flock是建议性锁,不具备强制性。一个进程使用flock将文件锁住,另一个进程可以直接操作正在被锁的文件,修改文件中的数据,原因在于flock只是用于检测文件是否被加锁,针对文件已经被加锁,另一个进程写入数据的情况,内核不会阻止这个进程的写入操作,也就是建议性锁的内核处理策略。

 

先通过汇编触发系统调用

#include<stdio.h>
#include<sys/file.h>
#include <fcntl.h>
#include <unistd.h>
int main(void){
    int f;
    f=open("test.txt",O_WRONLY|O_CREAT);
    printf("The fd value is : %d \n", f);
    int ret = flock(f,1);
    printf("The return is : %d \n", ret);
    close(f);
    return 0;
}

通过gcc编译后,利用objdump反编译,查看汇编代码:

gcc -o test test.c -static
objdump -S test > test.S

找到flock的汇编代码如下:

技术图片

 

之后编写内嵌汇编代码,手动触发系统调用

#include<stdio.h>
#include<sys/file.h>
# include <fcntl.h>
#include <unistd.h>
int main(void){
    int f;
    int ret;
    f=open("test.txt",O_WRONLY|O_CREAT);
    asm volatile(
        "movl $0x1, %%esi\n\t"    
        "movl $0x3, %%edi\n\t" 
        "mov $0x49, %%eax\n\t" 
        "syscall\n\t"
        "movq %%rax,%0\n\t"      //保存返回值
        :"=m"(ret)
    );
    printf("The return is : %d \n", ret);
    close(f);
    return 0;
}

重新编译和并运行:

技术图片

 

 返回0说明程序可以正常运行,系统调用成功。

GDB调试跟踪

把编译好的testa文件放在rootfs/syscall目录下,重新生成根文件系统:

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

使?gdb跟踪调试内核,加两个参数,?个是-s,在TCP 1234端?上创建了?个gdbserver。可以另外打开?个窗?,?gdb把带有符号表的内核镜像vmlinux加载进来,然后连接gdb server,设置断点跟踪内核。若不想使?1234端?,可以使?-gdb tcp:xxxx来替代-s选项),另?个是-S代表启动时暂停虚拟机,等待 gdb 执? continue指令(可以简写为c)。

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,并建立连接:

gdb vmlinux
target remote:1234

 

 技术图片

 

 

 设置好断点后,输入c继续,就会自动调用qemu运行,然后cd到程序所在目录下运行程序,程序将会在所设定的断点位置断开。(如果没断开,可能是最开始编译时,没能按照要求选择debug信息。)

 

 技术图片

 

 

技术图片

 

 系统调用分析

系统调用的入口在entry_SYSCALL_64(),在arch/x86/entry/syscalls/entry_64.S中可以找到此函数:

技术图片

 

 

 swapgs指令通过CPU内部的存储器,将保存现场和恢复现场时的寄存器保存起来,然后将pt_regs中的相关字段保存到内核栈中。

 

之后系统调用了do_syscall_64

技术图片

 

 

 

函数do_syscall_64接收系统调用号和pt_regs,根据相关参数执行系统调用,。系统调用完成后执行do_syscall_64 中的 syscall_return_slowpath() ,进行现场恢复操作,然后回用户态。

 

 技术图片

 

 

 

 

 

深入理解系统调用

标签:png   dom   管理   ddr   编译   com   pts   creat   gdbserver   

原文地址:https://www.cnblogs.com/waaq/p/12972773.html

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