I am developping a small kernel for Raspberry Pi as a school project. We are encountering an issue with static variable initialization: it seems that those are not initialized at all. I've found a few related topics, yet none have brought a solution so far, though this helped me understand the issue (at least, I think).
All the code can be found on this repository, but I will try to sum up the related code here.
Code extracted from the project showing the problem: (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
//...
}
The code is then compiled using (eg)
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
and built into a binary file using the same options, and finally assembled into a kernel.img using
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
(you can read the Makefile directly for more details: github.com/tobast/sysres-pikern/blob/staticNotWorking/kernel/Makefile).
The linker script used might as well be the problem, as we have tried to figure out how to write a working one without really knowing what we were doing (we use a modified linker script from another project): github.com/tobast/sysres-pikern/blob/staticNotWorking/kernel/kernel.ld
_start = 0x8000;
ENTRY(_start)
SECTIONS {
.init 0x8000 : {
*(.init)
}
.text : {
*(.text)
}
.data : {
*(.data)
}
.bss : {
*(.bss)
}
}
The program generated this way displays an apparently random value (which has, anyway, nothing to do with the expected value -- 42).
What I've understood so far is that the operating system is supposed to be responsible for initializing static variables before actually starting the program, but as we are writing an operating system, no one is doing it for us. Of course, we could manually initialize those variables (by calling a startup function for this purpose), but it would be an ugly and painful solution...
Is there any g++/linker options we are missing, or a problem in our linker script?
Thanks!
I see a couple of problems:
Your sections are not page aligned, i.e with ALIGN(0x1000)
in the linker script
You have no "start up" ASM script that sets up the stack and zeros the bss
section.
I have no idea how such a script would look like on ARM (I'm used to x86), but here's an example:
.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
Of course you would need to modify this to match the semantics of your kernel.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With