C语言 阻止 GCC 优化全局变量的问题



我正在使用ARM-GCC v4.9(发布于2015-06-23(作为STM32F105RC处理器。
我已经搜索了 stackoverflow.com,我找到了这个,以试图说服 gcc 不要优化全局变量,如下所示:

static const char AppVersion[] __attribute__((used)) = "v3.05/10.oct.2015";

然而,令我真正惊讶的是,编译器优化了 AppVersion 变量!
顺便说一句:我正在使用优化级别 -O0(默认值(。
我也尝试使用volatile关键字(如其他线程上建议的那样(,但它也不起作用:(
我已经试过(void)AppVersion;但它不起作用...
智能编译器!?我想太聪明了...

同时,我在代码中的某个地方使用了printf(AppVersion);,只是为了能够保留版本......但这是一个粗鲁的解决方案:(
所以,问题是:有没有其他技巧可以完成这项工作,即防止版本被 GCC 优化?

[编辑]:
我也尝试过这样(即没有static(:

const char AppVersion[] __attribute__((used)) = "v3.05/10.oct.2015";

。它也不起作用:(

不幸的是,

我不知道这样做的编译指示。
然而,还有另一种解决方案。将应用版本更改为:

static char * AppVersion = "v3.05/10.oct.2015";

并添加:

__asm__ ("" : : "" (AppVersion));

到您的主要功能。

你看我删除了"used"属性,根据文档,这是一个函数属性。

其他解决方案:gcc 是否有任何选项可以在 ELF 二进制文件中添加版本信息?

虽然我发现这个是最简单的。这基本上不会让编译器和链接器删除 AppVersion,因为我们告诉它这段内联程序集使用它,即使我们实际上没有插入任何内联程序集。

希望这会令您满意。

作者: 安德烈·西莫斯·迪亚斯·维埃拉
原文链接:https://answers.launchpad.net/gcc-arm-embedded/+question/280104

鉴于存在"static",您的声明所做的只是要求编译器包含表示字符串"v3.05/10.oct.2015"字符的字节在文件中的某个任意位置进行一些排序,但懒得告诉任何人把它放在哪里。 鉴于编译器可以合法地编写代码图像文件中某处的字节序列,无论它是否出现在代码中的任何位置,这样的声明真的不是很有用。 自可以肯定的是,这样的序列不太可能出现在代码中完全是偶然的,因此扫描二进制图像可能有点确定它出现在代码中的可靠方法,但总的来说它是最好有一些方法肯定地确定字符串的位置可能会被发现。

如果字符串未声明为静态,则编译器需要告诉链接器在哪里。 由于链接器通常输出名称和所有符号在各种位置的地址,包括符号表,调试信息文件等,这些文件可以以多种方式使用链接器对此一无所知,它也许能够判断出没有使用符号在代码中,但通常不知道是否还有其他一些实用程序可能希望在符号表中找到它并使用它。 一个指令说这个符号被"使用",会告诉链接器,即使它不知道任何对这个符号感兴趣的东西,在更大的宇宙中,链接器一无所知的东西对它感兴趣。

每个编译单元通常都会向链接器并说"这里有一些东西;我需要一个符号作为它的开始,但是我可以从中计算出所有内部的所有地址"。 链接器无法知道实际使用了这种 blob 的哪些部分,因此它别无选择,只能逐字接受整件事。 如果编译器是要在其 blob 中包含未使用的静态声明,它们将通过到输出文件。 另一方面,编译器知道,如果它不这样做导出该 blob 中某些内容的符号,下游没有其他人会无论是否包含对象,都能够找到它;因此,会有通常,能够包含此类 blob 没有什么好处,编译器编写者通常必须提供强制包含此类功能的理由。

似乎使用自定义部分也可以。

而不是

__attribute__((used))

尝试使用

__attribute__((section(".your.section.name.here")))

链接器不会触摸它,strip命令也不会。

最新更新