简体   繁体   English

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

[英]What do R_X86_64_32S and R_X86_64_64 relocation mean?

Got the following error when I tried to compile a C application in 64-bit FreeBSD:当我尝试在 64 位 FreeBSD 中编译 C 应用程序时出现以下错误:

relocation R_X86_64_32S can not be used when making a shared object; relocation R_X86_64_32S 在制作共享对象时不能使用; recompile with -fPIC用 -fPIC 重新编译

What is R_X86_64_32S relocation and what is R_X86_64_64 ?什么是R_X86_64_32S重定位,什么是R_X86_64_64

I've googled about the error, and it's possible causes - It'd be great if anyone could tell what R_X86_64_32S really means.我在谷歌上搜索了这个错误,这可能是原因 - 如果有人能说出 R_X86_64_32S 的真正含义,那就太好了。

The R_X86_64_32S and R_X86_64_64 are names of relocation types, for code compiled for the amd64 architecture. R_X86_64_32SR_X86_64_64是重定位类型的名称,用于为 amd64 架构编译的代码。 You can look all of them up in the amd64 ABI .您可以在amd64 ABI 中查找所有这些。 According to it, R_X86_64_64 is broken down to:根据它, R_X86_64_64被分解为:

  • R_X86_64 - all names are prefixed with this R_X86_64 - 所有名称都以 this 为前缀
  • 64 - Direct 64 bit relocation 64 - 直接 64 位重定位

and R_X86_64_32S to:R_X86_64_32S到:

  • R_X86_64 - prefix R_X86_64 - 前缀
  • 32S - truncate value to 32 bits and sign-extend 32S - 将值截断为 32 位并进行符号扩展

which basically means "the value of the symbol pointed to by this relocation, plus any addend", in both cases.在这两种情况下,这基本上意味着“此重定位指向的符号的值,加上任何加数”。 For R_X86_64_32S the linker then verifies that the generated value sign-extends to the original 64-bit value.对于R_X86_64_32S ,链接器然后验证生成的值是否符号扩展为原始 64 位值。

Now, in an executable file, the code and data segments are given a specified virtual base address.现在,在一个可执行文件中,代码和数据段被赋予了一个指定的虚拟基地址。 The executable code is not shared, and each executable gets its own fresh address space.可执行代码不共享,每个可执行文件都有自己的新地址空间。 This means that the compiler knows exactly where the data section will be, and can reference it directly.这意味着编译器确切地知道数据段的位置,并且可以直接引用它。 Libraries, on the other hand, can only know that their data section will be at a specified offset from the base address;另一方面,库只能知道它们的数据部分将位于距基地址的指定偏移处; the value of that base address can only be known at runtime.该基地址的值只能在运行时知道。 Hence, all libraries must be produced with code that can execute no matter where it is put into memory, known as position independent code (or PIC for short).因此,所有库都必须使用无论放入内存何处都可以执行的代码生成,称为位置无关代码(或简称 PIC)。

Now when it comes to resolving your problem, the error message speaks for itself.现在,在解决您的问题时,错误消息不言自明。

For any of this to make sense, you must first:要使其中任何一项有意义,您必须首先:

Standards标准

R_X86_64_64 , R_X86_64_32 and R_X86_64_32S are all defined by the System V AMD ABI , which contains the AMD64 specifics of the ELF file format. R_X86_64_64R_X86_64_32R_X86_64_32S都是由System V AMD ABI定义的,其中包含 ELF 文件格式的 AMD64 细节。

They are all possible values for the ELF32_R_TYPE field of a relocation entry, specified in the System V ABI 4.1 (1997) which specifies the architecture neutral parts of the ELF format.它们都是重定位条目的ELF32_R_TYPE字段的所有可能值,在System V ABI 4.1 (1997)中指定,它指定了 ELF 格式的体系结构中立部分。 That standard only specifies the field, but not it's arch dependant values.该标准仅指定字段,而不是它的依赖于拱的值。

Under 4.4.1 "Relocation Types" we see the summary table:在 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

We will explain this table later.我们稍后会解释这个表。

And the note:和注意事项:

The R_X86_64_32 and R_X86_64_32S relocations truncate the computed value to 32-bits. R_X86_64_32R_X86_64_32S重定位将计算值截断为 32 位。 The linker must verify that the generated value for the R_X86_64_32 (R_X86_64_32S) relocation zero-extends (sign-extends) to the original 64-bit value.链接器必须验证为 R_X86_64_32 (R_X86_64_32S) 重定位生成的值零扩展(符号扩展)到原始 64 位值。

Example of R_X86_64_64 and R_X86_64_32 R_X86_64_64 和 R_X86_64_32 示例

Let's first look into R_X86_64_64 and R_X86_64_32 :我们先来看看R_X86_64_64R_X86_64_32

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

Then:然后:

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

Contains:包含:

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)

Tested on Ubuntu 14.04, Binutils 2.24.在 Ubuntu 14.04、Binutils 2.24 上测试。

