1
0
mirror of https://github.com/rfivet/stm32bringup.git synced 2024-12-21 00:06:22 -05:00
stm32bringup/docs/17_cstartup.html

251 lines
8.3 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>1.7 C Startup</title>
<link type="text/css" rel="stylesheet" href="style.css">
</head>
<body>
<h1>1.7 C Startup</h1>
The C compiler uses a memory model where the RAM is divided into four
contiguous sections. The linker provides the symbols needed to make sure
the initial state meet the requirements of this memory model. So I need
to write a piece of code to use those symbols to initialize or clear the
RAM accordingly.
<pre>
<b>Section</b><b>Description</b>
├─────────┼──────────────────────────────────────────────┤
│ data │ static initialized, initial values in flash │
│ bss │ static unassigned, cleared │
│ heap │ dynamically allocated, user managed │
│ stack │ automatically allocated, stack frame managed │
</pre>
My bootstrap since the first <b>boot.c</b> already initializes the stack. I
need now to copy the initial values from flash to the <b>data</b> section and
clear the <b>bss</b> section.
<p>
You can check your understanding of the C memory model by looking at the
C test code below and figuring where the linker will allocate the
variables.
<pre>
/** Test code: main.c *********************************************************/
const char hexa[] = "0123456789abcdef" ;
long first = 1 ;
long i ;
int main( void) {
static char c = 'a' ;
char *cp = &c ;
*cp += i ;
i += hexa[ 13] - c + first++ ;
return 0 ;
}
</pre>
<ul>
<li> <b>data</b> section holds <code>first</code> and <code>c</code>, for a
total of 8 bytes as sections are word aligned.
</ul><ul>
<li> <b>bss</b> section holds <code>i</code> for a total of 4 bytes.
</ul><ul>
<li> <b>text</b> section holds <code>hexa</code> with all the const data
located after the code. As it is a zero terminated string, it occupies 17 bytes
and is padded with 3 zero for word alignment.
</ul><ul>
<li> <b>text</b> section holds the initial value of <code>first</code> and
<code>c</code> for a total of 8 bytes located after the const data.
</ul><ul>
<li> <b>stack</b> section holds <code>cp</code>, it is dynamically managed by
the code generated by the C compiler.
</ul><ul>
<li> after executing <code>main()</code>, <code>hexa</code> and <code>c</code>
are unchanged, <code>first</code> has the value 2, <code>i</code> has the
value 4 and <code>cp</code> has been deallocated.
</ul>
<h2>Evolving the bootstrap</h2>
First I make a copy of <b>boot.c</b> into <b>cstartup.c</b>.
<p>
I add the symbols defined by the linker script:
<ul>
<li> <code>__etext</code>, start of initial value copy in FLASH.
<li> <code>__data_start</code>, start of initialized data in RAM.
<li> <code>__bss_start</code>, start of unitialized data in RAM, it is the same
location as <code>__data_end</code>.
<li> <code>__bss_end</code>, first location after the bss section.
</ul>
I rework <code>Reset_handler()</code> to:
<ul>
<li> Initialize the <b>data</b> section with the initial values stored in flash.
<li> Clear the <b>bss</b> section
<li> Call the <code>main()</code> C function.
<li> Fallback to idle loop after <code>main()</code> has been executed.
</ul>
Finally I append the test code for validation.
<pre>
/* Memory locations defined by linker script */
extern long __StackTop ; /* &__StackTop points after end of stack */
void Reset_Handler( void) ; /* Entry point for execution */
extern const long __etext[] ; /* start of initialized data copy in flash */
extern long __data_start__[] ;
extern long __bss_start__[] ;
extern long __bss_end__ ; /* &__bss_end__ points after end of bss */
/* Interrupt vector table:
* 1 Stack Pointer reset value
* 15 System Exceptions
* NN Device specific Interrupts
*/
typedef void (*isr_p)( void) ;
isr_p const isr_vector[ 2] __attribute__((section(".isr_vector"))) = {
(isr_p) &__StackTop,
/* System Exceptions */
Reset_Handler
} ;
extern int main( void) ;
void Reset_Handler( void) {
const long *f ; /* from, source constant data from FLASH */
long *t ; /* to, destination in RAM */
/* Assume:
** __bss_start__ == __data_end__
** All sections are 4 bytes aligned
*/
f = __etext ;
for( t = __data_start__ ; t < __bss_start__ ; t += 1)
*t = *f++ ;
while( t < &__bss_end__)
*t++ = 0 ;
main() ;
for( ;;) ;
}
/** Test code: main.c *********************************************************/
const char hexa[] = "0123456789abcdef" ;
long first = 1 ;
long i ;
int main( void) {
static char c = 'a' ;
char *cp = &c ;
*cp += i ;
i += hexa[ 13] - c + first++ ;
return 0 ;
}
</pre>
<h2>Build</h2>
Building a binary, I can see that the <b>data</b> and <b>bss</b> sections are
not empty anymore and their sizes match my estimations.
<pre>
$ make cstartup.bin
cstartup.elf
text data bss dec hex filename
121 8 4 133 85 cstartup.elf
cstartup.bin
rm cstartup.o cstartup.elf
</pre>
If I look further in the <b>cstartup.map</b> generated by the linker.
<pre>
.text 0x08000000 0x79
*(.isr_vector)
.isr_vector 0x08000000 0x8 cstartup.o
0x08000000 isr_vector
*(.text*)
.text 0x08000008 0x34 cstartup.o
0x08000008 Reset_Handler
.text.startup 0x0800003c 0x2c cstartup.o
0x0800003c main
*(.rodata*)
.rodata 0x08000068 0x11 cstartup.o
0x08000068 hexa
.data 0x20000000 0x8 load address 0x0800007c
0x20000000 __data_start__ = .
*(.data*)
.data 0x20000000 0x8 cstartup.o
0x20000004 first
0x20000008 . = ALIGN (0x4)
0x20000008 __data_end__ = .
.bss 0x20000008 0x4 load address 0x08000084
0x20000008 . = ALIGN (0x4)
0x20000008 __bss_start__ = .
*(.bss*)
.bss 0x20000008 0x0 cstartup.o
*(COMMON)
COMMON 0x20000008 0x4 cstartup.o
0x20000008 i
0x2000000c . = ALIGN (0x4)
0x2000000c __bss_end__ = .
*(.stack*)
0x20001000 __StackTop = (ORIGIN (RAM) + LENGTH (RAM))
</pre>
<ul>
<li> <code>hexa</code> is located in <b>.rodata</b> at 0x08000068
<li> <code>first</code> is located in <b>.data</b> at 0x20000004
<li> <code>i</code> is located in <b>.bss</b> at 0x20000008
<li> <code>c</code> is not listed as it doesnt have global scope, but I can
guess its located at 0x20000000.
<li> Initial values for the <b>.data</b> section are located at 0x0800007c.
</ul>
A hexadecimal dump of <b>cstartup.bin</b> confirms that the initial value
of <code>c</code> is at offset 0x7c, which also means that <code>c</code> has
been located at 0x20000000.
<pre>
$ hexdump -C cstartup.bin
00000000 00 10 00 20 09 00 00 08 10 b5 08 4a 08 4b 09 49 |... .......J.K.I|
00000010 8b 42 06 d3 00 21 08 4a 93 42 05 d3 00 f0 0e f8 |.B...!.J.B......|
00000020 fe e7 01 ca 01 c3 f3 e7 02 c3 f5 e7 7c 00 00 08 |............|...|
00000030 00 00 00 20 08 00 00 20 0c 00 00 20 30 b5 08 49 |... ... ... 0..I|
00000040 08 48 0a 78 04 68 4b 68 12 19 d2 b2 5d 1c 9b 1a |.H.x.hKh....]...|
00000050 64 33 1b 19 4d 60 03 60 0a 70 00 20 30 bd c0 46 |d3..M`.`.p. 0..F|
00000060 00 00 00 20 08 00 00 20 30 31 32 33 34 35 36 37 |... ... 01234567|
00000070 38 39 61 62 63 64 65 66 00 00 00 00 61 00 00 00 |89abcdef....a...|
00000080 01 00 00 00 |....|
00000084
</pre>
<h2>Debug</h2>
I use the STM32 Cube Programmer to check that the code behaves as
expected by checking the RAM content after <code>main()</code> has been
executed.
<p>
<img alt="RAM display in STM32 Cube Programmer" src="img/17_cube.png"
width="1024">
<h2>Checkpoint</h2>
I have now a sample bootstrap that puts the RAM memory in a state
required for a C startup.
<p>
<a href="18_3stages.html">Next</a>, I will merge the C startup initialization with
the <b>ledtick</b> code.
<hr>© 2020-2024 Renaud Fivet
</body>
</html>