gcc / ld:允许代码放置和删除未使用的函数

时间:2014-08-21 13:47:16

标签: gcc linker ld

我试图允许在输出二进制文件中指定特定符号的位置,而不放弃ld的垃圾收集功能。例如:如果我在MyInclude.h

#ifndef MY_INCLUDE_H_
#define MY_INCLUDE_H_

void CalledFunc(void);
void UncalledFunc(void);

#endif

和一个主程序:

#include "MyInclude.h"
int main(void)
{
    CalledFunc();
    return 0;
}

使用带有ffunction-sections -fdata-sections的gcc进行编译,并在地图文件中显示--gc-sections已删除的.text.UncalledFunc

我现在需要将某些功能放在不同的部分。在这个例子中,如果恰好调用UncalledFunc(),我希望它在一个特殊的部分。我有一个链接器参数文件,如下所示:

MEMORY
{
    FLASH (rx) : ORIGIN = 0x10000000, LENGTH = 512K
}

SECTIONS
{
    .text.myregion ORIGIN(FLASH):
    {
        *(.text.myregion)
        *(.text.myregion*)
    } >FLASH
    ASSERT ( . <= 0x10010000, "Too much stuff in myregion!")
    .text :
    {
        *(.text)
        *(.text*)
    } >FLASH
}

UncalledFunc()CalledFunc()定义为:

void CalledFunc(void) __attribute__ ((section (".text.myregion")))
{
    /* ... */
}
void UncalledFunc(void) __attribute__ ((section (".text.myregion")))
{
    /* ... */
}

在这种情况下,似乎函数属性会覆盖发送到GCC的每个函数段参数。因此,由于两个函数都在相同的输入部分中,因此它们都出现在输出图像中。有没有办法告诉链接器UncalledFunc()如果被调用.text.myregion但仍然删除它?如上所示,myregion的空间有限,最好不要在那里放置任何不必要的东西。

2 个答案:

答案 0 :(得分:2)

编译器正在做它所说的;你要求它把那个功能放在那个部分,那还有什么呢?

然后链接器会在一个部分中看到所有函数,因此垃圾收集不是很有帮助。

我没试过这个,但我想可以简单地为每个函数分配不同的手册名称来解决问题:

void CalledFunc(void) __attribute__ ((section (".text.myregion.CalledFunc")))
{
    /* ... */
}
void UncalledFunc(void) __attribute__ ((section (".text.myregion.UncalledFunc")))
{
    /* ... */
}

但是,如果这是大量输入(或者如果你使用宏来应用属性),那么它可能会更好:

#define STRINGIFY(S) #S
#define TOSTRING(S) STRINGIFY(S)
#define NAME __FILE__ "." TOSTRING(__LINE__)
void CalledFunc(void) __attribute__ ((section (".text.myregion." NAME)))
{
    /* ... */
}

这样你可以通过搜索和替换来完成它,并且每个函数仍然具有唯一的部分名称。 (有必要使用宏,因为__LINE__是一个整数值,但我们需要一个字符串,而#“stringify”运算符只能在宏内部使用。显然没有间接性的间接原因__LINE__将被评估为实际行号。)

可能是__FUNCTION__宏有效,但鉴于这不在函数体之内,我不自信。

答案 1 :(得分:0)

如果您使用链接时优化,编译器应该能够删除未使用的函数,即使您将所有函数放入公共部分。

所以保留模块(比方说include.c include.h test.c),但是这样构建:

gcc -c -Os -flto include.c -o include.o
gcc -c -Os -flto test.c -o test.o
gcc -flto -Os test.o include.o -o test

这可能(取决于实际代码)内联使用的函数并删除未使用的函数(除非你使用属性noinline。