|
原始的汇编语句:
链接到可执行程序后:
80484ac: f3 a5 repz movsl %ds:(%esi),%es:(%edi)
|
而标签3就是处理异常的指令的地址,在我们的这个例子中就是80484b0。
原始的汇编语句:
3: lea 0(%eax,%ecx,4),%ecx
|
链接到可执行程序后:
8048530: 8d 4c 88 00 lea 0x0(%eax,%ecx,4),%ecx
|
因此,相应的汇编语句:
.section __ex_table,"a"
.align 4
.long 0b,3b
|
就变成了:
8048578 80484ac 8048530 …………
|
这样,异常表中的地址对(80484ac,8048530)就诞生了,而对于地址对(80484b0 80484b2)的生成,情况相同,不再赘述。
读到这儿了,有一件事要告诉读者的是,其实例子中异常表的安排在用户空间是不会得到执行的。当运行在用户态的进程访问到标签0处的指令出现缺页异常时,do_page_fault只会把该指令对应的进程页调入内存中,使指令能够重新正确执行,或者直接就杀死该进程,并不会到达函数search_exception_table处。
也许有的读者会问了,既然不执行,前面的例子和围绕例子所展开的讨论又有什么作用呢?大家大可打消这样的疑虑,我们前面的分析并没有白费,因为真正的内核异常表中地址对的生成机制和前面讲述的原理是完全一样的,笔者通过一个运行在用户空间的程序来讲解也是希望让读者能够更加容易的理解异常表的机制,不至于陷入到内核源码的汪洋大海中去。现在,我们可以自己通过objdump工具查看一下内核中的异常表:
$objdump --full-contents --section=__ex_table vmlinux
vmlinux: file format elf32-i386
Contents of section __ex_table:
c024ac80 e36d10c0 e66d10c0 8b7110c0 6c7821c0
……………………
|
做一下转化:
|