静态变量未初始化

时间:2016-05-10 11:21:59

标签: c++ compilation arm

我正在为Raspberry Pi开发一个小内核作为学校项目。我们遇到了静态变量初始化的问题:它们似乎根本没有初始化。我找到了一些相关的主题,但到目前为止还没有人提出解决方案,尽管this帮助我理解了这个问题(至少,我认为)。

可以找到所有代码on this repository,但我会在此处总结相关代码。

从显示问题的项目中提取的代码:(kernel / src / kernel.cpp)

static int staticVal = 42;

void doStuff() { // Prevent the compiler from optimizing the value of staticVal
    staticVal++;
}

__attribute__((section(".init")))
int main(void) {
    //...
    gpio::blinkValue(staticVal); // Displays the value through LEDs
    //...
}

然后使用(例如)

编译代码
arm-none-eabi-g++ -O2 -std=c++11 -mfpu=vfp -mfloat-abi=hard -march=armv6zk -mtune=arm1176jzf-s -nostartfiles -Wall -Wextra -pedantic -I src/ -I uspi/include -DHW_PI_1B -c src/[file].cpp -o _build/[file].o

并使用相同的选项内置到二进制文件中,最后使用

组装成kernel.img
arm-none-eabi-ld --no-undefined _build/master.bin -Map _build/kernel.map -o _build/output.elf -T kernel.ld
arm-none-eabi-objcopy _build/output.elf -O binary kernel.img

(您可以直接阅读Makefile以获取更多详细信息:github.com/tobast/sysres-pikern/blob/staticNotWorking/kernel/Makefile)。

使用的链接器脚本也可能是问题,因为我们试图弄清楚如何在不知道我们在做什么的情况下编写工作脚本(我们使用来自另一个项目的修改过的链接描述文件): github.com/tobast/sysres-pikern/blob/staticNotWorking/kernel/kernel.ld

_start = 0x8000;
ENTRY(_start)

SECTIONS {
    .init 0x8000 : {
        *(.init)
    }

    .text : {
        *(.text)
    }

    .data : {
        *(.data)
    }

    .bss : {
        *(.bss)
    }
}

以这种方式生成的程序显示一个明显随机的值(无论如何,它与预期值无关 - 42)。

到目前为止我所理解的是操作系统应该负责在实际启动程序之前初始化静态变量,但是当我们编写操作系统时,没有人为我们这样做。当然,我们可以手动初始化这些变量(通过为此目的调用启动函数),但这将是一个丑陋而痛苦的解决方案......

我们缺少任何g ++ / linker选项,或者我们的链接描述文件中存在问题吗?

谢谢!

2 个答案:

答案 0 :(得分:2)

我看到了几个问题:

  • 您的部分不是页面对齐的,即链接描述文件中的ALIGN(0x1000)

  • 你没有"启动" ASM脚本,用于设置堆栈并将bss部分归零。

我不知道这样的脚本在ARM上会是什么样子(我已经习惯了x86),但这里有一个例子:

        .section "vectors"
reset:  b     start
undef:  b     undef
swi:    b     swi
pabt:   b     pabt
dabt:   b     dabt
        nop
irq:    b     irq
fiq:    b     fiq

        .text
start:
        @@ Copy data to RAM.
        ldr   r0, =flash_sdata
        ldr   r1, =ram_sdata
        ldr   r2, =data_size

        @@ Handle data_size == 0
        cmp   r2, #0
        beq   init_bss
copy:
        ldrb   r4, [r0], #1
        strb   r4, [r1], #1
        subs   r2, r2, #1
        bne    copy

init_bss:
        @@ Initialize .bss
        ldr   r0, =sbss
        ldr   r1, =ebss
        ldr   r2, =bss_size

        @@ Handle bss_size == 0
        cmp   r2, #0
        beq   init_stack

        mov   r4, #0
zero:
        strb  r4, [r0], #1
        subs  r2, r2, #1
        bne   zero

init_stack:
        @@ Initialize the stack pointer
        ldr   sp, =0xA4000000

        bl    main

stop:   b     stop

当然,您需要修改它以匹配内核的语义。

答案 1 :(得分:1)

您当前可能还会遇到.bss部分也未清除。在main启动之前,你应该有一个特殊的精心设计(汇编程序)块,用rom中的初始数据初始化运行时数据,清除bss并设置堆栈指针。

当您使用libc(以及像Keil这样的嵌入式编译器,只是在使用他们的IDE时隐藏此过程)时,这个启动blob通常会到位。

如果不使用libc,那么应该有一些名为crt * .o的文件可以与编译器一起使用(并且你可能需要在链接器脚本中提供一些更多的细节,以获得内存实际存在的目标地址会等等)