Chapter 03 - Hongjayeong-02/Basic_SoC_implementation GitHub Wiki

03. Build Process & GNU Toolchain

Goal

Understand what actually happens when an embedded C project is built.

In this chapter:

  • Build the Ch02 program without relying on an IDE build button
  • Run each GNU ARM toolchain stage manually
  • Inspect .i, .s, .o, .elf, and .hex
  • Understand compiler options for Cortex-M4
  • Inspect generated machine code with objdump
  • Understand where compile errors and link errors occur

1. Why Study the Build Process?

STM32CubeIDE์—์„œ๋Š” ๋ณดํ†ต:

Build

๋ฒ„ํŠผ ํ•œ ๋ฒˆ์œผ๋กœ ํ”„๋กœ๊ทธ๋žจ์ด ๋งŒ๋“ค์–ด์ง„๋‹ค.

ํ•˜์ง€๋งŒ ์‹ค์ œ ๋‚ด๋ถ€์—์„œ๋Š” ์—ฌ๋Ÿฌ ๋‹จ๊ณ„๊ฐ€ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰๋œ๋‹ค.

main.c
  โ”‚
  โ–ผ
Preprocessor
  โ”‚
  โ–ผ
main.i
  โ”‚
  โ–ผ
Compiler
  โ”‚
  โ–ผ
main.s
  โ”‚
  โ–ผ
Assembler
  โ”‚
  โ–ผ
main.o
  โ”‚
  โ–ผ
Linker
  โ”‚
  โ–ผ
program.elf
  โ”‚
  โ–ผ
objcopy
  โ”‚
  โ”œโ”€โ”€ program.hex
  โ””โ”€โ”€ program.bin

์ด ๊ณผ์ •์„ ์•Œ์•„์•ผ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ์–ด๋А ๋‹จ๊ณ„์—์„œ ๋ฐœ์ƒํ–ˆ๋Š”์ง€ ํŒ๋‹จํ•  ์ˆ˜ ์žˆ๋‹ค.

syntax error
undefined reference
multiple definition
region FLASH overflowed
section overlaps

์˜ˆ๋ฅผ ๋“ค์–ด:

undefined reference to `foo`

๋Š” C ๋ฌธ๋ฒ• ์˜ค๋ฅ˜๊ฐ€ ์•„๋‹ˆ๋‹ค.

๊ฐ .c ํŒŒ์ผ์€ ์ •์ƒ์ ์œผ๋กœ compile๋˜์—ˆ์ง€๋งŒ, link ๋‹จ๊ณ„์—์„œ foo์˜ ์‹ค์ œ ์ •์˜๋ฅผ ์ฐพ์ง€ ๋ชปํ–ˆ๋‹ค๋Š” ๋œป์ด๋‹ค.


2. GNU ARM Embedded Toolchain

STM32F439ZI๋Š” ARM Cortex-M4 ๊ธฐ๋ฐ˜ MCU์ด๋ฏ€๋กœ ์ผ๋ฐ˜ PC์šฉ GCC๊ฐ€ ์•„๋‹ˆ๋ผ ARM target์šฉ cross compiler๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

๋Œ€ํ‘œ ๋ช…๋ น:

arm-none-eabi-gcc
arm-none-eabi-as
arm-none-eabi-ld
arm-none-eabi-objcopy
arm-none-eabi-objdump
arm-none-eabi-size

3. What Does arm-none-eabi Mean?

Toolchain prefix:

arm-none-eabi

๋ฅผ ๋ถ„ํ•ดํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค.

arm
 โ”‚
 โ””โ”€โ”€ Target architecture

none
 โ”‚
 โ””โ”€โ”€ No operating-system dependency

eabi
 โ”‚
 โ””โ”€โ”€ Embedded Application Binary Interface

์ฆ‰:

ARM ๊ธฐ๋ฐ˜ bare-metal embedded system์„ ์œ„ํ•œ toolchain

์ด๋ผ๊ณ  ์ดํ•ดํ•˜๋ฉด ๋œ๋‹ค.

PC์—์„œ GCC๋ฅผ ์‹คํ–‰ํ•˜์ง€๋งŒ ์ƒ์„ฑ๋˜๋Š” machine code๋Š” x86์ด ์•„๋‹ˆ๋ผ ARM Cortex-M4์šฉ ์ฝ”๋“œ๋‹ค.

Development PC
    x86/x64
       โ”‚
       โ”‚ arm-none-eabi-gcc
       โ–ผ
ARM Machine Code
       โ”‚
       โ–ผ
STM32F439ZI

์ด๊ฒƒ์ด Cross Compilation์ด๋‹ค.


4. Full Build Pipeline

์ด๋ฒˆ ์‹ค์Šต์—์„œ๋Š” ๋‹ค์Œ 5๋‹จ๊ณ„๋ฅผ ์ง์ ‘ ์‹คํ–‰ํ•œ๋‹ค.

1. Preprocessing
2. Compilation
3. Assembly
4. Linking
5. Binary/Image Generation

๊ฐ ๋‹จ๊ณ„์˜ ์ž…๋ ฅ๊ณผ ์ถœ๋ ฅ:

main.c
  โ†“ preprocessing
main.i
  โ†“ compilation
main.s
  โ†“ assembly
main.o
  โ†“ linking
