스타트업 코드 분석
- 전원을 인가하면 ARM core는 최초 Reset 신호(PORESETn)가 인가 된다.
- Reset_Handler가 호출된다.
0x0000004에 어떻게 Reset_Handler의 어드레스 값이 저장되는지 확인해 보았다.
스타트업 코드를 확인하면 아래와 같이 Vector Table이 정의 되어 있다.
![]() | ![]() |
스타트업 코드에 정의된 Vector Table | 레퍼런스 문서에 정의된 Vector Table |
Vector Table이란 프로그램이 동작중에 문제가 생기거나 인터럽트가 걸리기 되었을 때 Jump되는 Address를 정의한 Table 이다.
Cortex-M3에 정의된 Vector Table 가이드: https://developer.arm.com/documentation/dui0552/a/the-cortex-m3-processor/exception-model/vector-table?lang=en
.section .isr_vector,"a",%progbits
.type g_pfnVectors, %object
.size g_pfnVectors, .-g_pfnVectors
.section 이란 memory map에 공간을 차지하는 영역(chunk)이다.
.section name[, “flags”] : 새로운 코드 섹션 또는 데이터 섹션을 지정한다.
섹션 명(name)은 링크 디스크립터에 정의 되어 있어야 한다.
참고 홈페이지: https://damduc.tistory.com/398
참고 홈페이지: https://developer.arm.com/documentation/100068/0612/migrating-from-armasm-to-the-armclang-integrated-assembler/sections
.section .isr_vector,"a",%progbits
위 문법을 분석하면 메모리 공간에 “a” : allocatable 가능한 .isr_vector를 할당을 한다.
%progbits은 초기화된 data와 instruction 혹은 instruction만을 section이 담는다는 의미를 갖는다.
참고 홈페이지: https://developer.arm.com/documentation/101754/0618/armclang-Reference/armclang-Integrated-Assembler/Section-directives
.isr_vector는 아래와 같이 링크 스트립트(STM32F103C8TX_FLASH.ld)에 정의 되어 있다.
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of "RAM" Ram type memory */
/* => 계산하면 (0x20000000 + 20*1024) = 0x20005000 */
_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
/* Memories definition */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 64K
}
/* Sections */
SECTIONS
{
/* The startup code into "FLASH" Rom type memory */
.isr_vector :
{
. = ALIGN(4); /* 주소를 4의 배수로 맞추기 위함 작업 */
KEEP(*(.isr_vector)) /* Startup code */ /* 링크 시 가비지 컬랙션을 (--gc-sections)한다면, 제거 되지 않도록 표시
. = ALIGN(4); /* 주소를 4의 배수로 맞추기 위함 작업 */
} >FLASH /* .isr_vector를 FLASH로 정의된 메모리 영역으로 할당한다. */
참고 홈페이지: http://korea.gnu.org/manual/release/ld/ld-sjp/ld-ko_3.html#SEC21
참고 홈페이지: https://stackoverflow.com/questions/8458084/align-in-linker-scripts
참고 홈페이지: http://korea.gnu.org/manual/release/ld/ld-mahajjh/ld_3.html#SEC26
참고 홈페이지: https://software-dl.ti.com/ccs/esd/documents/sdto_cgt_linker_migration_gcc_to_tiarmclang.html
참고 홈페이지: https://en-support.renesas.com/knowledgeBase/19597376
.type g_pfnVectors, %object
g_pfnVectors는 data object이다.
참고 홈페이지: https://developer.arm.com/documentation/100067/0612/armclang-Integrated-Assembler/Type-directive
.size g_pfnVectors, .-g_pfnVectors
g_pfnVectors의 size를 할당한다. 해석하면 g_pfnVectors라는 symbol의 size를 현재 주소에서 g_pfnVector의 시작주소 값을 뺀 값으로 하겠다는 의미이다.
참고 홈페이지: http://web.mit.edu/rhel-doc/3/rhel-as-en-3/size.html
참고 홈페이지: https://stackoverflow.com/questions/11058361/meaning-of-main-expression
참고 홈페ㅣ지: https://hackmd.io/@SgyGB0h2QGWBfbHp9n_ArQ/BygAD3fU_
g_pfnVectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler
.word MemManage_Handler
.word BusFault_Handler
.word UsageFault_Handler
.word 0
.word 0
.word 0
.word 0
.word SVC_Handler
.word DebugMon_Handler
.word 0
.word PendSV_Handler
.word SysTick_Handler
.word WWDG_IRQHandler
.word PVD_IRQHandler
.word TAMPER_IRQHandler
.word RTC_IRQHandler
.word FLASH_IRQHandler
.word RCC_IRQHandler
.word EXTI0_IRQHandler
.word EXTI1_IRQHandler
.word EXTI2_IRQHandler
.word EXTI3_IRQHandler
.word EXTI4_IRQHandler
.word DMA1_Channel1_IRQHandler
.word DMA1_Channel2_IRQHandler
.word DMA1_Channel3_IRQHandler
.word DMA1_Channel4_IRQHandler
.word DMA1_Channel5_IRQHandler
.word DMA1_Channel6_IRQHandler
.word DMA1_Channel7_IRQHandler
.word ADC1_2_IRQHandler
.word USB_HP_CAN1_TX_IRQHandler
.word USB_LP_CAN1_RX0_IRQHandler
.word CAN1_RX1_IRQHandler
.word CAN1_SCE_IRQHandler
.word EXTI9_5_IRQHandler
.word TIM1_BRK_IRQHandler
.word TIM1_UP_IRQHandler
.word TIM1_TRG_COM_IRQHandler
.word TIM1_CC_IRQHandler
.word TIM2_IRQHandler
.word TIM3_IRQHandler
.word TIM4_IRQHandler
.word I2C1_EV_IRQHandler
.word I2C1_ER_IRQHandler
.word I2C2_EV_IRQHandler
.word I2C2_ER_IRQHandler
.word SPI1_IRQHandler
.word SPI2_IRQHandler
.word USART1_IRQHandler
.word USART2_IRQHandler
.word USART3_IRQHandler
.word EXTI15_10_IRQHandler
.word RTC_Alarm_IRQHandler
.word USBWakeUp_IRQHandler
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word 0
.word BootRAM /* @0x108. This is for boot in RAM mode for
STM32F10x Medium Density devices. */
.word expr 현재 주소에 4byte를 생성 후 expr로 채워 넣는다.
g_pfnVectors 주소에 4byte를 생성 후 expr로 채워 넣는다.
참고홈페이지: https://velog.io/@coral2cola/ARM-Instruction-Set-Architecture-1
.isr_vector 섹션은 링커스크립터에서 FLASH 메모리에 가장 처음에 위치해 있도록 정의되어 있다. 이 의미는 g_pfnVectors라는 것은 FLASH의 맨처음 주소인 0x8000000 주소에 위치한다는 것이다. 따라서 _estack은 0x8000000 위치에 들어가게 되며 address가 4 바트씩 증가하면서 해당 expr 값을 저장하는 것이다. 정리하면 아래 같다.
vector들이 flash memory에 저장된 위치
링커 스크립터에서 정의한 메모리 구역
Flash 메모리에 정의된 Section들
링커는 링커스크립트와 스타트업 코드에 정의된 Section들을 기준으로 Flash 메모리에 0x8000000 부터 시작하는 메모리 맵을 설정한다. 이 메모리 맵으로 설정된 실행 파일이 생성 되며 부팅 후 STM32는 0x0000000 주소 부터 0x8000000 부터 시작하는 메모리의 주소의 값을 복사한다. STM32에 리셋 신호가 들어오고 PC(Program Counter) 레지스터는 0x0000004에 있는 값으로 설정이 되는데 이 값이 Reset_Handler가 되어 부팅 시 Reset_Handler부터 시작이 되는 것이다.
–gc-sections 옵션 시 링크 스트립트에 정의된 KEEP을 정의하지 않으면 어떻게 삭제가 되는지 확인해 보았다.
KEEP(*(.isr_vector)) /* Startup code */ /* 링크 시 가비지 컬랙션을 (--gc-sections)한다면, 제거 되지 않도록 표시
아래 그림과 같이 Command Line에 ,–print-gc-sections 을 추가하면 사용하지 않는 삭제된 section들을 확인할 수 있다.
아래 그림과 같이 KEEP Command를 제거한 후 빌드를 해 보았다.
빌드 결과 아래 그림과 같이 로그가 출력되는 것을 확인할 수 있다.
빌드로그 확인 결과 .isr_vector가 삭제되었다는 메시지는 출력이 되지 않았다. 아래 그림과 같이 Memory Details에서는 .isr_vector가 삭제 되었다. –print-gc-sections 이 정보는 .s에 대한 정보는 출력되지 않는 것 같다.
아래 그림과 같이 스타트업 코드에서 .isr_vector를 삭제하며 링크 스크립트에는 아래 그림과 같이 KEEP을 유지하여 빌드를 한 후 Memory Details에서 is_vector를 확인한 결과 존재하지 않았다.
.isr_vector 정의 부분이 삭제된 스타트업 코드
링커 스크립터 코드
Flash 메모리에 정의된 Section들
링크 스크립트에는 KEEP 을 사용하였지만 .s나 .c에 정의되어 있지 않은 section은 삭제된다.
–gc-sections 옵션 시 .c 또는 .s 파일(input file)에서 정의는 되어 있으나 사용되지 않으면 링커에서 삭제를 한다. section을 함수명 또는 변수라고 생각하면 이해하기 쉬울 것 같다. 삭제를 방지하기 위해 KEEP 옵션을 사용하는 것이다.
–gc-sections 옵션 시 링커 스크립트에 section이 정의 되어 있어도 input file에서 정의 되어 있지 않으면 삭제 된다. input section이란 input file 안에 있는 section을 의미한다.
참고홈페이지: http://korea.gnu.org/manual/release/ld/ld-mahajjh/ld_2.html
참고홈페이지: https://blog.dasomoli.org/linker-linker-scripts-ld/
참고홈페이지: https://embed-avr.tistory.com/86
아래와 같이 빌드를 하여 테스트를 진행해 보았다. 맥북에서는 -gc-sections 옵션시 컴파일 진행이 되지 않는다.
참고홈페이지: https://hyeyoo.com/136