【问题标题】:Relative vs Absolute jmp in Assembly汇编中的相对与绝对 jmp
【发布时间】:2011-01-15 03:51:48
【问题描述】:

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

【问题讨论】:

  • 请注意,在大多数情况下,您使用的是当前可用的地址,而不是您选择的任何地址。

标签: assembly x86


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    值得您花时间用 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 块的未执行分支。无论链接器将代码放在内存中的哪个位置,这些跳转都将起作用。如果它们是绝对跳转,则链接器每次链接代码时都需要重新计算地址。

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

    希望有帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-11
      • 2011-02-18
      • 1970-01-01
      • 1970-01-01
      • 2019-07-10
      • 2018-10-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多