본문 바로가기
Robot/MCU

Cortex-M3 Link Script

by lifeseed 2013. 9. 2.

※ 아래의 내용은 직접 작성한 내용이며, 경어를 사용하지 않았습니다.

읽으시는동안 불편하시더라도 이해 부탁드립니다.

 

그리고 테스트를 위한 보드는 http://oroca.org 에서 공동구매한 stm32 smart robot board를 사용하였습니다.

 

 

cf) 관련 글 목록 

0. STM32F103CB 개발을 위한 ST Micro Resource 활용 

http://lifeseed.tistory.com/57 

2. Cortex-M3 Start Up Code 분석 1부

 http://lifeseed.tistory.com/56

3. Cortex-M3 Start Up Code 분석 2부 

 http://lifeseed.tistory.com/58

 

 

 

0. 시작하기 전에

1) CMSIS (Cortex Microcontroller Software Interface Standard)

- ARM에서 Cortex-M 관련 Library들을 제공하는데, 이를 CMSIS라고 부르며, 여기에는 Cortex M seriese에서 제공하는 Register Control관련 API와 각 Device에서 사용가능한 Start Up 코드 및 Link Script 들이 포함되어 있다.

Cortex-M3 Build를 위해 실제 여기에 포함된 Link Script 및 Start Up 코드를 이용하고자 한다.

 

2) Download

http://www.arm.com/cmsis 에 접속하면 CMSIS Package를 다운 받을 수 있다.

지금 배포하고 있는 버전 중 가장 최신 버전인 r3p2-00rel1 버전을 다운 받는다.

다운로드 

 

3) CMSIS Code Tree

 

CMSIS에는 Core, DSP, RTOS 관련 Library들이 포함되어 있으며, 각 Device들을 Support하기 위한 코드들이 Device Directory에 포함되어 있따.

여기서는 Cortex-M3의 GCC 버전을 살펴보고자 한다.


 

 

4) 이번 강좌의 목적

- Link Script들이 어떻게 구성되어 있는지 살펴보고, 한줄 한줄의 의미보다 나의 시스템에 맞게 어떻게 수정해서 적용하며, 코드에서 어떻게 참조하는지를 이해하는 것으로 강좌를 정리하고자 한다.

 

1. Link Script  구성

 

/* Linker script to configure memory regions. */
MEMORY
{
}

 

ENTRY(Reset_Handler)

SECTIONS
{
}

 

Memory 와 Section으로 구성되어 있다.

Memory 는 전체적인 코드의 분포(?)를 설정하며, SECTION의 경우 각각의 Component들이 어떻게 배치될 것인지 Define된다.

 

2. Memory

 

MEMORY
{
  FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 0x20000   /* 128k */
  RAM (rwx)  : ORIGIN = 0x20000000, LENGTH = 0x05000   /*  20k */
}

 

우선 눈여겨 볼 부분은 Memory 영역이다.

FLASH (rx) 와 RAM (rwx)로 나누어진다.

STM32F103CBT6 의 경우 128k의 embedded nor flash와 20k의 sram으로 구성되어 있다.

따라서 각각 시작 주소와 해당하는 크기를 써 주면 된다.

 

1) FLASH

여기서 FLASH 로 표기된 영역은 read & excute (rx) 속성을 가진다.

소위 말하는 Code Area + Read Only Data 영역이 여기에 포함될 것이다.

 

2) RAM

마찬가지로 RAM영역은 read, write & excute (rwx)속성을 가지며,

Writable Data 즉 Non Zero Initialized Data 및 Zero Initialized Data 영역  heap, stack 영역이 여기에 포함된다.

세부적인 내용은 SECTIONS 에서 확인 가능하다.

 

3. SECTIONS

 

 .text :
 {

  KEEP(*(.isr_vector))
  *(.text*)

   . . . . . .

  *(.rodata*)
 } > FLASH

 .ARM.extab :
 {
 } > FLASH

 

 __exidx_start = .;
 .ARM.exidx :
 {
 } > FLASH
 __exidx_end = .;

 

.text, .ARM.extab, .ARM.exidx 영역이 FLASH영역으로 할당되며, FLASH의 ORIGIN으로 정의된 start address 부터 배치된다.

 

1) .text

.isr_vector 및 read only data를 포함하고 있으며, FLASH 영역에서 첫번째로 할당된다. 즉 0x08000000 부터 순서대로 배치된다.

 

여기서 .isr_vector는 start up code에서 .section .isr_vector 로 정의된 vector handler table의 시작 주소를 의미 한다.

그리고 *(.rodata*) 라고 정의된 Read Only data 영역또한 .text에 포함됨을 알 수 있다.

 

FLASH 영역중 .ARM.extab 과  .ARM.exidx  영역은 정확히 무엇을 위한 영역인지 확인하지 못했다. 다만 컴파일 후 맵파일을 보면 아래와 같이 아무런 정보를 포함하지 않는다. 우선은 그냥 Skip... ^^;;

.ARM.extab
 *(.ARM.extab* .gnu.linkonce.armextab.*)
                0x0800366c                __exidx_start = .

.ARM.exidx
 *(.ARM.exidx* .gnu.linkonce.armexidx.*)
                0x0800366c                __exidx_end = .

 

2) .data, .bss, .heap, and stack

RAM영역에 포함되는 것은 크게 data영역, heap 영역, 그리고 stack 영역으로 나눌 수 있으며, data영역은 다시 0으로 초기화 되는 .bss영역과 0이 아닌 값으로 초기화 되는 .data 영역으로 나눌 수 있다.

아래는 link script에서 RAM영역에 포함된 section들이다.

 

 __etext = .;

 .data : AT (__etext)
 {
  __data_start__ = .;

  __data_end__ = .;

 } > RAM

 .bss :
 {
  __bss_start__ = .;
  __bss_end__ = .;

 } > RAM

 .heap :
 {
  __end__ = .;
  __HeapLimit = .;
 } > RAM

 .stack_dummy :
 {
 } > RAM

 __StackTop = ORIGIN(RAM) + LENGTH(RAM);
 __StackLimit = __StackTop - SIZEOF(.stack_dummy);

 PROVIDE(__stack = __StackTop);

 ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")

 

 컴파일시 전역 변수들은 지정을 하든 하지 않든 초기 값을 가지게 되는데, 코드에서 미리 지정한 경우 지정한 값으로 초기화가 되며 그렇지 않는 경우는 0으로 초기화 된다. 이와 관련된 변수 영역이 0으로 초기화 되는 것은 .bss, 그렇지 않은 경우는 .data 에 포함된다.

영역이.bss , .data 로 나뉘어 졌다 하더라도 실제 코드에서 초기화 되는가의 여부는 start up code에서 이를 처리해 주느냐에 달려 있다.

이 후 start up코드 분석시 0으로 초기화 되는 부분과 0이 아닌 값들이 초기화 되는 부분이 구현되어 있는 것을 확인할 수 있을 것이다.

 

 마지막으로 살펴 볼 것이 stack 영역이다. stack의 경우 다른 영역들이 순서대로 차곡 차곡 쌓이는 것과 달리 제일 마지막 주소를 Top으로 그 크기 많큼 감소하는 구조로 되어 있다.

즉, __StackTop = ORIGIN(RAM) + LENGTH(RAM); 으로 Stack의 Top 정보를 지정하고, 그 크기 많큼감소한 주소가 Stack의 limit 영역이 되는 것이다.

 

 

.text FLASH
.data  
.bss  
.heap RAM
reserved  
.stack  

 

4. predefined symbol

- link script 에 아래와 같이 symbol에 관련 된 주석을 확인 할 수 있다. 

 

/* Linker script to place sections and symbol values. Should be used together
 * with other linker script that defines memory regions FLASH and RAM.
 * It references following symbols, which must be defined in code:
 *   Reset_Handler : Entry of reset handler
 *
 * It defines following symbols, which code can use without definition:
 *   __exidx_start
 *   __exidx_end
 *   __etext
 *   __data_start__
 *   __preinit_array_start
 *   __preinit_array_end
 *   __init_array_start
 *   __init_array_end
 *   __fini_array_start
 *   __fini_array_end
 *   __data_end__
 *   __bss_start__
 *   __bss_end__
 *   __end__
 *   end
 *   __HeapLimit
 *   __StackLimit
 *   __StackTop
 *   __stack
 */

 

그리고 이 주석에 정의된 값들이 실제 Link Script 중간 중간에 __etext = .; ,  __bss_start__ = .; 등의 표현으로 정의되어 있다.

 

실제 코드에서 이 symbol등을 이용하여 각 역역에 대한 초기화나, 필요시 data copy 등의 동작을 할 수 있다.

아래는 컴파일시 생성되는 symbol 정보를 담은 파일의 일부이며, 아래와 같이 symbol이 할당됨을 확인할 수 있다.

 

0800366c A __etext
0800366c A __exidx_end
0800366c A __exidx_start

. . .

20000000 D __data_start__
. . .
20000128 B __bss_start__
20000128 D __data_end__
. . .
2000012c B __bss_end__
20000130 N __HeapBase
20000130 N __end__
20000130 N end
20000d30 N __HeapLimit
20004c00 A __StackLimit
20005000 A __StackTop