在gcc中,使用"-fdata-sections"和"-ffunction-sections"这两个选项的目的是什么?

4

正如man页面所述:

-ffunction-sections
-fdata-sections
如果目标支持任意节段,则将每个函数或数据项放置在其自己的节段中输出到文件中。 函数的名称或数据项的名称决定了输出文件中节段的名称。

编译此代码后:

...

int bss_var_1 = 0;
int bss_var_2;
int bss_var_3;

int data_var_1 = 90;
int data_var_2 = 47;
int data_var_3[128] = {212};

int foo() {
    printf("hello, foo()\n");
}

int func() {
    printf("hello, func()\n");
}

int main(void) {
    ...
}

我在我的文件夹里得到了main.o,然后我列出了它的所有部分,它确实将每个函数和数据放入了自己的部分,但是为什么开发人员需要这两个选项呢?(例如,获取他们的工作完成的任何特殊用途)

$ readelf build/main.o -S
There are 34 section headers, starting at offset 0xeb0:

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        00000000 000034 000000 00  AX  0   0  2
  [ 2] .data             PROGBITS        00000000 000034 000000 00  WA  0   0  1
  [ 3] .bss              NOBITS          00000000 000034 000000 00  WA  0   0  1
  [ 4] .bss.bss_var_1    NOBITS          00000000 000034 000004 00  WA  0   0  4
  [ 5] .bss.bss_var_2    NOBITS          00000000 000034 000004 00  WA  0   0  4
  [ 6] .bss.bss_var_3    NOBITS          00000000 000034 000004 00  WA  0   0  4
  [ 7] .data.data_var_1  PROGBITS        00000000 000034 000004 00  WA  0   0  4
  [ 8] .data.data_var_2  PROGBITS        00000000 000038 000004 00  WA  0   0  4
  [ 9] .data.data_var_3  PROGBITS        00000000 00003c 000200 00  WA  0   0  4
  [10] .rodata           PROGBITS        00000000 00023c 000047 00   A  0   0  4
  [11] .text.foo         PROGBITS        00000000 000284 000014 00  AX  0   0  4
  [12] .rel.text.foo     REL             00000000 000b78 000010 08   I 31  11  4
  [13] .text.func        PROGBITS        00000000 000298 000014 00  AX  0   0  4
  [14] .rel.text.func    REL             00000000 000b88 000010 08   I 31  13  4
  [15] .text.main        PROGBITS        00000000 0002ac 000028 00  AX  0   0  4
  [16] .rel.text.main    REL             00000000 000b98 000020 08   I 31  15  4

  ...


1
https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html ---> 描述下面有两段解释为什么。 - Haris
1个回答

6

这允许链接器删除未使用的部分 [source]

从最终可执行文件中消除未使用的代码和数据的操作是由链接器直接执行的。

为了做到这一点,它必须使用以下选项编译对象:-ffunction-sections -fdata-sections。

这些选项可用于 C 和 Ada 文件。它们将分别在生成的对象文件中将每个函数或数据放置在单独的部分中。

一旦使用这些选项创建了对象和静态库,链接器就可以执行死代码消除。您可以通过将 -Wl,--gc-sections 选项设置为 gcc 命令或在 gnatmake 的 -largs 部分中执行此操作。这将执行对从未引用的代码和数据的垃圾回收。

此外,Haris 提供了 标志文档 中提供的使用指南:

与链接器垃圾回收(链接器--gc-sections选项)一起使用,这些选项可能会导致较小的静态链接可执行文件(剥离后)。
在ELF/DWARF系统上,这些选项不会降低调试信息的质量。其他目标文件/调试信息格式可能存在问题。
只有当这样做有明显好处时才使用这些选项。当您指定这些选项时,汇编器和链接器将创建更大的目标和可执行文件,并且速度较慢。这些选项会影响代码生成。它们通过在翻译单元内使用相对位置来防止编译器和汇编器进行优化,因为这些位置在链接时是未知的。这种优化的一个例子是将调用转换为短调用指令。

由于问题似乎不是特定于Ada语言的,也许可以使用@Haris在上面评论中提供的链接,并从那里复制粘贴? - janneb
@janneb 感谢您的建议。我认为这两个页面互补,所以我会包含它们两个。 - Armandas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接