我正在编写一些固件,需要使用C代码而不使用数据部分。假设人们远离全局变量,这是非常简单的。还是我想。
我写了一些功能类似于下面的代码:
void func()
{
int feature_set[][2] = {
{feature0, 1},
{feature1, 0},
{feature2, 0}
};
//Use 'feature_set' for some hardware init
}
在我的特定用例中,feature_set
是指一些我需要用于初始化的配置数据。因为我是在堆栈上创建此数据集,所以我期望在使用之前先在堆栈上构造它。我意识到这会创建更多的指令,但是在这种情况下我可以选择这样做。
但是,看完反汇编后,我意识到它实际上是在做这样的事情:
mov ecx, <size>
lea edi, <stack addr>
lea esi, <somewhere in .data>
rep movs
很明显,编译器试图通过在.data
中创建结构的const版本并在需要时将其复制到堆栈中来优化此操作。
问题:有没有办法防止这种情况?有没有办法告诉编译器不要将数据段用于此操作?更改优化级别可能会起作用,但是我 do 希望进行优化工作……只是不是专门针对这种构造。
答案 0 :(得分:6)
初始化器列表必须存储在某个地方,您不能随意分配它。通常,初始化列表在.text
/ .rodata
中。然后,编译器可以通过将feature_set
(而不是堆栈)放置在.data
中来优化初始化,以更快地进行初始化。
无论如何,您可以改为这样做:
static const uint32_t FEATURE_SET [][2] =
{
{feature0, 1},
{feature1, 0},
{feature2, 0}
};
现在,应将阵列放入闪存(.rodata
或类似的存储器)中,否则链接器设置中的某些内容会混乱。
然后在堆栈上需要可修改的运行时版本:
uint32_t feature_set [ sizeof(FEATURE_SET) / sizeof(*FEATURE_SET) ] [2];
memcpy(feature_set, FEATURE_SET, sizeof feature_set);
还要确保不要使用任何怪异的RAM调试版本,而无论调试还是发布版本,都应始终将程序下载到闪存中。