
임베디드 시스템의 이해 2번째 편이다.
순서 상으로는 ARM프로세서 이전이라고 보면 된다.
기초 임베디드 시스템 관련 포스팅은 다음 글이 마지막일 것 같다.
이번 글에서는 컴파일, 링크, 실행 과정에 관한 내용이 대부분이다.
컴파일-링크-실행 과정 개요
소스 코드가 실행파일로 만들어지고, 메모리(RAM/ROM)에 올려 실행되기까지의 과정
각 과정에서 데이터와 코드가 .text, .data, .bss, .const 등 다양한 메모리 구역(섹션)으로 분리되어 관리됨
소스 코드 → 오브젝트 파일(.o) 변환
소스(.c) 파일을 컴파일하면, 해당 소스의 코드(.text), 상수(.const), 초기화 데이터(.data), 초기화되지 않은 데이터(.bss) 등이 분리되어 오브젝트 파일에 저장
.text : 실행 코드 영역
.const : 상수 데이터
.data : 초기값이 있는 전역변수
.bss : 초기값이 없는 전역/정적 변수
여러 오브젝트 파일 → 실행 파일(ELF, BIN 등) 생성
각각의 오브젝트 파일(A.o, B.o 등)을 링커가 하나로 합쳐 실행 파일(a.out 등)을 만듦
이 과정에서 각 섹션들도 합쳐지고, 실제 메모리상 배치 정보가 결정됨
Load View (LMA, Load Memory Address)
링커 단계에서 결정되는, 코드와 데이터가 플래시/ROM에 저장될 실제 주소
(예: a.out(passive), Load View(LMA))
Virtual View (VMA, Virtual Memory Address)
프로그램이 실행될 때, RAM 등에서 각 섹션(.text, .data, .bss 등)이 실제로 매핑되는 실행 시점의 주소
ROM 등 외부 저장소에서 RAM으로 섹션이 복사되어 실행
섹션별 데이터 구분
ROM: 변경 불가능한 코드/상수
RAM: 변경 가능한 데이터/초기화 데이터
섹션별 데이터 구분으로 메모리 사용을 최적화하고 신뢰성을 확보
Code (.text)
함수, 실행 명령어 등 프로그램의 동작 코드가 포함된 영역
ROM(Flash)에 저장되어 직접 실행하는 경우가 많고, 일반적으로 변경되지 않음
Read-only Data (RO, .rodata, .const)
수정될 수 없는 데이터, (예: const 변수, 상수 테이블)
코드와 마찬가지로 ROM 또는 Flash에 저장
Read-write Data (RW, .data)
초기화 값이 있지만 실행 중 변경 가능한 데이터 영역
초기값은 ROM/Flash에서 저장되지만, 실행 시 RAM에 복사되어 사용
예: 초기값이 있는 전역변수, static 변수 등
Zero-initialized Data (ZI, .bss)
초기값이 '0'인 글로벌/static 변수 영역
ROM에는 저장되지 않고, 프로그램 시작 시 RAM(또는 SDRAM)에서 0으로 초기화되어 사용
빌드 과정
소스 코드(.c, .h) → 컴파일 → 오브젝트 파일(.o) 생성
각 오브젝트 파일 내부에 .text, .rodata, .data, .bss 등이 각각 할당
링크 과정
여러 오브젝트(.o) → 실행파일(ELF, BIN 등) 병합
링커 스크립트에 따라 각 섹션별 ROM/Flash, RAM 맵핑 결정
실행 과정
ROM에는 code, ro-data, rw-data(초기값), 루트로더 등 필수 데이터 저장
RAM에는 code(필요시), ro-data(필요시), rw-data(변수), zi-data(0으로 초기화) 등이 적재
스타트업 코드(Startup Code)가 RAM으로 데이터 복사 및 초기화 실행
로케이터
로케이터(링커와 함께)는 여러 오브젝트 파일의 섹션을 합치고, 실제 실행 타겟의 메모리 주소에 각 섹션을 배치
최종 프로그램의 코드, 데이터, 스택 등이 RAM, ROM, Flash 등 실제 위치에 올라갈 자리를 결정
로케이터의 섹션별 데이터 배치 원리
초기화된 전역 변수
코드 내에서 값이 지정된 전역변수(예: int a = 10;)
컴파일 시 ROM(Flash)에 저장, 프로그램 시작 시 RAM으로 복사됨(.data 영역)
초기화되지 않은 전역 변수
값이 없는 전역/정적 변수(예: int b;)
실행 시작 시 RAM(.bss 영역)에 공간을 할당, 값은 0으로 자동 초기화
문자열 리터럴/포인터
상수 문자열은 ROM에 위치, char* 포인터 변수는 RAM에서 해당 위치를 가리킴
(예: 전역 char = "문자열")
지역 변수
함수 내 선언된 변수, 실행 시간에 스택(RAM)에 할당/소멸 (.stack 영역)
타겟 모델 구성하기
타겟 MCU나 SoC별로 RAM, NAND Flash/NOR Flash/ROM 등 구성이 다름
예: 라즈베리파이의 구성
MCU(메인 프로세서)
RAM(실행 중 데이터 저장)
NAND Flash(대용량 저장 매체, OS/파일시스템 등)
ROM Writer
BIN/HEX 등 실행 가능한 이미지 파일을 Flash나 ROM에 직접 기록하는 장치/툴
부트/실행을 위해 MCU가 해당 ROM/Flash에서 코드를 읽어옴
프로그램 카운터, 스택 포인터, 링크 레지스터
PC(Program Counter)
다음에 실행할 명령어의 주소를 가리키는 레지스터
SP(Stack Pointer)
스택 영역의 최상단(최근)에 있는 데이터 주소
LR(Link Register)
함수 호출 시 복귀 주소 저장, ARM 아키텍처 등에서 사용