阻止 GCC 优化全局变量的问题
Issue preventing GCC from optimizing out global variable
我正在为 STM32F105RC 处理器使用 ARM-GCC v4.9(2015 年 6 月 23 日发布)。
我搜索了 whosebug.com 并且发现了这个是为了试图说服 gcc 而不是 来优化全局变量,如下所示:
static const char AppVersion[] __attribute__((used)) = "v3.05/10.oct.2015";
然而,令我真正惊讶的是,编译器优化了 AppVersion 变量!
顺便说一句:我正在使用优化级别 -O0(默认)。
我也尝试使用 volatile
关键字(如其他线程所建议的那样),但它也不起作用:(
我已经尝试了 (void)AppVersion;
但它不起作用...
智能编译器!?我想太聪明了...
与此同时,我在我的代码中的某个地方使用了 printf(AppVersion);
,只是为了能够保持版本...但这是一个粗鲁的解决方案:(
所以,问题是:是否有任何 other 技巧可以完成这项工作,即防止版本被 GCC 优化?
[编辑]:
我也试过这样(即没有 static
):
const char AppVersion[] __attribute__((used)) = "v3.05/10.oct.2015";
...它也没有用:(
鉴于 "static" 的存在,您的所有声明所做的就是要求编译器将表示字符串 "v3.05/10.oct.2015" 的字符的字节包含在
文件中任意位置的一些顺序,但懒得告诉
任何人把它们放在哪里。假设编译器可以合法地写
代码图像文件中某处的字节序列 无论是否
出现在代码的任何地方 这样的声明真的不是很有用。到
可以肯定的是,这样的序列不太可能出现在代码中
完全是偶然的,所以扫描二进制图像可能有点
确定它出现在代码中的可靠方法,但通常它是
最好有一些方法来肯定地确定字符串的位置
可能会找到。
如果字符串没有被声明为静态的,那么编译器需要告诉
链接器在哪里。由于链接器通常输出名称和
各种地方的所有符号的地址,包括符号 tables,
调试信息文件等,可以以多种方式使用
链接器对此一无所知,它可能能够判断出未使用符号
在代码中,但通常不知道是否有其他一些
实用程序可能期望在符号 table 中找到它并使用它。说明该符号是 "used" 的指令将告诉链接器,即使它不知道任何对该符号感兴趣的东西,但在更大的宇宙中,链接器一无所知的东西对此感兴趣。
通常每个编译单元都会向
链接器并说“这是一些东西;我需要一个符号作为它的开始,但是
我可以从中计算出所有内部结构的所有地址。链接器
无法知道实际使用了这样一个 blob 的哪些部分,因此它
别无选择,只能逐字接受整个事情。如果编译器是
在它的 blob 中包含未使用的静态声明,他们会通过
到输出文件。另一方面,编译器知道如果它不
为那个 blob 中的东西导出一个符号,下游没有其他人会
无论是否包含该对象,都能够找到它;因此,会有
能够包含这样的 blob 通常没有什么好处,编译器编写者通常不得不提供一个功能来强制包含这样的内容。
不幸的是,我不知道执行此操作的编译指示。
然而,还有另一种解决方案。将 AppVersion 更改为:
static char * AppVersion = "v3.05/10.oct.2015";
并添加:
__asm__ ("" : : "" (AppVersion));
到你的主要功能。
你看我删除了 'used' 属性,根据文档这是一个函数属性。
其他解决方案:Does gcc have any options to add version info in ELF binary file?
虽然我发现这个是最简单的。这基本上不会让编译器和 linker 删除 AppVersion,因为我们告诉它这段内联汇编使用它,即使我们实际上没有插入任何内联汇编。
希望您满意。
作者:安德烈·西蒙斯·迪亚斯·维埃拉
原文link:https://answers.launchpad.net/gcc-arm-embedded/+question/280104
似乎使用自定义部分也可以。
而不是
__attribute__((used))
试试
__attribute__((section(".your.section.name.here")))
链接器不会触及它,strip
命令也不会。
我正在为 STM32F105RC 处理器使用 ARM-GCC v4.9(2015 年 6 月 23 日发布)。
我搜索了 whosebug.com 并且发现了这个是为了试图说服 gcc 而不是 来优化全局变量,如下所示:
static const char AppVersion[] __attribute__((used)) = "v3.05/10.oct.2015";
然而,令我真正惊讶的是,编译器优化了 AppVersion 变量!
顺便说一句:我正在使用优化级别 -O0(默认)。
我也尝试使用 volatile
关键字(如其他线程所建议的那样),但它也不起作用:(
我已经尝试了 (void)AppVersion;
但它不起作用...
智能编译器!?我想太聪明了...
与此同时,我在我的代码中的某个地方使用了 printf(AppVersion);
,只是为了能够保持版本...但这是一个粗鲁的解决方案:(
所以,问题是:是否有任何 other 技巧可以完成这项工作,即防止版本被 GCC 优化?
[编辑]:
我也试过这样(即没有 static
):
const char AppVersion[] __attribute__((used)) = "v3.05/10.oct.2015";
...它也没有用:(
鉴于 "static" 的存在,您的所有声明所做的就是要求编译器将表示字符串 "v3.05/10.oct.2015" 的字符的字节包含在 文件中任意位置的一些顺序,但懒得告诉 任何人把它们放在哪里。假设编译器可以合法地写 代码图像文件中某处的字节序列 无论是否 出现在代码的任何地方 这样的声明真的不是很有用。到 可以肯定的是,这样的序列不太可能出现在代码中 完全是偶然的,所以扫描二进制图像可能有点 确定它出现在代码中的可靠方法,但通常它是 最好有一些方法来肯定地确定字符串的位置 可能会找到。
如果字符串没有被声明为静态的,那么编译器需要告诉 链接器在哪里。由于链接器通常输出名称和 各种地方的所有符号的地址,包括符号 tables, 调试信息文件等,可以以多种方式使用 链接器对此一无所知,它可能能够判断出未使用符号 在代码中,但通常不知道是否有其他一些 实用程序可能期望在符号 table 中找到它并使用它。说明该符号是 "used" 的指令将告诉链接器,即使它不知道任何对该符号感兴趣的东西,但在更大的宇宙中,链接器一无所知的东西对此感兴趣。
通常每个编译单元都会向 链接器并说“这是一些东西;我需要一个符号作为它的开始,但是 我可以从中计算出所有内部结构的所有地址。链接器 无法知道实际使用了这样一个 blob 的哪些部分,因此它 别无选择,只能逐字接受整个事情。如果编译器是 在它的 blob 中包含未使用的静态声明,他们会通过 到输出文件。另一方面,编译器知道如果它不 为那个 blob 中的东西导出一个符号,下游没有其他人会 无论是否包含该对象,都能够找到它;因此,会有 能够包含这样的 blob 通常没有什么好处,编译器编写者通常不得不提供一个功能来强制包含这样的内容。
不幸的是,我不知道执行此操作的编译指示。
然而,还有另一种解决方案。将 AppVersion 更改为:
static char * AppVersion = "v3.05/10.oct.2015";
并添加:
__asm__ ("" : : "" (AppVersion));
到你的主要功能。
你看我删除了 'used' 属性,根据文档这是一个函数属性。
其他解决方案:Does gcc have any options to add version info in ELF binary file?
虽然我发现这个是最简单的。这基本上不会让编译器和 linker 删除 AppVersion,因为我们告诉它这段内联汇编使用它,即使我们实际上没有插入任何内联汇编。
希望您满意。
作者:安德烈·西蒙斯·迪亚斯·维埃拉
原文link:https://answers.launchpad.net/gcc-arm-embedded/+question/280104
似乎使用自定义部分也可以。
而不是
__attribute__((used))
试试
__attribute__((section(".your.section.name.here")))
链接器不会触及它,strip
命令也不会。