简体   繁体   English

编译器优化不能编译常量吗?

[英]Compiler optimizations not compiling constant?

I have the following string declared as a constant in my code. 我在代码中将以下字符串声明为常量。 The purpose is to provide a crude and simple way of storing simple metadata in the compiled output. 目的是提供一种粗略而简单的方法来将简单的元数据存储在已编译的输出中。

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

When I inspect the output with a hex editor, I see other string constants but "abc123" does not appear. 当我使用十六进制编辑器检查输出时,我看到了其他字符串常量,但未出现“ abc123”。 This leads me to believe that the optimizations that are enabled are causing the lines not to be compiled, as they are never referenced in the program. 这使我相信启用的优化导致行无法编译,因为它们从未在程序中引用。

Is there a way in code to force this to compile, or another way (in code) of getting this metadata into the binary? 有没有一种方法可以强制将其编译,也可以通过另一种方式(以代码方式)将此元数据转换为二进制文件? I don't want to do any manipulation of the binary post-compile, the goal is to keep it as simple as possible. 我不想对二进制后编译进行任何操作,目的是使它尽可能简单。

compiler flags 编译器标志

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

I think you are looking for the used attribute: 我认为您正在寻找used属性:

`used' `使用”

This attribute, attached to a variable, means that the variable must be emitted even if it appears that the variable is not referenced. 附加到变量的此属性意味着即使看起来未引用该变量,也必须发出该变量。

When applied to a static data member of a C++ class template, the attribute also means that the member will be instantiated if the class itself is instantiated. 当应用于C ++类模板的静态数据成员时,该属性还意味着,如果实例化了类本身,则将实例化该成员。

Apply it like 像这样应用

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

Given the compiler flags you posted, it is almost certainly the linker. 给定您发布的编译器标志,几乎可以肯定它是链接器。 The -ffunction-sections flag puts each definition into its own section in the object files. -ffunction-sections标志将每个定义放入目标文件中自己的部分。 This allows the linker to easily determine that a data item or function is not referenced and omit it from the final binary. 这使链接器可以轻松确定未引用数据项或函数,并从最终二进制文件中忽略它。

Use the binutils strings command to see if these strings are present in your binary. 使用binutils strings命令查看二进制文件中是否存在这些字符串。

If they have been optimized out, you can try to use the volatile qualifier when you declare them. 如果已经对它们进行了优化,则可以在声明它们时尝试使用volatile限定符。 Note that if they are not used even with the volatile qualifier some compilers can still optimized them out. 请注意,即使不使用volatile限定符也不能使用它们,某些编译器仍可以对其进行优化。

I've come up with a solution that uses attributes and involves modifying the link script. 我想出了一个使用属性并涉及修改链接脚本的解决方案。

First I define a custom section called ".metadata". 首先,我定义一个自定义部分,称为“ .metadata”。

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

Then, in the SECTIONS block of the .ld script I added a KEEP(*(.metadata)) which will force the linker to include .metadata even if it's not used 然后,在.ld脚本的SECTIONS块中,我添加了KEEP(*(.metadata)) ,即使未使用链接器,它也会强制链接器包括.metadata

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

} > MFlash32

NOTE 注意

I found that the __attribute__ keyword had to be on the same line as the variable or else it didn't actually show up in the binary, though the .metadata section did show up in the memory map. 我发现__attribute__关键字必须与变量在同一行上,否则它实际上并没有显示在二进制文件中,尽管.metadata节确实显示在内存映射中。

If you have these variables in file scope, the compiler must provide the strings, since he can't know if they will be used from a different compilation unit. 如果在文件范围内有这些变量,则编译器必须提供字符串,因为他不知道是否会在其他编译单元中使用它们。 So any of your ".o" files where you place these variables, must contain the string. 因此,放置这些变量的任何“ .o”文件都必须包含字符串。

Now a clever linker could decide for the final binary that these constants are not needed. 现在,一个聪明的链接器可以为最终的二进制文件决定不需要这些常量。 (I have never observed that, though.) If this is the case for your platform, you should use the variable on a "hypothetical" path, that in reality will never be taken by the program. (不过,我从未观察到。)如果您的平台是这种情况,则应在“假设的”路径上使用变量,实际上该程序永远不会采用该变量。 Something like 就像是

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM