浅析 Linux 系统调用

##用户态、内核态以及中断

  • 具有高执行级别的程序可以执行特权指令

  • intel X86 CPU 具有4种级别:0 ~ 3

  • Linux 只用了0和3(0表示内核态,3表示用户态)

  • 特权级的表示:使用 CS 寄存器的低2位

  • 内核态逻辑地址空间:0xc0000000以上

    用户态逻辑地址空间:0x00000000 ~ 0xbfffffff

  • 中断是从用户态到内核态的一种方式,即通过系统调用(系统调用是一种特殊的中断

  • 中断过程寄存器上下文的保存

    • 保存到什么地方?堆栈
    • 保存的内容: 用户态栈顶地址、当时的状态字、当时的 cs:eip的值

##系统调用概述

  • 系统调用是操作系统为用户态进程和硬件设备交互提供的一组接口

    • 把用户从底层编程中解放出来
    • 提高系统安全性
    • 提高用户程序的可移植性
  • API(应用编程接口)

    • libc库定义的一些 API引用了封装例程(为了发布系统调用)
      • 一般一个系统调用对应一个封装例程
      • 库通过封装例程定义提供给用户的 API
    • 不是每个 API都对应一个特定的系统调用
      • API 可能直接提供用户态的服务
      • 一个 API 可能对应几个系统调用
      • 不同的 API 可能对应一个系统调用
  • 系统调用和 API 比较:

    • 系统调用通过软中断向内核发出一个明确的请求
    • API只是一个函数定义
  • 使用寄存器传递参数

    • 传递一个重要的参数系统调用号:使用 eax 寄存器
    • 每个参数长度不能超过寄存器长度
    • 每个参数长度不能超过6个
    • 如果超过6个?把某一个寄存器作为指针指向内存地址空间

##实验

###使用库 API 来完成系统调用 chmod

  • 源代码(chmod.c)

    #include<sys/types.h>
    #include<stdio.h>
    #include<sys/stat.h>
    #include<errno.h>
    
    int main()
    {
        int i;
    
        i = chmod("file", 0777);
    
        if(i == -1)
            fprintf(stderr,"chmod failed, errer number = %d\n",errno);
        else
            printf("chmod success !\n");
    
        return 0;
    }
    
  • 编译&执行

    gcc chmod.c -o chmod -m32
    ./chmod
    
  • 执行结果

如果不存在 file

image

建立文件 file 之后,chmod 成功

image

###使用汇编来完成系统调用 chmod

  • 找到 chmod 对应的系统调用号

    arch/x86/syscalls/syscall_32.tbl 中我们可以找到15 i386 chmod sys_chmod,由此可知,chmod 系统中断号为15(0xf)

image

  • 源代码(chmod_asm.c)

    #include<sys/types.h>
    #include<stdio.h>
    #include<sys/stat.h>
    #include<errno.h>
    
    int main()
    {
        int i;
        char* name = "file";
    
        asm volatile(
            "mov $0777, %%ecx\n\t"
            "mov $0xf, %%eax\n\t"
            "int $0x80\n\t"
            "mov %%eax, %0\n\t"
            :"=m" (i)
            :"b" (name)
        );
    
    if(i == -1)
        fprintf(stderr,"chmod failed, errer number = %d\n",errno);
    else
        printf("chmod success !\n");

    return 0;
}
  • 编译&执行

    gcc chmod_asm.c -o chmod_asm -m32
    ./chmod_asm
    
  • 执行结果

image

  • 汇编代码分析

mov $0777, %%ecx\n\t: 将chmod参数放入 ecx 寄存器

mov $0xf, %%eax\n\t: 将系统调用号15(0xf对应 chmod)放入 eax 寄存器

int $0x80\n\t: 启动系统调用(中断号0x80)

mov %%eax, %0\n\t: 将执行完 chmod 的返回值返回至 i

:"=m" (i): i 作为输出参数

:"b" (name): name 作为输入参数放入 ebx 中

###简述系统调用 chmod 的过程

首先程序触发中断 int 0x80(系统中断),然后存放于 eax 中的数值作为系统调用号,这样系统就知道对应的是哪一个系统调用,然后系统会检查参数无误后,将返回值置于 eax 中。


版权声明:本文为博主原创文章,未经博主允许不得转载。

文章来源:http://blog.luoyuanhang.com