汇编中的相对vs绝对jmp

the*_*tro 8 x86 assembly

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

Rap*_*ien 14

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

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


Ada*_*iss 9

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

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

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

// 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
Run Code Online (Sandbox Code Playgroud)

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

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

希望有所帮助!