我有一个静态库(用arm-gcc编译),由第三方提供 . 我没有可能(让第三方)重新编译库 .
在调查库内容时,我发现gcc选项-ffunction-sections和-fdata-sections尚未用于编译库 . 但这对于减少项目的二进制大小非常有帮助 .
编译完成时使用:(ARM嵌入式处理器的GNU工具)4.8.4 20140526(发布)[ARM / embedded-4_8-branch revision 211358] .
有没有办法将每个数据和每个函数放入它们自己的单独部分,以便为这个库启用函数级链接,而无需重新编译代码?
我想到了这种可能的方法:
-
将库拆分为其目标文件 .
-
对于每个目标文件:
-
编写代码以将符号移动到自己的部分
-
将新对象文件放回存档文件中
这可行,或者你有其他建议,理想情况下只使用arm-gcc提供的工具?
1 回答
我知道这已经过时了,但我也遇到了这个问题,并且认为我会提供我的发现 .
TL;DR: It's possible, but incredibly difficult. You can't simply move symbols into their own sections. Relocations will bite you.
当编译器生成机器代码时,如果提供或未提供
-ffunction-sections
和-fdata-sections
标志,它将生成略微不同的指令 . 这是由于编译器能够对符号所在的位置做出的假设 . 这些假设根据提供的标志而变化 .这通过示例得到最好的说明 . 请使用以下非常简单的代码段:
以下是
arm-none-eabi-objdump -xdr test.o
的结果:arm-none-eabi-gcc -c -Os -mthumb -mcpu=cortexm3 -mlittle-endian -o test.o test.c
:arm-none-eabi-gcc -c -Os -ffunction-sections -fdata-sections \ -mthumb -mcpu=cortexm3 -mlittle-endian -o test.o test.c
:差异很微妙,但很重要 . 标志启用代码执行两个单独的加载,而禁用的代码执行单个"load multiple."启用的代码执行此操作,因为它知道两个符号按特定顺序包含在同一部分中 . 使用启用的代码,情况并非如此 . 符号分为两个单独的部分,虽然它们很可能会保持其顺序和接近程度,但不能保证 . 更重要的是,如果未引用这两个部分,链接器可能会决定不使用一个部分,并将其删除 .
另一个例子:
并生成代码 . 首先没有旗帜:
并带着旗帜:
在这种情况下,差异更加微妙 . 启用的代码加载偏移量为0,而禁用的代码使用4.由于禁用的代码引用了该部分的开头,因此需要偏移到
b
的位置 . 但是,启用的代码引用仅包含b
的部分,因此不需要偏移量 . 如果我们拆分它并且仅更改重定位,则新代码将包含对a
部分的引用,但不包含b
. 这又会导致链接器垃圾收集错误的部分 .这些只是我在看到这个问题时遇到的两个场景,可能还有更多 .
生成有效的目标文件在功能上等同于使用
-ffunction-sections
和-fdata-sections
标志编译的代码,需要解析机器指令以查找可能出现的这些以及任何其他重定位问题 . 这不是一件容易完成的任务 .