危险的搬迁错误意味着什么?

Fre*_*sen 8 c++ linker build linker-errors linker-scripts

我收到链接错误:

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

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

简而言之,什么是" 危险的搬迁 "?

LTh*_*ode 10

这是一个两部分的答案,因为这里有真正的两个问题,一个一般的("什么是危险的搬迁?")和一个特定的Xtensa可("为什么你不能有一个文字放置后,它在的地方的二手码?").

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

要了解"危险的搬迁"是什么,我们必须首先了解搬迁的内容.当编译器从某段代码生成目标文件时,它需要引用在其他地方定义的符号:可能在链接中的另一个目标文件中,或者可能在共享库中.但是,编译器在编译给定目标文件时不知道外部符号的地址.它必须发出搬迁作为一个名为占位符,告诉链接器"OK,推的地址foobar到这个点了,呵呵,你所要做的X,Y和Z到它,使之融入我们的指导. "

大部分时间,这都顺利工作,你从你的链接器中得到一个二进制文件,鲍勃是你的叔叔.当这个过程发生故障,并链接器无法使编译器把它融入在拆迁现场指令的符号的地址,它就会放弃,并扔了一个"危险的搬迁"的消息(等等 - 所有-too-common'重定位被截断以适应'弹出这个过程')以通知程序员某些事情已经非常错误.

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

现在我们知道通用的"危险重定位"是什么,我们可以继续讨论错误消息的后半部分,即"l32r:使用后放置的文字".Xtensa使用一条称为L32R加载来自内存的常量值的MOVI指令,这些指令不适合Xtensa的立即加载指令,该指令具有12位带符号的立即数字段.该L32R指令在Xtensa ISA参考中描述如下:

L32R是来自内存的PC相对32位负载.当常量不能在MOVI指令中编码时,它通常用于将常量值加载到寄存器中.

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

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

如何解决这个问题?

不幸的是,这样的一个"危险的搬迁"取决于代码大小,所以除非你有你的手一个真正的编译器或链接错误,用一小段代码重现这将是不可能的.但是,您可以尝试解决两种可能的原因.

我的文字池没有空间!

如果您正在使用-mno-text-section-literals(这是默认值)进行编译,则链接器将文字池作为单独的部分提供,然后它们必须与代码部分交错.如果你在你的链接一个特别大的目标文件,它可能超过在其代码256KB .text部分,留下瞬间便无处范围L32R为链接器放置相关的文字池部分的指令.编译-mtext-section-literals应该消除错误; 如果它不工作,你有该标志上已经,或者如果你正在使用-ffunction-sections(其中地方各功能到自己的部分;它有时在嵌入式工作用来允许链接抛出了未使用的代码),请继续阅读.

链接器(或汇编程序)仍然无法找到放置文字的地方!

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

还有什么可以产生这个?

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

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

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

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

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