防止gcc删除未使用的变量

时间:2015-04-09 17:32:07

标签: c gcc

在我们的源文件中,我们通常有一个类似的版本字符串:

static const char srcvers[] = "VERSION/foo.c/1.01/09.04.15";

当该字符串未被优化时,它在某些情况下非常有用,因为只需调用strings a.out | grep VERSION即可确定链接到可执行文件的每个源文件的版本。

不幸的是, 优化了gcc(使用'-O')。所以我的问题是,是否有一种简单的方法(编译器开关会很棒)使gcc保持该变量(其名称始终相同)而不关闭任何其他优化。

修改

在我看来,这个问题与that one不同,是我希望找到一个解决方案,我不必触及数千个源文件。

5 个答案:

答案 0 :(得分:24)

您可以使用__attribute__((used)) gcc(也适用于clang)具体(我看到问题标记为gcc)属性:

  

此属性附加到函数,意味着即使看起来函数未被引用,也必须为函数发出代码。这很有用,例如,仅在内联汇编中引用该函数时。

来自https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html

演示:

$ cat a.c
static const char srcvers[] __attribute__((used)) = "VERSION/foo.c/1.01/09.04.15";
$ gcc -O3 -c a.c
$ strings a.o
VERSION/foo.c/1.01/09.04.15

您可以使用一些#if#define来制作此版本,并在不支持此扩展的编译器上进行编译。

答案 1 :(得分:5)

据我所知,您需要在不触及源的情况下将版本字符串添加到每个目标文件中。它可以使用下一种方式完成。

创建标题文件,例如include/version.h

#ifndef VERSION_H
#define VERSION_H

static const char _ver[] __attribute__((used)) = "VERSION/foo.c/1.01/09.04.15";

#endif /* VERSION_H */

然后在你的Makefile(或任何你的构建系统)添加下一个gcc标志:

CPPFLAGS += -include include/version.h

当然应将其传递给gcc,例如像这样:

%.o: %.c
    $(CC) $(CFLAGS) $(CPPFLAGS) -o $(*).o -c $(*).c

现在,您可以观察编译到每个目标文件的_ver字符串:

$ objdump -DS src/main.o | grep _ver

这将显示类似的内容:

Disassembly of section .rodata._ver:
00000000 <_ver>:

答案 2 :(得分:1)

将变量声明为volatile也可以提供帮助。这就是为什么首先使用它,防止编译器对该变量进行任何优化。

答案 3 :(得分:1)

由于似乎所有解决方案都需要对源代码中的版本字符串进行某种修饰,因此可能有助于定义包含所有必要语法的宏,然后在需要时在源文件或头文件中使用此宏: / p>

#define SRCVERSION(file, version, data) static const char _ver[] __attribute__((used)) = "VERSION/" file "/" version "/" date;

然后在您的来源中添加

SRCVERSION("foo.c", "1.01", "09.04.15")

宏可能位于中央项目头文件中或编译器的命令行中。

这样,如果您想要更改有关定义的内容,至少您不必再次触摸所有源文件。

请注意宏定义如何使用字符串连接来构建最终版本字符串。 它还包含最终的分号,因此您可以根据需要通过定义空宏来删除所有内容。

答案 4 :(得分:0)

您担心gcc删除未使用的static char[]变量。 AFAIK,编译器是正确的。

其他答案提供了改善这一点的建议。但是你不想改变成千上万个文件的源代码。

然后,您可能会更改您的构建(例如某些Makefile),以便使用您的技巧(稍微错误,如此处所讨论的......)的每个此类源文件都不需要更改。所以你可以invoke GCC具体。你想要

 static const char _ver[] __attribute__((used));

(这是一个声明,而不是一个定义)要在其他任何东西之前编译。将上面的行放在某个_declare_ver.h文件中,然后编译with gcc -include _declare_ver.h命令(而不是gcc)。如果使用make添加

 CFLAGS += -include _declare_ver.h

Makefile

BTW,这是一个肮脏的把戏。你应该考虑做一些更好的事情(遵循其他答案)。