1.3. Startup Code


1. Introduction

This tutorial addresses something called the startup code (a.k.a. bootstrap). The startup code is the code that is executed by the MCU before main() function is called.
This code is implemented in the very first function being executed which is the reset handler function. Moreover, it should be strongly associated with the linker script for some reasons we will discuss.
To illustrate the topic, let us reuse our first blink project. Since we’ve changed it for the debugger lab, you can just copy/paste the code below to retrieve the original version. Actually, what main() is doing doesn’t really matters in this lab.
 

/*
 * main.c
 */

#define PERIOD	100000

static void 	reset_handler 		(void);
static void 	default_handler		(void);
int 		main 			(void);

/* Minimal vector table */
__attribute__ ((section(".isr_vector")))
void (* const table_interrupt_vector[])(void) =
{
	(void *)0x20000800, 	// 0 - stack
	reset_handler, 	 	// 1 - reset handler
	default_handler, 	// 2 - NMI handler
	default_handler, 	// 3 - Hardfault handler
};

/* Main program */
int main(void)
{
	int i;

	*(int *)0x40021014 |=  (0x01 <<17U);
	*(int *)0x48000000 &= ~(0xC00);
	*(int *)0x48000000 |=  (0x01 <<10U);

	while(1)
	{
	    *(int *)0x48000014 ^= 0x00000020U;
	    for (i=0; i<PERIOD; i++);
	}
}

/* Reset handler */
void reset_handler (void)
{
   main();
}

/* Default handler */
void default_handler(void)
{
   for(;;);
}

 

Make sure the project folder only shows main.c and linkerscript.ld (apart from compiler includes and post-bluid folders) :

 

2. Meaning of object file ‘Size’

 

Click the rebuild button image010.png

The console reports build information and the output of GNU ARM Cross Print Size function.

09:34:15 **** Rebuild of configuration Debug for project blink ****
Info: Internal Builder is used for build
arm-atollic-eabi-gcc -c ..\main.c -mthumb -mcpu=cortex-m0 -std=gnu11 -O0 -g -fstack-usage -Wall -specs=nano.specs -o main.o 
arm-atollic-eabi-gcc -o blink.elf main.o -mthumb -mcpu=cortex-m0 -TC:\Atollic\tuto_workspace\blink\linkerscript.ld -specs=nosys.specs -static -Wl,-cref,-u,Reset_Handler -Wl,-Map=blink.map -Wl,--defsym=malloc_getpagesize_P=0x80 -Wl,--start-group -lc -lm -Wl,--end-group -specs=nano.specs 
C:\Atollic\TrueSTUDIO for STM32 9.3.0\ide\jre\bin\java -jar C:\Atollic\TrueSTUDIO for STM32 9.3.0\Tools\arm-atollic-reports.jar sizeinfo list blink.elf 
Generate build reports...
Print size information
   text	   data	    bss	    dec	    hex	filename
    244	     12	     28	    284	    11c	blink.elf
Print size information done
Generate listing file
Output sent to: blink.list
Generate listing file done
Generate build reports done

09:34:15 Build Finished (took 595ms)

What’s the meaning of these reported sizes?

Let start with general definitions:

  • text → Refers to the application code size (bytes). It is stored in the FLASH memory
  • bss → Refers to ‘uninitialized variables’. Those variables have reserved locations in RAM memory
  • data → Refers to ‘initialized variables’. Those variables have reserved location in RAM memory and their initial value is stored in the FLASH memory. In short, an initialized variable occupies 2x its own size (one in RAM, one in FLASH).

Take a look at the Build Analyzer window (bottom part of the IDE):

It reports that 40B (bytes) are used in RAM for variables storage. That corresponds to data (12 bytes) + bss(28 bytes). You can further explore the RAM region by opening the Memory Details tab:

 

First observation: Our code has only one 32-bit variable i, and it is reported nowhere, neither in the bss nor in the data section. Why is that?

