카드뉴스










startup file은 자동 생성되지만 빈 장식 파일이 아닙니다
STM32 같은 MCU 프로젝트를 만들면 startup_stm32xxxx.s 같은 어셈블리 파일이 함께 생깁니다. 처음에는 직접 수정할 일이 거의 없어서 무시하기 쉽지만, 이 파일은 reset 이후 CPU가 어디로 들어가고 interrupt handler를 어떻게 찾을지 정하는 중요한 시작점입니다. C 코드의 main이 실행되기 전, 실제로는 startup file에 들어 있는 코드와 벡터 테이블을 먼저 거칩니다.
startup file을 알면 프로젝트에 왜 Reset_Handler, Default_Handler, weak symbol 같은 이름이 등장하는지 이해할 수 있습니다. 인터럽트 함수 이름을 잘못 쓰면 사용자가 만든 handler가 연결되지 않고 기본 handler로 빠질 수 있는데, 이 구조도 startup file의 weak 정의와 연결됩니다.
벡터 테이블은 시작 주소와 handler 주소를 담습니다
일반적인 Cortex-M startup file의 앞부분에는 벡터 테이블이 있습니다. 첫 항목에는 초기 stack pointer 값이 들어가고, 그다음에는 Reset_Handler 주소가 들어갑니다. 이후에는 NMI, HardFault, SysTick, UART, TIM, ADC 같은 예외와 주변장치 인터럽트 handler 주소가 이어집니다.
CPU가 reset되면 이 테이블을 기준으로 스택을 잡고 Reset_Handler로 이동합니다. 인터럽트가 발생했을 때도 벡터 테이블의 주소를 따라 handler로 분기합니다. 그래서 링커 스크립트에서 벡터 테이블을 플래시 시작 주소에 배치하는 일도 중요합니다. 부트로더를 쓰는 프로젝트라면 애플리케이션의 벡터 테이블 위치와 VTOR 설정을 함께 확인해야 합니다.
Reset_Handler는 C 실행 환경을 만듭니다
Reset_Handler는 C 코드가 정상적으로 실행되기 위한 RAM 초기화를 담당합니다. 플래시에 저장된 초기화 값을 RAM의 data 섹션으로 복사하고, bss 섹션은 0으로 지웁니다. 이 과정이 있어야 전역 변수와 static 변수가 main 진입 시점에 의도한 값으로 보입니다.
그 뒤에는 SystemInit 같은 저수준 초기화 함수가 호출될 수 있고, C 라이브러리 초기화 후 main으로 분기합니다. 툴체인과 MCU 패키지마다 이름과 순서는 조금씩 다를 수 있지만, 목적은 같습니다. reset 직후의 날것에 가까운 CPU 상태를 C 프로그램이 실행될 수 있는 상태로 바꾸는 것입니다.
직접 고칠 일은 적지만 읽을 줄은 알아야 합니다
대부분의 입문 프로젝트에서는 startup file을 수정하지 않아도 됩니다. 하지만 인터럽트가 동작하지 않거나, main에 도달하지 않거나, 메모리 맵을 바꾸거나, 부트로더와 애플리케이션을 나눌 때는 이 파일을 읽을 수 있어야 합니다. 디버깅할 때는 벡터 테이블 주소, handler 이름, stack pointer, Reset_Handler 진입 여부를 차례로 확인하면 문제 위치를 더 빠르게 찾을 수 있습니다.
실제로 확인할 때는 map 파일에서 벡터 테이블 배치 주소를 보고, 디버거로 초기 SP와 Reset_Handler 분기 지점을 추적해보는 것이 좋습니다. startup file, 링커 스크립트, interrupt handler 이름을 함께 비교하면 Reset 이후 main까지 이어지는 흐름을 더 정확하게 검증할 수 있습니다.