美文网首页
Relocation truncated to fit?

Relocation truncated to fit?

作者: 罗蓁蓁 | 来源:发表于2018-08-06 19:08 被阅读258次

    Relocation truncated to fit?

    如果你在x86-64上编码的时间足够长,你最终会遇到如下错误:

    (.text+0x3): relocation truncated to fit: R_X86_64_32S against symbol `array' defined in foo section in ./pcrel8.o
    

    这里有一个小例子可以帮助你弄清楚你做错了什么。

    请考虑以下代码:

    $ cat foo.s
    .globl foovar
      .section   foo, "aw",@progbits
      .type foovar, @object
      .size foovar, 4
    foovar:
       .long 0
    
    .text
    .globl _start
     .type function, @function
    _start:
      movq $foovar, %rax
    

    如果不清楚,她也像源码文件:

    int foovar = 0;
    
    void function(void) {
      int *bar = &foovar;
    }
    

    让我们构建该代码,看看它是什么样的:

     gcc -c foo.s
    
    $ objdump --disassemble-all ./foo.o
    
    ./foo.o:     file format elf64-x86-64
    
    
    Disassembly of section .text:
    
    0000000000000000 <_start>:
       0:        48 c7 c0 00 00 00 00   mov    $0x0,%rax
    
    Disassembly of section foo:
    
    0000000000000000 <foovar>:
       0:        00 00          add    %al,(%rax)
       ...
    

    我们可以看到mov指令只为链接器分配了4个字节(00 00 00 00)以放入foovar的地址。如果我们检查重定位:

    $ readelf --relocs ./foo.o
    
    Relocation section '.rela.text' at offset 0x3a0 contains 1 entries:
      Offset          Info           Type           Sym. Value    Sym. Name + Addend
    000000000003  00050000000b R_X86_64_32S      0000000000000000 foovar + 0
    

    R_X86_64_32S搬迁的确是只有32位的搬迁。现在我们可以发现这个错误。请考虑以下链接器脚本,它将foo部分放在距离代码大约5千兆字节的位置。

    $ cat test.lds
    SECTIONS
    {
     . = 10000;
     .text : { *(.text) }
     . = 5368709120;
     .data : { *(.foo) }
    }
    

    这意味着我们无法在重定位分配的空间内放置foovar的地址。当我们尝试时:

     ld -Ttest.lds ./foo.o
    ./foo.o: In function `_start':
    (.text+0x3): relocation truncated to fit: R_X86_64_32S against symbol `foovar' defined in foo section in ./foo.o
    

    这意味着foovar的完整64位地址(现在位于5千兆字节以上)无法在为其分配的32位空间内表示。

    出于代码优化的目的,mov指令的默认即时大小 是32位值。这是有道理的,因为在大多数情况下,程序可以愉快地存在于32位地址空间中,并且人们不会做一些事情,比如让他们的数据远离他们的代码,它需要的不仅仅是一个32位的地址来表示它。因此,默认使用32位immediate会大大减少代码大小,因为您不必为每个mov腾出64位立即空间。

    所以,如果你想真正的移动完整的64位立即到寄存器中,你想要的movabs指令。尝试使用上面的代码 - 使用movabs你应该得到一个R_X86_64_64重定位和64位的空间来修补地址。

    如果你看到这个并且你不是手工编码,你可能想要查看gcc的-mcmodel参数。

    相关文章

      网友评论

          本文标题:Relocation truncated to fit?

          本文链接:https://www.haomeiwen.com/subject/pingvftx.html