扒开系统调用的三层皮?(上)

第4章的基础知识

  • Linux系统调用的三层机制:xyz()(API函数)、system_call(系统调用处理入口) 、 sys_xyz()(系统调用内核处理函数)。
  • 32位的X86机器上在用户态的时候只能访问0x00000000—0xbfffffff的地址空间,而在内核态下可以访问所有的地址空间。
  • 中断,系统调用是最常用的两种方式,从用户态切换到内核态。
  • int指令触发中断机制会在堆栈上保存一些寄存器的值,会保存用户态栈顶地址,当时的状态字,当时的CS:EIP的值。
  • 中断发生后的第一件事就是保存现场,中断结束的最后一件事就是恢复现场。
  • 系统调用的意义可以把用户从底层的硬件编程中解放出来,极大的提高了系统的安全性,使用户程序具有可移植性。
  • API(应用程序编程接口)是函数定义,一个API可以对应多个系统调用,他们之间是多对多的关系。
  • 使用EAX寄存器传递一个名为系统调用号的参数。
  • Linux操作系统中采用了0和3两个特权级别,分别对应内核态和用户态。
  • 在Linux中,系统调用是用户空间访问内核的惟一手段;除异常和中断外,它们是内核惟一的合法入口。   而kernel留给用户层的接口其实就只有一个:软中断(int 0x80)。用户态通过它来陷入内核态,完成系统调用。为了方便使用,kernel与用户层之间又增加了API与一些库(例如libc库)来封装这一过程。因此,目前的资料里大部分都写,调用一个系统调用有三种方法:

           (1)通过 glibc 提供的库函数

           (2)使用 syscall 函数直接调用

           (3)通过 int 0x80指令陷入
  • API/libc与系统调用的关系:既然API与libc对软中断进行了封装,那我们先一起看看它们之间的具体关系。一般情况下,应用程序通过应用编程接口(API)而不是直接通过系统调用来编程。这点很重要,因为应用程序使用的这种编程接口实际上并不需要和内核提供的系统调用一一对应。一个API定义了一组应用程序使用的编程接口。从程序员的角度看,系统调用无关紧要,他们只需要跟API打交道就可以了。相反,内核只跟系统调用打交道;库函数及应用程序是怎么使用系统调用不是内核所关心的。

系统调用实现机制

与调用函数一样,系统调用也需要输入输出参数。每个系统调用至少有一个参数,即系统调用号(由eax传递),其他参数依次由ebx、ecx、edx、esi、edi、ebp传入。 由于使用寄存器传递参数,因此对参数的长度做了限制:

(1)每个参数的长度不能超过寄存器的长度,即32位

(2)在系统调用号(eax)之外,参数的个数不能超过6个(ebx、ecx、edx、esi、edi、ebp)如果超过六个,可以传入一个地址,地址所在地存放多个参数

系统调用的三个层次依次是:xyz函数(API)、system_ call(中断向量)和 sys_ xyz(中断服务程序)。

触发一个系统调用的三种方式

1.API函数的方式

首先我选取的是20号的getpid系统调用

编译的结果如下:

2.嵌入式汇编方式

编译运行完的结果

3.调用库函数syscall

编译完运行的结果

4.用gdb进行调试看API的调用是否就是像我们之前分析的对系统调用的封装那样执行的

在getpid处设置断点,运行到断点处。

使用ni命令,对汇编指令逐条运行,前面的清理寄存器的值此处先不讨论,直接一直ni运行到传递系统调用号处(箭头所指的为下一条将要运行的指令, 利用info r命令来查看当前寄存器的值,系统调用号还未传入,eax还为0)。

ni一下,再次查看,发现系统调用号已经传入,确实是利用eax的。

再ni一下,此时该系统调用的实际工作已经完成了,结果(也就是pid)保存在eax中。

