韩玉琪 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

一、用户态、内核态和中断处理过程

1. 用户态和内核态

CPU指令执行级别
- 高级别:执行特权指令,访问任意的物理地址——内核态。
- 低级别:代码只能在级别允许的特定范围内活动——用户态。在日常操作下,执行系统调用的方式是通过库函数,库函数封装系统调用,为用户提供接口以便直接使用。
  • Intel x86 CPU有四种不同的执行级别0~3,Linux只用其中的0和3来表示内核态和用户态

  • 区分内核态和用户态:CPU每条指令的读取都是通过cs:eip,cs寄存器最低两位表明了当前代码的特权级。

    • 内核态下可访问所有地址空间
    • 0xc0000000(逻辑地址)以上的空间只能在内核态下访问
    • 0x00000000 ~ 0xbfffffff 内核态和用户态均可访问
  • 用户态转换为内核态的主要方式:中断

2. 中断处理

  • 用户态到内核态的切换:必须保存用户态的寄存器上下文,包括用户态栈顶地址、当时的状态字、cs:eip的值,以及内核态的栈顶地址、当时的状态字、中断处理程序入口。

    • 中断发生后的第一件事:保存现场(SAVE_ALL:保存需要用到的寄存器数据)。
    • 中断处理结束前的最后一件事:恢复现场(RESTORE_ALL:退出中断程序,恢复保存寄存器的数据)。
  • 完整过程:

二、系统调用

1. 意义

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

2. API与系统调用

API:应用程序编程接口,是一个函数定义。
系统调用:通过软中断向内核发出一个明确的请求。
  • 一般每个系统调用对应一个封装例程,库再用这些封装例程定义出用户的API,方便用户使用。所以,API与系统调用不是一一对应的

      - API可以直接提供用户态服务(如:数学函数)
    - 一个单独的API可能调用几个系统调用
    - 不同的API可能调用了同一个系统调用
  • 返回值

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

3. 系统调用“三层皮”

- API
- 中断向量
- 中断服务程序
  • 当用户态进程调用一个系统调用时,CPU切换到内核态并开始执行一个内核函数。

  • Linux中是通过执行int $0x80来执行系统调用,这条汇编指令产生向量为128的编程异常 —— 即中断向量0x80与System_call绑定起来。

  • 系统调用号将函数xyz()和中断服务程序sys_xyz关联起来。

4. 参数传递

  • 内核实现了很多不同的系统调用,进程用系统调用号这个参数指明需要哪个系统调用。

  • system_call是linux中所有系统调用的入口点,每个系统调用至少有一个参数,使用eax寄存器传递系统调用号。

  • 寄存器传递参数的限制

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

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

1. 使用库函数API获取系统当前时间

2. 使用嵌入式汇编代码获取系统当前时间

  • 内嵌汇编在语法上要求先声明输出参数,然后声明输出参数值。

  • 系统调用的参数,按照顺序分别放在ebx、ecx、edx、esi、edi和ebp中。上述代码中time不需要参数,只需要一个输出值,所以ebx在这里是NULL。

  • eax传递系统调用号,这里time是13

  • 执行的效果与上面的是完全一样的:

我们使用int 0x80触发中断,然后中断处理程序保存现场,我们的进程陷入内核态。

四、实验

参考:系统调用列表

1. 选取了122号系统调用:uname

  • 获取当前内核名称和其它信息

2. 使用man查看有关uname的说明

  • man 2 uname

      - char sysname[_UTSNAME_SYSNAME_LENGTH];   //当前操作系统名
    - char nodename[_UTSNAME_NODENAME_LENGTH]; //网络上的名称
    - char release[_UTSNAME_RELEASE_LENGTH]; //当前发布级别
    - char version[_UTSNAME_VERSION_LENGTH]; //当前发布版本
    - char machine[_UTSNAME_MACHINE_LENGTH]; //当前硬件体系类型

3. 编写C语言代码并运行

4. 编写嵌入式汇编代码

5. 运行与比较

  • 在实验楼环境下运行

  • 可以运行出来,但是sysname是空的,没有搞明白为什么...

  • 同样的环境对比一下C语言代码

五、总结

1. 系统调用

  • 即便是最简单的程序,在进行输入输出等操作时也会需要调用操作系统所提供的服务,也就是系统调用。
  • Linux下的系统调用是通过中断(int 0x80)来实现的。

