简体   繁体   English

这个 GCC 错误“...重定位被截断以适应...”是什么意思?

[英]What does this GCC error "... relocation truncated to fit..." mean?

I am programming the host side of a host-accelerator system.我正在对主机加速器系统的主机端进行编程。 The host runs on the PC under Ubuntu Linux and communicates with the embedded hardware via a USB connection.主机在 Ubuntu Linux 下的 PC 上运行,并通过 USB 连接与嵌入式硬件通信。 The communication is performed by copying memory chunks to and from the embedded hardware's memory.通过在嵌入式硬件的 memory 之间复制 memory 块来执行通信。

On the board's memory there is a memory region which I use as a mailbox where I write and read the data.在板上的 memory 上有一个 memory 区域,我将其用作我写入和读取数据的邮箱。 The mailbox is defined as a structure and I use the same definition to allocate a mirror mailbox in my host space.邮箱被定义为一个结构,我使用相同的定义在我的主机空间中分配一个镜像邮箱。

I used this technique successfully in the past so now I copied the host Eclipse project to my current project's workspace, and made the appropriate name changes.我过去成功地使用了这种技术,所以现在我将主机 Eclipse 项目复制到我当前项目的工作区,并进行了适当的名称更改。 The strange thing is that when building the host project I now get the following message:奇怪的是,在构建宿主项目时,我现在收到以下消息:

Building target: fft2d_host构建目标:fft2d_host
Invoking: GCC C Linker调用:GCC C Linker
gcc -L/opt/adapteva/esdk/tools/host/x86_64/lib -o "fft2d_host"./src/fft2d_host.o -le_host -lrt gcc -L/opt/adapteva/esdk/tools/host/x86_64/lib -o "fft2d_host"./src/fft2d_host.o -le_host -lrt

./src/fft2d_host.o: In function `main': ./src/fft2d_host.o:在 function `main' 中:

fft2d_host.c:(.text+0x280): relocation truncated to fit: R_X86_64_PC32 against symbol `Mailbox' defined in COMMON section in./src/fft2d_host.o fft2d_host.c:(.text+0x280): 重定位被截断以适应:R_X86_64_PC32 反对在./src/fft2d_host.o 的 COMMON 部分中定义的符号“邮箱”

What does this error mean and why it won't build on the current project, while it is OK with the older project?这个错误是什么意思,为什么它不会在当前项目上构建,而在旧项目上是可以的?

You are attempting to link your project in such a way that the target of a relative addressing scheme is further away than can be supported with the 32-bit displacement of the chosen relative addressing mode.您正在尝试以这样一种方式链接您的项目,即相对寻址方案的目标比所选相对寻址模式的 32 位位移所能支持的更远。 This could be because the current project is larger, because it is linking object files in a different order, or because there's an unnecessarily expansive mapping scheme in play.这可能是因为当前项目较大,因为它以不同的顺序链接目标文件,或者因为有一个不必要的扩展映射方案在起作用。

This question is a perfect example of why it's often productive to do a web search on the generic portion of an error message - you find things like this:这个问题是一个完美的例子,说明为什么对错误消息的通用部分进行网络搜索通常很有成效——你会发现这样的事情:

http://www.technovelty.org/code/c/relocation-truncated.html http://www.technovelty.org/code/c/relocation-truncated.html

Which offers some curative suggestions.这提供了一些治疗建议。

Minimal example that generates the error产生错误的最小示例

main.S moves an address into %eax (32-bit). main.S地址移入%eax (32 位)。

main.S电源

_start:
    mov $_start, %eax

linker.ld链接器.ld

SECTIONS
{
    /* This says where `.text` will go in the executable. */
    . = 0x100000000;
    .text :
    {
        *(*)
    }
}

Compile on x86-64:在 x86-64 上编译:

as -o main.o main.S
ld -o main.out -T linker.ld main.o

Outcome of ld : ld的结果:

(.text+0x1): relocation truncated to fit: R_X86_64_32 against `.text'

