Chapter 04 - Hongjayeong-02/Basic_SoC_implementation GitHub Wiki
04. Linker Script & Startup Code
Goal
STM32F439ZI๊ฐ Reset๋ ๋ค main()์ ๋๋ฌํ๊ธฐ๊น์ง์ ๊ณผ์ ์ ์ดํดํ๊ณ , Linker Script์ Startup Code๊ฐ .data, .bss, Stack, Vector Table์ ์ด๋ป๊ฒ ์ค๋นํ๋์ง ํ์ธํ๋ค.
Reset
โ
Vector Table
โ
Initial MSP / Reset_Handler
โ
.data Copy
โ
.bss Clear
โ
SystemInit()
โ
main()
Ch02~03์์๋ ์์ linker/startup ํ์ผ์ ์ฌ์ฉํ๋ค.
Ch04๋ถํฐ๋ ์ดํ ๋ชจ๋ chapter์์ ์ฌ์ฉํ :
common/linker/stm32f439zi.ld
common/startup/startup_stm32f439zi.s
๋ฅผ ๊ธฐ์ค์ผ๋ก buildํ๋ค.
1. Theory
STM32F439ZI Memory
์ด๋ฒ project์์ ์ฌ์ฉํ๋ ์ฃผ์ memory:
FLASH
Start : 0x08000000
Size : 2048 KB
SRAM
Start : 0x20000000
Size : 128 KB
CCM RAM
Start : 0x10000000
Size : 64 KB
CCM RAM์ ์ด๋ฒ ์ค์ต์์๋ ์ฌ์ฉํ์ง ์๋๋ค.
STM32F439ZI์ 128KB SRAM ๋ ์ฃผ์:
0x20000000 + 0x00020000
=
0x20020000
๋ฐ๋ผ์ initial stack pointer๋ก ์ฌ์ฉํ๋ _estack์:
0x20020000
์ด๋ค.
2. Linker Script
Linker Script๋ ํ๋ก๊ทธ๋จ์ section์ ์ด๋ memory address์ ๋ฐฐ์นํ ์ง ๊ฒฐ์ ํ๋ค.
๋ํ section:
.isr_vector โ FLASH
.text โ FLASH
.rodata โ FLASH
.data โ RAM, initial value๋ FLASH
.bss โ RAM
๊ฐ๋ ์ ์ธ memory layout:
FLASH
0x08000000
โโโโโโโโโโโโโโโโโโโโ
โ .isr_vector โ
โโโโโโโโโโโโโโโโโโโโค
โ .text โ
โโโโโโโโโโโโโโโโโโโโค
โ .rodata โ
โโโโโโโโโโโโโโโโโโโโค
โ .data init value โ
โโโโโโโโโโโโโโโโโโโโ
RAM
0x20000000
โโโโโโโโโโโโโโโโโโโโ
โ .data โ
โโโโโโโโโโโโโโโโโโโโค
โ .bss โ
โโโโโโโโโโโโโโโโโโโโค
โ heap / stack โ
โโโโโโโโโโโโโโโโโโโโ
0x20020000
.data
์ด๊ธฐ๊ฐ์ด ์๋ global/static variable.
Example:
unsigned int g_blink_count = 5;
์คํ ์ค์๋ RAM์ ์์ด์ผ ํ์ง๋ง, ์ ์์ด ๊บผ์ ธ๋ ์ด๊ธฐ๊ฐ 5๋ firmware์ ๋จ์ ์์ด์ผ ํ๋ค.
๋ฐ๋ผ์:
FLASH
initial value = 5
โ
Reset_Handler copy
โ
RAM
g_blink_count = 5
๊ฐ ๋๋ค.
.bss
์ด๊ธฐ๊ฐ์ด ์๋ global/static variable.
Example:
unsigned int g_toggle_flag;
C์์๋ program ์์ ์:
g_toggle_flag = 0
์ด์ด์ผ ํ๋ค.
๋ฐ๋ผ์ Reset_Handler๊ฐ .bss ์์ญ์ RAM์์ 0์ผ๋ก ์ฑ์ด๋ค.
3. LMA and VMA
.data๋ฅผ ์ดํดํ ๋ ์ค์ํ ๊ฐ๋
์ด๋ค.
LMA
Load Memory Address
Firmware image์์ ์ด๊ธฐ๊ฐ์ด ์ ์ฅ๋ ์์น.
.data์ ๊ฒฝ์ฐ:
FLASH
VMA
Virtual / Run Memory Address
์คํ ์ค CPU๊ฐ ์ค์ variable์ ์ ๊ทผํ๋ ์์น.
.data์ ๊ฒฝ์ฐ:
RAM
๋ฐ๋ผ์:
.data
LMA โ FLASH
VMA โ RAM
์ด๋ค.
4. Startup Code
Cortex-M4๋ Reset ์งํ main()์ผ๋ก ๋ฐ๋ก ๊ฐ์ง ์๋๋ค.
Vector Table์ ์ฒซ ๋ word๋ฅผ hardware๊ฐ ์ฝ๋๋ค.
Vector[0]
โ Initial MSP
Vector[1]
โ Reset_Handler
์ฆ conceptually:
MSP โ Vector[0]
PC โ Vector[1]
๊ฐ ๋๋ค.
Reset_Handler
Startup code์ ํต์ฌ ์์:
Reset_Handler
โ
Initial Stack
โ
Copy .data
FLASH โ RAM
โ
Clear .bss
RAM โ 0
โ
SystemInit()
โ
main()
์ด ์์ ์ด ๋๋์ผ C program์ด ๊ธฐ๋ํ๋ runtime environment๊ฐ ๋ง๋ค์ด์ง๋ค.
5. Vector Table & Weak Handler
STM32F439ZI๋ Cortex exception๋ฟ ์๋๋ผ ๋ง์ peripheral IRQ๋ฅผ ๊ฐ์ง๋ค.
์ด project์ startup file์๋ STM32F439ZI์ ๋ง๋ IRQ vector table์ ๊ตฌ์ฑํ๋ค.
์ฌ์ฉํ์ง ์๋ handler๋ ๋ณดํต:
weak symbol
โ
Default_Handler
๋ก ์ฐ๊ฒฐํ๋ค.
๋์ค์ application์์:
void EXTI15_10_IRQHandler(void)
{
...
}
์ฒ๋ผ ๊ฐ์ ์ด๋ฆ์ handler๋ฅผ ์ ์ํ๋ฉด strong symbol์ด weak symbol์ ๋์ ํ๋ค.
์ฆ startup file์ ๋งค๋ฒ ์์ ํ ํ์๊ฐ ์๋ค.
6. Practice Files
์ด chapter์ ์ค์ ์ค์ต ๊ตฌ์ฑ:
Ch04/
โโโ main.c
โโโ stm32f439zi.ld
โโโ startup_stm32f439zi.s
์ดํ chapter์์๋ ๊ณต์ฉํํด์:
common/
โโโ linker/
โ โโโ stm32f439zi.ld
โโโ startup/
โโโ startup_stm32f439zi.s
ํํ๋ก ์ฌ์ฉํ๋ค.
stm32f439zi.ld์startup_stm32f439zi.s์ ์ ์ฒด ์๋ณธ์ ํ์ฌ Notion ๋ณธ๋ฌธ์๋ ํฌํจ๋์ด ์์ง ์๋ค. ์ฌ์ค์ต ์ archived project์ ์ค์ ํ์ผ์ ์ด Wiki์ ์ถ๊ฐํ๋ค.
7. Practice Code
main.c
#define PERIPH_BASE (0x40000000UL)
#define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000UL)
#define RCC_BASE (AHB1PERIPH_BASE + 0x3800UL)
#define GPIOB_BASE (AHB1PERIPH_BASE + 0x0400UL)
#define RCC_AHB1ENR \
(*(volatile unsigned int *)(RCC_BASE + 0x30UL))
#define GPIOB_MODER \
(*(volatile unsigned int *)(GPIOB_BASE + 0x00UL))
#define GPIOB_ODR \
(*(volatile unsigned int *)(GPIOB_BASE + 0x14UL))
#define GPIOBEN (1UL << 1)
#define LD1_PIN (1UL << 0)
/* .data section verification */
unsigned int g_blink_count = 5;
/* .bss section verification */
unsigned int g_toggle_flag;
static void delay(volatile unsigned int count)
{
while (count--)
{
__asm__("nop");
}
}
int main(void)
{
RCC_AHB1ENR |= GPIOBEN;
GPIOB_MODER &= ~(0x3UL << (0 * 2));
GPIOB_MODER |= (0x1UL << (0 * 2));
/*
* .bss initialization check
*
* g_toggle_flag should be 0 after Reset_Handler.
* If not, use fast blinking as an error indication.
*/
if (g_toggle_flag != 0)
{
while (1)
{
GPIOB_ODR ^= LD1_PIN;
delay(50000);
}
}
while (1)
{
for (unsigned int i = 0;
i < g_blink_count;
i++)
{
GPIOB_ODR ^= LD1_PIN;
delay(800000);
}
delay(3200000);
g_toggle_flag++;
}
}
8. Why These Two Variables?
g_blink_count
unsigned int g_blink_count = 5;
์ด๊ธฐ๊ฐ์ด ์์ผ๋ฏ๋ก:
.data
section์ ์์นํ๋ค.
Startup์ด ์ ์์ด๋ผ๋ฉด:
FLASH์ 5
โ
Reset_Handler
โ
RAM g_blink_count = 5
๊ฐ ๋์ด์ผ ํ๋ค.
g_toggle_flag
unsigned int g_toggle_flag;
์ด๊ธฐ๊ฐ์ด ์์ผ๋ฏ๋ก:
.bss
section์ ์์นํ๋ค.
Startup์ด ์ ์์ด๋ผ๋ฉด main() ์ง์
์:
g_toggle_flag = 0
์ด์ด์ผ ํ๋ค.
๊ทธ๋์:
if (g_toggle_flag != 0)
์ด๋ฉด startup ๋ฌธ์ ๊ฐ ์๋ค๊ณ ํ๋จํ๊ณ LED๋ฅผ ๋น ๋ฅด๊ฒ ๊น๋นก์ด๊ฒ ํ๋ค.
์ฆ ์ด chapter์ LED ๋์์ ๋จ์ blink๊ฐ ์๋๋ผ:
.data / .bss Startup Verification
์ฉ์ด๋ค.
9. Linker Symbols
Startup code์ linker script๋ symbol์ ํตํด ์ฃผ์๋ฅผ ๊ณต์ ํ๋ค.
๋ํ์ ์ผ๋ก:
_estack
_sidata
_sdata
_edata
_sbss
_ebss
์ ์๋ฏธ๋ ๋ค์๊ณผ ๊ฐ๋ค.
_estack
โ initial stack address
_sidata
โ FLASH์ ์ ์ฅ๋ .data ์ด๊ธฐ๊ฐ ์์
_sdata
โ RAM์ .data ์์
_edata
โ RAM์ .data ๋
_sbss
โ .bss ์์
_ebss
โ .bss ๋
Startup์ ์ด๋ฅผ ์ด์ฉํด:
_sidata โ _sdata ~ _edata
๋ฒ์๋ก data๋ฅผ ๋ณต์ฌํ๊ณ :
_sbss ~ _ebss
๋ฒ์๋ฅผ 0์ผ๋ก ์ด๊ธฐํํ๋ค.
10. Execution Flow
Power / Reset
โ
Vector Table
โ
MSP = _estack
โ
PC = Reset_Handler
โ
.data Copy
โ
.bss Clear
โ
SystemInit()
โ
main()
โ
g_blink_count = 5
g_toggle_flag = 0
11. Practice Commands
Build:
make
Symbol ํ์ธ:
arm-none-eabi-nm \
ch04_linker_startup.elf \
| grep -E "_estack|_sdata|_edata|_sbss|_ebss"
Section ํ์ธ:
arm-none-eabi-objdump \
-h ch04_linker_startup.elf
Program size:
arm-none-eabi-size \
ch04_linker_startup.elf
12. Recorded Result
์ค์ต์์ ํ์ธํ symbol:
20000008 B _ebss
20000004 D _edata
20020000 R _estack
20000004 B _sbss
20000000 D _sdata
_estack
RAM Start = 0x20000000
RAM Size = 128 KB = 0x20000
0x20000000
+
0x00020000
=
0x20020000
์ค์ ๊ฒฐ๊ณผ:
_estack = 0x20020000
์ ํํ ์ผ์นํ๋ค.
.data
_sdata = 0x20000000
_edata = 0x20000004
ํฌ๊ธฐ:
4 bytes
์ด๋:
unsigned int g_blink_count = 5;
ํ๋์ ์ผ์นํ๋ค.
.bss
_sbss = 0x20000004
_ebss = 0x20000008
์ค์ global variable ์์ญ:
4 bytes
๋ก:
unsigned int g_toggle_flag;
์ ์ผ์นํ๋ค.
Build ๊ฒฐ๊ณผ์์๋ heap/stack reservation๊น์ง ํฌํจํด .bss ๊ด๋ จ RAM ์ฌ์ฉ๋์ด ๋ ํฌ๊ฒ ํ์๋ ์ ์๋ค.
13. Verification
์ฌ์ค์ตํ ๋๋ build ์ฑ๊ณต๋ง ๋ณด๋ ๊ฒ๋ณด๋ค runtime variable๊น์ง ์ง์ ํ์ธํ๋ ๊ฒ์ด ์ข๋ค.
1. Build
make clean
make
2. Symbol
arm-none-eabi-nm \
ch04_linker_startup.elf \
| grep -E "_estack|_sdata|_edata|_sbss|_ebss"
ํ์ธ:
_estack = 0x20020000
3. ELF Sections
arm-none-eabi-objdump \
-h ch04_linker_startup.elf
ํ์ธ:
.isr_vector
.text
.data
.bss
4. Debugger
main() ์ง์
์งํ:
g_blink_count = 5
g_toggle_flag = 0
์ธ์ง ํ์ธํ๋ค.
์ด ํ๋ฉด์ด:
.data copy PASS
.bss clear PASS
๋ฅผ ๊ฐ์ฅ ์ง์ ์ ์ผ๋ก ๋ณด์ฌ์ค๋ค.
5. Board
์ ์ startup:
Normal blink pattern
.bss ์ด๊ธฐํ ์ด์:
Fast continuous blink
14. Screenshots to Add
images/ch04_build.png
images/ch04_symbols.png
images/ch04_sections.png
images/ch04_debug_variables.png
images/ch04_led.gif
์ด chapter์์๋ ํนํ:
nm symbol result
+
Debugger variable result
๋ ์ฅ์ด ๊ฐ์ฅ ์ค์ํ๋ค.
15. Key Points
Linker Script
โ Where?
Startup Code
โ What happens after reset?
- Linker Script๋ Flash/RAM๊ณผ section ๋ฐฐ์น๋ฅผ ๊ฒฐ์ ํ๋ค.
- Vector Table์ ์ฒซ word๋ initial MSP, ๋ ๋ฒ์งธ word๋
Reset_Handler๋ค. .data๋ ์ด๊ธฐ๊ฐ์ด Flash์ ์๊ณ runtime์๋ RAM์ ์กด์ฌํ๋ค..bss๋ RAM ๊ณต๊ฐ๋ง ํ์ํ๋ฉฐ startup์์ 0์ผ๋ก ์ด๊ธฐํํ๋ค..data๋ LMA์ VMA๊ฐ ๋ค๋ฅด๋ค.Reset_Handler๊ฐ C runtime์ ์ค๋นํ ๋คmain()์ ํธ์ถํ๋ค.- weak interrupt handler๋ฅผ ์ฌ์ฉํ๋ฉด application์์ ํ์ํ IRQ๋ง overrideํ ์ ์๋ค.
nm,objdump, debugger๋ฅผ ํตํด linker/startup ๋์์ ๊ฒ์ฆํ ์ ์๋ค.