gpt4 book ai didi

c - -ffunction-sections -fdata-sections 和 --gc-sections 不工作吗?

转载 作者:可可西里 更新时间:2023-11-01 11:51:21 30 4
gpt4 key购买 nike

我想在编译时从代码中删除未使用的函数。然后我写一些代码(main.c):

#include <stdio.h>

const char *get1();

int main()
{
puts( get1() );
}

和getall.c:

const char *get1()
{
return "s97symmqdn-1";
}


const char *get2()
{
return "s97symmqdn-2";
}

const char *get3()
{
return "s97symmqdn-3";
}

生成文件

test1   :
rm -f a.out *.o *.a
gcc -ffunction-sections -fdata-sections -c main.c getall.c
ar cr libgetall.a getall.o
gcc -Wl,--gc-sections main.o -L. -lgetall

运行后make test1 && objdump --sym a.out | grep get ,我只找到接下来的两行输出:

0000000000000000 l    df *ABS*  0000000000000000              getall.c
0000000000400535 g F .text 000000000000000b get1

我猜 get2get3 被删除了。但是当我用vim打开a.out时,发现s97symmqdn-1 s97symmqdn-2 s97symmqdn-3存在。函数 get2 get3 真的被删除了吗?如何删除符号 s97symmqdn-2 s97symmqdn-3 ?感谢你的回复。我的系统是centos7,gcc版本是4.8.5

最佳答案

编译选项-ffunction-sections -fdata-sections 和链接选项--gc-sections在您的示例中正常工作。你的静态库是多余的,所以它可以简化为:

$ gcc -ffunction-sections -fdata-sections -c main.c getall.c
$ gcc -Wl,--gc-sections main.o getall.o -Wl,-Map=mapfile

其中我还要求链接器的映射文件。

可执行文件中没有未使用的函数 get2get3:

$ nm a.out | grep get
0000000000000657 T get1

并且映射文件显示未使用的函数部分 .text.get2.text.get3 其中 get2 get3 是分别定义在链接中被丢弃:

map 文件(一)

...
Discarded input sections
...
.text.get2 0x0000000000000000 0xd getall.o
.text.get3 0x0000000000000000 0xd getall.o
...

然而,如您所见,所有三个字符串文字 "s97symmqdn-(1|2|3)"在节目中:

$ strings a.out | egrep 's97symmqdn-(1|2|3)'
s97symmqdn-1
s97symmqdn-2
s97symmqdn-3

那是因为 -fdata-sections 只适用于相同的数据对象 __attribute__ ((__section__("name")))适用于1,即适用于定义具有 static storage duration变量 .它不适用于像你这样的匿名字符串文字“s97symmqdn-(1|2|3)”。它们都像往常一样放在 .rodata 部分,我们在那里找到了它们:

$ objdump -s -j .rodata a.out

a.out: file format elf64-x86-64

Contents of section .rodata:
06ed 73393773 796d6d71 646e2d31 00733937 s97symmqdn-1.s97
06fd 73796d6d 71646e2d 32007339 3773796d symmqdn-2.s97sym
070d 6d71646e 2d3300 mqdn-3.

--gc-sections 不允许链接器从程序中丢弃 .rodata因为它不是未使用的部分:它包含 "s97symmqdn-1",已引用在程序中通过 get1 以及未引用的字符串 "s97symmqdn-2"“s97symmqdn-3”

修复

要将这三个字符串文字分成不同的数据部分,您需要将它们分配给不同的命名对象,例如

getcall.c(2)

const char *get1()
{
static const char s[] = "s97symmqdn-1";
return s;
}


const char *get2()
{
static const char s[] = "s97symmqdn-2";
return s;
}

const char *get3()
{
static const char s[] = "s97symmqdn-3";
return s;
}

如果我们重新编译并重新链接该更改,我们会看到:

map 文件(2)

...
Discarded input sections
...
.text.get2 0x0000000000000000 0xd getall.o
.text.get3 0x0000000000000000 0xd getall.o
.rodata.s.1797
0x0000000000000000 0xd getall.o
.rodata.s.1800
0x0000000000000000 0xd getall.o
...

现在有两个新的丢弃数据部分,其中包含我们不需要的两个字符串文字,正如我们在目标文件中看到的那样:

$ objdump -s -j .rodata.s.1797 getall.o

getall.o: file format elf64-x86-64

Contents of section .rodata.s.1797:
0000 73393773 796d6d71 646e2d32 00 s97symmqdn-2.

和:

$ objdump -s -j .rodata.s.1800 getall.o

getall.o: file format elf64-x86-64

Contents of section .rodata.s.1800:
0000 73393773 796d6d71 646e2d33 00 s97symmqdn-3.

只有引用的字符串 "s97symmqdn-1" 现在出现在程序的任何位置:

$ strings a.out | egrep 's97symmqdn-(1|2|3)'
s97symmqdn-1

而且它是程序的.rodata中唯一的字符串:

$ objdump -s -j .rodata a.out

a.out: file format elf64-x86-64

Contents of section .rodata:
06f0 73393773 796d6d71 646e2d31 00 s97symmqdn-1.


[1] 同样, -function-sections 与限定使用 __attribute__ ((__section__(".text.foo")))

定义每个函数 foo

关于c - -ffunction-sections -fdata-sections 和 --gc-sections 不工作吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54996229/

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