Keep in mind that:请记住:

  • as puts everything on the .text if no other section is specified如果没有指定其他部分,则将所有as放在.text
  • ld uses the .text as the default entry point if ENTRY .如果ENTRYld使用.text作为默认入口点。 Thus _start is the very first byte of .text .因此_start.text的第一个字节。

How to fix it: use this linker.ld instead, and subtract 1 from the start:如何修复它:改用这个linker.ld ,并从开始减去 1:

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

Notes:笔记:

  • we cannot make _start global in this example with .global _start , otherwise it still fails.在此示例中,我们不能使用.global _start使_start成为全局,否则它仍然会失败。 I think this happens because global symbols have alignment constraints ( 0xFFFFFFF0 works).我认为这是因为全局符号具有对齐约束( 0xFFFFFFF0有效)。 TODO where is that documented in the ELF standard? TODO 在 ELF 标准中记录在哪里?

  • the .text segment also has an alignment constraint of p_align == 2M . .text段还具有p_align == 2M的对齐约束。 But our linker is smart enough to place the segment at 0xFFE00000 , fill with zeros until 0xFFFFFFFF and set e_entry == 0xFFFFFFFF .但是我们的链接器足够聪明,可以将段放在0xFFE00000 ,用零填充直到0xFFFFFFFF并设置e_entry == 0xFFFFFFFF This works, but generates an oversized executable.这可行,但会生成一个过大的可执行文件。

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

Explanation解释

First you must understand what relocation is with a minimal example: https://stackoverflow.com/a/30507725/895245首先,您必须通过一个最小的示例了解什么是重定位: https ://stackoverflow.com/a/30507725/895245

Next, take a look at objdump -Sr main.o :接下来,看看objdump -Sr main.o

0000000000000000 <_start>:
   0:   b8 00 00 00 00          mov    $0x0,%eax
                        1: R_X86_64_32  .text

If we look into how instructions are encoded in the Intel manual, we see that:如果我们查看英特尔手册中指令的编码方式,我们会看到:

  • b8 says that this is a mov to %eax b8说这是%eaxmov
  • 0 is an immediate value to be moved to %eax . 0是要移动到%eax的立即值。 Relocation will then modify it to contain the address of _start .然后重定位将修改它以包含_start的地址。

When moving to 32-bit registers, the immediate must also be 32-bit.移动到 32 位寄存器时,立即数也必须是 32 位的。

But here, the relocation has to modify those 32-bit to put the address of _start into them after linking happens.但是在这里,重定位必须修改那些 32 位,以便在链接发生后将_start的地址放入其中。

0x100000000 does not fit into 32-bit, but 0xFFFFFFFF does. 0x100000000不适合 32 位,但0xFFFFFFFF可以。 Thus the error.因此错误。

This error can only happen on relocations that generate truncation, eg R_X86_64_32 (8 bytes to 4 bytes), but never on R_X86_64_64 .此错误只会发生在产生截断的重定位上,例如R_X86_64_32 (8 字节到 4 字节),但绝不会发生在R_X86_64_64上。

And there are some types of relocation that require sign extension instead of zero extension as shown here, eg R_X86_64_32S .并且有一些类型的重定位需要符号扩展而不是零扩展,如这里所示,例如R_X86_64_32S See also: https://stackoverflow.com/a/33289761/895245另请参阅: https ://stackoverflow.com/a/33289761/895245

R_AARCH64_PREL32 R_AARCH64_PREL32