Ignore the disassembly for now (which is meaningless since this is data), and look only to the labels, bytes and relocations.暂时忽略反汇编(这是没有意义的,因为这是数据),只查看标签、字节和重定位。

The first relocation:第一次搬迁:

0: R_X86_64_32  .text+0xc

Which means:意思是:

  • 0 : acts on byte 0 (label a ) 0 :作用于字节 0(标签a
  • R_X86_64_ : prefix used by all relocation types of the AMD64 system V ABI R_X86_64_ : AMD64 系统 V ABI 的所有重定位类型使用的前缀
  • 32 : the 64-bit address of the label s is truncated to a 32 bit address because we only specified a .long (4 bytes) 32 :标签s的 64 位地址被截断为 32 位地址,因为我们只指定了一个.long (4 个字节)
  • .text : we are on the .text section .text :我们在.text部分
  • 0xc : this is the addend , which is a field of the relocation entry 0xc :这是加数,它是重定位条目的一个字段

The address of the relocation is calculated as:重定位地址计算如下:

A + S

Where:在哪里:

  • A : the addend, here 0xC A : 加数,这里是0xC
  • S : the value of the symbol before relocation, here 00 00 00 00 == 0 S : 重定位前符号的值,这里00 00 00 00 == 0

Therefore, after relocation, the new address will be 0xC == 12 bytes into the .text section.因此,重定位后,新地址将是.text部分的 0xC == 12 个字节。

This is exactly what we expect, since s comes after a .long (4 bytes) and a .quad (8 bytes).这正是我们所期望的,因为s.long (4 字节)和.quad (8 字节)之后。

R_X86_64_64 is analogous, but simpler, since here there is no need to truncate the address of s . R_X86_64_64类似,但更简单,因为这里不需要截断s的地址。 This is indicated by the standard through word64 instead of word32 on the Field column.这由标准通过Field列上的word64而不是word32指示。

R_X86_64_32S vs R_X86_64_32 R_X86_64_32S 对比 R_X86_64_32

The difference between R_X86_64_32S vs R_X86_64_32 is when the linker will complain "with relocation truncated to fit": R_X86_64_32SR_X86_64_32之间的区别在于链接器何时会抱怨“重定位被截断以适合”:

  • 32 : complains if the truncated after relocation value does not zero extend the old value, ie the truncated bytes must be zero: 32 :如果重定位后截断的值不为零扩展旧值,即被截断的字节必须为零,则抱怨:

    Eg: FF FF FF FF 80 00 00 00 to 80 00 00 00 generates a complaint because FF FF FF FF is not zero.例如: FF FF FF FF 80 00 00 0080 00 00 00产生投诉,因为FF FF FF FF不为零。

  • 32S : complains if the truncated after relocation value does not sign extend the old value. 32S :如果重定位后截断的值没有对旧值进行符号扩展,则会报错。

    Eg: FF FF FF FF 80 00 00 00 to 80 00 00 00 is fine, because the last bit of 80 00 00 00 and the truncated bits are all 1.例如: FF FF FF FF 80 00 00 0080 00 00 00就可以了,因为80 00 00 00的最后一位和被截断的位都是 1。

See also: What does this GCC error "... relocation truncated to fit..." mean?另请参阅: 这个 GCC 错误“...重定位被截断以适合...”是什么意思?

R_X86_64_32S can be generated with: R_X86_64_32S可以通过以下方式生成:

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

Then:然后:

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

Gives:给出:

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

Now we can observe the "relocation" truncated to fit on 32S with a linker script:现在我们可以使用链接描述文件观察被截断以适合32S的“重定位”:

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

Now:现在:

ld -Tlink.ld a.o

Is fine, because: 0xFFFFFFFF80000000 gets truncated into 80000000 , which is a sign extension.很好,因为: 0xFFFFFFFF80000000被截断为80000000 ,这是一个符号扩展。

But if we change the linker script to:但是如果我们将链接描述文件更改为:

. = 0xFFFF0FFF80000000;

It now generates the error, because that 0 made it not be a sign extension anymore.它现在生成错误,因为0使它不再是符号扩展。

Rationale for using 32S for memory access but 32 for immediates: When is it better for an assembler to use sign extended relocation like R_X86_64_32S instead of zero extension like R_X86_64_32?使用32S进行内存访问但使用32进行立即数访问的基本原理: 汇编程序何时使用 R_X86_64_32S 之类的符号扩展重定位而不是 R_X86_64_32 之类的零扩展更好?

R_X86_64_32S and PIE (position independent executables R_X86_64_32S 和 PIE(位置无关的可执行文件

R_X86_64_32S cannot be used in position independent executables, eg done with gcc -pie , otherwise link fails with: 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

l

I have provided a minimal example explaining it at: What is the -fPIE option for position-independent executables in gcc and ld?我提供了一个最小的例子来解释它: gcc 和 ld 中位置无关的可执行文件的 -fPIE 选项是什么?

That means that compiled a shared object without using -fPIC flag as you should:这意味着在不使用-fPIC标志的情况下编译共享对象,您应该这样做:

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

You need to call你需要打电话

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

Under ELF platform (Linux) shared objects are compiled with position independent code - code that can run from any location in memory, if this flag is not given, the code that is generated is position dependent, so it is not possible to use this shared object.在 ELF 平台 (Linux) 下,共享对象是使用位置无关代码编译的 - 代码可以从内存中的任何位置运行,如果没有给出此标志,则生成的代码是位置相关的,因此无法使用此共享目的。

I ran into this problem and found this answer didn't help me.我遇到了这个问题,发现这个答案对我没有帮助。 I was trying to link a static library together with a shared library.我试图将静态库与共享库链接在一起。 I also investigated putting the -fPIC switch earlier on the command line (as advised in answers elsewhere).我还研究了将 -fPIC 开关更早地放在命令行上(如其他地方的答案中所建议的那样)。 The only thing that fixed the problem, for me, was changing the static library to shared.对我来说,解决问题的唯一方法是将静态库更改为共享。 I suspect the error message about -fPIC can happen due to a number of causes but fundamentally what you want to look at is how your libraries are being built, and be suspicious of libraries that are being built in different ways.我怀疑有关 -fPIC 的错误消息可能由于多种原因而发生,但从根本上说,您想要查看的是您的库是如何构建的,并对以不同方式构建的库持怀疑态度。

In my case the issue arose because the program to compile expected to find shared libraries in a remote directory, while only the corresponding static libraries were there in a mistake.在我的情况下,问题出现是因为要编译的程序希望在远程目录中找到共享库,而只有相应的静态库出错了。

Actually, this relocation error was a file-not-found error in disguise.实际上,这个重定位错误是变相的文件未找到错误。

I have detailed how I coped with it in this other thread https://stackoverflow.com/a/42388145/5459638我在另一个线程中详细说明了我是如何处理它的https://stackoverflow.com/a/42388145/5459638

The above answer demonstrates what these relocations are, and I found building x86_64 objects with GCC -mcmodel=large flag can prevent R_X86_64_32S because the compiler has no assumption on the relocated address in this model.上面的答案演示了这些重定位是什么,我发现使用 GCC -mcmodel=large 标志构建 x86_64 对象可以防止 R_X86_64_32S,因为编译器对这个模型中的重定位地址没有任何假设。

In the following case:在以下情况下:

extern int myarr[];

int test(int i)
{
  return myarr[i];
}

Built with gcc -O2 -fno-pie -c test_array.c and disassemble with objdump -drz test_array.o , we have:gcc -O2 -fno-pie -c test_array.c并用objdump -drz test_array.o反汇编,我们有:

 0: 48 63 ff                movslq %edi,%rdi
 3: 8b 04 bd 00 00 00 00    mov    0x0(,%rdi,4),%eax
        6: R_X86_64_32S myarr
 a: c3                      ret    

With -mcmodel=large, ie gcc -mcmodel=large -O2 -fno-pie -c test_array.c , we have:使用 -mcmodel=large,即gcc -mcmodel=large -O2 -fno-pie -c test_array.c ,我们有:

 0: 48 b8 00 00 00 00 00    movabs $0x0,%rax
 7: 00 00 00 
        2: R_X86_64_64  myarr
 a: 48 63 ff                movslq %edi,%rdi
 d: 8b 04 b8                mov    (%rax,%rdi,4),%eax
10: c3                      ret    

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用简单的链接描述文件将“重新定位到适合的位置:R_X86_64_32S” - Using simple linker script gives “relocation truncated to fit: R_X86_64_32S” 制作共享库时,不能使用针对.text的重定位R_X86_64_32S - relocation R_X86_64_32S against `.text' can not be used when making a shared object 制作共享库(64位NASM + gcc)时,不能使用针对.data的重定位R_X86_64_32S - Relocation R_X86_64_32S against .data cannot be used when making a shared object (64 bit NASM + gcc) 重定位 R_X86_64_32S 针对符号 `stdout@@GLIBC_2.2.5' 制作 PIE 时不能使用 object - relocation R_X86_64_32S against symbol `stdout@@GLIBC_2.2.5' can not be used when making a PIE object 搬迁被截断以适应:R_X86_64_32 - Relocation truncated to fit: R_X86_64_32 截断重定位以适合:R_X86_64_PC32针对未定义符号`cfree&#39; - relocation truncated to fit: R_X86_64_PC32 against undefined symbol `cfree' 在制作共享对象时,不能使用针对`.data&#39;的重定位R_X86_64_32; - relocation R_X86_64_32 against `.data' can not be used when making a shared object; 从内联汇编调用函数时,对符号重新定位R_X86_64_PC32 - Relocation R_X86_64_PC32 against symbol when calling function from inline assembly “relocation truncated to fit: R_X86_64_PC32 against symbol `__imp_Sleep'”的问题 - Problem with “ relocation truncated to fit: R_X86_64_PC32 against symbol `__imp_Sleep' ” C编译:重定位被截断以适合R_X86_64_PC32针对符号 - C compiling: relocation truncated to fit R_X86_64_PC32 against symbol
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM