13

我收到一个链接错误:

危险搬迁:l32r:使用后放置文字:

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

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

4

2 回答 2

23

这是一个由两部分组成的答案,因为这里实际上有两个问题,一个是一般性的(“什么是危险的搬迁?”),另一个是 Xtensa 特有的(“为什么你不能在它的使用位置之后放置一个文字?代码?”)。

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

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

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

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

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

L32R 是从内存加载的与 PC 相关的 32 位。当常量无法在 MOVI 指令中编码时,它通常用于将常量值加载到寄存器中。

L32R 通过将指令字中编码的 16 位单扩展常量值向左移 2 与 L32R 的地址加 3 相加,同时清除两个最低有效位,形成一个虚拟地址。因此,偏移量始终可以从 L32R 指令的地址指定从 -262141 到 -4 字节的 32 位对齐地址。从物理地址读取 32 位(四个字节)。然后将该数据写入地址寄存器at

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

如何解决这个问题?

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

我的字面池没有空间了!

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

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

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

还会发生什么来产生这种情况?

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

汇编器会自动将文本节文字池放置在ENTRY 指令之前,因此该.literal_position指令只需要为文字池指定其他位置。您可能需要添加显式跳转指令来跳过内联文字池。

例如,中断向量不以ENTRY指令开头,因此汇编器将无法自动找到放置文字池的好位置。此外,中断向量的代码必须位于特定的起始地址,因此字面量池不能位于代码开始之前。向量的文字池必须显式定位在向量的中间(在使用任何文字之前,由于 PC 相关L32R指令使用的负偏移量)。

等等,我使用的是绝对文字选项!

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

于 2014-10-28T13:57:49.170 回答
0

这是http://www.mail-archive.com/mspgcc-users@lists.sourceforge.net/msg11488.html 这可能对你有帮助。

祝你好运 :)

于 2013-10-24T10:51:15.347 回答