ch03_build.elf
  โ†“ objcopy
ch03_build.hex

5. Practice Source Code

Ch03์—์„œ๋Š” Ch02์—์„œ ์‚ฌ์šฉํ•œ LED blink source๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

main.c

#define PERIPH_BASE        (0x40000000UL)
#define AHB1PERIPH_BASE    (PERIPH_BASE + 0x00020000UL)

#define RCC_BASE           (AHB1PERIPH_BASE + 0x3800UL)
#define GPIOB_BASE         (AHB1PERIPH_BASE + 0x0400UL)

/* Register mapping */
#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))

/* Bit definitions */
#define GPIOBEN       (1UL << 1)
#define LD1_PIN       (1UL << 0)

static void delay(volatile unsigned int count)
{
    while (count--)
    {
        __asm__("nop");
    }
}

int main(void)
{
    /* Enable GPIOB clock */
    RCC_AHB1ENR |= GPIOBEN;

    /* PB0 -> General Purpose Output */
    GPIOB_MODER &= ~(0x3UL << (0 * 2));
    GPIOB_MODER |=  (0x1UL << (0 * 2));

    while (1)
    {
        GPIOB_ODR ^= LD1_PIN;
        delay(800000);
    }
}

The hardware operation is unchanged from Chapter 02.

The focus of this chapter is:

How does main.c become machine code?

6. Stage 1 โ€” Preprocessing

Command:

arm-none-eabi-gcc \
    -mcpu=cortex-m4 \
    -mthumb \
    -mfloat-abi=soft \
    -E main.c \
    -o main.i

Input:

main.c

Output:

main.i

7. What Does the Preprocessor Do?

Preprocessor๋Š” ์‹ค์ œ C compiler๋ณด๋‹ค ๋จผ์ € ๋™์ž‘ํ•œ๋‹ค.

์ฃผ์š” ์ž‘์—…:

#include
#define
#if
#ifdef
#ifndef

๋“ฑ์„ ์ฒ˜๋ฆฌํ•œ๋‹ค.

๊ฐ€์žฅ ์ค‘์š”ํ•œ ์ :

Preprocessor๋Š” C ๋ฌธ๋ฒ•์˜ ์˜๋ฏธ๋ฅผ ์ดํ•ดํ•˜๋Š” compiler๊ฐ€ ์•„๋‹ˆ๋‹ค.

์ฃผ๋กœ text substitution์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด:

#define GPIOBEN (1UL << 1)

RCC_AHB1ENR |= GPIOBEN;

๋Š” preprocessing ํ›„ ๊ฐœ๋…์ ์œผ๋กœ:

RCC_AHB1ENR |= (1UL << 1);

์ฒ˜๋Ÿผ ์น˜ํ™˜๋œ๋‹ค.


8. Register Macro Expansion

Ch02์—์„œ ์‚ฌ์šฉํ•œ:

#define GPIOB_ODR \
    (*(volatile unsigned int *)(GPIOB_BASE + 0x14UL))

๋„ preprocessing ๋‹จ๊ณ„์—์„œ ์น˜ํ™˜๋œ๋‹ค.

๊ทธ๋ฆฌ๊ณ :

#define GPIOB_BASE \
    (AHB1PERIPH_BASE + 0x0400UL)

๋“ฑ๋„ ์—ฐ์‡„์ ์œผ๋กœ ์น˜ํ™˜๋œ๋‹ค.

๊ฒฐ๊ตญ compiler๊ฐ€ ๋ณด๋Š” ์ฝ”๋“œ๋Š” ๊ฐœ๋…์ ์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ€๊นŒ์›Œ์ง„๋‹ค.

(*(volatile unsigned int *)
    ((0x40000000UL + 0x00020000UL)
     + 0x0400UL
     + 0x14UL))
    ^= (1UL << 0);

์ฆ‰ #define์€ ์ƒˆ๋กœ์šด ๋ณ€์ˆ˜๋‚˜ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค.

Source Text
    โ†“
Preprocessor
    โ†“
Expanded Source Text

์ด๋‹ค.


9. Inspecting main.i

์ƒ์„ฑ๋œ ํŒŒ์ผ ํ™•์ธ:

less main.i

๋˜๋Š”:

head main.i

.i ํŒŒ์ผ์€ preprocessing์ด ๋๋‚œ C source๋‹ค.

์•„์ง ARM assembly๋„ ์•„๋‹ˆ๊ณ  machine code๋„ ์•„๋‹ˆ๋‹ค.

main.c
 โ”‚
 โ”‚ #define / #include expanded
 โ–ผ
main.i

10. Stage 2 โ€” Compilation

Command:

arm-none-eabi-gcc \
    -mcpu=cortex-m4 \
    -mthumb \
    -mfloat-abi=soft \
    -S main.i \
    -o main.s

Input:

main.i

Output:

main.s

11. What Does the Compiler Do?

Compiler๋Š” C ์–ธ์–ด๋ฅผ target processor์˜ assembly language๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค.

C
 โ†“
Compiler
 โ†“
ARM / Thumb Assembly

์˜ˆ๋ฅผ ๋“ค์–ด C ์ฝ”๋“œ:

count--;

๋Š” architecture์™€ optimization์— ๋”ฐ๋ผ assembly์—์„œ:

subs r3, r3, #1

๊ฐ™์€ instruction์œผ๋กœ ๋ฐ”๋€” ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ :

while (count--)

๊ฐ™์€ ๊ตฌ์กฐ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ:

subtract
compare
branch

๊ณ„์—ด instruction์œผ๋กœ ๊ตฌํ˜„๋œ๋‹ค.


12. C Control Flow vs CPU Instructions

C์—์„œ๋Š”:

while (count--)
{
    __asm__("nop");
}

๋ผ๊ณ  ์ž‘์„ฑํ•˜์ง€๋งŒ CPU๋Š” while์ด๋ผ๋Š” ๊ฐœ๋…์„ ๋ชจ๋ฅธ๋‹ค.

CPU๊ฐ€ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์€:

Load
Subtract
Compare
Branch

๊ฐ™์€ instruction๋ฟ์ด๋‹ค.

๊ฐœ๋…์ ์œผ๋กœ:

while(count--)
      โ”‚
      โ–ผ
load count
      โ”‚
      โ–ผ
subtract
      โ”‚
      โ–ผ
compare with zero
      โ”‚
      โ–ผ
branch if not finished

์ด๋‹ค.

์ด ๋ถ€๋ถ„์ด C programming๊ณผ Computer Architecture๊ฐ€ ์ง์ ‘ ์—ฐ๊ฒฐ๋˜๋Š” ์ง€์ ์ด๋‹ค.


13. Inspecting main.s

less main.s

๋˜๋Š”:

grep -A30 main main.s

์‹ค์ œ assembly๋ฅผ ํ™•์ธํ•˜๋ฉด:

C variable
C loop
C pointer access

๊ฐ€ Cortex-M4 instruction์œผ๋กœ ์–ด๋–ป๊ฒŒ ๋ณ€ํ™˜๋˜๋Š”์ง€ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.


14. Stage 3 โ€” Assembly

Command:

arm-none-eabi-gcc \
    -mcpu=cortex-m4 \
    -mthumb \
    -mfloat-abi=soft \
    -c main.s \
    -o main.o

Input:

main.s

Output:

main.o

15. What Does the Assembler Do?

Assembler๋Š” assembly instruction์„ machine code๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค.

ARM Assembly
     โ†“
Assembler
     โ†“
Binary Machine Instructions

์˜ˆ:

nop

๊ฐ™์€ assembly mnemonic์ด ์‹ค์ œ CPU๊ฐ€ ์‹คํ–‰ํ•  binary instruction์œผ๋กœ encoding๋œ๋‹ค.

ํ•˜์ง€๋งŒ .o ํŒŒ์ผ์€ ์•„์ง ์™„์ „ํ•œ ์‹คํ–‰ ์ด๋ฏธ์ง€๊ฐ€ ์•„๋‹ˆ๋‹ค.


16. What Is an Object File?

main.o๋Š” object file์ด๋‹ค.

Object file์—๋Š” ๋ณดํ†ต ๋‹ค์Œ ์ •๋ณด๊ฐ€ ๋“ค์–ด์žˆ๋‹ค.

Machine Code
Sections
Symbols
Relocation Information
Debug Information

์ค‘์š”ํ•œ ์ :

.o์—๋Š” machine code๊ฐ€ ์กด์žฌํ•˜์ง€๋งŒ ์•„์ง ์ตœ์ข… ์ฃผ์†Œ๊ฐ€ ํ™•์ •๋˜์ง€ ์•Š์€ symbol์ด ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด:

foo();

๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค๊ณ  ํ•˜์ž.

Compiler์™€ assembler๋Š”:

foo๋ผ๋Š” symbol์„ ํ˜ธ์ถœํ•œ๋‹ค

๋Š” ์ •๋ณด๋Š” ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ foo()๊ฐ€ ๋‹ค๋ฅธ object file์— ์ •์˜๋˜์–ด ์žˆ๋‹ค๋ฉด ์‹ค์ œ ์ฃผ์†Œ๋Š” ์•„์ง ์•Œ ์ˆ˜ ์—†๋‹ค.

main.o
 โ””โ”€โ”€ needs symbol: foo

foo.o
 โ””โ”€โ”€ defines symbol: foo

์ด ๋‘˜์„ ์—ฐ๊ฒฐํ•˜๋Š” ๋‹จ๊ณ„๊ฐ€ Linking์ด๋‹ค.


17. Object File Is Not a Flash Image

.o๋Š” ๋ฐ”๋กœ MCU Flash์— ์“ธ ํŒŒ์ผ์ด ์•„๋‹ˆ๋‹ค.

main.o
startup.o
driver.o
...

๊ฐ object file์€ ์•„์ง ๋ถ„๋ฆฌ๋˜์–ด ์žˆ๋‹ค.

๋”ฐ๋ผ์„œ ๋‹ค์Œ ๋‹จ๊ณ„์—์„œ linker๊ฐ€ ํ•ฉ์ณ์•ผ ํ•œ๋‹ค.


18. Inspecting main.o

Disassemble:

arm-none-eabi-objdump -d main.o

์ด ๋ช…๋ น์€ object file ์•ˆ์˜ machine code๋ฅผ ์‚ฌ๋žŒ์ด ์ฝ๊ธฐ ์‰ฌ์šด assembly ํ˜•ํƒœ๋กœ ๋‹ค์‹œ ๋ณด์—ฌ์ค€๋‹ค.

Machine Code
    โ†“
objdump
    โ†“
Assembly View

์ด ๊ณผ์ •์„ Disassembly๋ผ๊ณ  ํ•œ๋‹ค.


19. objdump Example

Notion ์‹ค์Šต์—์„œ๋Š” delay()์˜:

while (count--)

๊ฐ€ ์‹ค์ œ๋กœ ์ €์ˆ˜์ค€์—์„œ:

subtract
compare
conditional branch

ํ˜•ํƒœ์˜ instruction์œผ๋กœ ๋ฐ”๋€Œ๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ๋‹ค.

์‹ค์ œ instruction์€ compiler option์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ์ง€๋งŒ ๋Œ€ํ‘œ์ ์œผ๋กœ:

subs
cmp
bne

๊ฐ™์€ instruction์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.


20. Stage 4 โ€” Linking

Command:

arm-none-eabi-gcc \
    -mcpu=cortex-m4 \
    -mthumb \
    -mfloat-abi=soft \
    -T linker.ld \
    main.o \
    startup.o \
    -o ch03_build.elf

Input:

main.o
startup.o
linker.ld

Output:

ch03_build.elf

21. What Does the Linker Do?

Linker์˜ ์ค‘์š”ํ•œ ์—ญํ• ์€ ํฌ๊ฒŒ ์„ธ ๊ฐ€์ง€๋‹ค.

1. Combine Object Files

main.o
startup.o
other.o
   โ”‚
   โ–ผ
Linker
   โ”‚
   โ–ผ
One Executable Image

2. Resolve Symbols

์˜ˆ:

main.o
 โ””โ”€โ”€ references Reset_Handler

startup.o
 โ””โ”€โ”€ defines Reset_Handler

ํ˜น์€ ๋ฐ˜๋Œ€๋กœ startup code๊ฐ€:

main

symbol์„ ์ฐธ์กฐํ•œ๋‹ค.

Linker๊ฐ€ ์‹ค์ œ ์ฃผ์†Œ๋ฅผ ์ฐพ์•„ ์—ฐ๊ฒฐํ•œ๋‹ค.

3. Place Sections in Memory

.text
.rodata
.data
.bss
.vector_table

๋“ฑ์„ ์‹ค์ œ FLASH / SRAM address์— ๋ฐฐ์น˜ํ•œ๋‹ค.

์ด ์œ„์น˜๋ฅผ ์ง€์ •ํ•˜๋Š” ๊ฒƒ์ด:

linker.ld

์ฆ‰ Linker Script๋‹ค.


22. Why Is a Linker Script Required?

PC ํ”„๋กœ๊ทธ๋žจ์€ Operating System๊ณผ runtime environment๊ฐ€ ๋งŽ์€ ๋ถ€๋ถ„์„ ๊ด€๋ฆฌํ•œ๋‹ค.

Bare-metal MCU๋Š” ๊ทธ๋ ‡์ง€ ์•Š๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ์ง์ ‘ ์•Œ๋ ค์ค˜์•ผ ํ•œ๋‹ค.

์˜ˆ:

FLASH starts here
FLASH size is this

RAM starts here
RAM size is this

.text goes to FLASH
.data initial image goes to FLASH
.data runtime location goes to RAM
.bss goes to RAM

์ด๋ฅผ linker์—๊ฒŒ ์•Œ๋ ค์ฃผ๋Š” ํŒŒ์ผ์ด:

linker.ld

์ด๋‹ค.

Chapter 04์—์„œ ์ง์ ‘ ์ž‘์„ฑํ•œ๋‹ค.


23. STM32F439ZI Memory Concept

๊ฐœ๋…์ ์œผ๋กœ:

FLASH
0x08000000
โ”‚
โ”œโ”€โ”€ Vector Table
โ”œโ”€โ”€ .text
โ”œโ”€โ”€ .rodata
โ””โ”€โ”€ Initial values for .data

SRAM
0x20000000
โ”‚
โ”œโ”€โ”€ .data
โ”œโ”€โ”€ .bss
โ”œโ”€โ”€ Heap
โ””โ”€โ”€ Stack

์ฒ˜๋Ÿผ code์™€ data๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ memory ์˜์—ญ์— ๋ฐฐ์น˜๋œ๋‹ค.

์ •ํ™•ํ•œ section placement๋Š” linker script๊ฐ€ ๊ฒฐ์ •ํ•œ๋‹ค.


24. Why startup.o Is Needed

Bare-metal MCU์—์„œ processor๋Š” power-on ์งํ›„ ๋ฐ”๋กœ main()์„ ์‹คํ–‰ํ•˜์ง€ ์•Š๋Š”๋‹ค.

๋Œ€๋žต:

RESET
  โ†“
Vector Table
  โ†“
Initial Stack Pointer
  โ†“
Reset_Handler
  โ†“
Runtime Initialization
  โ†“
main()

๋”ฐ๋ผ์„œ Reset_Handler์™€ vector table์„ ๊ฐ€์ง„ startup code๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

Chapter 03์—์„œ๋Š” ๊ธฐ์กด startup object๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , ์ž์„ธํ•œ ๊ตฌํ˜„์€ Chapter 04์—์„œ ๋‹ค๋ฃฌ๋‹ค.


25. Link Error Example

Suppose:

void foo(void);

int main(void)
{
    foo();
}

๊ทธ๋Ÿฐ๋ฐ ์–ด๋””์—๋„:

void foo(void)
{
}

๊ฐ€ ์—†๋‹ค๋ฉด compiler๋Š” prototype์„ ์•Œ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— compile์€ ๊ฐ€๋Šฅํ•˜๋‹ค.

ํ•˜์ง€๋งŒ linker๋Š” ์‹ค์ œ foo implementation์„ ์ฐพ์ง€ ๋ชปํ•œ๋‹ค.

๊ฒฐ๊ณผ:

undefined reference to `foo'

์ฆ‰:

Compile
  PASS
    โ†“
Link
  FAIL

์ด๋‹ค.


26. Compile Error vs Link Error

Compile Error

Examples:

syntax error
undeclared identifier
wrong type
missing semicolon

๋ณดํ†ต:

.c โ†’ .o

๊ณผ์ •์—์„œ ์‹คํŒจํ•œ๋‹ค.

Link Error

Examples:

undefined reference
multiple definition
region overflowed

๋ณดํ†ต:

.o files โ†’ .elf

๊ณผ์ •์—์„œ ์‹คํŒจํ•œ๋‹ค.

์ด ์ฐจ์ด๋ฅผ ์•„๋Š” ๊ฒƒ์ด build debugging์—์„œ ๋งค์šฐ ์ค‘์š”ํ•˜๋‹ค.


27. ELF File

Linking์ด ์„ฑ๊ณตํ•˜๋ฉด:

ch03_build.elf

๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.

ELF:

Executable and Linkable Format

์ด๋‹ค.

ELF์—๋Š” ๋‹จ์ˆœ machine code ์™ธ์—๋„ ์—ฌ๋Ÿฌ ์ •๋ณด๊ฐ€ ํฌํ•จ๋  ์ˆ˜ ์žˆ๋‹ค.

Executable Code
Data
Sections
Symbols
Debug Information
Address Information

๋”ฐ๋ผ์„œ debugger๊ฐ€:

main()
uart_init()
line 37
variable x

๋“ฑ์„ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค.


28. Inspecting ELF Size

Command:

arm-none-eabi-size ch03_build.elf

์‹ค์Šต ๊ฒฐ๊ณผ:

text    data    bss
252       0      0

Meaning:

text

Program code and read-only data.

์ฃผ๋กœ Flash์— ์œ„์น˜ํ•œ๋‹ค.

data

์ดˆ๊ธฐ๊ฐ’์ด ์žˆ๋Š” global/static variable.

Example:

int count = 10;

์ดˆ๊ธฐ๊ฐ’์€ Flash image ์•ˆ์— ์ €์žฅ๋˜์–ด ์žˆ๊ณ  runtime์—๋Š” RAM์œผ๋กœ ๋ณต์‚ฌ๋œ๋‹ค.

bss

์ดˆ๊ธฐ๊ฐ’์ด ์—†๊ฑฐ๋‚˜ 0์œผ๋กœ ์ดˆ๊ธฐํ™”๋˜๋Š” global/static variable.

Example:

int count;

๋ณดํ†ต Flash image์— ์‹ค์ œ 0 ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋ถ€ ์ €์žฅํ•˜๋Š” ๋Œ€์‹ :

์ด ์˜์—ญ์„ startup์—์„œ 0์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•˜๋ผ

๋Š” ์ •๋ณด๋งŒ ๊ฐ€์ง„๋‹ค.


29. Why Is .data = 0 and .bss = 0?

์ด๋ฒˆ Ch02/Ch03 source๋Š” global variable์„ ๊ฑฐ์˜ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.

Registers๋Š”:

#define

macro์ด๊ณ  ์‹ค์ œ RAM variable์ด ์•„๋‹ˆ๋‹ค.

์˜ˆ:

#define GPIOB_ODR \
    (*(volatile unsigned int *)0x40020414UL)

๋Š” RAM ๊ณต๊ฐ„์„ ์ฐจ์ง€ํ•˜๋Š” ์ „์—ญ ๋ณ€์ˆ˜๊ฐ€ ์•„๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ:

data = 0
bss  = 0

์ด ๋‚˜์˜ค๋Š” ๊ฒƒ์ด ์ž์—ฐ์Šค๋Ÿฝ๋‹ค.


30. Stage 5 โ€” Generate Flash Image

Command:

arm-none-eabi-objcopy \
    -O ihex \
    ch03_build.elf \
    ch03_build.hex

Input:

ch03_build.elf

Output:

ch03_build.hex

31. What Does objcopy Do?

ELF์—๋Š” flashing์— ํ•„์š”ํ•˜์ง€ ์•Š์€ ์ •๋ณด๋„ ๋งŽ์ด ํฌํ•จ๋˜์–ด ์žˆ๋‹ค.

์˜ˆ:

debug symbols
section metadata
symbol names
source mapping

Flash programmer๊ฐ€ ํ•„์š”ํ•œ ๊ฒƒ์€ ์‹ค์ œ MCU memory์— ๊ธฐ๋กํ•  content๋‹ค.

๋”ฐ๋ผ์„œ:

ELF
 โ”‚
 โ”‚ objcopy
 โ–ผ
Flash Image

๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค.


32. HEX vs BIN

Intel HEX

ch03_build.hex

Text-based format.

๋‚ด์šฉ์—๋Š”:

Address
Data
Record Type
Checksum

๋“ฑ์ด ํฌํ•จ๋œ๋‹ค.

์˜ˆ:

:1000000068030020650100006D0100006F01000021

์‚ฌ๋žŒ์ด text file๋กœ ์—ด ์ˆ˜ ์žˆ๋‹ค.


Binary

Binary image๋ฅผ ๋งŒ๋“ค๋ ค๋ฉด:

arm-none-eabi-objcopy \
    -O binary \
    ch03_build.elf \
    ch03_build.bin

.bin์€ ์ˆœ์ˆ˜ binary byte stream์ด๋‹ค.

HEX
โ†’ address information included

BIN
โ†’ raw bytes only

33. Complete Practice Build Script

Notion Ch03์—์„œ ์‚ฌ์šฉํ•œ ํ•ต์‹ฌ build sequence:

arm-none-eabi-gcc \
    -mcpu=cortex-m4 \
    -mthumb \
    -mfloat-abi=soft \
    -E main.c \
    -o main.i

arm-none-eabi-gcc \
    -mcpu=cortex-m4 \
    -mthumb \
    -mfloat-abi=soft \
    -S main.i \
    -o main.s

arm-none-eabi-gcc \
    -mcpu=cortex-m4 \
    -mthumb \
    -mfloat-abi=soft \
    -c main.s \
    -o main.o

arm-none-eabi-gcc \
    -mcpu=cortex-m4 \
    -mthumb \
    -mfloat-abi=soft \
    -T linker.ld \
    main.o startup.o \
    -o ch03_build.elf

arm-none-eabi-objcopy \
    -O ihex \
    ch03_build.elf \
    ch03_build.hex

34. Recommended build.sh

The same sequence can be written as:

#!/bin/bash

CPU="-mcpu=cortex-m4"
THUMB="-mthumb"
FLOAT="-mfloat-abi=soft"

echo "[1] Preprocess"
arm-none-eabi-gcc \
    $CPU $THUMB $FLOAT \
    -E main.c \
    -o main.i

echo "[2] Compile"
arm-none-eabi-gcc \
    $CPU $THUMB $FLOAT \
    -S main.i \
    -o main.s

echo "[3] Assemble"
arm-none-eabi-gcc \
    $CPU $THUMB $FLOAT \
    -c main.s \
    -o main.o

echo "[4] Link"
arm-none-eabi-gcc \
    $CPU $THUMB $FLOAT \
    -T linker.ld \
    main.o startup.o \
    -o ch03_build.elf

echo "[5] Generate HEX"
arm-none-eabi-objcopy \
    -O ihex \
    ch03_build.elf \
    ch03_build.hex

echo "[6] Size"
arm-none-eabi-size ch03_build.elf

Execute:

chmod +x build.sh
./build.sh

35. Compiler Option โ€” -mcpu=cortex-m4

-mcpu=cortex-m4

Compiler์—๊ฒŒ target CPU architecture๋ฅผ ์•Œ๋ ค์ค€๋‹ค.

STM32F439ZI core:

ARM Cortex-M4

๋”ฐ๋ผ์„œ compiler๋Š” Cortex-M4๊ฐ€ ์ง€์›ํ•˜๋Š” instruction์„ ๊ธฐ์ค€์œผ๋กœ code๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

์ž˜๋ชป๋œ CPU option์„ ์„ ํƒํ•˜๋ฉด:

  • ์ง€์›ํ•˜์ง€ ์•Š๋Š” instruction ์ƒ์„ฑ
  • ์ตœ์ ํ™” ๋ฐฉ์‹ ์ฐจ์ด
  • architecture incompatibility

๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.


36. Compiler Option โ€” -mthumb

-mthumb

Thumb instruction set์„ ์‚ฌ์šฉํ•˜๋„๋ก ์ง€์ •ํ•œ๋‹ค.

Cortex-M series๋Š” Thumb instruction execution์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ๋‹ค.

C Source
   โ†“
Thumb Instructions
   โ†“
Cortex-M4

๋”ฐ๋ผ์„œ STM32 firmware build์—์„œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ํ•„์š”ํ•œ option์ด๋‹ค.


37. Compiler Option โ€” -mfloat-abi

Ch03 practice:

-mfloat-abi=soft

๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค.

ํ˜„์žฌ code๋Š”:

GPIO register access
integer operation
bit operation

๋งŒ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ hardware floating-point unit์„ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.


38. STM32F439ZI FPU

STM32F439ZI์˜ Cortex-M4 core๋Š” hardware floating-point support๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

Floating-point๋ฅผ ์‹ค์ œ hardware FPU๋กœ ์ฒ˜๋ฆฌํ•˜๋ ค๋ฉด ์ผ๋ฐ˜์ ์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์€ option ์กฐํ•ฉ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

-mfloat-abi=hard
-mfpu=fpv4-sp-d16

๊ฐœ๋…:

soft
 โ””โ”€โ”€ Floating-point ABI does not require hardware FPU instructions

hard
 โ””โ”€โ”€ Hardware FPU calling convention / instructions used

์ค‘์š”ํ•œ ์ ์€ object files์™€ libraries๊ฐ€ ํ˜ธํ™˜๋˜๋Š” ABI ์„ค์ •์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

์„œ๋กœ ๋‹ค๋ฅธ floating-point ABI์˜ object/library๋ฅผ ์„ž์œผ๋ฉด link ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.


39. gcc vs as vs ld

GNU toolchain์—๋Š” ๊ฐ๊ฐ ๋…๋ฆฝ๋œ ํ”„๋กœ๊ทธ๋žจ์ด ์กด์žฌํ•œ๋‹ค.

gcc
as
ld

ํ•˜์ง€๋งŒ ์‹ค์Šต์—์„œ๋Š” ๋Œ€๋ถ€๋ถ„:

arm-none-eabi-gcc

driver๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค.

gcc driver๋Š” option์— ๋”ฐ๋ผ ๋‚ด๋ถ€์ ์œผ๋กœ ํ•„์š”ํ•œ tool์„ ํ˜ธ์ถœํ•œ๋‹ค.

์˜ˆ:

gcc -c main.s

๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ assembler๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

๊ทธ๋ฆฌ๊ณ :

gcc main.o startup.o -o app.elf

๋Š” linker๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

๋”ฐ๋ผ์„œ:

GCC๋Š” ๋‹จ์ˆœํžˆ C compiler ํ•˜๋‚˜๋งŒ ์˜๋ฏธํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ build toolchain์˜ driver ์—ญํ• ๋„ ํ•œ๋‹ค.


40. Source File to CPU Execution

์ „์ฒด ๊ณผ์ •์„ hardware ๊ด€์ ๊นŒ์ง€ ์—ฐ๊ฒฐํ•˜๋ฉด:

main.c
  โ”‚
  โ–ผ
Preprocessor
  โ”‚
  โ–ผ
Compiler
  โ”‚
  โ–ผ
ARM Assembly
  โ”‚
  โ–ผ
Assembler
  โ”‚
  โ–ผ
Machine Code
  โ”‚
  โ–ผ
Linker
  โ”‚
  โ–ผ
Absolute Memory Layout
  โ”‚
  โ–ผ
ELF
  โ”‚
  โ–ผ
HEX / BIN
  โ”‚
  โ–ผ
FLASH
  โ”‚
  โ–ผ
Cortex-M4 Instruction Fetch
  โ”‚
  โ–ผ
Execution

์ฆ‰ ์šฐ๋ฆฌ๊ฐ€ ์ž‘์„ฑํ•œ C code๊ฐ€ ์ตœ์ข…์ ์œผ๋กœ๋Š” Flash memory์— ์ €์žฅ๋œ machine instruction์ด ๋œ๋‹ค.


41. Build Result

Notion์— ๊ธฐ๋ก๋œ Ch03 ๊ฒฐ๊ณผ:

text : 252 bytes
data : 0 bytes
bss  : 0 bytes

Ch02์˜ Makefile build ๊ฒฐ๊ณผ์™€ ๋™์ผํ–ˆ๋‹ค.

Ch02
Makefile
   โ”‚
   โ””โ”€โ”€ 252 / 0 / 0

Ch03
Manual Toolchain
   โ”‚
   โ””โ”€โ”€ 252 / 0 / 0

๊ฐ™์€ source์™€ ๊ฐ™์€ build configuration์„ ์‚ฌ์šฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋™์ผํ•œ result๊ฐ€ ๋‚˜์˜จ๋‹ค.

์ด ์‹ค์Šต์˜ ํ•ต์‹ฌ์€:

IDE๋‚˜ Make๊ฐ€ ํŠน๋ณ„ํ•œ binary๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ๊ฒฐ๊ตญ ๋™์ผํ•œ compiler / assembler / linker๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰ํ•œ๋‹ค.

๋Š” ๊ฒƒ์„ ํ™•์ธํ•œ ๊ฒƒ์ด๋‹ค.


42. Useful Inspection Commands

Preprocessed C

less main.i

Generated Assembly

less main.s

Object Disassembly

arm-none-eabi-objdump -d main.o

ELF Disassembly

arm-none-eabi-objdump -d ch03_build.elf

Section Headers

arm-none-eabi-objdump -h ch03_build.elf

Symbols

arm-none-eabi-nm ch03_build.elf

Program Size

arm-none-eabi-size ch03_build.elf

HEX Preview

head ch03_build.hex

์ด ๋ช…๋ น๋“ค์„ ๊ฐ™์ด ์ตํ˜€๋‘๋ฉด build/debugging ๋•Œ ๋งค์šฐ ์œ ์šฉํ•˜๋‹ค.


43. Common Error Mapping

Build error๋ฅผ ๋ณด๋ฉด ์–ด๋А ๋‹จ๊ณ„๋ฅผ ๋จผ์ € ์˜์‹ฌํ•ด์•ผ ํ•˜๋Š”์ง€ ์ •๋ฆฌํ•˜๋ฉด:

#include file not found
        โ†“
Preprocessor

syntax error
type error
undeclared identifier
        โ†“
Compiler

invalid instruction
        โ†“
Assembler

undefined reference
multiple definition
FLASH overflow
RAM overflow
        โ†“
Linker

HEX conversion failure
        โ†“
objcopy

44. undefined reference

Example:

undefined reference to `MYX_LWIP_Init'