This is because i is local to the main() function. RAM space, for variables that are defined inside functions, is dynamically allocated at runtime, into a segment of available RAM called the stack. The physical RAM is temporarily associated to local variables and then cleaned up (freed) when the function exits, making it available for other variables of other functions. These variables, and associated RAM requirements are therefore NOT reported into the size of the object file. This is an important issue with projects requiring large amount of RAM (e.g. to store big arrays) with no clue of that in the build report when declared locally.

The object file only includes variables with statically allocated memory. That means:

  • Global variables
  • Static variables within functions

Let us experiment this!

 

3. Experiment on size and variables initialization

Let us add a global 32-bit integer variable count, we could use for instance as a blink counter:
 

/*
 * main.c
 */

#define PERIOD	100000

static void 	reset_handler 		(void);
static void 	default_handler		(void);
int 		main 			(void);

/* Global variable */
int count;

/* Minimal vector table */
__attribute__ ((section(".isr_vector")))
void (* const table_interrupt_vector[])(void) =
{
	(void *)0x20000800, 	// 0 - stack
	reset_handler, 	 	// 1 - reset handler
	default_handler, 	// 2 - NMI handler
	default_handler, 	// 3 - Hardfault handler
};

/* Main program */
int main(void)
{
	int i;

	*(int *)0x40021014 |=  (0x01 <<17U);
	*(int *)0x48000000 &= ~(0xC00);
	*(int *)0x48000000 |=  (0x01 <<10U);

	while(1)
	{
		*(int *)0x48000014 ^= 0x00000020U;
		for (i=0; i<PERIOD; i++);
		
		count++;
	}
}

/* Reset handler */
void reset_handler (void)
{
	main();
}

/* Default handler */
void default_handler(void)
{
	for(;;);
}

 

Save main.c and build image010.png the project:

Generate build reports...
Print size information
   text	   data	    bss	    dec	    hex	filename
    256	     12	     32	    300	    12c	blink.elf
Print size information done

Note that code (text) size inflates by 12 bytes (addition of count++ instruction) and we have an additionnal 4 bytes (28→32) of bss uninitialized variable (in RAM) allocated for count global variable. Take a look in the Memory Details:

 

Start the debugger  and note the initial values of both i and count variables:

image029.png
 

As you may expect from uninitialized variables, the value of both count and i are something random…

Well, if you look at C99 standard section 6.7.8 Initialization, you’ll find this:

“If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate.

If an object that has static storage duration is not initialized explicitly, then:

  • if it has pointer type, it is initialized to a null pointer;
  • if it has arithmetic type, it is initialized to (positive or unsigned) zero;
  • if it is an aggregate, every member is initialized (recursively) according to these rules;
  • if it is a union, the first named member is initialized (recursively) according to these rules"

 

This means that according to C99 standard, a global variable that is not explicitly initialized should be initialized to zero somewhere. It is obviously not the case here. Therefore, our code is not C99 compliant… That’s dangerous…

Let us try to explicitly initialize count now:

int		count = 0;

If what’s before is true, the allocated 4 bytes should move from the bss to the data section, now that count is initialized.

Save main.c and build  the project:

Generate build reports...
Print size information
   text	   data	    bss	    dec	    hex	filename
    256	     12	     32	    300	    12c	blink.elf
Print size information done

count still appears in the bss section… Strange…

At least, let see if it is well initialized. Launch the debugger…

image029.png
 
It is not initialized!

Let’s try this:

int		count = 5;

 

Save main.c and build  the project:

Generate build reports...
Print size information
   text	   data	    bss	    dec	    hex	filename
    256	     16	     28	    300	    12c	blink.elf
Print size information done

 
OK! 4 bytes have been shifted from bss to data section. So, if the initialization value is not 0, then the variable appears in the ‘initialized’ data variable section, at last!

