防止将数据段使用(优化副本)到本地堆栈数据结构/阵列

she*_*lbc 2 c embedded optimization gcc

我正在编写一些固件,需要使用C代码而不使用数据部分。假设人们远离全局变量,这是非常简单的。还是我想。

我写了一些功能类似于以下代码的内容:

void func()
{
    int feature_set[][2] = {
        {feature0, 1},
        {feature1, 0},
        {feature2, 0}
    };

    //Use 'feature_set' for some hardware init
}
Run Code Online (Sandbox Code Playgroud)

在我的特定用例中,feature_set是指我需要用于初始化的一些配置数据。因为我是在堆栈上创建此数据集,所以我期望在使用之前先在堆栈上构造它。我意识到这会创建更多的指令,但是在这种情况下我可以选择这样做。

但是,看完反汇编后,我意识到它实际上是在做这样的事情:

mov ecx, <size>
lea edi, <stack addr>
lea esi, <somewhere in .data>
rep movs
Run Code Online (Sandbox Code Playgroud)

很显然,编译器试图通过在结构中创建const版本.data并在需要时将其复制到堆栈中来优化此操作。

问题:有没有办法防止这种情况?有没有办法告诉编译器不要将数据段用于此操作?更改优化级别可能会起作用,但是我确实希望进行优化……只是不专门针对这种构造。

Lun*_*din 6

初始化列表必须存储在某个地方,您不能随意分配它。通常,初始化列表在.text/中.rodata。编译器可以那么也许通过将优化初始化feature_set.data,而不是堆栈,更快初始化它。

无论如何,您可以改为执行以下操作:

static const uint32_t FEATURE_SET [][2] = 
{
  {feature0, 1},
  {feature1, 0},
  {feature2, 0}
};
Run Code Online (Sandbox Code Playgroud)

现在,应该将阵列放置在闪存(.rodata或类似的闪存)中,否则链接器设置中的某些内容会混乱。

然后,如果您需要堆栈上的可修改运行时版本:

uint32_t feature_set [ sizeof(FEATURE_SET) / sizeof(*FEATURE_SET) ] [2];
memcpy(feature_set, FEATURE_SET, sizeof feature_set);
Run Code Online (Sandbox Code Playgroud)

还要确保不要使用任何奇怪的RAM调试版本,而无论调试还是发布版本,都应始终将程序下载到闪存中。