浅析 Linux 系统调用

举报
远航 | FIBOS 发表于 2020/12/01 22:33:21 2020/12/01
【摘要】 浅析 Linux 系统调用 用户态、内核态以及中断 具有高执行级别的程序可以执行特权指令intel X86 CPU 具有4种级别:0 ~ 3Linux 只用了0和3(0表示内核态,3表示用户态)特权级的表示:使用 CS 寄存器的低2位内核态逻辑地址空间:0xc0000000以上 用户态逻辑地址空间:0x00000000 ~ 0xbfffffff中断是从用户态到内核...

浅析 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;
    }
    
        
       
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
  • 编译&执行

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

如果不存在 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;
    }
    
        
       
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
  • 编译&执行

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

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

文章来源: blog.csdn.net,作者:冰水比水冰,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/luoyhang003/article/details/46844901

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。