As it was mentionned before, now that count is initialized to a non-zero value, you'll notice that count occupies 4 bytes in RAM (for the variable itself) and also 4 bytes in FLASH (to store the initial value, which is 5 here).

 

Well, let make sure it is indeed initialized to 5.
Start the debugger…

image029.png

Still not correctly initialized! It seems that nothing can be done here to get something correctly initialized...

 

Let’s now try to declare i as a static variable:

/* Main program */
int main(void)
{
	static int i;

	*(int *)0x40021014 |=  (0x01 <<17U);
	*(int *)0x48000000 &= ~(0xC00);
	*(int *)0x48000000 |=  (0x01 <<10U);

	while(1)
	{
		*(int *)0x48000014 ^= 0x00000020U;
		for (i=0; i<PERIOD; i++);

		count++;
	}
}

 

Save main.c and build  the project:

Generate build reports...
Print size information
   text	   data	    bss	    dec	    hex	filename
    268	     16	     32	    316	    13c	blink.elf
Print size information done

Note that bss section gained 4 bytes compared to the previous build. We have now 4 bytes for ‘initialized’ data variables (count) and 4 bytes again for ‘uninitialized’ bss variables (i). That makes sense.

Debugger…

image037.png

The ‘random’ value of i has changed. It is likely that the physical RAM location associated to the variable i has changed. That’s understandable since i is no more stored on the stack. But count is still not initialized…

 

Another attempt:

/* Main program */
int main(void)
{
	static int i = 10;

	*(int *)0x40021014 |=  (0x01 <<17U);
	*(int *)0x48000000 &= ~(0xC00);
	*(int *)0x48000000 |=  (0x01 <<10U);

	while(1)
	{
		*(int *)0x48000014 ^= 0x00000020U;
		for (i=0; i<PERIOD; i++);

		count++;
	}
}

 

Save main.c and build  the project:

Generate build reports...
Print size information
   text	   data	    bss	    dec	    hex	filename
    268	     20	     28	    316	    13c	blink.elf
Print size information done

Well, both i and count are now part of the data section as expected since we have explicit initialization.
Debugger…

image037.png

But neither are effectively initialized…

One last attempt. Set i as a regular local variable again, but add an initialization value:

/* Main program */
int main(void)
{
	int i = 10;

	*(int *)0x40021014 |=  (0x01 <<17U);
	*(int *)0x48000000 &= ~(0xC00);
	*(int *)0x48000000 |=  (0x01 <<10U);

	while(1)
	{
		*(int *)0x48000014 ^= 0x00000020U;
		for (i=0; i<PERIOD; i++);

		count++;
	}
}

 
Save main.c and build  the project:

Generate build reports...
Print size information
   text	   data	    bss	    dec	    hex	filename
    260	     16	     28	    304	    130	blink.elf
Print size information done

 
As expected, i has disappeared from both data and bss section, but the code is bigger by 4 bytes than the same one with no i initialization.

Debugger…

image042.png

count is not initialized (we’re getting accustomed to this, now…)

i is neither initialized, but looking closer into the very first assembly code of main() function we find this:

image043.png

These are the two machine cycles that set i to 10 (producing four additional bytes in the text section).

In conclusion, it would have been the same to write:

	int i;
	i = 10;

For now, you can remember that initializing a local variable at declaration is strictly the same as setting the variable apart from the declaration. This is not the same for global and static variables since no code is produced in this case. Static and global variables initialization must therefore rely on another process that is not working in our example.

 

4. Debrief

Initialization of global or static variables is neither automatic nor magic. It has to be done by the CPU before main(). And a CPU does only what he is told to…
In other words, you must write a startup code that performs initialization!
This is usually something done within the reset handler function. In our example, the reset handler is nothing more than a call to main(). That’s the reason why we didn’t get any variable initialization.

/* Reset handler */
void reset_handler (void)
{
	main();
}