Asked at: How to prevent "main.o:(.eh_frame+0x1c): relocation truncated to fit: R_AARCH64_PREL32 against `.text'" when creating an aarch64 baremetal program?提问: 在创建 aarch64 裸机程序时,如何防止“main.o:(.eh_frame+0x1c): relocation truncated to fit: R_AARCH64_PREL32 against `.text'”?

On Cygwin -mcmodel=medium is already default and doesn't help.在 Cygwin -mcmodel=medium上已经是默认值并且没有帮助。 To me adding -Wl,--image-base -Wl,0x10000000 to GCC linker did fixed the error.对我来说,将-Wl,--image-base -Wl,0x10000000添加到 GCC 链接器确实修复了错误。

Often, this error means your program is too large , and often it's too large because it contains one or more very large data objects.通常,此错误意味着您的程序太大,而且通常太大,因为它包含一个或多个非常大的数据对象。 For example,例如,

char large_array[1ul << 31];
int other_global;
int main(void) { return other_global; }

will produce a "relocation truncated to fit" error on x86-64/Linux, if compiled in the default mode and without optimization.如果在默认模式下编译并且没有优化,将在 x86-64/Linux 上产生“relocation truncated to fit”错误。 (If you turn on optimization, it could, at least theoretically, figure out that large_array is unused and/or that other_global is never written, and thus generate code that doesn't trigger the problem.) (如果您打开优化,至少在理论上,它可以找出未使用的large_array和/或从未编写过other_global ,从而生成不会触发问题的代码。)

What's going on is that, by default, GCC uses its "small code model" on this architecture, in which all of the program's code and statically allocated data must fit into the lowest 2GB of the address space.发生的事情是,默认情况下,GCC 在此架构上使用其“小代码模型”,其中所有程序代码和静态分配的数据必须适合最低 2GB 的地址空间。 (The precise upper limit is something like 2GB - 2MB, because the very lowest 2MB of any program's address space is permanently unusable. If you are compiling a shared library or position-independent executable, all of the code and data must still fit into two gigabytes, but they're not nailed to the bottom of the address space anymore.) large_array consumes all of that space by itself, so other_global is assigned an address above the limit, and the code generated for main cannot reach it. (精确的上限是 2GB - 2MB,因为任何程序地址空间的最低 2MB 是永久不可用的。如果您正在编译共享库或与位置无关的可执行文件,所有代码和数据必须仍然适合两个千兆字节,但它们不再固定在地址空间的底部。) large_array消耗所有空间,因此other_global被分配了一个超出限制的地址,并且为main生成的代码无法到达它。 You get a cryptic error from the linker, rather than a helpful " large_array is too large" error from the compiler, because in more complex cases the compiler can't know that other_global will be out of reach, so it doesn't even try for the simple cases.您从链接器中得到一个神秘的错误,而不是来自编译器的有用的“ large_array is too large”错误,因为在更复杂的情况下,编译器无法知道other_global将无法触及,所以它甚至不会尝试对于简单的情况。

Most of the time, the correct response to getting this error is to refactor your program so that it doesn't need gigantic static arrays and/or gigabytes of machine code.大多数时候,对出现此错误的正确响应是重构您的程序,以便它不需要巨大的静态数组和/或千兆字节的机器代码。 However, if you really have to have them for some reason, you can use the "medium" or "large" code models to lift the limits, at the price of somewhat less efficient code generation.但是,如果您出于某种原因确实必须拥有它们,您可以使用“中型”或“大型”代码模型来提升限制,但代价是代码生成效率稍低。 These code models are x86-64-specific;这些代码模型是特定于 x86-64 的; something similar exists for most other architectures, but the exact set of "models" and the associated limits will vary.大多数其他架构也存在类似的情况,但确切的“模型”集和相关限制会有所不同。 (On a 32-bit architecture, for instance, you might have a "small" model in which the total amount of code and data was limited to something like 2 24 bytes.) (例如,在 32 位架构上,您可能有一个“小型”模型,其中代码和数据的总量被限制在 2 24字节。)

I ran into this problem while building a program that requires a huge amount of stack space (over 2 GiB).我在构建需要大量堆栈空间(超过 2 GiB)的程序时遇到了这个问题。 The solution was to add the flag -mcmodel=medium , which is supported by both GCC and Intel compilers.解决方案是添加标志-mcmodel=medium ,GCC 和 Intel 编译器都支持该标志。

Remember to tackle error messages in order.请记住按顺序处理错误消息。 In my case, the error above this one was "undefined reference", and I visually skipped over it to the more interesting "relocation truncated" error.在我的例子中,这个错误上面的错误是“未定义的引用”,我在视觉上跳过了它到更有趣的“重定位截断”错误。 In fact, my problem was an old library that was causing the "undefined reference" message.事实上,我的问题是一个导致“未定义引用”消息的旧库。 Once I fixed that, the "relocation truncated" went away also.一旦我解决了这个问题,“重定位被截断”也消失了。

I may be wrong, but in my experience there's another possible reason for the error, the root cause being a compiler (or platform) limitation which is easy to reproduce and work around.我可能错了,但根据我的经验,错误还有另一个可能的原因,根本原因是编译器(或平台)的限制,它很容易重现和解决。 Next the simplest example接下来是最简单的例子

  1. define an array of 1GB with:定义一个 1GB 的数组:
    char a[1024 x 1024 x 1024];

Result: it works, no warnings.结果:它有效,没有警告。 Can use 1073741824 instead of the triple product naturally自然可以用1073741824代替三联产品

  1. Double the previous array:将前一个数组加倍:
    char a[2 x 1024 x 1024 x 1024];

Result in GCC: "error: size of array 'a' is negative" => That's a hint that the array argument accepted/expected is of type signed int GCC 中的结果:“错误:数组 'a' 的大小为负数” => 这暗示接受/预期的数组参数是带符号的 int类型

  1. Based on the previous, cast the argument:在前面的基础上,转换参数:
    char a[(unsigned)2 x 1024 x 1024 x 1024];

Result: error relocation truncated to fit appears, along with this warning: "integer overflow in expression of type 'int'"结果:错误重定位被截断以适应出现,同时出现以下警告:“'int' 类型的表达式中的整数溢出”

  1. Workaround: use dynamic memory.解决方法:使用动态内存。 Function malloc() takes an argument of type size_t which is a typedef of unsigned long long int thus avoiding the limitation函数 malloc() 采用 size_t 类型的参数,它是unsigned long long int的 typedef,从而避免了限制

This has been my experience using GCC on Windows.这是我在 Windows 上使用 GCC 的经验。 Just my 2 cents.只是我的2美分。

I ran into the exact same issue.我遇到了完全相同的问题。 After compiling without the -fexceptions build flag, the file compiled with no issue在没有-fexceptions构建标志的情况下编译后,文件编译没有问题

I ran into this error on 64 bit Windows when linking a c++ program which called a nasm function.在链接一个调用 nasm 函数的 c++ 程序时,我在 64 位 Windows 上遇到了这个错误。 I used nasm for assembly and g++ to compile the c++ and for linking.我使用 nasm 进行汇编,使用 g++ 编译 c++ 和链接。

In my case this error meant I needed DEFAULT REL at the top of my nasm assembler code.在我的情况下,这个错误意味着我需要在我的 nasm 汇编代码顶部使用 DEFAULT REL。

It's written up in the NASM documentation: Chapter 11: Writing 64-bit Code (Unix, Win64)它写在 NASM 文档中:第 11 章:编写 64 位代码(Unix,Win64)

Obvious in retrospect, but it took me days to arrive there, so I decided to post this.回想起来很明显,但是我花了几天时间才到达那里,所以我决定发布这个。

This is a minimal version of the C++ program:这是 C++ 程序的最小版本:

> extern "C" { void matmul(void); }
 int main(void) {
     matmul();
     return 0;
}

This is a minimal version of the nasm program:这是 nasm 程序的最小版本:

    ; "DEFAULT REL" means we can access data in .bss, .data etc
; because we generate position-independent code in 64-bit "flat" memory model.
; see NASM docs
; Chapter 11: Writing 64-bit Code (Unix, Win64)
;DEFAULT REL

global matmul

section .bss
align 32       ; because we want to move 256 bit packed aligned floats to and from it
saveregs  resb 32

section .text
matmul:
push   rbp     ; prologue
mov    rbp,rsp ; aligns the stack pointer

    ; preserve ymm6 in local variable 'saveregs'
    vmovaps [saveregs], ymm6

    ; restore ymm6 from local variable 'saveregs'
    vmovaps ymm6, [saveregs]

mov   rsp,rbp ; epilogue
pop   rbp     ; re-aligns the stack pointer
ret

With DEFAULT REL commented out, I got the error message above:注释掉 DEFAULT REL 后,我收到了上面的错误消息:

g++ -std=c++11 -c   SO.cpp -o SOcpp.o
\bin\nasm -f win64  SO.asm -o SOnasm.obj
g++ SOcpp.o SOnasm.obj -o SO.exe
SOnasm.obj:SO.asm:(.text+0x9): relocation truncated to fit: IMAGE_REL_AMD64_ADDR32 against `.bss'
SOnasm.obj:SO.asm:(.text+0x12): relocation truncated to fit: IMAGE_REL_AMD64_ADDR32 against `.bss'
collect2.exe: error: ld returned 1 exit status

I encountered the "relocation truncated" error on a MIPS machine.我在 MIPS 机器上遇到了“重定位被截断”错误。 The -mcmodel=medium flag is not available on mips, instead -mxgot may help there. -mcmodel=medium标志在 mips 上不可用,相反-mxgot可能会有所帮助。

With GCC, there's a -Wl,--default-image-base-low option that sometimes helps to deal with such errors, eg in some MSYS2 / MinGW configurations.对于 GCC,有一个 -Wl -Wl,--default-image-base-low选项有时有助于处理此类错误,例如在某些MSYS2 / MinGW配置中。

hello i have been trying to compile this code and it is generating these errors and even when i add at the end -mcmodel=large or mcmodel=medium it does not even compile it but freezes the whole computer instead. 你好,我一直在尝试编译此代码,并且正在生成这些错误,即使当我在末尾添加-mcmodel = large或mcmodel = medium时,它甚至都不会编译它,而是冻结了整个计算机。 how can i solve it. 我该怎么解决。

bm gcc 4play_gsfma236.c -o 4play_gsfma236 -lm 4play_gsfma236.c: In function 'setup_replay': 4play_gsfma236.c:230:14: warning: format '%s' expects argument of type 'char ', but argument 3 has type 'char ( )[80]' [-Wformat=] /tmp/ccl2URqB.o: In function setup_replay': 4play_gsfma236.c:(.text+0xb1d): relocation truncated to fit: R_X86_64_PC32 against symbol gd' defined in COMMON section in /tmp/ccl2URqB.o 4play_gsfma236.c:(.text+0xb35): relocation truncated to fit: R_X86_64_PC32 against symbol gd' defined in COMMON section in /tmp/ccl2URqB.o 4play_gsfma236.c:(.text+0xc5d): relocation truncated to fit: R_X86_64_32 against symbol ndiskfiles' defined in COMMON section in /tmp/ccl2URqB.o 4play_gsfma236.c:(.text+0xc75): relocation truncated to fit: R_X86_64_PC32 against symbol ndiskfiles' defined in COMMON section in /tmp/ccl2URqB.o 4play_gsfma236.c:(.text+0xcb0): relocation truncated to fit: R_X86_64_32S against symbol diskfilename' defined in COMMON section in /tmp/ccl2URqB.o 4play_gsfma236. bm gcc 4play_gsfma236.c -o 4play_gsfma236 -lm 4play_gsfma236.c:在函数'setup_replay'中:4play_gsfma236.c:230:14:警告:格式'%s'期望类型为'char ',但是参数3的类型为'char ( )[80]'[-Wformat =] /tmp/ccl2URqB.o:在函数setup_replay': 4play_gsfma236.c:(.text+0xb1d): relocation truncated to fit: R_X86_64_PC32 against symbol /中的COMMON部分中定义的setup_replay': 4play_gsfma236.c:(.text+0xb1d): relocation truncated to fit: R_X86_64_PC32 against symbol gd' tmp / ccl2URqB.o 4play_gsfma236.c :(。text + 0xb35):截断以适合:R_X86_64_PC32针对gd' defined in COMMON section in /tmp/ccl2URqB.o 4play_gsfma236.c:(.text+0xc5d): relocation truncated to fit: R_X86_64_32 against symbol符号gd' defined in COMMON section in /tmp/ccl2URqB.o 4play_gsfma236.c:(.text+0xc5d): relocation truncated to fit: R_X86_64_32 against symbol在/tmp/ccl2URqB.o 4play_gsfma236.c :(。text + 0xc75)的ndiskfiles' defined in COMMON section in /tmp/ccl2URqB.o 4play_gsfma236.c:(.text+0xcb0): relocation truncated to fit: R_X86_64_32S against symbol符号ndiskfiles' defined in COMMON section in /tmp/ccl2URqB.o 4play_gsfma236.c:(.text+0xcb0): relocation truncated to fit: R_X86_64_32S against symbol :重新定位截断以适合:R_X86_64_PC32针对ndiskfiles' defined in COMMON section in /tmp/ccl2URqB.o 4play_gsfma236.c:(.text+0xcb0): relocation truncated to fit: R_X86_64_32S against symbol文件名'在/ tmp / ccl2URqB。的COMMON部分中定义。o 4play_gsfma236。 c:(.text+0xce7): relocation truncated to fit: R_X86_64_32S against symbol diskfilename' defined in COMMON section in /tmp/ccl2URqB.o 4play_gsfma236.c:(.text+0xd0b): relocation truncated to fit: R_X86_64_PC32 against symbol ndiskfiles' defined in COMMON section in /tmp/ccl2URqB.o 4play_gsfma236.c:(.text+0xe3c): relocation truncated to fit: R_X86_64_32 against symbol ndet' defined in COMMON section in /tmp/ccl2URqB.o 4play_gsfma236.c:(.text+0xe54): relocation truncated to fit: R_X86_64_PC32 against symbol ndet' defined in COMMON section in /tmp/ccl2URqB.o 4play_gsfma236.c:(.text+0xe71): relocation truncated to fit: R_X86_64_32 against symbol `beta' defined in COMMON section in /tmp/ccl2URqB.o 4play_gsfma236.c:(.text+0xe8b): additional relocation overflows omitted from the output collect2: error: ld returned 1 exit status c :(。text + 0xce7):截断为适合的位置:R_X86_64_32S针对符号磁盘diskfilename' defined in COMMON section in /tmp/ccl2URqB.o 4play_gsfma236.c:(.text+0xd0b): relocation truncated to fit: R_X86_64_PC32 against symbol ndisk的diskfilename' defined in COMMON section in /tmp/ccl2URqB.o 4play_gsfma236.c:(.text+0xd0b): relocation truncated to fit: R_X86_64_PC32 against symbol R_X86_64s32 '在/tmp/ccl2URqB.o 4play_gsfma236.c :(。text + 0xe3c)的COMMON部分中定义:截断以适合:R_X86_64_32对符号ndet' defined in COMMON section in /tmp/ccl2URqB.o 4play_gsfma236.c:(.text+0xe54): relocation truncated to fit: R_X86_64_PC32 against symbol ndet,在/tmp/ccl2URqB.o 4play_gsfma236.c :(。text + 0xe71)中定义的ndet' defined in COMMON section in /tmp/ccl2URqB.o 4play_gsfma236.c:(.text+0xe54): relocation truncated to fit: R_X86_64_PC32 against symbol ndet:重新截断以适合:R_X86_64_32针对符号'beta'定义/tmp/ccl2URqB.o 4play_gsfma236.c中的COMMON部分:(.text + 0xe8b):输出collect2中省略了其他重定位溢出:错误:ld返回了1退出状态

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM