ARM + gcc:不要使用一个大的.rodata部分

我想用gcc编译一个带有ARM处理器链接时间优化的程序。 当我在没有LTO的情况下编译时,系统会被编译。 当我启用LTO(使用-flto)时,我得到以下汇编程序错误:

错误:文字常量无效:池需要更近

环顾网络,我发现这与我系统中的常量有关,这些常量放在一个名为.rodata的特殊部分中,它被称为常量池,位于我系统中的.text部分之后。 似乎在使用LTO进行编译时,由于内联和其他优化,这个.rodata部分离指令太远,因此不再可能寻址常量。 是否可以在使用它们的函数之后放置常量? 或者是否可以使用其他寻址模式,以便仍然可以解决.rodata部分? 谢谢。

这是汇编程序消息,而不是链接程序消息,因此在生成节之前会发生这种情况。

汇编程序有一个伪指令,用于将常量加载到寄存器中:

  ldr r0, =0x12345678 

这扩展到了

  ldr r0, [constant_12345678, r15] ... bx lr constant_12345678: dw 0x12345678 

常量池通常遵循返回指令。 使用函数内联,函数可以变得足够长,返回指令太远; 遗憾的是,编译器不知道内存地址之间的距离,并且汇编器不知道控制流,除了“流不会超出返回指令,所以在这里发出常量池是安全的”。

不幸的是,目前没有好的解决方案。

您可以尝试包含的asm

  b 1f .ltorg 1: 

这将强制发出此时的常量池,代价是额外的分支指令。

如果常量池为空,则可以指示汇编程序省略分支,但此时我无法测试,因此这可能无效:

  .if (2f - 1f) .b 2f .endif 1: .ltorg 2: 

“这是一个汇编器消息,而不是链接器消息,因此这会在生成节之前发生” – 我不确定,但我认为LTO稍微复杂一点。 在启用LTO的情况下编译(包括组装)各个c文件可以正常工作并且不会导致任何问题。 当我尝试在启用LTO的情况下将它们链接在一起时会发生此问题。 我不知道LTO是如何完成的,但显然这还包括再次调用汇编程序然后我收到此错误消息。 在没有LTO的情况下进行链接时,一切都很好,当我看到disassemly时,我可以看到我的常量不会放在函数之后。 相反,所有常量都放在.rodata部分中。 由于内联启用了LTO,我的函数可能会变大以达到常量池…