gpt4 book ai didi

c++ - 危险的重定位错误是什么意思?

转载 作者:行者123 更新时间:2023-12-02 02:53:24 24 4
gpt4 key购买 nike

我收到链接错误:

dangerous relocation: l32r: Literal placed after use:



我还在尝试调试;但是,我想更好地理解这个错误。我明白什么是搬迁;但是,我不确定它是如何危险的,并且正在寻找一些说明。此外,可能会产生此类错误的小代码片段会有所帮助。

简而言之,什么是“危险搬迁”?

最佳答案

这是一个由两部分组成的答案,因为这里真的有两个问题,一个是一般问题(“什么是危险的重定位?”)和一个特定于 Xtensa(“为什么不能在代码?”)。

无论如何,这些危险的搬迁都是关于什么的?

要了解什么是“危险搬迁”,我们必须首先了解什么是搬迁。当编译器从某段代码生成目标文件时,它需要引用在其他地方定义的符号:可能在链接中的另一个目标文件中,或者可能在共享库中。但是,编译器在编译给定的目标文件时并不知道外部符号的地址。它必须发出一个重定位来充当命名占位符,告诉链接器“好吧,把 foobar 的地址推到这个位置,哦,你必须对它做 X、Y 和 Z 以使其适合那里有指示。”

大多数情况下,这可以顺利运行,您从链接器中得到一个二进制文件,而 Bob 是您的叔叔。当这个过程发生故障,并且链接器无法使编译器给它的符号地址适合重定位站点的指令时,它放弃并抛出“危险重定位”消息(其中包括所有-too-common 'relocation truncated to fit' 也会从这个过程中弹出)通知程序员某些事情已经发生了严重的错误。

放置在使用位置之后的文字有什么问题?

现在我们知道什么是一般的“危险重定位”,我们可以继续看错误消息的后半部分,即“l32r:使用后放置的文字”。 Xtensa 使用称为 L32R 的指令。从内存中加载不适合 Xtensa 的常量值 MOVI立即加载指令,具有 12 位有符号立即数字段。 L32R指令在 Xtensa ISA reference 中描述如下:

L32R is a PC-relative 32-bit load from memory. It is typically used to load constant values into a register when the constant cannot be encoded in a MOVI instruction.

L32R forms a virtual address by adding the 16-bit one-extended constant value encoded in the instruction word shifted left by two to the address of the L32R plus three with the two least significant bits cleared. Therefore, the offset can always specify 32-bit aligned addresses from -262141 to -4 bytes from the address of the L32R instruction. 32 bits (four bytes) are read from the physical address. This data is then written to address register at.



鉴于 L32R 的限制上面引用的错误消息很好地分解了:编译器生成了 L32R在代码中的某处加载一个常量(可以是一个值或一个地址),但是编译器无法使用该常量的值(想想 extern const ),或者链接器需要填充的地址(这个是可能的情况)。所以,它发出了这个 L32R重定位告诉链接器在 L32R 中“填空”程序中某处具有常量值或常量地址的指令。但是,链接器在之前的 256KB 代码(或文字池,具体取决于您的编译器和 Xtensa 内核的配置方式)中找不到任何地方来推送常量,因此它放弃并吐出您询问的错误消息关于。

如何解决这个问题?

不幸的是,这种“危险的重定位”取决于代码大小,因此除非您手头有真正的编译器或链接器错误,否则用一小段代码复制它是不可能的。不过,您可以尝试解决两个可能的原因。

我的文字池没有空间了!

如果您使用 -mno-text-section-literals 进行编译(这是默认设置),链接器将文字池作为单独的部分提供给它,然后它必须与代码部分交错。如果您的链接中有一个特别大的目标文件,它的 .text 中可能有超过 256KB 的代码。部分,在 L32R 的范围内无处可去链接器放置相关文字池部分的指令。编译 -mtext-section-literals应消除错误;如果它不起作用,则您已经打开了该标志,或者如果您正在使用 -ffunction-sections (将每个函数放入其自己的部分;有时在嵌入式工作中使用它以允许链接器丢弃未使用的代码),请继续阅读。

链接器(或汇编器)仍然找不到放置我的文字的地方!

当编译器和汇编器被告知将文字发送到 text 部分时,它们将文字池的放置限制在使用它们的函数之前(即在函数的 ENTRY 指令之前),以最大限度地减少文字的风险pools 将作为代码执行,结果显然很糟糕。如果你的代码中有一个非常长的函数——我不知道什么样的函数可以生成超过 256KB 的代码——放置在 ENTRY 之前的“默认”文字池指令可能会超出 L32R 的范围接近函数末尾的指令。通常,编译器会发出一个名为 .literal_position 的汇编指令。 ,以及围绕中间函数文字池的跳转,为汇编器和链接器提供一个额外的地方来将文字插入。您可以使用 -save-temps 告诉编译器输出汇编器列表。然后搜索 .literal_position指令;如果在具有 L32R 的函数中不存在指令超过 256KB 标记,恭喜!您刚刚发现了一个编译器错误!

还有什么可能会产生这种情况?

我看到的唯一可以引发此类问题的其他情况是 ENTRY 之前没有任何地方编译器或链接器可以放置文字池的指令,而编译器无法自行解决——这可能发生在中断处理程序或链接器显式放置在物理内存边界开头的函数中脚本。在这种情况下,您需要插入 .literal_position指令及其相关的跳转和标签在 asm 中手动语句在罪魁祸首函数的顶部,以便为汇编程序提供一个放置罪魁祸首函数文字的地方。如 GAS manual说:

The assembler will automatically place text section literal pools before ENTRY instructions, so the .literal_position directive is only needed to specify some other location for a literal pool. You may need to add an explicit jump instruction to skip over an inline literal pool.

For example, an interrupt vector does not begin with an ENTRY instruction so the assembler will be unable to automatically find a good place to put a literal pool. Moreover, the code for the interrupt vector must be at a specific starting address, so the literal pool cannot come before the start of the code. The literal pool for the vector must be explicitly positioned in the middle of the vector (before any uses of the literals, due to the negative offsets used by PC-relative L32R instructions).



等等,我正在使用绝对文字选项!

如果您有 LITBASE Xtensa 核心中启用的选项并收到此错误,这表明您的文字池已溢出。在这种情况下,编译器应该生成切换文字池所需的“胶水”:如果没有,恭喜!您刚刚发现了一个编译器错误!

关于c++ - 危险的重定位错误是什么意思?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19532826/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com