์ด ์ข…๋ฅ˜์˜ error๋Š” ๋Œ€ํ‘œ์ ์ธ linker error๋‹ค.

์˜๋ฏธ:

Function call exists
        โ†“
Compiler accepts it
        โ†“
Object file references symbol
        โ†“
Linker searches definition
        โ†“
Definition not found
        โ†“
FAIL

๋”ฐ๋ผ์„œ ์ด ์˜ค๋ฅ˜์—์„œ๋Š”:

C syntax

๋ณด๋‹ค:

source file included?
object file generated?
function actually defined?
library linked?

๋ฅผ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค.


45. multiple definition

๋‘ object file์ด ๊ฐ™์€ global symbol์„ ์ •์˜ํ•˜๋ฉด:

file1.o
 โ””โ”€โ”€ foo

file2.o
 โ””โ”€โ”€ foo

linker๊ฐ€ ์–ด๋А ๊ฒƒ์„ ์‚ฌ์šฉํ• ์ง€ ๊ฒฐ์ •ํ•  ์ˆ˜ ์—†๋‹ค.

๋”ฐ๋ผ์„œ:

multiple definition of `foo'

๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.


46. region overflowed

Linker script๊ฐ€:

FLASH size
RAM size

๋ฅผ ์ •์˜ํ•œ๋‹ค.

Program section์ด ํ•ด๋‹น memory region๋ณด๋‹ค ์ปค์ง€๋ฉด:

region `FLASH' overflowed

