Linux内核分析-异常处理

来源:互联网 发布:caffe 中文教程 编辑:程序博客网 时间:2024/05/17 04:20

对IDT的初始化就懒得记录了.以后有心情就补.

 

文件:arch/x86/kernel/entry_32.S

 

CPU异常的时候有的异常会压入错误码有的不,为了保证栈格式统一,对于没有压入错误码的异常内核会自己压入一个0.

 

对于有错误吗的就略过压0这一步.代码中的宏基本不用看,貌似不太影响阅读,不过我也真的想弄清这些宏的作用,有谁知道麻烦指导一下.

 

我们知道对x86CPU会在异常的时候自动向栈中顺序压入ss, esp, eflags, cs, eip,所以就可以得出当前内核栈的情况如下

 

上面的代码接着又调往error_code处执行,在跳往error_code前压入了一个地址,为什么要在jmp前压入这个地址一会儿再讲,现在先来看看error_code处的代码.可以看到其实error_code的代码是嵌在处理page_fault异常的代码内部的,个人觉得这绝不是写这段代码的人偷懒为了在page_fault中少写一个jmp error_code.我认为因为page_fault这个异常应该是内核中最经常发生的一个异常,所以省去的这一条指令也体现了Linux内核设计者们在细微之处的周到用心.

 

好了我们直接来看error_code处的代码,从1218行到1245行都是一系列的push操作,非常简单.这个时候栈的变化情况我们也能了解清楚了.

 

1249-1250:把__KERNEL_PERCPU存入到fs中,__KERNEL_PERCPU是GDT中第27(offset to per-cpu data area)个描述符的偏移值,貌似是给SMP用的.

1252:把gs存入ecx中

1253:意思是把栈中gs的位置的值存入edi中,你也许会说你在栈上找不到gs,其实存gs的位置就是funcaddr的位置.

1254-1255:把栈上的错误码(errcode)存入edx中,并把栈上的该值改写为-1.

1256:把ecx中的值存入栈上的gs的位置,即funcaddr的位置,通过上面分析,ecx中的值其实就是gs.

1258-1260:将ds和es设为用户数据段.

1262:就是将栈的位置存入eax.

 

现在我们整理一下:

栈上的errcode已经被设为-1,funcaddr已经被设为gs,而errcode和funcaddr分别被存入了edx和edi中,1263行就是要跳到edi指向的地方也就是funcaddr处执行.我们想如果funcaddr处理的函数需要访问这个栈怎么办呢?没事,已经通过eax传递这个参数了.不难看出funcaddr就是在压错误码之后压入的那个参数,当funcaddr完成后会返回到1264行执行jmp ret_from_exception.

 

To Be Continued...

原创粉丝点击