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

| 当我尝试在64位FreeBSD中编译C应用程序时出现以下错误:   创建共享库时,不能使用重定位R_X86_64_32S;用-fPIC重新编译 什么是“ 0”重定位,什么是“ 1”重定位? 我一直在搜索该错误,并且可能是由该原因引起的-如果有人能说出R_X86_64_32S的真正含义,那就太好了。     
已邀请:
R_X86_64_32S
R_X86_64_64
是重定位类型的名称,用于为amd64架构编译的代码。您可以在amd64 ABI中查找所有这些文件。 根据它,ѭ1被分解为: R_X86_64-所有名称都带有前缀 64-直接64位重定位 和
R_X86_64_32S
到: R_X86_64-前缀 32S-将值截断为32位并进行符号扩展 在两种情况下,这基本上表示\“此重定位所指向的符号的值加上任何加数\”。然后对于链接器“ 0”,验证生成的值是否符号扩展为原始的64位值。 现在,在可执行文件中,为代码和数据段指定了指定的虚拟基址。可执行代码不共享,每个可执行文件都有其自己的新地址空间。这意味着编译器确切知道数据段将在哪里,并可以直接引用它。另一方面,库只能知道其数据段与基地址之间有指定的偏移量。该基地址的值只能在运行时知道。因此,所有库必须使用无论位置如何都可以执行的代码(称为位置无关代码(简称PIC))生成。 现在,当要解决您的问题时,错误消息说明了一切。     
为了使这一切有意义,您必须首先: 查看重新定位的最小示例:https://stackoverflow.com/a/30507725/895245 了解ELF文件的基本结构:https://stackoverflow.com/a/30648229/895245 标准品
R_X86_64_64
R_X86_64_32
R_X86_64_32S
均由System V AMD ABI定义,其中包含ELF文件格式的AMD64细节。 它们都是重定位条目的“ 10”字段的所有可能值,在System V ABI 4.1(1997)中指定,该字段指定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
我们将在后面解释该表。 并注意:   
R_X86_64_32
R_X86_64_32S
重定位将计算值截断为32位。链接器必须验证R_X86_64_32(R_X86_64_32S)重定位的生成值零扩展(符号扩展)为原始64位值。 R_X86_64_64和R_X86_64_32的示例 让我们先来看看
R_X86_64_64
R_X86_64_32
.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
意思是:
0
:作用于字节0(标签
a
R_X86_64_
:AMD64系统V ABI的所有重定位类型使用的前缀
32
:标签
s
的64位地址被截断为32位地址,因为我们仅指定了
.long
(4个字节)
.text
:我们在
.text
部分
0xc
:这是加数,是重定位条目的字段 重定位的地址计算如下:
A + S
哪里:
A
:加号,here31ѭ
S
:重定位前符号的值,here33ѭ 因此,在重定位之后,新的地址将在“ 26”节中为0xC == 12个字节。 这正是我们的期望,因为
s
紧随
.long
(4字节)和
.quad
(8字节)之后。
R_X86_64_64
与之类似,但是更简单,因为这里不需要截断
s
的地址。这是通过through40ѭ而不是
Field
列中的
word32
表示的。 R_X86_64_32S和R_X86_64_32
R_X86_64_32S
R_X86_64_32
的区别在于链接器将抱怨“截断位置适合””:
32
:抱怨如果重定位后的截断值不为零,则扩展旧值,即截断的字节必须为零: 例如:
FF FF FF FF 80 00 00 00
80 00 00 00
会产生投诉,因为
FF FF FF FF
不为零。
32S
:抱怨如果重定位后的截断值没有符号,则扩展旧值。 例如:
FF FF FF FF 80 00 00 00
80 00 00 00
很好,因为
80 00 00 00
的最后一位和截短的位都为1。 另请参阅:这个GCC错误“ ...重定位被截断以适合...”是什么意思?
R_X86_64_32S
可通过以下方式生成:
.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
现在我们可以观察到带有链接描述文件的\“ relocation \”被截断以适合
32S
SECTIONS
{
    . = 0xFFFFFFFF80000000;
    .text :
    {
        *(*)
    }
}
现在:
ld -Tlink.ld a.o
很好,因为:
0xFFFFFFFF80000000
被截断为into61ѭ,这是一个符号扩展。 但是,如果我们将链接描述文件更改为:
. = 0xFFFF0FFF80000000;
现在它会产生错误,因为ѭ20不再使它成为符号扩展。 使用ѭ49进行内存访问而用ѭ23进行即时访问的理由:什么时候汇编程序最好使用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选项是什么?     
这意味着编译共享对象时无需使用
-fPIC
标志:
 gcc -shared foo.c -o libfoo.so # Wrong
你需要打电话
 gcc -shared -fPIC foo.c -o libfoo.so # Right
在ELF平台(Linux)下,共享对象使用位置无关的代码进行编译-可以在内存中任何位置运行的代码,如果未指定此标志,则生成的代码与位置有关,因此无法使用此共享宾语。     
我遇到了这个问题,发现这个答案并没有帮助我。我试图将静态库与共享库链接在一起。我还研究了如何将-fPIC开关放在命令行的前面(如其他答案中所建议)。 对我来说,唯一解决此问题的方法是将静态库更改为共享库。我怀疑有关-fPIC的错误消息可能由于多种原因而发生,但从根本上讲,您要查看的是如何构建库,并对以不同方式构建的库感到怀疑。     
在我的情况下,出现了这个问题,因为要编译的程序希望在远程目录中找到共享库,而只有相应的静态库才出错。 实际上,此重定位错误是一种变相的文件找不到错误。 我已经在另一个线程中详细介绍了如何应对它https://stackoverflow.com/a/42388145/5459638     

要回复问题请先登录注册