๊ฐ™์€ link error๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

๋”ฐ๋ผ์„œ ์ด ์˜ค๋ฅ˜๋Š” compile ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ memory placement ๋ฌธ์ œ๋‹ค.


47. Makefile and IDE Relationship

์ด๋ฒˆ ์‹ค์Šต์—์„œ๋Š” ์ง์ ‘ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ–ˆ์ง€๋งŒ ์‹ค์ œ project์—์„œ๋Š” ๋ณดํ†ต:

Makefile
IDE
CMake
Build Script

๋“ฑ์ด ๋™์ผํ•œ ๋ช…๋ น์„ ์ž๋™์œผ๋กœ ๊ด€๋ฆฌํ•œ๋‹ค.

Manual Commands
      โ†“
Shell Script
      โ†“
Makefile
      โ†“
IDE Build System

์ถ”์ƒํ™” ์ˆ˜์ค€๋งŒ ๋‹ค๋ฅผ ๋ฟ underlying build flow๋Š” ๊ฐ™๋‹ค.


48. Key Questions

Q1. What is the complete build order?

Preprocess
   โ†“
Compile
   โ†“
Assemble
   โ†“
Link
   โ†“
Generate Flash Image

Q2. What does .i contain?

Preprocessed C source.

#define expanded
#include expanded

