c-R_X86_64_32S和R_X86_64_64重定位是什么意思?

当我尝试在64位FreeBSD中编译C应用程序时出现以下错误:

创建共享库时,不能使用重定位R_X86_64_32S; 用-fPIC重新编译

什么是R_X86_64_32S迁移,什么是R_X86_64_64

我已经搜索了这个错误,并且可能是原因-如果有人能说出R_X86_64_32S的真正含义,那就太好了。

Raj asked 2020-02-13T12:24:30Z
5个解决方案
35 votes

R_X86_64_32SR_X86_64_64是重定位类型的名称,用于为amd64架构编译的代码。 您可以在amd64 ABI中查找所有这些文件。根据它,R_X86_64_64细分为:

  • R_X86_64-所有名称都带有前缀
  • 64-直接64位重定位

R_X86_64_32S,以:

  • R_X86_64-前缀
  • 32S-将值截断为32位并进行符号扩展

在两种情况下,这基本上表示“此重定位所指向的符号的值加上任何加数”。 然后,对于R_X86_64_32S,链接器会验证生成的值是否符号扩展为原始的64位值。

现在,在可执行文件中,为代码段和数据段指定了指定的虚拟基址。 可执行代码不共享,每个可执行文件都有其自己的新地址空间。 这意味着编译器确切知道数据节将在哪里,并可以直接引用它。 另一方面,库只能知道它们的数据段与基地址之间有指定的偏移量。 该基地址的值只能在运行时知道。 因此,所有库必须使用无论位置如何都可以执行的代码生成,称为位置无关代码(简称PIC)。

现在,当要解决您的问题时,错误消息说明了一切。

Michael Foukarakis answered 2020-02-13T12:25:16Z
25 votes

