gpt4 book ai didi

c - 第三方C静态库: Add -ffunction-sections -fdata-sections

转载 作者:太空宇宙 更新时间:2023-11-03 23:24:07 27 4
gpt4 key购买 nike

我现在有一个第三方提供的c静态库(用arm-gcc编译的)。我不可能(让第三方)重新编译库。

在调查库内容时,我发现 gcc 选项 -ffunction-sections-fdata-sections 没有用于编译库。但这对于减少项目的二进制大小非常有帮助。

编译完成:(ARM 嵌入式处理器的 GNU 工具)4.8.4 20140526(发布)[ARM/embedded-4_8-branch 修订版 211358]。

有没有什么方法可以将每个数据和每个函数放到它们自己单独的部分中,以便为该库启用函数级链接,而无需重新编译代码?

我想到了这种可能的做法:

  • 将库拆分为目标文件。
  • 对于每个目标文件:
    • 编写代码将符号移动到自己的部分
  • 将新的目标文件放回归档文件中

这行得通吗,或者您有其他建议,最好只使用 arm-gcc 提供的工具吗?

最佳答案

我知道这已经过时了,但我也遇到了这个问题,我想我会提供我的发现。

TL;DR:这是可能的,但非常困难。您不能简单地将符号移动到它们自己的部分中。搬迁会给您带来麻烦。

当编译器生成机器代码时,如果提供或不提供 -ffunction-sections-fdata-sections 标志,它将生成略有不同的指令。这是由于编译器能够做出符号所在位置的假设。这些假设会根据提供的标志而变化。

这最好用例子来说明。采用以下非常简单的代码片段:

int a, b;

int getAPlusB()
{
return a + b;
}

下面是arm-none-eabi-objdump -xdr test.o的结果:

arm-none-eabi-gcc -c -Os -mthumb -mcpu=cortexm3 -mlittle-endian -o test.o test.c:

SYMBOL TABLE:
00000000 g F .text 0000000c getAPlusB
00000004 g O .bss 00000004 b
00000000 g O .bss 00000004 a

Disassembly of section .text:

00000024 <getAPlusB>:
24: 4b01 ldr r3, [pc, #4] ; (2c <getAPlusB+0x8>)
26: cb09 ldmia r3, {r0, r3}
28: 4418 add r0, r3
2a: 4770 bx lr
2c: 00000000 .word 0x00000000
2c: R_ARM_ABS32 .bss

arm-none-eabi-gcc -c -Os -ffunction-sections -fdata-sections\
-mthumb -mcpu=cortexm3 -mlittle-endian -o test.o test.c
:

SYMBOL TABLE:
00000000 g F .text.getAPlusB 00000014 getAPlusB
00000000 g O .bss.b 00000004 b
00000000 g O .bss.a 00000004 a

Disassembly of section .text.getAPlusB:

00000000 <getAPlusB>:
0: 4b02 ldr r3, [pc, #8] ; (c <getAPlusB+0xc>)
2: 6818 ldr r0, [r3, #0]
4: 4b02 ldr r3, [pc, #8] ; (10 <getAPlusB+0x10>)
6: 681b ldr r3, [r3, #0]
8: 4418 add r0, r3
a: 4770 bx lr
...
c: R_ARM_ABS32 .bss.a
10: R_ARM_ABS32 .bss.b

区别很微妙,但很重要。启用标志的代码执行两个单独的加载,而禁用的代码执行单个“多次加载”。启用的代码执行此操作是因为它知道这两个符号都包含在同一部分中,并按特定顺序排列。使用启用的代码,情况并非如此。这些符号位于两个不同的部分,虽然它们很可能会保持顺序和接近度,但不能保证。更重要的是,如果两个部分都未被引用,链接器可能会决定一个部分未被使用,并将其删除。

另一个例子:

int a, b;

int getB()
{
return b;
}

以及生成的代码。首先没有标志:

SYMBOL TABLE:
00000000 g F .text 0000000c getB
00000004 g O .bss 00000004 b
00000000 g O .bss 00000004 a

Disassembly of section .text:

00000018 <getB>:
18: 4b01 ldr r3, [pc, #4] ; (20 <getB+0x8>)
1a: 6858 ldr r0, [r3, #4]
1c: 4770 bx lr
1e: bf00 nop
20: 00000000 .word 0x00000000
20: R_ARM_ABS32 .bss

还有旗帜:

SYMBOL TABLE:
00000000 g F .text.getB 00000014 getB
00000000 g O .bss.b 00000004 b
00000000 g O .bss.a 00000004 a

Disassembly of section .text.getB:

00000000 <getB>:
0: 4b01 ldr r3, [pc, #4] ; (8 <getB+0x8>)
2: 6818 ldr r0, [r3, #0]
4: 4770 bx lr
6: bf00 nop
8: 00000000 .word 0x00000000
8: R_ARM_ABS32 .bss.b

在这种情况下,差异更加微妙。启用的代码加载偏移量为 0,而禁用的代码使用 4。由于禁用的代码引用该部分的开头,因此它需要偏移到 b 的位置。然而,启用的代码引用仅包含 b 的部分,因此不需要偏移量。如果我们将其拆分并仅更改重定位,则新代码将包含对 a 所在部分的引用,但不包含 b。这同样会导致链接器对错误的部分进行垃圾回收。

这只是我在查看此问题时遇到的两种情况,可能还有更多。

生成功能上等同于使用 -ffunction-sections-fdata-sections 标志编译的代码的有效目标文件将需要解析机器指令以查找这些和任何其他可能出现的搬迁问题。这不是一项容易完成的任务。

关于c - 第三方C静态库: Add -ffunction-sections -fdata-sections,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31426182/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com