A well-written startup code must perform the following:

  • Fill the interrupt vector table. The address of the reset handler code being the first one.
  • Implement the reset handler function, which includes:
  • Initialize the stack pointer register. For this, it needs to know where the available RAM starts (after space for global and static variables has been allocated)
  • Copy the initial values of data variables from the FLASH, to the RAM. For this, it needs to know where variables are in RAM, and where initial values are in FLASH
  • Fill with zeros the bss segment in order to reset all the ‘uninitialized’ variables. For this, it needs to know where the bss is in RAM.
  • Call other initialization functions (clock for instance)
  • Call the main function

 

Because it is better to go fast during the initialization, the startup code is often written in assembler.

Note that explicitly initializing a global or static variable to 0 would use space in FLASH to store 0 as initial value. Because all bss variables are initialized to 0 by the startup code, its better doing nothing. That’s the reason why the linker considers that a zero-initialized variable is of bss type. Historically (1950) bss meant “Block Started by Symbol”.

"Some people like to remember it as 'Better Save Space.' Since the BSS segment only holds variables that don't have any value yet, it doesn't actually need to store the image of these variables. The size that BSS will require at runtime is recorded in the object file, but BSS (unlike the data segment) doesn't take up any actual space in the object file." https://en.wikipedia.org/wiki/.bss

 

All the addresses, in both the RAM and the FLASH, required by startup code to perform initializations are provided by the linker script. Well, not OUR linker script, but a well-written one…
In the following, we’re going to use linker scripts and startup code written by professional people… At least, you understand now the reason why.
And everything should work has expected…

 

5. Annex A: startup_stm32f072xb.s

/**
  ******************************************************************************
  * @file      startup_stm32f072xb.s
  * @author    MCD Application Team
  * @brief     STM32F072x8/STM32F072xB devices vector table for Atollic TrueSTUDIO toolchain.
  *            This module performs:
  *                - Set the initial SP
  *                - Set the initial PC == Reset_Handler,
  *                - Set the vector table entries with the exceptions ISR address
  *                - Branches to main in the C library (which eventually
  *                  calls main()).
  *            After Reset the Cortex-M0 processor is in Thread mode,
  *            priority is Privileged, and the Stack is set to Main.
  ******************************************************************************
  * 
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */

  .syntax unified
  .cpu cortex-m0
  .fpu softvfp
  .thumb

.global g_pfnVectors
.global Default_Handler

/* start address for the initialization values of the .data section.
defined in linker script */
.word _sidata
/* start address for the .data section. defined in linker script */
.word _sdata
/* end address for the .data section. defined in linker script */
.word _edata
/* start address for the .bss section. defined in linker script */
.word _sbss
/* end address for the .bss section. defined in linker script */
.word _ebss

  .section .text.Reset_Handler
  .weak Reset_Handler
  .type Reset_Handler, %function

Reset_Handler:
  ldr   r0, =_estack
  mov   sp, r0          /* set stack pointer */


/* Copy the data segment initializers from flash to SRAM */
  movs r1, #0
  b LoopCopyDataInit

CopyDataInit:
  ldr r3, =_sidata
  ldr r3, [r3, r1]
  str r3, [r0, r1]
  adds r1, r1, #4

LoopCopyDataInit:
  ldr r0, =_sdata
  ldr r3, =_edata
  adds r2, r0, r1
  cmp r2, r3
  bcc CopyDataInit
  ldr r2, =_sbss
  b LoopFillZerobss

/* Zero fill the bss segment. */
FillZerobss:
  movs r3, #0
  str  r3, [r2]
  adds r2, r2, #4


LoopFillZerobss:
  ldr r3, = _ebss
  cmp r2, r3
  bcc FillZerobss

/* Call the clock system intitialization function.*/
  bl  SystemInit

/* Call static constructors */
  bl __libc_init_array

/* Call the application's entry point.*/
  bl main

LoopForever:
    b LoopForever


.size Reset_Handler, .-Reset_Handler


