Linux第四周学习总结——扒开系统调用的三层皮(上)

一、用户态、内核态和中断

系统调用通过库函数。

1.用户态和内核态

区分(不同的指令执行级别):

  • 用户态:在相应的低执行状态下,代码的掌控范围受到限制,只能在对应级别允许的范围内活动
  • 内核态:在高执行级别下,代码可以执行特权指令,访问任意的物理地址。

Intel x86 CPU有四种不同的执行级别0—3,Linux只是用了期中的0级和3级分别表示内核态和用户态。

注意逻辑地址和物理地址的区别。逻辑地址是进程地址空间里面的

2.中断

中断处理是从用户态进入内核态主要的方式

系统调用是只是一种特殊的中断

中断指令或向量发生之后发生中断处理程序,刚一开始执行SAVE ALL,即把其他的寄存器的值push到内核堆栈上去,结束之后,把用户态的寄存器的值在popl出来,最后iret,对应着中断信号(int指令),发生时的CPU动作相反。

  • 保护现场就是进入中断程序,保存需要用到的寄存器的数据;
  • 恢复现场就是退出中断程序,恢复保存寄存器的数据。

中断处理的完整过程:

理解:中断信号(int指令)完成:保存cs:eip的值、当前堆栈段栈顶和当前标志,同时加载了当前中断信号或是系统调用的相关联的中断服务入口到cs:eip里面,把当前对战段和esp也加载到CPU里面。

SAVE ALL完成后若没有发生调度,则接着执行RESTORE_ALL;若发生进程调度,则当前的状态会暂时的保存在系统里面,当下一次发生进程调度切换到当前进程时再接着执行完毕。

二、系统调用概述

1.系统调用的意义:

操作系统为用户态进程与硬件设备进行交互提供的一组接口。可以把用户从底层的硬件变成中解放出来,极大的提高了系统的安全性,使用户程序具有可移植性。

2.API应用程序编程接口:

只是一个函数定义,系统调用通过软中断向内核发出一个明确的请求。

Libc库定义的一些API引用了一些封装例程,目的是发布系统调用,让程序员写代码的时候可以通过函数调用而非汇编指令触发一个系统调用。

3.返回值:

  • 大部分封装例程返回一个整数,其值的含义依赖于相应的系统调用;
  • -1在多数情况下表示内核不能满足进程的请求;
  • Libc中定义的errno变量包含特定的出错码。

4.系统调用的三个层次

应用程序编程接口里封装了一个系统调用,int 0x80中断向量,对应着system_call内核代码的起点,执行完中断服务程序,返回。

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

5.传参

内核实现了很多不同的系统调用,进程必须指明需要哪个系统调用,这需要传递一个名为系统调用号的参数,使用eax寄存器传递。

系统调用号将xyz和sys_xyz关联起来了。

system_call是linux中所有系统调用的入口点,每个系统调用至少有一个参数,即由eax传递的系统调用号。具体过程:

1.一个应用程序调用fork()封装例程,那么在执行int $0x80之前就把eax寄存器的值置为2(即__NR_fork)。
2.这个寄存器的设置是libc库中的封装例程进行的,因此用户一般不关心系统调用号
3.进入sys_call之后,立即将eax的值压入内核堆栈。

寄存器传递参数具有如下限制:

  • 每个参数的长度不能超过寄存器的长度,即32位
  • 在系统调用号( eax)之外,参数的个数不能超过6个( ebx,ecx, edx, esi, edi, ebp)
  • 参数个数超过6个则把某一个寄存器作为指针指向一块内存,进入内核态之后可以访问所有的地址空间,通过那块内存传递参数。

三、使用库函数API和C代码中嵌入汇编代码触发系统调用

1. 内嵌汇编语法:

__asm__(
汇编语句模板:
输入部分:
输出部分:
破坏描述部分:);

这部分内容前几周已经讲过,这里不再重复。

2. 用汇编方式出发系统调用获取系统当前时间

汇编代码分析:

