I'm currently trying to understand how bootloaders work and wanted to create a small example for this. My first step was to just re-locate my application code into a different area of the FLASH for my STM32F072RB Nucleo board. But here I already encountered the first problems.
Mainly I currently don't understand what the ENTRY() command inside ST's Linker Script is doing.
But lets start from the top.
What I know so far is the following:
- When powering up the MCU will fetch the Stack starting address from 0x0000 0000 and save it in the MSP
- After this it will execute the instructions located at address 0x0000 0004
- The first address is connected to the beginning of FLASH which is 0x0800 0000
- This means the first instruction that should be executed must be located at 0x0800 0004
- Per default the isr_vector table will be put into 0x0800 0000
- The first entry of the vector table is the stack starting address and the second one the needed Reset_Handler
- Thus the Reset_Handler is located at address 0x8000 0004 and will be executed after power-up
Now I want to move my whole application a bit further into the FLASH memory. So I set the Origin of my FLASH 2KB away to the address 0x0800 0800. Now my vector table will be located at this address and thus the Reset_Handler will be at 0x0800 0804.
Of course this will not work because the instruction pointer will start at 0x0800 0004 and will find nothing there.
Then I noticed the ENTRY(Reset_Handler) command and read the documentation that states: "The linker command language includes a command specifically for defining the first executable instruction in an output file (its entry point)"
So I thought that this command will instruct the linker to somehow make it so, that the Reset_Handler is called regardless of where its located in memory. But it seems that this is not the case as my program is not executing at all, which leaves me wondering, what is the actual purpose of this command?
And furthermore, is there a way to solve this without writing a custom method that performs a jump to the Reset_Handler and must somehow be located at 0x0800 0004? So basically is there a way to instruct the MCU to not jump from 0x0000 0000 -> 0x0800 0000 but to 0x0800 0800 by just adjusting the Linker Script?
Here is my slightly adjusted Linker Script:
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 16K
FLASH (rx) : ORIGIN = 0x8000800, LENGTH = 126K /*Adjusted be me!*/
}
/* Define output sections */
SECTIONS
{
/* The startup code goes first into FLASH */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
*(.eh_frame)
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* define a global symbols at end of code */
} >FLASH
I attached a picture to try and make it more clear.
Thanks in advance :)