/**
 * @brief  This is the code that gets called when the processor receives an
 *         unexpected interrupt.  This simply enters an infinite loop, preserving
 *         the system state for examination by a debugger.
 *
 * @param  None
 * @retval : None
*/
    .section .text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop:
  b Infinite_Loop
  .size Default_Handler, .-Default_Handler

/******************************************************************************
*
* The minimal vector table for a Cortex M0.  Note that the proper constructs
* must be placed on this to ensure that it ends up at physical address
* 0x0000.0000.
*
******************************************************************************/
   .section .isr_vector,"a",%progbits
  .type g_pfnVectors, %object
  .size g_pfnVectors, .-g_pfnVectors


g_pfnVectors:
  .word  _estack
  .word  Reset_Handler
  .word  NMI_Handler
  .word  HardFault_Handler
  .word  0
  .word  0
  .word  0
  .word  0
  .word  0
  .word  0
  .word  0
  .word  SVC_Handler
  .word  0
  .word  0
  .word  PendSV_Handler
  .word  SysTick_Handler
  .word  WWDG_IRQHandler                   /* Window WatchDog              */
  .word  PVD_VDDIO2_IRQHandler             /* PVD and VDDIO2 through EXTI Line detect */
  .word  RTC_IRQHandler                    /* RTC through the EXTI line    */
  .word  FLASH_IRQHandler                  /* FLASH                        */
  .word  RCC_CRS_IRQHandler                /* RCC and CRS                  */
  .word  EXTI0_1_IRQHandler                /* EXTI Line 0 and 1            */
  .word  EXTI2_3_IRQHandler                /* EXTI Line 2 and 3            */
  .word  EXTI4_15_IRQHandler               /* EXTI Line 4 to 15            */
  .word  TSC_IRQHandler                    /* TSC                          */
  .word  DMA1_Channel1_IRQHandler          /* DMA1 Channel 1               */
  .word  DMA1_Channel2_3_IRQHandler        /* DMA1 Channel 2 and Channel 3 */
  .word  DMA1_Channel4_5_6_7_IRQHandler    /* DMA1 Channel 4, Channel 5, Channel 6 and Channel 7*/
  .word  ADC1_COMP_IRQHandler              /* ADC1, COMP1 and COMP2         */
  .word  TIM1_BRK_UP_TRG_COM_IRQHandler    /* TIM1 Break, Update, Trigger and Commutation */
  .word  TIM1_CC_IRQHandler                /* TIM1 Capture Compare         */
  .word  TIM2_IRQHandler                   /* TIM2                         */
  .word  TIM3_IRQHandler                   /* TIM3                         */
  .word  TIM6_DAC_IRQHandler               /* TIM6 and DAC                 */
  .word  TIM7_IRQHandler                   /* TIM7                         */
  .word  TIM14_IRQHandler                  /* TIM14                        */
  .word  TIM15_IRQHandler                  /* TIM15                        */
  .word  TIM16_IRQHandler                  /* TIM16                        */
  .word  TIM17_IRQHandler                  /* TIM17                        */
  .word  I2C1_IRQHandler                   /* I2C1                         */
  .word  I2C2_IRQHandler                   /* I2C2                         */
  .word  SPI1_IRQHandler                   /* SPI1                         */
  .word  SPI2_IRQHandler                   /* SPI2                         */
  .word  USART1_IRQHandler                 /* USART1                       */
  .word  USART2_IRQHandler                 /* USART2                       */
  .word  USART3_4_IRQHandler               /* USART3 and USART4            */
  .word  CEC_CAN_IRQHandler                /* CEC and CAN                  */
  .word  USB_IRQHandler                    /* USB                          */
 
