韩玉琪 + 原创作品转载请注明出处 + 《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. CentOS中Device eth0 does not seem to be present错误解决办法

    今天克隆的虚拟机,当需要多台虚拟机的时候,试用克隆真是方便,不过遇到了 Device eth0 does not seem to be present 的问题,在网上找到遇到同样问题的解决方法, 很顺 ...

  2. python+php+redis+shell实现几台redis的同步数据

    之所以使用python,是因为python多线程非常简单. 之所以使用shell,是因为写了个服务,可以方便的重启python写的那个脚本. 总体思路:利用redis的发布订阅,php作为生产者,py ...

  3. 微信自定义菜单view类型获取openid访问网页

    用户点击view类型按钮后,微信客户端将会打开开发者在按钮中填写的url值 (即网页链接),达到打开网页的目的,但是view不能获取用户的openid,需与网页授权获取用户基本信息接口结合使用,获得用 ...

  4. PageRank与TrustRank影响因素分析

    PageRank(PR)里的page不是指网页,而是指Google创始人拉里?佩奇(Larry Page),是他在2001年申请的专利中以自己名字命名的,Google的PageRank根据网站的外部链 ...

  5. JAVA监听器原理

    http://blog.csdn.net/longyulu/article/details/25054697 JAVA监听器原理 标签: 监听器 2014-05-05 15:40 9070人阅读 评论 ...

  6. cg资讯网址

    cg教程下载: http://cgpeers.com http://cgpersia.com http://bbs.ideasr.com/forum-328-1.html http://bbs.ide ...

  7. 通过List<String>动态传递参数给 sqlcommand.Parameters

    通过List<String>动态传递参数 private void GetallChecked_TreeNote(TreeNodeCollection aNodes, ref int To ...

  8. JAVA_Java常用核心包(概念)

    20150802 Created By BaoXinjian

  9. Hololens开发笔记之Gesture手势识别(单击,双击)

    本文使用手势识别实现识别单击及双击手势的功能,当单击Cube时改变颜色为蓝色,当双击Cube时改变颜色为绿色. 手势识别是HoloLens交互的重要输入方法之一.HoloLens提供了底层API和高层 ...

  10. C++模板元编程 - 挖新坑的时候探索到了模板元编程的新玩法

    C++真是一门自由的语言,虽然糖没有C#那么多,但是你想要怎么写,想要实现什么,想要用某种编程范式或者语言特性,它都会提供. 开大数运算类的新坑的时候(又是坑),无意中需要解决一个需求:大数类需要分别 ...