JINTBEAT Design Life

Linker - (1) 본문

🖥️ - ARM

Linker - (1)

jintbeat_design 2026. 4. 9. 00:18
반응형
Linker에서 Symbol이란 ?

 

주소(또는 값)에 이름을 붙인 것을 말한다.

 

Symbol이 필요한 이유?

컴파일 단계에서는 변수/함수의 정확한 주소를 모름 → 그래서 이름(Symbol)으로만 관리하는 것

 

링커가 마지막에

- 실제 메모리 배치를 결정하고

- 각 Symbol에 주소를 Mapping한다.

 

Example
int global_var = 10;

void func() {
}

 

컴파일하면 내부적으로 :

 

Symbol Table
------------
global_var
func

 

: 아직 주소는 없다.

 

Linker 이후 :

 

링커 배치 이후에는

Symbol Table
------------
global_var -> 0x20000000
func       -> 0x08000100

 

이제 실제 주소가 붙는 것이다.

 

Linker Script에서 Symbol

 

링커 스크립트에서 직접 심볼을 정의할 수 있다.

_estack = 0x20010000;

 

의미 : "_estack"이라는 이름의 Symbol을 만들고 값은 0x20010000이다.

 

실제 많이 쓰는 Symbol들
_sdata
_edata
_sbss
_ebss
_estack
_etext

 

Linker Script 예시
.data : {
    _sdata = .;
    *(.data)
    _edata = .;
} > RAM

 

해석 : _sdata의 의미는 data 시작 주소

_edata는 data 끝 주소

 

extern int _sdata;
extern int _edata;

void init_data() {
    int *src = &_etext;
    int *dst = &_sdata;

    while (dst < &_edata) {
        *dst++ = *src++;
    }
}

 

- Linker가 만든 Symbol을 C 코드에서 주소처럼 사용한다.

- Symbol = 이름 + 주소(또는 값)

- 컴파일 단계 → 이름만 있음

- 링크 단계 → 실제 주소가 결정된다.

- C코드에서 extern으로 접근 가능하다. 

 

RW / ZI / RO 개념
구분 의미 특징
RO (Read Only) 읽기 전용 Flash에 있음
RW (Read Write) 초기값 있는 변수 Flash → RAM 복사
ZI (Zero Init) 0으로 초기화 RAM에서 memset

 

const int a = 10;     // RO
int b = 20;           // RW
int c;                // ZI

 

Flash (ROM)
-----------
.text        (코드)
.rodata      (RO)
.data init   (RW 초기값 저장됨)

RAM
-----------
.data        (RW 실행 영역)
.bss         (ZI)

 

> .text는 "실행 코드(Instruction)만 있는 영역"

 

왜 이렇게 배치하지?

 

- Flash는 읽기만 가능 (실행 가능)

- RAM은 빠르고 쓰기 가능

 

구분 어디 있음
.text Flash 실행만 하면 됨
.rodata Flash 읽기만
.data init Flash 초기값 저장
.data RAM 실행 중 변경
.bss RAM 초기화 필요

 

BSS가 뭐지 ?

 

- 초기 값이 없는 전역 / 정적 변수 영역 (자동으로 0으로 초기화 됨)

int a;          // BSS
static int b;   // BSS
int c = 0;      // 이것도 보통 BSS로 감

 

- 특징은 초기 값이 없고, 실행 전에 반드시 0으로 채워야 한다.

RAM
-----------
.data   → 초기값 있는 변수 (RW)
.bss    → 초기값 없는 변수 (ZI)

 

> BSS는 RAM에만 존재

> Flash에는 없다.

 

왜 Flash에 안넣나?

 

> 굳이 저장할 이유가 없으니까 (낭비)

> 그냥 RAM에서 0으로 채우자....가 되는 것이다.

extern int _sbss;
extern int _ebss;

void init_bss() {
    int *dst = &_sbss;

    while (dst < &_ebss) {
        *dst++ = 0;
    }
}

 > 그래서 부팅 시에 처리한다. 역할은 bss 영역을 전부 0으로 초기화하는 것이다.

 

왜 이름이 "bss"지 ?

> BSS = Block Started by Symbol

> 초기값 없는 변수들을 위한 RAM 공간이고, 부팅 시 0으로 채워준다.

 

RW일 때, Flash랑 RAM 모두에 있어야하는 이유는 뭘까 ?

- RW(.data)는 초기 값은 Flash에 저장 + 실행은 RAM에서 해야 하기 때문이다.

 

왜 RAM에서 실행해야 하나?
int counter = 10;

counter++;

> 이 변수는 계속 바뀐다. 이걸 Flash에 쓸 수는 없다. 쓰기가 너무 느리기 때문이다.

> RW 변수는 반드시 RAM에 있어야 한다.

> 초기 값을 Flash에 저장해주고, 부팅 시에 Flash → RAM 복사가 필요하다.

 

실제 동작
src = _sidata; // Flash
dst = _sdata;  // RAM

while (dst < _edata)
    *dst++ = *src++;
Flash (ROM)
-----------
.text
.rodata
.data init  ← RW 초기값 저장

RAM
-----------
.data       ← 실행 (여기로 복사됨)
.bss

 

정리하면

 

- .data는 2개 존재한다. Flash쪽엔 초기값, RAM쪽에서 실제 실행!

 

Linker 관점
.data : AT(...)
{
    _sdata = .;
    *(.data)
    _edata = .;
} > RAM

_sidata = LOADADDR(.data);

 

Symbol 의미
_sidata Flash 주소
_sdata RAM 주소

 

 

*************************************************************

이 글은 ChatGPT 질의 응답을 바탕으로 작성되었습니다.

*************************************************************

반응형