/*******************************************************************************
*
* Provide weak aliases for each Exception handler to the Default_Handler.
* As they are weak aliases, any function with the same name will override
* this definition.
*
*******************************************************************************/

  .weak      NMI_Handler
  .thumb_set NMI_Handler,Default_Handler

  .weak      HardFault_Handler
  .thumb_set HardFault_Handler,Default_Handler

  .weak      SVC_Handler
  .thumb_set SVC_Handler,Default_Handler

  .weak      PendSV_Handler
  .thumb_set PendSV_Handler,Default_Handler

  .weak      SysTick_Handler
  .thumb_set SysTick_Handler,Default_Handler

  .weak      WWDG_IRQHandler
  .thumb_set WWDG_IRQHandler,Default_Handler

  .weak      PVD_VDDIO2_IRQHandler
  .thumb_set PVD_VDDIO2_IRQHandler,Default_Handler

  .weak      RTC_IRQHandler
  .thumb_set RTC_IRQHandler,Default_Handler

  .weak      FLASH_IRQHandler
  .thumb_set FLASH_IRQHandler,Default_Handler

  .weak      RCC_CRS_IRQHandler
  .thumb_set RCC_CRS_IRQHandler,Default_Handler

  .weak      EXTI0_1_IRQHandler
  .thumb_set EXTI0_1_IRQHandler,Default_Handler

  .weak      EXTI2_3_IRQHandler
  .thumb_set EXTI2_3_IRQHandler,Default_Handler

  .weak      EXTI4_15_IRQHandler
  .thumb_set EXTI4_15_IRQHandler,Default_Handler

  .weak      TSC_IRQHandler
  .thumb_set TSC_IRQHandler,Default_Handler

  .weak      DMA1_Channel1_IRQHandler
  .thumb_set DMA1_Channel1_IRQHandler,Default_Handler

  .weak      DMA1_Channel2_3_IRQHandler
  .thumb_set DMA1_Channel2_3_IRQHandler,Default_Handler

  .weak      DMA1_Channel4_5_6_7_IRQHandler
  .thumb_set DMA1_Channel4_5_6_7_IRQHandler,Default_Handler

  .weak      ADC1_COMP_IRQHandler
  .thumb_set ADC1_COMP_IRQHandler,Default_Handler

  .weak      TIM1_BRK_UP_TRG_COM_IRQHandler
  .thumb_set TIM1_BRK_UP_TRG_COM_IRQHandler,Default_Handler

  .weak      TIM1_CC_IRQHandler
  .thumb_set TIM1_CC_IRQHandler,Default_Handler

  .weak      TIM2_IRQHandler
  .thumb_set TIM2_IRQHandler,Default_Handler

  .weak      TIM3_IRQHandler
  .thumb_set TIM3_IRQHandler,Default_Handler

  .weak      TIM6_DAC_IRQHandler
  .thumb_set TIM6_DAC_IRQHandler,Default_Handler

  .weak      TIM7_IRQHandler
  .thumb_set TIM7_IRQHandler,Default_Handler

  .weak      TIM14_IRQHandler
  .thumb_set TIM14_IRQHandler,Default_Handler

  .weak      TIM15_IRQHandler
  .thumb_set TIM15_IRQHandler,Default_Handler

  .weak      TIM16_IRQHandler
  .thumb_set TIM16_IRQHandler,Default_Handler

  .weak      TIM17_IRQHandler
  .thumb_set TIM17_IRQHandler,Default_Handler

  .weak      I2C1_IRQHandler
  .thumb_set I2C1_IRQHandler,Default_Handler

  .weak      I2C2_IRQHandler
  .thumb_set I2C2_IRQHandler,Default_Handler

  .weak      SPI1_IRQHandler
  .thumb_set SPI1_IRQHandler,Default_Handler

  .weak      SPI2_IRQHandler
  .thumb_set SPI2_IRQHandler,Default_Handler

  .weak      USART1_IRQHandler
  .thumb_set USART1_IRQHandler,Default_Handler

  .weak      USART2_IRQHandler
  .thumb_set USART2_IRQHandler,Default_Handler

  .weak      USART3_4_IRQHandler
  .thumb_set USART3_4_IRQHandler,Default_Handler

  .weak      CEC_CAN_IRQHandler
  .thumb_set CEC_CAN_IRQHandler,Default_Handler

  .weak      USB_IRQHandler
  .thumb_set USB_IRQHandler,Default_Handler

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

 

