The startup files for STM32 Cortex-M MCU's, for most GCC toolchains, often bundle the Atollic TrueStudio startup assembly files with HAL libraries, like for example in my case, STM32CubeF4.
I'm looking at startup_stm32f407xx.s, and it starts with a section looking as follows
.syntax unified
.cpu cortex-m4
.fpu softvfp
.thumb
I want to rewrite the assembler startup script to C, as part of learning the Cortex-M startup process.
When compiling with the GCC ARM Toolchain, or perhaps any other GCC based toolchain, does that mean I have to transfer these arguments, found in the assembly startup file, to command line arguments for arm-none-eabi-gcc:
arm-none-eabi-gcc -mcpu=cortex-m4 --mfpu=softvfp --mthumbz ...
Do these assembler lines correlate to the respective GCC arguments, or are they used for something entirely different?
Best Answer
This page gives a nice overview over the "special" assembler directives of the GNU ARM assembler.
As you suspected, these directives are basically used in the way of the compiler switches and should have their representation when compiling the sources.
The ones used:
.syntax [unified | divided]
: This directive sets the Instruction Set Syntax as described in the ARM-Instruction-Set section. (unified: ARM and THUMB use the same syntax).cpu cortex-m4
: Select the target processor. Valid values for name are the same as for the -mcpu commandline option. Specifying .cpu clears any previously selected architecture extensions..fpu softvfp
: Select the floating-point unit to assemble for. Valid values for name are the same as for the -mfpu commandline option.thumb
: This performs the same action as .code 16..code 16
: This directive selects the instruction set being generated. The value 16 selects Thumb, with the value 32 selecting ARM.Some, if not all, of them can also be configured via the command-line interface. I'd guess that they included it in the assembly file to make sure, that it gets assembled exactly the way it was thought to be. The inline directives take a higher priority as the command line switches.
As for the description of the start-up process, don't know if you actually asked this, but I felt like writing it:
From a hardware point of view it is a thing of the core and is described in the ARMv7-M Architecture Reference Manual (available upon registration). In section B1.5.5 the reset behaviour is explained.
The steps you have to take to implement the startup behaviour in software is dependent on the compiler and linker you use, so a general solution will probably not exist.
It usually consists of creating a reset and vector table structure and filling it with the right values. The stackpointer is the first value, it has to be initialized with the RAM address where your stack will reside. This value is usually defined in the linker control file as exported symbol. The next value is the address of your startup code, so you just put the function pointer to
c_startup()
or whatever there.What follows is a long list of function pointers pointing to the individual interrupt service handlers. You have to take care, that you don't skip positions in the table just because the ISR is not implemented. Initialize those values either with
0
(things can go wrong) or with a "not-implemented handler" consisting of awhile(true)
(safe way).After that you have to fill the
c_startup()
with life, which depends on the compiler. Typical things to do are: initializing RAM with global values, initialize the FPU is, calling constructors of static objects and finally jumping tomain()
.As a last step you have to tell the linker that it places your newly created super-structure to the very beginning of the vector table (usually the first address of the flash, but this might vary depending on how the vector is fetched in the device).