由此可见,.fixup是作为一个单独的段出现在可执行程序中的,而此段中所包含的语句则正好是和源程序hello.c中的两条语句相对应的。
将.fixup段和.text段独立开来的目的是为了提高CPU流水线的利用率。熟悉体系结构的读者应该知道,当前的CPU引入了流水线技术来加快指令的执行,即在执行当前指令的同时,要将下面的一条甚至多条指令预取到流水线中。这种技术在面对程序执行分支的时候遇到了问题:如果预取的指令并不是程序下一步要执行的分支,那么流水线中的所有指令都要被排空,这对系统的性能会产生一定的影响。在我们的这个程序中,如果将.fixup段的指令安排在正常执行的.text段中,当程序执行到前面的指令时,这几条很少执行的指令会被预取到流水线中,正常的执行必然会引起流水线的排空操作,这显然会降低整个系统的性能。
下面我们就可以看到异常表是如何形成的了:
$objdump --full-contents --section=__ex_table hello hello: file format elf32-i386 Contents of section __ex_table: 8048578 ac840408 30850408 b0840408 b2840408 ....0...........
由于x86使用小尾端的编址方式,上面的这段数据比较凌乱。让我把上面的__ex_table中的内容转变成大家通常看到的样子,相信会更容易理解一些:
8048578 80484ac 8048530 80484b0 80484b2 ....0...........
上面的红色部分就是我们最感兴趣的地方,而这段数据是如何形成的呢?将前面objdump生成的可执行程序中的汇编语句和hello.c中的源程序结合起来看,就可以发现一些有趣的东西了!
先让我们回头看看hello.c中__ex_table段的语句 .long 0b,3b。其中标签0b(b代表backward,即往回的标签0)是可能出现异常的指令的地址。结合objdump生成的可执行程序.text段的汇编语句可以知道标签0就是80484ac:
原始的汇编语句:
0: rep; movsl
链接到可执行程序后:
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
|