2. 传递参数

  • 在执行int 80指令时,寄存器 eax 中存放的是系统调用的功能号,而传给系统调用的参数则必须按顺序放到寄存器 ebx,ecx,edx,esi,edi 中,当系统调用完成之后,返回值可以在寄存器 eax 中获得。
  • Linux 采用的是 C 语言的调用模式,这就意味着所有参数必须以相反的顺序进栈,即最后一个参数先入栈,而第一个参数则最后入栈。

六、待解决问题

1. 为什么用嵌入式汇编代码运行的sysname是空?

  • 编写的代码:

  • 运行结果:

2. 问题解决

  • 反思一下其实是我一开始就没有认真看man中的信息,里面明确的写着:

      int uname(struct utsname *buf);
  • 返回值是int,传入指针之后系统调用直接将信息写入指针指向位置!

Linux内核分析第四周学习总结:扒开系统调用的三层皮(上)的更多相关文章

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

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

  2. 《Linux内核分析》 第四节 扒开系统调用的三层皮(上)

    <Linux内核分析> 第四节 扒开系统调用的三层皮(上) 张嘉琪 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com ...

  3. 《Linux内核分析》 第五节 扒开系统调用的三层皮(下)

    <Linux内核分析> 第五节 扒开系统调用的三层皮(下) 20135307 一.给MenusOS增加time和time-asm命令 给MenuOS增加time和time-asm命令需要 ...

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

    [刘蔚然 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000] WEEK FIVE( ...

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

    Linux第四周学习总结--扒开系统调用的三层皮(上) 一.用户态.内核态和中断 系统调用通过库函数. 1.用户态和内核态 区分(不同的指令执行级别): 用户态:在相应的低执行状态下,代码的掌控范围受 ...

  6. LINUX内核分析第四周学习总结——扒开应用系统的三层皮(上)【转】

    转自:http://www.cnblogs.com/lalacindy/p/5276874.html 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://moo ...

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

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

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

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

  9. linux内核分析第四周学习笔记

    linux内核分析第四周学习笔记 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.co ...

  10. Linux内核分析第四周学习总结——系统调用的工作机制

    Linux内核分析第四周学习总结--系统调用的工作机制 内核态 执行级别高,可以执行特权指令,访问任意物理地址,在intel X86 CPU的权限分级为0级. 用户态 执行级别低,只能访问0x0000 ...

随机推荐

  1. UVa 二叉树重建(先序+中序求后序)

    题意是给出先序和中序,求出后序. 先序遍历先访问根结点,通过根结点可以在中序中把序列分为左子树部分和右子树部分,我建了一个栈,因为后序遍历最后访问根结点,所以把每次访问的根结点放入栈中.因为后序遍历先 ...

  2. kuangbin_MST B (POJ 1287)

    裸的模板题 因为直接用的邻接矩阵所以用最小值覆盖先前输入的重复边 #include <cstdio> #include <cstring> #include <queue ...

  3. [BZOJ 3530][Sdoi 2014]数数

    阿拉~好像最近总是做到 AC 自动机的题目呢喵~ 题目的算法似乎马上就能猜到的样子…… AC 自动机 + 数位 dp 先暴力转移出 f[i][j] :表示从 AC 自动机上第 j 号节点走 i 步且不 ...

  4. css transform skew变换

    两个参数,x-保持纵坐标不变,所有点旋转逆时针旋转x度,y-横坐标不变所有点顺时针旋转y度

  5. ABBYY如何使用电子邮件发送OCR结果

    ABBYY FineReader作为一款OCR图文识别软件,在识别文档之后,可以以任何受支持的格式(除HTML外),通过电子邮件发送识别结果,不仅可以发送文档,还可以发送页面图像,本文将为大家讲解如何 ...

  6. urllib2.open(req).read() 报403的错误:怎么办?

    http://www.douban.com/group/topic/18095751/ heads = {'Accept':'text/html,application/xhtml+xml,appli ...

  7. CentOS 7 做服务器 CentOS 5 做客服机 搭建Apache+php+mysql网页

    1:在CentOS 7搭建yum源和php.Apache 安装    yum install php-mysql -y 文件 重启httpd服务:systemctl restart httpd.ser ...

  8. NetCFSvcUtil.exe and Windows 7

    NetCFSvcUtil.exe is the analogous of Svcutil.exe but for devices. You can use it to generate a WCF c ...

  9. ios实现屏幕旋转的方法

    1.屏蔽AppDelegate下面的屏幕旋转方法 #pragma mark - 屏幕旋转的 //- (UIInterfaceOrientationMask)application:(UIApplica ...

  10. Perl 随笔

    1.    .pl  文件带入参数: ./auto_cfg.pl ./mconfig.config ./boardconfig.config ./menuconfig.config .ver  ./a ...