更详细的讲解和代码调试演示过程,请参看视频
用java开发C语言编译器

更详细的讲解和代码调试演示过程,请参看视频
如何进入google,算法面试技能全面提升指南

如果你对机器学习感兴趣,请参看一下链接:
机器学习:神经网络导论

更详细的讲解和代码调试演示过程,请参看视频
Linux kernel Hacker, 从零构建自己的内核

微软早期的DOS系统,存在一个严重的问题是,如果应用程序运行出现问题,它会导致整个系统完全奔溃掉,我们当前的系统内核也存在这一的问题,例如打开api_call.asm,其内容如下:

[SECTION .s32]
BITS 32
call main
retf

api_putchar:
mov edx, 1
mov al, [www.vboyule66.cn esp + 4]
int 02Dh
ret

%include "app.asm"
call main 时CPU控制权会提交给应用程序,执行应用程序的代码,应用程序执行完毕后,返回到call main语句的下一条指令继续执行,call main 的下一条语句是retf, 它的作用是从堆栈上得到内核代码的全局描述符,把该描述符在描述符表中的下标赋值给寄存器cs, 同时把内核要执行语句的地址从堆栈上取得,并赋值给寄存器ip, 这样CPU的控制器会重新交还给内核,假设我们对上面代码做一个修改如下:

[SECTION .s32]
BITS 32
call main
pop eax ;故意让返回地址出错造成异常保护中断
retf
我们在执行retf语句时,把存储在堆栈上的内核要执行的语句地址弹出,这样要返回的内核地址就会遭遇破坏,当执行retf语句后,ip指针会执行内存的任意一个无法确定的地方,于是CPU在接下来的执行中就会遇到错误,上面代码修改后运行起来,情况如下:
这里写图片描述

由于ip指针指向了无效地址,致使CPU执行了无效指令进而导致系统的整体奔溃,接下来我们看看如何处理让系统从这种严重错误中恢复回来,这样就可以防止应用程序执行恶意代码而对系统造成伤害。

当CPU在执行指令出现错误时,例如遇到了无效指令,那么CPU会出发0Dh号中断,让该中断来处理当前所出现的异常局面,如果该中断无法处理,那么CPU就会停止运行,于是就出现了上面的情况。为了让系统能从错误中恢复,我们需要实现0Dh号中断,在中断中,我们直接结束掉当前正在运行的应用程序,直接把CPU的控制全交还给内核。

我们现在kernel.asm中注册0Dh号中断,代码修改如下:

LABEL_IDT:
%rep 13
Gate SelectorCode32, SpuriousHandler,0, DA_386IGate
%endrep

.0Dh:
Gate SelectorCode32, www.yszxylpt.com exceptionHandler,0, DA_386IGate

%rep 18
Gate SelectorCode32, www.boayulevip.cn SpuriousHandler,0, DA_386IGate
%endrep
上面代码在中断描述符表中注册了一个0Dh号中断,当中断发送时,CPU会调用exceptionHandler函数。我们看看该函数的实现,同样也是在kernel.asm中:

_exceptionHandler:
exceptionHandler equ _exceptionHandler - $$
cli
;把内存段切换到内核
mov ax, SelectorVram
mov ds, ax
mov es, ax
mov ax, www.vboyl130.cn SelectorStack ;切换到内核堆栈段
mov ss, ax

mov ecx, [0xfe4];获取内核堆栈指针
add ecx, -8
mov [ecx+4], ss ;保存中断时的堆栈段
mov [ecx], esp ;保存中断时堆栈指针

mov esp, ecx ;切换内核指针

call intHandlerForException

.kill: ;通过把CPU交给内核的方式直接杀掉应用程序
mov esp, [0xfe4]
sti
popad
ret
中断运行时,先把内核专有内存段的描述符赋值给寄存器ds,es,这样代码运行时可以直接读写内核的数据,同时把内核的堆栈描述符赋值给寄存器ss,这样代码运行时使用的堆栈就是内核的专有堆栈。然后把错误发生时的应用程序使用的堆栈段描述符和堆栈指针存入内核堆栈,接着调用函数intHandlerForException进行错误处理,该函数实现在内核的C语言部分,也就是在write_vga_desktop.c中,我们看看此函数的实现:

void intHandlerForException(int *esp) {
g_Console.cur_x = 8;
cons_putstr("INT 0D ");
g_Console.cur_x = 8;
g_Console.cur_y += 16;
cons_putstr("General Protected Exception");
g_Console.cur_y += 16;
g_Console.cur_x = 8;
return 1;
它的做法很简单,只是在控制台上打印出两行字符串,分别是”INT OD”,和”General Protected Exception”,然后就返回了。回到中断实现部分,也就是.kill对应的代码,在内核把控制权交给应用程序时,会把它当时的堆栈指针存储到内存[0xfe4]处,内核时通过start_app把控制权交给应用程序的,我们再看看start_app的代码:

start_app: ;void start_app(int eip, int cs,int esp, int ds)
cli
pushad
...
mov [0xfe4], esp
...
大家看,start_app在执行时,通过指令把当时所有通用寄存器的数据存储到堆栈上,同时把esp指针的值,也就是当时的内核堆栈指针存储到内存0xfe4这个地方,因此.kill 的指令 mov esp [0xfe4]实际上就是对上面指令mov [0xfe4], esp 的逆操作,同时popad也是对上面指令pushad的逆操作。我们再看看start_app是如何被调用的,在write_vga_desktop.c中:

void cmd_hlt() {
....
start_app(0, 11*8,64*1024, 12*8);

char *pApp = (char*)(q + 0x100);
showString(shtctl, sht_back, 0, 179, COL8_FFFFFF, pApp);

memman_free_4k(memman, buffer.pBuffer, buffer.length);
memman_free_4k(memman, q, 64 * 1024);
start_app是在cmd_hlt中被调用的,我们知道c语言在调用子函数时,会把调用子函数后要执行的下一条指令的地址压入堆栈,因此当上面代码在调用start_app函数时,下一条指令,也就是char *pApp=(char*)这条语句的地址会被压入到堆栈上。

当.kill处的代码执行完语句popad后,此时堆栈上存储的恰好就是语句char *pApp=(char*)的地址,于是当我们执行指令ret的时候,该语句的地址会赋值给ip寄存器,这样CPU就会直接从char *pApp=(char*)这条语句开始执行,这就类似与应用程序正常执行完毕后,CPU控制权正常返还给内核的情况是一样的。

这样,当应用程序执行出现严重错误时,CPU触发0Dh号异常处理中断,在该中断中,代码会把CPU控制权直接交还给内核,着就相当于把出现异常的应用程序毁尸灭迹,内核就好像什么事都没发生过一样,继续按照老样子运行,上面代码修改后,执行错误的应用程序后,情况如下:

这里写图片描述

由此可见,当错误发生时0Dh号中断确实被调用了,两行字符串被显示到控制台,然后内核可以正常继续运行而不会像前面的例子一样,整个系统会奔溃掉。

更详实的讲解和代码演示,请参看视频。

java开发系统内核:让内核从严重错误中恢复的更多相关文章

  1. 我的Java开发学习之旅------>求字符串中出现次数最多的字符串以及出现的次数

    金山公司面试题:一个字符串中可能包含a~z中的多个字符,如有重复,如String data="aavzcadfdsfsdhshgWasdfasdf",求出现次数最多的那个字母及次数 ...

  2. java开发两年,连Spring中bean的装配都不知道?你怎么涨薪啊

    Spring 1.1.1.1 创建一个bean package com.zt.spring; public class MyBean { private String userName; privat ...

  3. 使用 Java 开发兼容 IPv6 的网络应用程序

    根据现有 IPv4 地址的部署速度,剩余的地址将在 10 到 20 年被使用殆尽.因此网络逐渐从 IPv4 向 IPv6 转换是不可避免的,相应的各种网络应用程序都将支持 IPv6.对于 Java,从 ...

  4. 20175208 实验一 Java开发环境的熟悉

    20175208 实验一 Java开发环境的熟悉 一.实验报告封面 课程:Java程序设计 班级:1752班 姓名:张家华  学号:20175208 指导教师:娄嘉鹏 实验日期:2019年4月2日 实 ...

  5. Java 开发环境配置--eclipse工具进行java开发

    Java 开发环境配置 在本章节中我们将为大家介绍如何搭建Java开发环境. Windows 上安装开发环境 Linux 上安装开发环境 安装 Eclipse 运行 Java Cloud Studio ...

  6. 20165336 实验一 Java开发环境的熟悉

    20165336 实验一 Java开发环境的熟悉 一.实验报告封面 课程:Java程序设计 班级:1653班 姓名:康志强 学号:20165336 指导教师:娄嘉鹏 实验日期:2018年4月2日 实验 ...

  7. 十四种Java开发工具点评

    在计算机开发语言的历史中,从来没有哪种语言象Java那样受到如此众多厂商的支持,有如此多的开发工具,Java菜鸟们如初入大观园的刘姥姥,看花了眼,不知该何种选择.的确,这些工具各有所长,都没有绝对完美 ...

  8. Java开发前期准备工作

    配置Java开发环境变量 在"系统变量"中设置3项属性,JAVA_HOME, PATH, CLASSPATH. 变量设置参数如下: 变量名:JAVA_HOME 变量值:C:\Pro ...

  9. Java-Runoob:Java 开发环境配置

    ylbtech-Java-Runoob:Java 开发环境配置 1.返回顶部 1. Java 开发环境配置 在本章节中我们将为大家介绍如何搭建Java开发环境. Windows 上安装开发环境 Lin ...

随机推荐

  1. leetcode609

    public class Solution { public IList<IList<string>> FindDuplicate(string[] paths) { Dict ...

  2. linux中ftp配置文件详解

    vsftpd配置文件采用"#"作为注释符,以"#"开头的行和空白行在解析时将被忽略,其余的行被视为配置命令行,每个配置命令的"="两边不要留 ...

  3. web页面在ios下不支持fixed可用absolute替代的方案

    本文引用出处:http://www.cnblogs.com/PeunZhang/p/3553020.html. 对于 ios4 和 android2.2 以下不支持 position:fixed 的问 ...

  4. 图解KMP算法

  5. 16.数据类型(data_type)

    CREATE TABLE 语句 CREATE TABLE 语句用于创建数据库中的表. SQL CREATE TABLE 语法 CREATE TABLE 表名称 ( 列名称1 数据类型, 列名称2 数据 ...

  6. UOJ#46. 【清华集训2014】玄学

    传送门 分析 清华集训真的不是人做的啊嘤嘤嘤 我们可以考虑按操作时间把每个操作存进线段树里 如果现在点x正好使一个整块区间的右端点则更新代表这个区间的点 我们不难发现一个区间会因为不同的操作被分成若干 ...

  7. VS2013中全局属性与局部属性的设置

    为了更好的体现程序与库的独立性,vc++2013 中库路径设置不再采用全局设置,就是说在每个工程中都可以有自己独立的库路径设置,当然你如果不设置,那默认就是vs2013自己的库路径.但是如果你需要用到 ...

  8. Python基础入门-集合

    今天给大家分享的是python中集合(set)的概念,集合这个词其实和高中学的数学集合的概念很相近,或者作为初学者你就可以把它理解为数学当中的集合.在python中集合(set)是由一个个键组成的,但 ...

  9. 如何看待那些不能重现的bug?

    在我们日常测试活动中,经常会发现一些bug,但是这些bug可能就是昙花一现,再也无法(或者很难)重现出来,内心灰常崩溃.那到底有哪些方面可能会导致这类的缺陷发生呢? 我以自己工作中所遇到的给出一些自己 ...

  10. C# 操作Excel基础篇(读取Excel、写入Excel)

    注意事项:Excel的数据表中最多只能储存65535行数据,超出后,需要将数据分割开来进行储存.同时对于Excel中的乱码象限,是由于编码的错误方式导致引起的! 一.读取Excel数据表,获得Data ...