I try to make some example for stm32f334 (just led blink). I had a problem with the linker when I want to constrain using .data section (by use initialized global variable) I got a problem. Global variable got incorrect value!
This is my code:
startup.s
:
.global _start
.thumb_func
_start:
.word 0x20003000
.word reset
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.word hang
.thumb_func
reset:
bl main
b hang
.thumb_func
hang: b .
blink.c
:
#define RCCBASE 0x40021000
#define GPIOBBASE 0x48000400
static int wymuszenie_bss;
int wymuszenie_data = GPIOBBASE;
int main ( void )
{
unsigned int* ptr;
wymuszenie_bss = 0x40021000;
ptr = (unsigned int*)(wymuszenie_bss+0x14);
*ptr |= 1<<18; //enable port B;
//moder
ptr = (unsigned int*)(wymuszenie_data+0x00);
*ptr &= ~(3<<24); //PB12
*ptr |= 1<<24; //PB12
//OTYPER
ptr = (unsigned int*)(wymuszenie_data+0x04);
*ptr &= ~(1<<6); //PB12
//ospeedr
ptr = (unsigned int*)(GPIOBBASE+0x08);
*ptr |= ~(3<<24); //PB12
//pupdr
ptr = (unsigned int*)(GPIOBBASE+0x0C);
*ptr &= ~(3<<24); //PB12
while(1)
{
ptr = (unsigned int*)(GPIOBBASE+0x18);
*ptr = (1<<12)<<0;
for(int ra=0;ra<400000;ra++) asm("NOP");;
ptr = (unsigned int*)(GPIOBBASE+0x18);
*ptr = (1<<12)<<16;
for(int ra=0;ra<400000;ra++) asm("NOP");;
}
return(0);
}
linker script:
MEMORY
{
flash : ORIGIN = 0x08000000, LENGTH = 0x1000
SRAM : ORIGIN = 0x20000000, LENGTH = 12K
}
SECTIONS
{
.text :
{
__text_start__ = .;
*(.text)
startup.o (.text);
blink.o (.text);
__text_end__ = .;
} > flash
.data :
{
__data_start__ = .;
KEEP (*(.data))
KEEP (*(.data*))
__data_end__ = .;
} > SRAM AT > flash
.bss :
{
__bss_start__ = .;
*(.bss)
__bss_end__ = .;
} > SRAM
}
makefile
:
ARMGNU = arm-none-eabi
gcc : blink.bin
all : gcc
clean:
rm -f *.bin
rm -f *.o
rm -f *.elf
rm -f *.list
rm -f *.bc
rm -f *.opt.s
rm -f *.norm.s
rm -f *.nm
startup.o : startup.s
$(ARMGNU)-as --warn --fatal-warnings -mcpu=cortex-m4 startup.s -o startup.o
blink.o : blink.c
$(ARMGNU)-gcc -Wall -Wint-to-pointer-cast -g -c -march=armv7e-m -mfloat-abi=hard -mfpu=fpv4-sp-d16 -c blink.c -o blink.o
blink.bin : startup.o blink.o
$(ARMGNU)-ld -o blink.elf -T startup.ld startup.o blink.o
$(ARMGNU)-objdump -D blink.elf > blink.list
$(ARMGNU)-nm blink.elf > blink.nm
$(ARMGNU)-objcopy blink.elf blink.bin -O binary
on the .list I see correct value and adress:
Disassembly of section .data:
20000000 <wymuszenie_data>:
20000000: 48000400 stmdami r0, {sl}
Disassembly of section .bss:
20000004 <__bss_start__>:
20000004: 00000000 andeq r0, r0, r0
but when I debug code value of variable "wymuszenie_data" is corrupted (0x2e006816).
I really don't know why there is incorrect global variable value.
Best regards, Marcin
This line
tells the linker that sections in the preceding block should be linked as if they were placed in RAM, but actually put to a different address in flash. The code looks for the data in RAM, but it's not there yet. You should arrange it to be copied before calling
main()
. As it is a bare metal embedded platform, there is no operating system loader to perform this task.First, create a symbol with the destination address in the linker script.
then copy
(&__data_end__ - &__data_start__)
bytes from&__data_start__
to&__data_destination__
before callingmain()
.You should as well clear
.bss
, i.e. fill it with zeroes to avoid the next surprise.If you are linking with a C library, you can use
memcpy()
andmemset()
, otherwise you must write you own code in C or assembly.