汇编中的相对vs绝对jmp

时间:2011-01-15 03:51:49

标签: assembly x86

我想知道以下情况。我注意到在编写汇编语言时,IA32的设计方式是促进相对跳跃的使用,即跳转位移量的字节与使用绝对跳转,即将eip更改为内存中的特定地址。这背后的逻辑是什么?

2 个答案:

答案 0 :(得分:14)

大多数跳跃都是距离跳转指令不远的目标。由于提供了带有带符号的16位值的跳转指令,因此它们可以比绝对跳转所需的字节少(通常是4个字节加上指令本身)。

相对分支的一个小额外优点是它们不需要在链接器中修复,或者就此而言,需要经过PIC中所需的额外间接(位置无关代码)。

答案 1 :(得分:9)

相对跳转使编译器可以生成可重定位的代码,这意味着代码将在内存中的任何位置运行;它不依赖于固定的位置。这是库背后的关键概念:您可以编写一次代码并将其编译为可重定位的对象文件,该文件可以按原样链接到任何程序中。链接器只需要为外部可访问的函数分配绝对地址(因此您自己的代码可以找到它们);所有“内部”跳转都是相对的,不需要从一个可执行文件更改为下一个。

值得花时间用C语言等高级语言编写代码,让编译器生成汇编代码(检查gcc的-S选项),然后读取汇编输出。特别注意条件和循环,例如ifforwhile,你会发现它们都会产生相对跳跃。

这是一个使用虚构装配说明的人为例子:

// Sample C code         Address  Assembly Code       Comments

if (x < 10) {            0000     CMP x,#10           ; Compare x to 10
   do_true_stuff();      0003     JGE +7              ; Skip 7 bytes to 000A if x>=10
} else {                 0005     SUB do_true_stuff   ; x<10
   do_false_stuff();     0008     JMP +5              ; Skip 5 bytes to 000D
}                        000A     SUB do_false_stuff  ; else-branch (x>=10)
do_more_stuff();         000D     SUB do_more_stuff   ; Finished if/else

这里,编译器生成相对跳转(JGEJMP)以跳过if-else块的未执行分支。无论链接器放置代码的内存在何处,这些跳转都将起作用。如果它们是绝对跳转,则链接器每次链接代码时都需要重新计算地址。

您甚至会发现许多函数调用将生成相对跳转,特别是如果函数在单个文件中作用域。这不仅加快了链接过程,而且使运行代码更小,更高效。这是因为相对地址通常限制在比绝对地址小得多的范围内,这意味着它们可以用更少的字节表示。

希望有所帮助!