韩玉琪 + 原创作品转载请注明出处 + 《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. Codeforces Round #159 (Div. 2)

    A. Sockets 当插口数不够时,显然找最大\(a_i\)进行扩展. B. Playing Cubes 枚举起始颜色,Petya会尽可能相同颜色,Vasya则相反. C. View Angle 极 ...

  2. DB2导出脚本,重新建立数据库

    在做项目的时候,我们经常会涉及到数据库的迁移 所以我们需要导出 db2数据的建库脚本,存储过程脚本,函数脚本, 我是这么做的 windows键---cmd---进入命令-----db2cmd----进 ...

  3. C#禁止程序重复启动

    采用线程互斥锁Mutex,在winform程序的主入口点中加入如下代码,将程序改为单实例运行. static class Program { /// <summary> /// 应用程序的 ...

  4. 为什么学习Ruby On Rails:

    简单总结了一下自己为什么喜欢ruby on rails: 语法简单,写代码很愉快,比较接近伪代码: 喜欢其强大的正则表达式和字符串操作. ruby中面向对象更自由,更动态: ruby给人信任,相信你了 ...

  5. 【java】之读取InputStream流

    如这个文件 @Test public void test01() throws Exception{ InputStream in=new FileInputStream("c://test ...

  6. java短信接口

    一.背景 从是Java一直想做一个跟生活联系特别紧密的东西,比如短信.邮箱.电话什么的一直是我感兴趣的,可是楞是当初没有头绪弄,恰巧今天公司在做一个 webrtc的视频会议的软件,刚好有短信这个需求, ...

  7. 关于JS中的JSON

    早期,一般是使用XML作为互联网上传输结构化数据的,但由于它解析麻烦,字符冗长,因此被轻量级的JSON所逐渐替代.JSON是JavaScript的一个严格子集,利用了JavaScript中一些模式来表 ...

  8. Bootstrap for MVC:Html.Bootstrap().TextBoxFor(model=>model.Name)

    在上篇博文中提到最近比较忙,也打过招呼Orchard系列文章更新速度可能会放缓,但还是会继续写下去,主要原因在最近想着开发一个新的东西(系统?组件?),等有一定成果时会跟大家分享一些相关的东西,今天介 ...

  9. Socket 连接"由于目标机器积极拒绝,无法连接" 的诊断

    1.如果是采用TCP/udp协议进行连接,检查windows防火墙是否开放相应SocketTCP/udp端口;   简单的检测方法是关闭windows防火墙后再试;2.如果服务器端和客户端均在本机上运 ...

  10. mybatis处理一对一查询

    有班级表,老师表,要求给定班级id查出班级信息和班级对应的老师信息 1.使用嵌套结果方式 sql语句: <select id="findClasses" parameterT ...