CubeMX가 알아서 만들어주는 링커 스크립트. 그동안 건드릴 일 없었다.
근데 부트로더 만들려면 이해해야 한다.
링커 스크립트란
.c 파일 컴파일하면 .o (오브젝트) 파일 생김.
링커가 .o 파일들을 묶어서 최종 바이너리 만듦.
링커 스크립트: 뭘 어디에 배치할지 알려주는 설정 파일.
기본 구조
/* 메모리 영역 정의 */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
}
/* 섹션 배치 */
SECTIONS
{
.isr_vector : { ... } > FLASH
.text : { ... } > FLASH
.data : { ... } > RAM AT> FLASH
.bss : { ... } > RAM
}
MEMORY 블록
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K
}
xrw: 실행(x), 읽기(r), 쓰기(w) 가능rx: 실행, 읽기만 (Flash는 런타임에 쓰기 불가)ORIGIN: 시작 주소LENGTH: 크기
부트로더용 수정
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 16K /* 16KB만 */
}
16KB 넘으면 빌드 에러:
region `FLASH' overflowed by 1234 bytes
앱용 수정
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 64K
FLASH (rx) : ORIGIN = 0x08042800, LENGTH = 246K
}
시작 주소가 0x08042800.
SECTIONS 블록
SECTIONS
{
/* Vector Table - 제일 먼저 */
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector))
. = ALIGN(4);
} >FLASH
/* 코드 */
.text :
{
. = ALIGN(4);
*(.text)
*(.text*)
. = ALIGN(4);
} >FLASH
/* 상수 데이터 */
.rodata :
{
. = ALIGN(4);
*(.rodata)
*(.rodata*)
. = ALIGN(4);
} >FLASH
}
.isr_vector: 인터럽트 벡터 테이블.text: 실행 코드.rodata: const 데이터
초기화 데이터
_sidata = LOADADDR(.data);
.data :
{
. = ALIGN(4);
_sdata = .;
*(.data)
*(.data*)
. = ALIGN(4);
_edata = .;
} >RAM AT> FLASH
>RAM AT> FLASH: RAM에 배치하지만 초기값은 Flash에 저장.
시작 시 startup 코드가 Flash에서 RAM으로 복사함.
BSS 섹션
.bss :
{
. = ALIGN(4);
_sbss = .;
*(.bss)
*(.bss*)
*(COMMON)
. = ALIGN(4);
_ebss = .;
} >RAM
초기화 안 된 전역 변수. startup에서 0으로 채움.
스택/힙
_Min_Heap_Size = 0x200;
_Min_Stack_Size = 0x400;
.heap :
{
. = ALIGN(8);
PROVIDE ( end = . );
. = . + _Min_Heap_Size;
} >RAM
.stack :
{
. = ALIGN(8);
. = . + _Min_Stack_Size;
_estack = .;
} >RAM
부트로더는 힙 거의 안 쓰니까 작게 잡아도 됨.
확인
빌드 후 .map 파일:
Memory Configuration
Name Origin Length
RAM 0x20000000 0x00010000
FLASH 0x08000000 0x00004000
.isr_vector 0x08000000 0x10c
.text 0x0800010c 0x1a34
다음 글에서 앱 유효성 검사.