如何防止链接器丢弃功能? [英] how to prevent linker from discarding a function?

查看:369
本文介绍了如何防止链接器丢弃功能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的C代码中有一个函数,该函数被隐式调用,并被链接器转储.我该如何预防这种现象?

我正在使用gcc和链接器标志-gc-sections进行编译,并且我不想从标志中排除整个文件.我尝试使用属性:"used"和"externally_visible",但都没有起作用.

void __attribute__((section(".mySec"), nomicromips, used)) func(){
...
}

在地图文件上,我可以看到该函数已编译但未链接.我使用错了吗?还有其他方法吗?

解决方案

您误解了 used属性

使用

此属性附加到函数上,意味着即使该函数似乎未被引用,也必须为该函数发出代码...

编译器必须发出函数定义,即使函数出现 未被引用.编译器永远不会得出函数未引用的结论 如果具有外部链接.因此,在此程序中:

main1.c

static void foo(void){}

int main(void)
{
    return 0;
}

编译为:

$ gcc -c -O1 main1.c

根本没有发布foo的定义:

$ nm main1.o
0000000000000000 T main

因为在翻译单元中未引用foo,不在外部, 因此可以进行优化.

但是在此程序中:

main2.c

static void __attribute__((used)) foo(void){}

int main(void)
{
    return 0;
}

__attribute__((used))迫使编译器发出本地定义:

$ gcc -c -O1 main2.c
$ nm main2.o
0000000000000000 t foo
0000000000000001 T main

但这并不能阻止 linker 丢弃某节 在其中定义了foo且在-gc-sections存在的情况下,即使foo 是外部的,也未使用该节:

main3.c

void foo(void){}

int main(void)
{
    return 0;
}

使用功能部分进行编译:

$ gcc -c -ffunction-sections -O1 main3.c

foo的全局定义在目标文件中:

$ nm main3.o
0000000000000000 T foo
0000000000000000 T main

但是在链接之后:

$ gcc -Wl,-gc-sections,-Map=mapfile main3.o

程序中未定义

foo:

$ nm a.out | grep foo; echo Done
Done

并删除了定义foo的功能部分:

地图文件

...
...
Discarded input sections
 ...
 ...
 .text.foo      0x0000000000000000        0x1 main3.o
 ...
 ...

根据Eric Postpischil的评论,强制保留链接器 一个显然未使用的功能部分,您必须告诉它假定该程序 使用链接器选项 {-u|--undefined} foo 引用未使用的函数:

main4.c

void __attribute__((section(".mySec"))) foo(void){}

int main(void)
{
    return 0;
}

如果您不这样说:

$ gcc -c main4.c
$ gcc -Wl,-gc-sections main4.o
$ nm a.out | grep foo; echo Done
Done

程序中未定义

foo.如果您告诉它:

$ gcc -c main4.c
$ gcc -Wl,-gc-sections,--undefined=foo main4.o
$ nm a.out | grep foo; echo Done
0000000000001191 T foo
Done

已定义.属性used没有用.

I have a function in my C code that is being called implicitly, and getting dumped by the linker. how can I prevent this phenomena?

I'm compiling using gcc and the linker flag -gc-sections, and I don't want to exclude the whole file from the flag. I tried using attributes: "used" and "externally_visible" and neither has worked.

void __attribute__((section(".mySec"), nomicromips, used)) func(){
...
}

on map file I can see that the function has compiled but didn't linked. am I using it wrong? is there any other way to do it?

解决方案

You are misunderstanding the used attribute

used

This attribute, attached to a function, means that code must be emitted for the function even if it appears that the function is not referenced...

i.e the compiler must emit the function definition even the function appears to be unreferenced. The compiler will never conclude that a function is unreferenced if it has external linkage. So in this program:

main1.c

static void foo(void){}

int main(void)
{
    return 0;
}

compiled with:

$ gcc -c -O1 main1.c

No definition of foo is emitted at all:

$ nm main1.o
0000000000000000 T main

because foo is not referenced in the translation unit, is not external, and so may be optimised out.

But in this program:

main2.c

static void __attribute__((used)) foo(void){}

int main(void)
{
    return 0;
}

__attribute__((used)) compels the compiler to emit the local definition:

$ gcc -c -O1 main2.c
$ nm main2.o
0000000000000000 t foo
0000000000000001 T main

But this does nothing to inhibit the linker from discarding a section in which foo is defined, in the presence of -gc-sections, even if foo is external, if that section is unused:

main3.c

void foo(void){}

int main(void)
{
    return 0;
}

Compile with function-sections:

$ gcc -c -ffunction-sections -O1 main3.c

The global definition of foo is in the object file:

$ nm main3.o
0000000000000000 T foo
0000000000000000 T main

But after linking:

$ gcc -Wl,-gc-sections,-Map=mapfile main3.o

foo is not defined in the program:

$ nm a.out | grep foo; echo Done
Done

And the function-section defining foo was discarded:

mapfile

...
...
Discarded input sections
 ...
 ...
 .text.foo      0x0000000000000000        0x1 main3.o
 ...
 ...

As per Eric Postpischil's comment, to force the linker to retain an apparently unused function-section you must tell it to assume that the program references the unused function, with linker option {-u|--undefined} foo:

main4.c

void __attribute__((section(".mySec"))) foo(void){}

int main(void)
{
    return 0;
}

If you don't tell it that:

$ gcc -c main4.c
$ gcc -Wl,-gc-sections main4.o
$ nm a.out | grep foo; echo Done
Done

foo is not defined in the program. If you do tell it that:

$ gcc -c main4.c
$ gcc -Wl,-gc-sections,--undefined=foo main4.o
$ nm a.out | grep foo; echo Done
0000000000001191 T foo
Done

it is defined. There's no use for attribute used.

这篇关于如何防止链接器丢弃功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