我想用gcc编译一个带有ARM处理器链接时优化的程序。当我在没有LTO的情况下编译时,系统会被编译。当我启用LTO时 (使用-flto),我得到以下汇编程序错误:
错误:文字常量无效:池需要更近
环顾网络我发现这与我系统中的常量有关,这些常量放在一个名为.rodata的特殊部分中,它被称为常量池,位于.text部分之后。我的系统。似乎在使用LTO进行编译时,由于内联和其他优化,这个.rodata部分离指令太远,因此不再可能寻址常量。是否可以在使用它们的函数之后放置常量?或者是否可以使用其他寻址模式,以便仍然可以解决.rodata部分?谢谢。
答案 0 :(得分:1)
这是汇编程序消息,而不是链接程序消息,因此在生成节之前会发生这种情况。
汇编程序有一条伪指令,用于将常量加载到寄存器中:
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:
答案 1 :(得分:0)
"这是汇编程序消息,而不是链接程序消息,所以这在部分生成之前发生" - 我不确定,但我觉得LTO有点复杂。在启用LTO的情况下编译(包括组装)各个c文件可以正常工作并且不会导致任何问题。当我尝试在启用LTO的情况下将它们链接在一起时,会出现问题。我不知道LTO是如何完成的,但显然这还包括再次调用汇编程序然后我收到此错误消息。在没有LTO的情况下进行链接时,一切都很好,当我看到disassemly时,我可以看到我的常量不是放在函数之后。相反,所有常量都放在.rodata部分中。由于内联启用了LTO,我的函数可能会变大以达到常量池......