#include <stdio.h>
#include <time.h>
int main()
{
time_t tt;//int型数值
struct tm *t;
asm volatile(
"mov $0,%%ebx\n\t"//将ebx寄存器清零,系统调用传递第一个参数使用ebx,这里是null
"mov $0xd,%%eax\n\t"//将0xd放入eax中,0xd为13,传递系统调用号13
"int $0x80\n\t"
"mov %%eax,$0\n\t"//通过eax这个寄存器返回系统调用值,和普通函数一样
:"=m"(tt)
);
t = localtime(&tt);
printf("time:%d:%d:%d:%d:%d:%d\n",t->tm_year+1900,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
return 0;
}

用户态进程向内核态传递了系统调用号。

四、实验——使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

本次实验我选择了24号系统调用,获取当前用户uid(用户ID)。

实验过程:

使用库函数API方式:

使用C代码中嵌入汇编代码方式:

编译运行:

汇编代码调用系统调用的工作过程分析:

  • 首先将ebx寄存器清零,表示无参数传入;

  • 然后将0x18放入eax,表示需要调用的系统调用号24;

  • 执行int 0x80来执行系统调用;

  • 之后eax寄存器保存了返回值,将它赋值给输出uid变量。

    完成整个汇编代码的系统调用。

总结:

在Linux系统中是通过激活0x80中断来触发系统调用的,需要调用的系统调用号实现赋值给eax存储器,如果有传入参数可赋值给ebx寄存器,如果多于1个则按顺序赋值给ebx、ecx、edx、esi、edi、ebp,如果超过6个则通过指针变量指向另一片堆栈区,如果无参数传入则赋值为0。

虽然Intel X86 CPU有4种执行级别0~3,但是在Linux系统中仅使用了0和3级,分别表示内核态和用户态。一些涉及底层、硬件、核心的操作必须在内核态下才允许执行,为操作系统程序和驱动程序专享,普通程序仅能执行在用户态下。如果普通程序需要涉及内核态的操作,就需要通过系统调用来实现。这样做的好处是屏蔽平台相关操作降低了软件开发难度,增强了系统安全性,使程序具有更好的移植性(Linux系统及其他Unix系统遵循统一标准,系统调用基本一样)。

另外,我想问一下老师,为什么我的API方法运行结果最后会多出来一个%?

参考资料:

http://www.iteedu.com/os/linux/linuxprgm/linuxcfunctions/user/getuid.php

#Linux第四周学习总结——扒开系统调用的三层皮(上)的更多相关文章

  1. 20135337朱荟潼 Linux第四周学习总结——扒开系统调用的三层皮(上)

    朱荟潼 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课http://mooc.study.163.com/course/USTC 1000029000 知识点梳理 一.用 ...

  2. LINUX内核分析第四周学习总结——扒开系统调用的“三层皮”

    LINUX内核分析第四周学习总结--扒开系统调用的"三层皮" 标签(空格分隔): 20135321余佳源 余佳源 原创作品转载请注明出处 <Linux内核分析>MOOC ...

  3. LINUX内核分析第五周学习总结——扒开系统调用的“三层皮”(下)

    LINUX内核分析第五周学习总结--扒开系统调用的"三层皮"(下) 标签(空格分隔): 20135321余佳源 余佳源 原创作品转载请注明出处 <Linux内核分析>M ...

  4. Linux第五周学习总结——扒开系统调用的三层皮(下

    Linux第五周学习总结--扒开系统调用的三层皮(下) 作者:刘浩晨 [原创作品转载请注明出处] <Linux内核分析>MOOC课程http://mooc.study.163.com/co ...

  5. 《Linux内核分析》第五周学习总结 扒开系统调用的三层皮(下)

    扒开系统调用的三层皮(下) 郝智宇 无转载 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.给Men ...

  6. linux 内核 第四周 扒开系统调用的三层皮 上

    姬梦馨 原创作品 http://mooc.study.163.com/course/USTC-1000029000 一.用户态.内核态和中断处理过程 用户通过库函数与系统调用联系起来:库函数帮我们把系 ...

  7. 20135337朱荟潼 Linux第五周学习总结——扒开系统调用的三层皮(下)

    朱荟潼 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课http://mooc.study.163.com/course/USTC 1000029000 一.学习内容 (一 ...

  8. Linux内核分析 笔记五 扒开系统调用的三层皮(下) ——by王玥

    (一)给MenuOs增加time和time-asm命令 更新menu代码到最新版 在main函数中增加MenuConfig 增加对应的Ttime和TimeAsm函数 make rootfs (二)使用 ...

  9. 《Linux内核分析》第四周学习总结 扒开系统调用的三成皮(上)

    第四周 扒开系统调用的三层皮(上) 郝智宇 无转载 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一. ...

随机推荐

  1. [python] 列表解析式的高效与简洁

    方法一(列表解析式): list1 = ["abc","efg","hij"] list2 = [i[0] for i in list1] ...

  2. MySql详解(三)

    MySql详解(三) 导入基础表 具体的SQL文件已经放入百度网盘,连接为:http://pan.baidu.com/s/1hseoVR2,后面的MySql内容都是按照这些基础表展开的. depart ...

  3. python第三十课--异常(with as操作)

    演示with...as...操作 path=r'kaifanglist1.txt' with open(path,'r',encoding='utf-8') as fr: print(fr.read( ...

  4. CentOS下iptables详解

    一:前言   防火墙,其实说白了讲,就是用于实现Linux下访问控制的功能的,它分为硬件的或者软件的防火墙两种.无论是在哪个网络中,防火墙工作的地方一定是在网络的边缘.而我们的任务就是需要去定义到底防 ...

  5. MetaMask/provider-engine-3-test

    通过看其test的代码去好好看看它是怎么使用的 1. provider-engine/test/basic.js const test = require('tape') const Provider ...

  6. WinForm中Component Class、User Control及Custom Control的区别和使用

    NET Framework 为您提供了开发和实现新控件的能力.除了常见的用户控件外,现在您会发现,您可以编写能执行自身绘图的自定义控件,甚至还可以通过继承扩展现有控件的功 能.确定创建何种类型的控件可 ...

  7. [转]改善C#程序的建议4:C#中标准Dispose模式的实现

    需要明确一下C#程序(或者说.NET)中的资源.简单的说来,C#中的每一个类型都代表一种资源,而资源又分为两类: 托管资源:由CLR管理分配和释放的资源,即由CLR里new出来的对象: 非托管资源:不 ...

  8. WorldWind源码剖析系列:外包围盒类BoundingBox和外包围球类BoundingSphere

    PluginSDK中的外包围盒.外包围球分别用类 BoundingBox和BoundingSphere描述,其类图如下所示. 外包围盒BoundingBox类的corners字段用来存储外包围盒的8个 ...

  9. 用BCP从SQL Server 数据库中导出Excel文件

    BCP(Bulk Copy Program)是一种简单高效的数据传输方式在SQL Server中,其他数据传输方式还有SSIS和DTS. 这个程序的主要功能是从数据库中查询Job中指定step的执行信 ...

  10. day36

    今日内容 1.GIL解释器锁 2.GIL解释器锁与自定义锁 3.死锁现象与递归锁 4.信息量 5.Event 6.线程queue 1.GIL解释器锁 from multiprocessing impo ...