6. Annex B: LinkerScript.ld

/*
*****************************************************************************
**
**  File        : LinkerScript.ld
**
**  Abstract    : Linker script for STM32F072RBTx Device with
**                128KByte FLASH, 16KByte RAM
**
**                Set heap size, stack size and stack location according
**                to application requirements.
**
**                Set memory bank area and size if external memory is used.
**
**  Target      : STMicroelectronics STM32
**
**
**  Distribution: The file is distributed as is, without any warranty
**                of any kind.
**
**  (c)Copyright Ac6.
**  You may use this file as-is or modify it according to the needs of your
**  project. Distribution of this file (unmodified or modified) is not
**  permitted. Ac6 permit registered System Workbench for MCU users the
**  rights to distribute the assembled, compiled & linked contents of this
**  file as part of an application binary file, provided that it is built
**  using the System Workbench for MCU toolchain.
**
*****************************************************************************
*/

/* Entry Point */
ENTRY(Reset_Handler)

/* Highest address of the user mode stack */
_estack = 0x20004000;    /* 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 = 0x8000000, LENGTH = 128K
}

/* 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

  /* Constant data goes into FLASH */
  .rodata :
  {
    . = ALIGN(4);
    *(.rodata)         /* .rodata sections (constants, strings, etc.) */
    *(.rodata*)        /* .rodata* sections (constants, strings, etc.) */
    . = ALIGN(4);
  } >FLASH

  .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
  .ARM : {
    __exidx_start = .;
    *(.ARM.exidx*)
    __exidx_end = .;
  } >FLASH

  .preinit_array     :
  {
    PROVIDE_HIDDEN (__preinit_array_start = .);
    KEEP (*(.preinit_array*))
    PROVIDE_HIDDEN (__preinit_array_end = .);
  } >FLASH
  .init_array :
  {
    PROVIDE_HIDDEN (__init_array_start = .);
    KEEP (*(SORT(.init_array.*)))
    KEEP (*(.init_array*))
    PROVIDE_HIDDEN (__init_array_end = .);
  } >FLASH
  .fini_array :
  {
    PROVIDE_HIDDEN (__fini_array_start = .);
    KEEP (*(SORT(.fini_array.*)))
    KEEP (*(.fini_array*))
    PROVIDE_HIDDEN (__fini_array_end = .);
  } >FLASH

  /* used by the startup to initialize data */
  _sidata = LOADADDR(.data);

  /* Initialized data sections goes into RAM, load LMA copy after code */
  .data : 
  {
    . = ALIGN(4);
    _sdata = .;        /* create a global symbol at data start */
    *(.data)           /* .data sections */
    *(.data*)          /* .data* sections */

    . = ALIGN(4);
    _edata = .;        /* define a global symbol at data end */
  } >RAM AT> FLASH

  
  /* Uninitialized data section */
  . = ALIGN(4);
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss secion */
    _sbss = .;         /* define a global symbol at bss start */
    __bss_start__ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)

    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
    __bss_end__ = _ebss;
  } >RAM
 

  /* User_heap_stack section, used to check that there is enough RAM left */
  ._user_heap_stack :
  {
    . = ALIGN(8);
    PROVIDE ( end = . );
    PROVIDE ( _end = . );
    . = . + _Min_Heap_Size;
    . = . + _Min_Stack_Size;
    . = ALIGN(8);
  } >RAM

  

  /* Remove information from the standard libraries */
  /DISCARD/ :
  {
    libc.a ( * )
    libm.a ( * )
    libgcc.a ( * )
  }

  .ARM.attributes 0 : { *(.ARM.attributes) }
}