数组和结构体可以以不同的方式初始化吗?

Gui*_*e D 5 c embedded storage linker-scripts riscv

我的问题可能看起来很奇怪,事实上,这是上下文:

我目前面临一个奇怪的问题,同时切换 -在我正在从事的项目上- 从pullinino到CV32的核心(也发生了一些其他变化,例如关于crt0,如一些数据RAM重置)。

这是一个(真实的)示例,说明了一个相当简单的 main 所发生的情况(我无法对startup/crt0 文件进行编辑:我在帖子后面部分给出了它)。

#include <string.h>
#include <inttypes.h>
#include <stdio.h>

typedef struct
{
    uintptr_t addr;
    uint32_t foo;  
} some_struct_t;

static uint32_t text_in_data[8] = {0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555, 0x66666666, 0x77777777, 0x88888888};
uint32_t text_in_data2[8] = {0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555, 0x66666666, 0x77777777, 0x88888888};

some_struct_t text_in = {(uintptr_t)text_in_data, 8};
static some_struct_t text_in2 = {(uintptr_t)text_in_data, 8};

int main(void)
{
    some_struct_t text_in3 = {(uintptr_t)text_in_data, 8};
    static some_struct_t text_in4 = {(uintptr_t)text_in_data, 8};
    static some_struct_t text_in5 = {(uintptr_t)text_in_data2, 8};

    printf("text_in_data[]: ");
    for (uint8_t i=0;i<8;i++)
    {
        printf("0x%08x, ",(unsigned int)text_in_data[i]);
    }
    printf("\n");
    printf("text_in_data2[]: ");
    for (uint8_t i=0;i<8;i++)
    {
        printf("0x%08x, ",(unsigned int)text_in_data2[i]);
    }
    printf("\n");
    printf("text_in1.addr 0x%08x -- @text_in_data 0x%08x\n",(unsigned int)text_in.addr,(unsigned int)text_in_data);
    printf("text_in2.addr 0x%08x -- @text_in_data 0x%08x\n",(unsigned int)text_in2.addr,(unsigned int)text_in_data);
    printf("text_in3.addr 0x%08x -- @text_in_data 0x%08x\n",(unsigned int)text_in3.addr,(unsigned int)text_in_data);
    printf("text_in4.addr 0x%08x -- @text_in_data 0x%08x\n",(unsigned int)text_in4.addr,(unsigned int)text_in_data);
    printf("text_in_data2.addr 0x%08x -- @text_in_data2 0x%08x\n",(unsigned int)text_in5.addr,(unsigned int)text_in_data2);

    text_in = (some_struct_t){(uintptr_t)text_in_data, 8};
    text_in2 = (some_struct_t){(uintptr_t)text_in_data, 8};
    text_in3 = (some_struct_t){(uintptr_t)text_in_data, 8};
    text_in4 = (some_struct_t){(uintptr_t)text_in_data, 8};
    text_in5 = (some_struct_t){(uintptr_t)text_in_data2, 8};

    printf("text_in1.addr 0x%08x -- @text_in_data 0x%08x\n",(unsigned int)text_in.addr,(unsigned int)text_in_data);
    printf("text_in2.addr 0x%08x -- @text_in_data 0x%08x\n",(unsigned int)text_in2.addr,(unsigned int)text_in_data);
    printf("text_in3.addr 0x%08x -- @text_in_data 0x%08x\n",(unsigned int)text_in3.addr,(unsigned int)text_in_data);
    printf("text_in4.addr 0x%08x -- @text_in_data 0x%08x\n",(unsigned int)text_in4.addr,(unsigned int)text_in_data);
    printf("text_in_data2.addr 0x%08x -- @text_in_data2 0x%08x\n",(unsigned int)text_in5.addr,(unsigned int)text_in_data2);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

给出

text_in_data[]: 0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555, 0x66666666, 0x77777777, 0x88888888, 
text_in_data2[]: 0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555, 0x66666666, 0x77777777, 0x88888888, 
text_in1.addr 0x00000000 -- @text_in_data 0x00140478
text_in2.addr 0x00000000 -- @text_in_data 0x00140478
text_in3.addr 0x00140478 -- @text_in_data 0x00140478
text_in4.addr 0x00000000 -- @text_in_data 0x00140478
text_in_data2.addr 0x00000000 -- @text_in_data2 0x00140498
text_in1.addr 0x00140478 -- @text_in_data 0x00140478
text_in2.addr 0x00140478 -- @text_in_data 0x00140478
text_in3.addr 0x00140478 -- @text_in_data 0x00140478
text_in4.addr 0x00140478 -- @text_in_data 0x00140478
text_in_data2.addr 0x00140498 -- @text_in_data2 0x00140498
Run Code Online (Sandbox Code Playgroud)

第一个问题是,text_in<x>.addr当使用静态存储定义时,它们不会被初始化,但本地定义会被初始化。

有很多事情可以解释这种行为,例如我们正在重置 crt0 中的数据内存。

编辑:重置不是由于测试固件代码没有发生的数据内存重置所致,已通过帖子后面提供的修复程序进行了纠正

但我无法理解的是,它text_in_data<x>初始化得很好,但text_in<x>事实并非如此。

它们应该共享相同的部分(=以相同的方式存储在相同的位置),不是吗?

它们之间的唯一区别是有些是数组,有些是结构......


我查看了原始的pullino crt0.riscv.S和我们正在使用的版本之间的差异。

没有任何差异可以解释这种行为,但我找到了这个补丁

事实上,最新的 crt0.S包含更多修正

但只要la a0, _edataby替换掉la a0, _bss_start代码片段就可以工作了

但无法真正解释为什么会有这种行为。由于edata在 bss 重置循环中使用,我想我明白最后一个edata未对齐的单词也被重置(在和. = ALIGN(4);之间)_edata_bss_start

但这并不能解释为什么在结构和数组之间修复之前有如此不同的行为......

这是链接器脚本的一部分

    .data : {
        . = ALIGN(4);
        sdata  =  .;
        _sdata  =  .;
        *(.data);
        *(.data.*)
        edata  =  .;
        _edata  =  .;
    } > dataram

    .bss :
    {
        . = ALIGN(4);
        _bss_start = .;
        *(.bss)
        *(.bss.*)
        *(.sbss)
        *(.sbss.*)
        *(COMMON)
        _bss_end = .;
    } > dataram

    /* ensure there is enough room for stack */
    .stack (NOLOAD): {
        . = ALIGN(4);
        . = . + _min_stack ;
        . = ALIGN(4);
        stack = . ;
        _stack = . ;
    } > stack

    .stab  0 (NOLOAD) :
    {
        [ .stab ]
    }

    .stabstr  0 (NOLOAD) :
    {
        [ .stabstr ]
    }

    .bss :
    {
        . = ALIGN(4);
        _end = .;
    } > dataram
Run Code Online (Sandbox Code Playgroud)

执行 a 后riscv32-corev-elf-objdump -d *.elf,两个报告之间的唯一区别是 bss 重置循环开始的地址。但地址更改为0x1405bc(对于工作)和0x14059c(对于不工作)。

0x14059ctext_in是这些二进制文件的地址。


您是否可以解释为什么数组和结构之间存在这种差异以及为什么此补丁纠正了该问题?