实验分析

  • getpid是一种函数,功能是取得进程识别码。
  • 函数原型:旧的原型为pid_t getpid(void);,推荐使用int _getpid( void );这种形式。注意,函数名第一个字符是下划线。
  • 函数说明:getpid函数用来取得目前进程的进程ID,许多程序利用取到的此值来建立临时文件,以避免临时文件相同带来的问题。
  • 返回值:目前进程的进程ID。
  • 在Linux系统中是通过激活0x80中断来触发系统调用的,需要调用的系统调用号实现赋值给eax存储器,如果有传入参数可赋值给ebx寄存器,如果多于1个则按顺序赋值给ebx、ecx、edx、esi、edi、ebp,如果超过6个则通过指针变量指向另一片堆栈区,如果无参数传入则赋值为0。

    汇编代码的分析

#include <stdio.h>
#include<unistd.h>
int main()
{
pid_t pid;
asm volatile(
"movl $0,%%ebx\n\t"//将ebx寄存器清零,系统调用传递第一个参数使用ebx,这里是null
"movl $0x14,%%eax\n\t"//将0xd放入eax中,0x14为20,传递系统调用号20
"int $0x80\n\t"
"movl %%eax,$0\n\t"//通过eax这个寄存器返回系统调用值,和普通函数一样
:"=m"(pid)
);
printf("this process's pid is : %u\n",pid);
return 0;
}

遇到的问题

1.我最开始在做书上给的38号系统调用的例子的时候,出现了下面的问题



后面再网上搜索资料可以得知是因为在64位系统下去编译32位的目标文件,这样是非法的。必须用”-m32”强制用32位ABI去编译,即可编译通过。

2.我在改写syscall函数的的时候,出现了下面的问题



最后发现是因为缺少必要的头文件,添加上 1 #include <unistd.h>2 #include <sys/syscall.h>3 #include <sys/types.h>即可

本章总结

  • 在Linux中我们可以通过三种方式也进行系统的调用分为:API方式,C代码中嵌入式汇编语言,和库函数syscall。API方法实现系统调用实现非常便捷,只需知道函数原型即可。
  • 经过这次实验,我们可以看到:

          (1)要查看系统资源(如pid等),只有处于内核态(0级)的时候才可以。

           (2)用户要从用户态(3级)切换到内核态(0级),就要通过软中断(int 0x80)来进行系统调用。

           (3)通过eax传递系统调用号,然后由system_call交给system_service完成工作。

           (4)system_service完成工作后,结果又由eax传递给用户态堆栈。

    我对API系统调用的理解:

  • 总之用户调用API函数,系统调用号和参数保存到 eax,ebx ,等寄存器中,通过 0x80 中断向量触发中断陷入内核态,中断服务程序根据系统调用号调用并执行对应的系统调用函数,执行完毕后将结果存放的 eax 中并返回给程序,程序返回用户态。

20189220 余超《Linux内核原理与分析》第五周作业的更多相关文章

  1. 20169212《Linux内核原理与分析》第二周作业

    <Linux内核原理与分析>第二周作业 这一周学习了MOOCLinux内核分析的第一讲,计算机是如何工作的?由于本科对相关知识的不熟悉,所以感觉有的知识理解起来了有一定的难度,不过多查查资 ...

  2. 20169210《Linux内核原理与分析》第二周作业

    <Linux内核原理与分析>第二周作业 本周作业分为两部分:第一部分为观看学习视频并完成实验楼实验一:第二部分为看<Linux内核设计与实现>1.2.18章并安装配置内核. 第 ...

  3. 2018-2019-1 20189221 《Linux内核原理与分析》第九周作业

    2018-2019-1 20189221 <Linux内核原理与分析>第九周作业 实验八 理理解进程调度时机跟踪分析进程调度与进程切换的过程 进程调度 进度调度时机: 1.中断处理过程(包 ...

  4. 2017-2018-1 20179215《Linux内核原理与分析》第二周作业

    20179215<Linux内核原理与分析>第二周作业 这一周主要了解了计算机是如何工作的,包括现在存储程序计算机的工作模型.X86汇编指令包括几种内存地址的寻址方式和push.pop.c ...

  5. 2019-2020-1 20199329《Linux内核原理与分析》第九周作业

    <Linux内核原理与分析>第九周作业 一.本周内容概述: 阐释linux操作系统的整体构架 理解linux系统的一般执行过程和进程调度的时机 理解linux系统的中断和进程上下文切换 二 ...

  6. 2019-2020-1 20199329《Linux内核原理与分析》第二周作业

    <Linux内核原理与分析>第二周作业 一.上周问题总结: 未能及时整理笔记 Linux还需要多用 markdown格式不熟练 发布博客时间超过规定期限 二.本周学习内容: <庖丁解 ...

  7. 2019-2020-1 20209313《Linux内核原理与分析》第二周作业

    2019-2020-1 20209313<Linux内核原理与分析>第二周作业 零.总结 阐明自己对"计算机是如何工作的"理解. 一.myod 步骤 复习c文件处理内容 ...

  8. 2018-2019-1 20189221《Linux内核原理与分析》第一周作业

    Linux内核原理与分析 - 第一周作业 实验1 Linux系统简介 Linux历史 1991 年 10 月,Linus Torvalds想在自己的电脑上运行UNIX,可是 UNIX 的商业版本非常昂 ...

  9. 《Linux内核原理与分析》第一周作业 20189210

    实验一 Linux系统简介 这一节主要学习了Linux的历史,Linux有关的重要人物以及学习Linux的方法,Linux和Windows的区别.其中学到了LInux中的应用程序大都为开源自由的软件, ...

  10. 2018-2019-1 20189221《Linux内核原理与分析》第二周作业

    读书报告 <庖丁解牛Linux内核分析> 第 1 章 计算工作原理 1.1 存储程序计算机工作模型 1.2 x86-32汇编基础 1.3汇编一个简单的C语言程序并分析其汇编指令执行过程 因 ...

随机推荐

  1. Flink入门 - API

    final StreamExecutionEnvironment streamExecutionEnvironment = StreamExecutionEnvironment.getExecutio ...

  2. linux下svn解决冲突

    1. 使用svn status + 文件路径+文件名 查看文件或目录的状态(该状态可自行进行百度),属性状态为'C'的表示,改文件或目录处于冲突状态 2. 使用svn resolve --accept ...

  3. MySQL Index--平衡树结构

    树结构 ==================================================B树,即平衡二叉树,每个非叶子节点最多拥有两个子节点.所有键值出现在叶子节点和非叶子节点. ...

  4. linux虚拟串口及远程访问

    1. 虚拟终端概念 linux中有很多终端,如下简单介绍下各种终端或串口的概念. 1.1 tty:终端设备的统称 tty是Teletype或TeletypeWriter的缩写,中文翻译为电传打字机.电 ...

  5. 《大象 Thinking in UML》读书笔记:软件开发——从现实世界到对象世界

    参考:Process-oriented vs. Object-oriented 前言 软件行业在采用OO的思想后,从一开始只对编码使用OO,到现在“分析-设计-编码”全部环节使用OO,形成了OOA.O ...

  6. linux设备驱动程序-设备树(0)-dtb格式

    linux设备树dtb格式 设备树的一般操作方式是:开发人员根据开发需求编写dts文件,然后使用dtc将dts编译成dtb文件. dts文件是文本格式的文件,而dtb是二进制文件,在linux启动时被 ...

  7. subprocess模块的使用注意

    subprocess.Popen()函数 语法格式: subprocess.Popen(arg,stdin=None,stdout=None,stderr=None,shell=False) 1.主要 ...

  8. 关于ssh_config和sshd_config

    转载:https://www.cnblogs.com/panda2046/p/5933498.html   在远程管理linux系统基本上都要使用到ssh,原因很简单:telnet.FTP等传输方式是 ...

  9. beta版本——第四次冲刺

    第四次冲刺 (1)SCRUM部分☁️成员描述: 姓名 李星晨 完成了哪个任务 进行注册的时候若不输入手机号,提醒用户的是未输入登录名,进行更改 花了多少时间 1.2h 还剩余多少时间 1.8h 遇到什 ...

  10. jni接口

    https://www.jianshu.com/p/d4a502420a89 #pragma once /*DO NOT EDIT THIS FILE - it is machine generate ...