Keil uVision Startup File: Startup Assembly code - Bare Minimum
-Aviral Mittal
Connect @


This web page explains the 'startup.s' file:
'startup.s' file is a assembly file used in almost all embedded C projects with the Keil uVision IDE.
This is where the user will define mandatory things, without which any C program which the user writes wont compile.
Here is an example of bare-minimum startup.s file that is necessary to start writing any c-code.
It must
1. Declare a Stack Pointer
2. Declare a Reset_Handler routine.
3. Define minimum 'Vectors'
The ARM cortex M processors starts its execution from memory location 0x0000_0000. It is certainly the case with Cortex-M3 and Cortex-M4.
However the 32 bit values stored at the location 0x0000_0000 and at 0x0000_0004 have a bit of special meaning.
The value stored at 0x0000_0000 is treated as the value to which the stack pointer will be initialized to
The value stored at 0x0000_0004 is treated as a jump location, where the processor will jump to after initializing its stack pointer.
At this jump location the user is expected to write their 'Reset_Handler' code. It can be very simple as shown in the following code.

  1 Stack_Size EQU 0x00000400
  3 __stack_limit
  4 Stack_Mem       SPACE Stack_Size
  5 __initial_sp
  7 ; Vector Table Mapped to Address 0 at Reset
  9  EXPORT __Vectors
 10  EXPORT __Vectors_End
 11  EXPORT __Vectors_Size
 12 __Vectors DCD __initial_sp ; Top of Stack
 13           DCD Reset_Handler ; Reset Handler
 15 __Vectors_End
 17 __Vectors_Size EQU __Vectors_End - __Vectors
 18                 AREA |.text|, CODE, READONLY
 19 Reset_Handler   PROC
 20                                 EXPORT Reset_Handler [Weak]
 21                                 IMPORT __main
 22                                 LDR R0, =__main
 23                                 BX  R0
 24                                 ENDP
 25                 EXPORT   __stack_limit
 26                 EXPORT   __initial_sp
 28                                 END

The line number 1. the user is declaring size of the stack. The word 'Stack_Size' is a key word, and 'EQU' is a assembler directive. EQU directive gives a symbolic name to a numeric constant. This line effectively describes the label 'Stack_Size' having a numeric value of 0x400.
What exactly 'Stack_Size' is, is still a mystery. It is being referred to as a 'Key Word' here. But it may be a 'Macro', or it may just be a pre-defined symbol or a label which is already know to the compiler. 'Pre-Defined label'  looks like the most suitable explanation for it.

The line number 2. The user defines the characteristics of the 'STACK' memory area using the 'AREA' compiler directive.
The 'AREA' directive is followed by user given 'section name'. In this line, the section name is 'STACK'. NOINIT is an 'attribute' means that this section is uninitialized or initialized to zero. READWRITE is an 'attribute' which means this area has read/write permissions.

The line number 3. It has label __stack_limit: This will automatically take an address where the stack finishes. i.e the lower limit of the stack address.
The line number 4. It has a key word 'Stack_Mem' followed by another assembler directive called 'SPACE'. This defines a region of the size of  'Stack_Size' i.e. 0x400 in this case initialized to zero. The 'SPACE' directive always reserves an area in the memory initialized to zero.

The line number 5. It just has a label/Symbol called __initial_sp. Not sure if this is also a keyword, but the label __initial_sp will now get a value of the start of the stack pointer.

Line 9,10,11 are simple, they are all trying to make the symbol labels __Vectors, __Vectors_End and __Vectors_Size visible outside this code, may be to the linker, using 'EXPORT' directive. 'EXPORT' directive declares a symbol that the linker uses to resolve symbol references anywhere in the code. 'GLOBAL' is same as 'EXPORT'
Line 11 declares a label called '__Vectors, then the directive DCD is used. DCD directive is used to store in memory location pointed to by the label '__Vectors', the value of the memory location pointed to by the label '__initial_sp.

Line 12, similarly stores the next memory location by the memory location pointed to by the label 'Reset_Handler'
Line 15. Label '__Vectors_End is declared.
Line 17. __Vectors_Size is declared which is assigned an numeric value using EQU. This numeric value is the difference between the memory address pointed to by the label __Vectors_End and __Vectors

Line 18. This defines another 'AREA' directive. This time the name of the area is '.text' it is enclosed in bars like this '|.text|' because it is starting from a special character i.e. the dot. An attribute 'CODE' is also added to it, indicating that this area contains executable code. That is to say it isnt data. The use of '.text' with the code area is conventional practice. The compiler puts this label on code areas it produce. User can look at the assembly code and see '.text' label just above several code sections.

        0x00000088:    4800        .H      LDR      r0,[pc,#0] ; [0x8c] = 0x9
        0x0000008a:    4700        .G      BX       r0

Line 19. It declares a 'PROC' called Reset_Handler. PROC is a short of procedure. The 'Reset_Handler' is mandatory for a start-up file as this defines what happens when the processor is first out of reset. This is the first thing an ARM cortex M3/M4 will execute straight out of reset.Well, actually the first thing that the processor would do is the stack-pointer loading form the address 0000_0000, but technically loading the stack-pointer register isn't 'executing' so its correct to say that the first thing that the ARM processor executes out of reset is the 'Reset_Handler', a pointer to which is stored in the program code at 0x0000_0004.
Line 20-Line24 'PROC' Reset_Handler Code.
The word 'Reset_Handler' is not a keyword. But by default Keil compiler looks for it. The user can change it by using their own name for it, e.g. 'MyReset_Handler'. But then the user must update the Linker command's '--entry' option, which defaults to '--entry Reset_Handler'.
The user may want to use a numeric value with '--entry' option e.g. '--entry=0x0', instead of symbol like 'Reset_Handler'

The 'Reset_Handler' in the above code does nothing but jumps to predefined function called '__main'. Note that this '__main' function is different from the user defined 'main()' function in c-code.

Note that there is no mention of 'Heap' in the above start-up file. As indicated, its just a bare-minimum start-up file. Heap definition is required when memory allocation (malloc etc) is used in the C-programs.


Decoding Keil Startup File
Kiel uVision assembly startup file
Bare-Minimum Assembly code for Keil uVision
Startup assembly code for ARM cortex-m processors.
Explaining the Keil Startup assembly code.
Keil Startup File explanation.
Decoding startup assembly file for arm cortex m series processors.