为了使这一切有意义,您必须首先:

  • 请参阅最小的重定位示例:[https://stackoverflow.com/a/30507725/895245]
  • 了解ELF文件的基本结构:[https://stackoverflow.com/a/30648229/895245]

标准品

R_X86_64_64gcc -pie32均由System V AMD ABI定义,其中包含ELF文件格式的AMD64细节。

它们都是系统V ABI 4.1(1997)中指定的重定位条目的gcc -pie字段的所有可能值,该字段指定ELF格式的体系结构中性部分。 该标准仅指定字段,但不指定与拱有关的值。

在4.4.1“重定位类型”下,我们看到摘要表:

Name          Field   Calculation
------------  ------  -----------
R_X86_64_64   word64  A + S
R_X86_64_32   word32  A + S
R_X86_64_32S  word32  A + S

稍后我们将解释此表。

并注意:

gcc -pie32重定位将计算值截断为32位。 链接器必须验证R_X86_64_32(R_X86_64_32S)重定位的生成值零扩展(符号扩展)到原始64位值。

R_X86_64_64和R_X86_64_32的示例

让我们首先看一下gcc -pie32

.section .text
    /* Both a and b contain the address of s. */
    a: .long s
    b: .quad s
    s:

然后:

as --64 -o main.o main.S
objdump -dzr main.o

包含:

0000000000000000 <a>:
   0:   00 00                   add    %al,(%rax)
                        0: R_X86_64_32  .text+0xc
   2:   00 00                   add    %al,(%rax)

0000000000000004 <b>:
   4:   00 00                   add    %al,(%rax)
                        4: R_X86_64_64  .text+0xc
   6:   00 00                   add    %al,(%rax)
   8:   00 00                   add    %al,(%rax)
   a:   00 00                   add    %al,(%rax)

在Ubuntu 14.04和Binutils 2.24上进行了测试。

暂时忽略反汇编(这是无意义的,因为这是数据),而只看标签,字节和重定位。

第一次搬迁:

0: R_X86_64_32  .text+0xc

意思是:

  • gcc -pie:作用于字节0(标签32
  • gcc -pie:AMD64系统V ABI的所有重定位类型使用的前缀
  • gcc -pie:标签32的64位地址被截断为32位地址,因为我们仅指定了80 00 00 00(4个字节)
  • gcc -pie:我们位于32部分
  • gcc -pie:这是加数,是重定位条目的字段

重定位的地址计算如下:

A + S

哪里:

  • gcc -pie:加号,此处32
  • gcc -pie:重定位之前的符号值,此处为32

因此,重定位后,新地址将为gcc -pie部分中的0xC == 12个字节。

这正是我们所期望的,因为gcc -pie之后是32(4个字节)和80 00 00 00(8个字节)。

gcc -pie是类似的,但更简单,因为这里不需要截断32的地址。这是通过80 00 00 00而不是word32列在word32上的标准指示的。

R_X86_64_32S和R_X86_64_32

gcc -pie32之间的区别是链接器会抱怨“截断位置合适”。

  • gcc -pie:抱怨如果重定位后的截断值不为零,则扩展旧值,即截断的字节必须为零:

    例如:gcc -pie32会产生投诉,因为80 00 00 00不为零。

  • gcc -pie:抱怨如果重定位后的截断值没有符号,则扩展旧值。

    例如:gcc -pie32很好,因为80 00 00 00的最后一位和截短的位都为1。

另请参阅:这个GCC错误“ ...重定位被截断以适合...”是什么意思?

gcc -pie可以通过以下方式生成:

.section .text
.global _start
_start:
    mov s, %eax
    s:

然后:

as --64 -o main.o main.S
objdump -dzr main.o

给出:

0000000000000000 <_start>:
   0:   8b 04 25 00 00 00 00    mov    0x0,%eax
                        3: R_X86_64_32S .text+0x7

现在,我们可以使用链接程序脚本观察到“重定位”被截断以适合gcc -pie的情况:

SECTIONS
{
    . = 0xFFFFFFFF80000000;
    .text :
    {
        *(*)
    }
}

现在:

ld -Tlink.ld a.o

很好,因为:gcc -pie被截断为32,这是一个符号扩展名。

但是,如果我们将链接描述文件更改为:

. = 0xFFFF0FFF80000000;

现在它会生成错误,因为gcc -pie使其不再是符号扩展名。

使用gcc -pie进行内存访问但使用32进行即时访问的理由:什么时候汇编程序最好使用R_X86_64_32S之类的符号扩展重定位而不是使用R_X86_64_32之类的零扩展名?

R_X86_64_32S和PIE(与位置无关的可执行文件

R_X86_64_32S不能用于位置无关的可执行文件,例如 使用gcc -pie完成,否则链接失败,并显示以下信息:

relocation R_X86_64_32S against `.text' can not be used when making a PIE object; recompile with -fPIC

我在下面提供了一个解释它的最小示例:gcc和ld中与位置无关的可执行文件的-fPIE选项是什么?

3 votes

这意味着您无需使用-fPIC标志就可以编译共享对象:

 gcc -shared foo.c -o libfoo.so # Wrong

你需要打电话

 gcc -shared -fPIC foo.c -o libfoo.so # Right

在ELF平台(Linux)下,共享对象使用位置无关的代码进行编译-可以在内存中任何位置运行的代码,如果未指定此标志,则生成的代码取决于位置,因此无法使用此共享 宾语。

Artyom answered 2020-02-13T12:29:43Z
3 votes

我遇到了这个问题,发现这个答案并没有帮助我。 我试图将静态库与共享库链接在一起。 我还研究了如何将-fPIC开关放在命令行的前面(如其他答案中所建议)。对我来说,唯一解决此问题的方法是将静态库更改为共享库。 我怀疑有关-fPIC的错误消息可能由于多种原因而发生,但从根本上讲,您要查看的是如何构建库,并对以不同方式构建的库感到怀疑。

jonawebb answered 2020-02-13T12:30:05Z
2 votes

在我的情况下,出现此问题是因为要编译的程序希望在远程目录中找到共享库,而只有相应的静态库才出现错误。

实际上,此重定位错误是一种变相的文件找不到错误。

我已经在其他线程中详细说明了如何应对[https://stackoverflow.com/a/42388145/5459638]

XavierStuvw answered 2020-02-13T12:30:34Z
translate from https://stackoverflow.com:/questions/6093547/what-do-r-x86-64-32s-and-r-x86-64-64-relocation-mean