Q3. What does .s contain?

Target assembly code generated by the compiler.

For STM32F439ZI:

ARM Cortex-M4 / Thumb assembly

Q4. What does .o contain?

Machine code plus section, symbol and relocation information.

It is not yet the final firmware image.


Q5. What does .elf contain?

Linked executable information including:

  • machine code
  • section layout
  • addresses
  • symbols
  • optional debug information

Q6. Why generate .hex?

Because a programmer/debugger needs an image describing the bytes to write into MCU memory.


Q7. What is the difference between .elf and .hex?

ELF
 โ”œโ”€โ”€ machine code
 โ”œโ”€โ”€ symbols
 โ”œโ”€โ”€ sections
 โ”œโ”€โ”€ addresses
 โ””โ”€โ”€ debug information

HEX
 โ”œโ”€โ”€ memory addresses
 โ”œโ”€โ”€ data
 โ””โ”€โ”€ checksum

Q8. Why can F439ZI use hardware floating point?

Because the Cortex-M4 implementation in STM32F439ZI includes an FPU.

For hardware-FPU builds, compatible options such as:

-mfloat-abi=hard
-mfpu=fpv4-sp-d16

can be used.


Q9. What stage causes undefined reference?

Linking

Q10. Why learn this if the IDE already builds automatically?

Because understanding the build stages makes errors much easier to diagnose.

Error Message
     โ†“
Identify Build Stage
     โ†“
Identify Responsible File / Tool
     โ†“
Fix Root Cause

49. Key Takeaways

C Source
   โ†“
Preprocessor
   โ†“
Expanded C
   โ†“
Compiler
   โ†“
Assembly
   โ†“
Assembler
   โ†“
Object File
   โ†“
Linker + Linker Script
   โ†“
ELF
   โ†“
objcopy
   โ†“
HEX / BIN
   โ†“
MCU Flash

The most important concepts are:

  1. A build is not one operation.
  2. Each intermediate file has a different purpose.
  3. Compilation and linking are separate processes.
  4. Object files can contain unresolved symbols.
  5. The linker resolves symbols and assigns addresses.
  6. The linker script defines the MCU memory layout.
  7. ELF is useful for debugging and analysis.
  8. HEX/BIN are used as programming images.
  9. objdump, nm, and size are essential low-level debugging tools.
  10. IDE, Makefile, and shell scripts eventually invoke the same toolchain.