【问题标题】:Compiler optimizations not compiling constant?编译器优化不编译常量?
【发布时间】:2012-09-06 23:57:49
【问题描述】:

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

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

【问题讨论】:

  • 我认为发布正在使用的编译器标志会有所帮助

标签: c gcc arm ld


【解决方案1】:

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

`使用'

这个属性,附加到一个变量,意味着该变量 即使看起来变量不是,也必须发出 参考。

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

像这样应用它

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

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

【讨论】:

  • +1,IAR 编译器有 __root,我正在寻找与 gcc 类似的东西。
  • 我已经尝试了 'used' 和 'unused' 属性,但没有成功。我将在 GCC 文档中进一步研究属性,看看我能想出什么。
  • @BrianV 我对 arm 的编译不太熟悉,但听起来链接器是删除数据的那个。也就是说,除非您实际上是在查看目标文件而不是找到数据。
  • @GeoffReedy 您的回复让我走上了正确的道路。看起来 ARM 工具链有一些特定的属性可以帮助我完成我想做的事情。
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

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

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

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

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

    .text :
    {
        KEEP(*(.isr_vector))
        KEEP(*(.metadata))
        *(.text*)
        *(.rodata*)
    
    } > MFlash32
    

    注意

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

    【讨论】:

      【解决方案4】:

      如果你在文件范围内有这些变量,编译器必须提供字符串,因为他不知道它们是否会被不同的编译单元使用。因此,放置这些变量的任何“.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]];
        }
        ...
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-05-06
        • 2011-11-07
        • 1970-01-01
        • 2011-02-10
        • 2013-08-15
        • 2014-02-21
        • 2011-08-24
        相关资源
        最近更新 更多