我一开始没注意这个问题,只是通过陷阱门觉得很绕弯子,为何不在3级用户代码里直接调用write_char,今天自己写程序想用call调用代码段,才发现了大问题。我写了个类似于write_char的过程,代码如下:

dividing_line:push %gspushl %ebxpushl %ecxmovl $10,%ecx/*输出10个空格'  '*/movl $SCRN_SEL,%ebxmovw %bx,%gs
1:  movl scr_loc,%ebxshl $1,%ebxmovb $32,%gs:(%ebx)/*' '空格ASCII码*/shr $1,%ebxincl %ebxcmpl $2000,%ebxjb   2fmovl $0,%ebx
2:  movl %ebx,scr_locloop 1bpopl %ecxpopl %ebxpop %gsret

其功能为在屏幕上输出10个空格而已。简直和write_char几乎一样,只不过我指定了要输出的字符,不是通过ax获取罢了。还有一个不同就是我要通过call来调用dividing_line,而不是像write_char一样被陷阱门调用。

结果程序挂了,没法运行。

后来分析了下,原因很简单。我在task1里面直接调用write_char也是不行。这两者原因是相同的,那就是这两行代码:

movl $SCRN_SEL,%ebx
movw %bx,%gs

在源代码中SCRN_SEL= 0x18是GDT中显示数据段的selector,甭管他是什么数据段,反正他是数据段就对了,这个数据段描述符DPL=0,属于高特权级,但是我们现在用特权级3级的代码去调用这个过程,那么这个处理过程此时就算作3级程序的一员,即他的特权级也是3级,CPL=3,尽管SCRN_SEL= 0x18中的RPL=0,但是CPL不够级别,这种加载SCRN_SEL= 0x18的请求必将被处理器驳回。处理器在加载selector进段寄存器时会将当前运作程序的CPL、selector的RPL、被指向描述符的DPL做综合比较,除非CPL和RPL在数值上都小于DPL,也就是特权级较高。否则,这种加载selector的行为都将被处理器拦截并产生保护异常。

回到我的程序,所以只要这个加载0x18 这个selector的行为存在,这个过程的调用就必然失败,因为0x18 这个selector所指向的数据段描述符DPL超高。于是乎,在3级程序里直接调用write_char也好,dividing_line也好,都会失败,无权访问此数据段,有意图也不行。

这就是为什么要通过陷阱门去调用write_char,处理器规定通过陷阱门只能向高特权级代码段转移,不得转入低特权级代码段,意思就是我从3级用户代码转入内核0级代码这是天经地义的。但是注意,3级代码的确可以通过陷阱门转入0级代码,但前提是陷阱门的门描述符DPL=3才行。不然用户程序根本没权限去访问陷阱门。好了,我们假设陷阱门描述符DPL=3,陷阱门描述符里面的目标代码selector指向一段内核0级代码。

这样当3级程序去加载陷阱门描述符,完全可行,因为CPL=3,我们再用RPL=3的selector去访问陷阱门,陷阱门DPL=3,这样完全可以访问陷阱门。然后陷阱门里面的目标selector部分指向0级代码,这没有关系,通过陷阱门我们完全可以转过去,处理器就要我们这样做!这才是应该的过程。低级程序访问低级陷阱门,低级陷阱门里有高特权级的代码段selector,这样可以通过陷阱门转入高特权级的内核代码当中去。这为一些系统调用提供了方便。

最后有一点,我们把这两行导致问题的代码去掉,能不能正常调用呢?答案是肯定的,既然把这两行去了,那么这个处理过程的功能就废了,好不如写个简单点的,比如:

example:pushl %eaxmovl $0x250,%eaxpop %eaxret

这个够简单,在3级用户代码里call example就可以调用了,没有输出提示所以我们可以通过bochs调试来确认,结果就是调用成功,执行过程成功进入此example代码。这就是个普通近调用,没啥特殊的。关于陷阱门特权级我们就说到这里。

说完了。

转载于:https://blog.51cto.com/mirage1993/1576602

Linux0.00内核为什么要自己设置0x80号陷阱门来调用write_char过程?相关推荐

  1. Linux0.11内核--系统中断处理程序int 0x80实现原理

    系统调用是一个软中断,中断号是0x80,它是上层应用程序与Linux系统内核进行交互通信的唯一接口. 这个中断的设置在kernel/sched.c中441行函数中 void sched_init(vo ...

  2. 仿制Linux0.00编写拜年系统

    首先看下效果 源代码 Makefile AS=as LD=ld CC=gcc LDFLAGS=-s -x --oformat binary CCFLAGS=-m32 -fno-pic NM=nmall ...

  3. Linux0.11内核源码解析-setup.s

    学习资料: Linux内核完全注释 操作系统真像还原 极客时间-Linux内核源码趣读 Linux0.11内核源码 ->setup程序将system模块从0x10000~0x8ffff整块向下移 ...

  4. Linux0.00 代码解析(二)

    Linux 0.00 的编译.运行.源码下载: http://blog.csdn.net/longintchar/article/details/78757065 Linux 0.00 Makefil ...

  5. Linux0.11内核剖析--内核体系结构

    一个完整可用的操作系统主要由 4 部分组成:硬件.操作系统内核.操作系统服务和用户应用程序,如下图所示: 用户应用程序是指那些字处理程序. Internet 浏览器程序或用户自行编制的各种应用程序: ...

  6. Linux-0.11内核学习-添加系统调用

    1.参考资料 赵炯博士的网站oldlinux Linux内核完全注释 Linux0.11 源码 2.概要 操作系统作为软件应用层和底层硬件之间的部分,向下提供服务,向上提供接口.系统调用便是操作系统向 ...

  7. 一站式linux0.11内核head.s代码段图表详解

    阅读本文章需要的基础: 计算机组成原理:针对8086,80386CPU架构的计算机硬件体系要有清楚的认知,我们都知道操作系统是用来管理硬件的,那我们就要对本版本的操作系统所依赖的硬件体系有系统的了解, ...

  8. LINUX0.11内核阅读笔记

    我是通过阅读赵炯老师编的厚厚的linux内核完全剖析看完LINUX0.11的代码,不得不发自内心的说Linus真的是个天才.虽然我觉得很多OS设计的思想他是从UNIX学来的,但是他自己很周全很漂亮很巧 ...

  9. VirtualBox虚拟机安装RedHat7.3编译Linux0.01内核

    引子 由于需要编译linux0.01内核,而目前的linux版本太高需要降低gcc版本等等,需要做不少调整非常不方便. 所以,直接安装RedHat7.3,这样就好编译linux0.01的内核了. 但是 ...

最新文章

  1. 如何使用 Python 操作 Git 代码?GitPython 入门介绍
  2. Python的控制语句4
  3. java不同网址提示过期_使用history.back()出现警告: 网页已过期的解决办法
  4. tomcat源码 Connector
  5. java学习(64):类访问私有内部内部类方法
  6. 【C++深度剖析教程27】多态的概念与意义
  7. idea+JRebel实现项目热部署
  8. 终于……我的游戏………简体版就要发布了!
  9. Jmeter设置代理,抓包之app请求
  10. linux如何导入种子文件格式,Linux下磁力链接种子文件下载
  11. openwrt中的mt7621、MAC存储、PPP、UCI、ubus
  12. NOIP2016排名(1~745)
  13. 解决isilon网络配置界面无配置显示
  14. 底量超顶量超级大黑马指标源码_清华女教授忠言:只要出现“底量超顶量”走势,后期必有暴走趋势...
  15. 华为nova5iotg功能使用_华为nova3怎么使用OTG功能教程,华为nova3 OTG功能详解
  16. 机器视觉镜头的计算方法
  17. maven的资源过滤filters
  18. CDC Schemes
  19. rtx3080ti参数 rtx3080ti什么水平 rtx3080ti评测
  20. linux运维自动化脚本,linux运维自动化shell脚本小工具

热门文章

  1. Silverlight Analytics Framework(开源分析框架)
  2. 软件包管理 之 软件在线升级更新yum 图形工具介绍
  3. 两道面试题,带你解析Java类加载机制
  4. Node.js服务器启用Gzip压缩
  5. js获取 浏览器,手机内核
  6. web-httpd2.4编译安装
  7. WPF窗口长时间无人操作鼠标自动隐藏
  8. 在cmd的方式下,简化mysql的输入的方法
  9. 提高PHP运行速度的小技巧
  10. BFD与IGP快速收敛应用测试