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

时间:2013-10-23 04:29:28

标签: c++ build linker linker-errors linker-scripts

我收到了链接错误:

  

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

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

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

2 个答案:

答案 0 :(得分:8)

这是一个由两部分组成的答案,因为这里有两个问题,一个是通用的("什么是危险的搬迁?")和一个特定的Xtensa("为什么你不能在代码中使用它后放置文字?")。

无论如何,所有这些危险的重新安置的东西是什么?

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

大部分时间,这都是顺利进行的,你从链接器中得到一个二进制文件,鲍勃是你的叔叔。当这个过程发生故障,并且链接器无法使编译器给出的符号的地址符合重定位站点的指令时,它就会放弃并抛弃危险的重定位'消息(以及其他 - 为了适应这个过程而被截断的非常常见的重定位),以通知程序员某些事情已经发生了严重的错误。

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

现在我们知道什么是通用的危险搬迁'是的,我们可以转到错误消息的后半部分,即" l32r:使用后放置的文字"。 Xtensa使用称为L32R的指令从内存加载常量值,这些值不适合Xtensa的MOVI立即加载指令,该指令具有12位带符号的立即数字段。 Xtensa ISA reference中描述了L32R指令,如下所示:

  

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

     

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

鉴于上面引用的L32R的限制,错误消息很好地分解:编译器生成了L32R以在代码中的某处加载常量(可能是值或地址) ,但是常量值不可用于编译器(想象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指令之前没有任何地方,编译器或链接器可以放置文字池,编译器可以& #39; t单独解决这个问题 - 这可能发生在中断处理程序或通过链接描述文件明确放置在物理内存边界开头的函数中。在这种情况下,您需要插入.literal_position指令及其相关的跳转&在罪魁祸首函数顶部的asm语句中手动标记,以便为汇编程序提供放置罪魁祸首函数文字的位置。正如GAS manual所说:

  

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

     

例如,中断向量不以ENTRY指令开头,所以   汇编程序将无法自动找到放置文字池的好地方。   而且,中断向量的代码必须在特定的起始地址,所以   文字池在代码开始之前不能出现。文字池为   vector必须明确地定位在向量的中间(在任何使用之前)   文字,由于PC相对L32R指令使用的负偏移量。

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

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

答案 1 :(得分:0)

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

祝你好运:)