编译器优化不编译常量?

时间:2012-09-13 20:08:08

标签: c gcc arm ld

我在代码中将以下字符串声明为常量。目的是提供一种在编译输出中存储简单元数据的粗略而简单的方法。

const char myString1[] ="abc123\0";
const char myString2[] = {'a','b','c','1','2','3','\0'};

当我用十六进制编辑器检查输出时,我看到其他字符串常量但是没有出现“abc123”。这使我相信启用的优化会导致不编译行,因为它们从未在程序中引用。

在代码中是否有一种方法可以强制执行此编译,或者以其他方式(在代码中)将此元数据转换为二进制文件?我不想对二进制后编译进行任何操作,目标是尽可能简单。

编译器标志

-O2 -g -Wall -c -fmessage-length=0 -fno-builtin -ffunction-sections -mcpu=cortex-m3 -mthumb

4 个答案:

答案 0 :(得分:3)

我认为您正在寻找used属性:

  

`使用的“

     
    

此属性附加到变量,表示该变量     必须发出即使看起来变量不是     引用。

         

当应用于C ++类模板的静态数据成员时,     属性还意味着如果成员将被实例化     类本身是实例化的。

  

一样应用它
__attribute__((used))
const char myString1[] ="abc123\0";
__attribute__((used))
const char myString2[] = {'a','b','c','1','2','3','\0'};

鉴于您发布的编译器标志,几乎可以肯定是链接器。 -ffunction-sections标志将每个定义放入目标文件中的自己的部分。这允许链接器轻松确定未引用数据项或函数,并从最终二进制文件中省略它。

答案 1 :(得分:1)

使用binutils strings命令查看二进制文件中是否存在这些字符串。

如果它们已经过优化,您可以在声明它们时尝试使用volatile限定符。请注意,如果即使使用volatile限定符也不使用它们,某些编译器仍然可以优化它们。

答案 2 :(得分:1)

我提出了一个使用属性的解决方案,并涉及修改链接脚本。

首先,我定义一个名为“.metadata”的自定义部分。

__attribute__ ((section(".metadata")))

然后,在.ld脚本的SECTIONS块中,我添加了KEEP(*(.metadata)),这将强制链接器包含.metadata,即使它未被使用

.text :
{
    KEEP(*(.isr_vector))
    KEEP(*(.metadata))
    *(.text*)
    *(.rodata*)

} > MFlash32

注意

我发现__attribute__关键字必须与变量位于同一行,否则它实际上不会显示在二进制文件中,尽管.metadata部分确实显示在内存映射中。< / p>

答案 3 :(得分:0)

如果在文件范围中有这些变量,编译器必须提供字符串,因为他不知道是否将从不同的编译单元使用它们。因此,放置这些变量的任何“.o”文件都必须包含字符串。

现在,一个聪明的链接器可以决定不需要这些常量的最终二进制文件。 (但我从来没有观察过。)如果您的平台就是这种情况,那么您应该在“假设”路径上使用该变量,实际上该程序永远不会使用该变量。像

这样的东西
int main(int argc, char*argv[]){
  switch (argv[0][0]) {
    case 1: return myString1[argv[0][1]];
    case 2: return myString2[argv[0][1]];
  }
  ...
}