25
링커 디렉티브 파일을 사용한 링커 설정 링커 디렉티브(.ld) 파일을 어떻게 사용하는지, 어떻게 프로그램 섹션을 정의하는지, 그리 고 어떻게 섹션을 메모리 블럭에 할당하는지를 설명합니다. 메모리 블럭의 이름, 속성, 사 이즈는 메모리 맵에 정의됩니다. 섹션의 이름, 속성, 배치는 섹션 맵에 정의됩니다. 이 문 서에서는 링커 디렉티브 파일의 문법을 설명하고, 4종류의 링커 디렉티브 관련 설명 후, 마지막으로 몇가지 최근 갱신된 내용을 안내합니다. [링커 디렉티브 파일의 문법] [OPTION 지시자를 통한 링커 옵션의 설정] [DEFAULTS 지시자를 통한 Defaults의 설정] [MEMORY 지시자를 통한 메모리 맵 정의] [SECTIONS 지시자를 통한 섹션 맵의 정의] [속도 또는 사이즈를 개선하기 위한 섹션 맵의 수정] [런타임 환경 프로그램 섹션의 커스터마이즈] 프로젝트 위자드에따라 프로젝트를 작성하면, 타겟 보드용의 다양한 프로그램 레이아웃 에 대응하는 링커 디렉티브 파일이 디폴트로 생성됩니다. 자체 링커 디렉티브 파일을 작성 하시고자 하는 경우에는, 이 파일들 중에 하나를 복사하여 내용을 변경하시는 것을 추천합 니다. 이 디폴트 파일들에 대한 추가 정보는 기본 섹션 맵의 프로그램 섹션을 제거하실 때에는 Green Hills의 런타임 환경이 해당 섹 션을사용하므로, 경고를 사용하여 주시기 바랍니다. 주의: elxr을 명령어 창에서 기동하며, 복수의 링커 디렉티브 파일을 지정하는 경우, elxr는 지 정한 순서대로 처리를 합니다. 메모리 맵과 섹션 맵을 각기 다른 파일에 정의하는 경우에 는 메모리 맵을 포함하는 파일을 최우선적으로 지정하실 필요가 있습니다. 링커 디렉티브 파일의 문법 이번 장에서는 일반적인 링커 디렉티브 파일의 문법과 식을 포함합니다. 특별한 지시자에 대한 문법을 확인하고 싶으시다면, 이어지는 다음 장으로 진행하여 주시기 바랍니다. Expressions 부작용을 가진 연산자 그대로, C의 표준 대입 연산자 모두를 해당 결합 순서와 함 께 포함 합니다. 아래의 장에서는 이름 지시자 안의 어디에 식이 사용되는지에 관 하여 설명하고 있습니다. Comments 숫자 심볼 (#)이나 더블 슬래쉬(//)로 시작합니다. Linker->Preprocess Linker Directives 옵션을 사용하는 경우에는 주석을 기재하실 때에 슬래쉬를 사용하실 필요가 있습니다. 도트 심볼(.) 메모리 영역이나 섹션의 레이아웃이 놓여지는 링커의 현재 위치를 링커에게 알립 니다.

링커 디렉티브 파일을 사용한 링커 설정kmd.co.kr/bbs/table/download/upload/LinkerDirective%C6%C4%C0%CF%BC%B3... · 메모리의 크기를 지정할 때, 바이트 수

  • Upload
    others

  • View
    0

  • Download
    0

Embed Size (px)

Citation preview

링커 디렉티브 파일을 사용한 링커 설정

링커 디렉티브(.ld) 파일을 어떻게 사용하는지, 어떻게 프로그램 섹션을 정의하는지, 그리

고 어떻게 섹션을 메모리 블럭에 할당하는지를 설명합니다. 메모리 블럭의 이름, 속성, 사

이즈는 메모리 맵에 정의됩니다. 섹션의 이름, 속성, 배치는 섹션 맵에 정의됩니다. 이 문

서에서는 링커 디렉티브 파일의 문법을 설명하고, 4종류의 링커 디렉티브 관련 설명 후,

마지막으로 몇가지 최근 갱신된 내용을 안내합니다.

[링커 디렉티브 파일의 문법]

[OPTION 지시자를 통한 링커 옵션의 설정]

[DEFAULTS 지시자를 통한 Defaults의 설정]

[MEMORY 지시자를 통한 메모리 맵 정의]

[SECTIONS 지시자를 통한 섹션 맵의 정의]

[속도 또는 사이즈를 개선하기 위한 섹션 맵의 수정]

[런타임 환경 프로그램 섹션의 커스터마이즈]

프로젝트 위자드에따라 프로젝트를 작성하면, 타겟 보드용의 다양한 프로그램 레이아웃

에 대응하는 링커 디렉티브 파일이 디폴트로 생성됩니다. 자체 링커 디렉티브 파일을 작성

하시고자 하는 경우에는, 이 파일들 중에 하나를 복사하여 내용을 변경하시는 것을 추천합

니다. 이 디폴트 파일들에 대한 추가 정보는

기본 섹션 맵의 프로그램 섹션을 제거하실 때에는 Green Hills의 런타임 환경이 해당 섹

션을사용하므로, 경고를 사용하여 주시기 바랍니다.

주의:

elxr을 명령어 창에서 기동하며, 복수의 링커 디렉티브 파일을 지정하는 경우, elxr는 지

정한 순서대로 처리를 합니다. 메모리 맵과 섹션 맵을 각기 다른 파일에 정의하는 경우에

는 메모리 맵을 포함하는 파일을 최우선적으로 지정하실 필요가 있습니다.

링커 디렉티브 파일의 문법

이번 장에서는 일반적인 링커 디렉티브 파일의 문법과 식을 포함합니다. 특별한 지시자에

대한 문법을 확인하고 싶으시다면, 이어지는 다음 장으로 진행하여 주시기 바랍니다.

Expressions

부작용을 가진 연산자 그대로, C의 표준 대입 연산자 모두를 해당 결합 순서와 함

께 포함 합니다. 아래의 장에서는 이름 지시자 안의 어디에 식이 사용되는지에 관

하여 설명하고 있습니다.

Comments

숫자 심볼 (#)이나 더블 슬래쉬(//)로 시작합니다. Linker->Preprocess Linker

Directives 옵션을 사용하는 경우에는 주석을 기재하실 때에 슬래쉬를 사용하실

필요가 있습니다.

도트 심볼(.)

메모리 영역이나 섹션의 레이아웃이 놓여지는 링커의 현재 위치를 링커에게 알립

니다.

OPTION 지시자에 의한 링커 옵션의 설정

커맨드 라인의 옵션은, 아래의 구문을 사용하여 링커 디렉티브 파일에 기재 가능합니다.

OPTION (“option”)

OPTION 지시자의 안에 연산식을 사용하는 것은 불가능합니다.

주의:

이 지시자는 과거의 호환성을 공급하는하는 것에 주의하여 주십시오. 링커 옵션은 드라

이버를 사용하여 지정되는 것을 추천합니다.

예 1. OPTION 지시자를 사용

이번 예는, -extractweak와 -manysegments 옵션을 지정하는 OPTION 지시자를 정의

합니다.

OPTION (“-extractweak -manysegments”)

주의:

OPTION 문은, 아래의 구문을 사용하면, 링크 대상 파일의 지정도 사용 가능합니다.

OPTION (“file”)

DEFAULT 지시자에 의한 Defaults 의 설정

Defaults는 링커 디렉티브 파일에 섹션과 메모리 맵을 정의할 때의 절대값을 대체할 문자

열입니다. Defaults는 아래의 문법으로 지정합니다.

DEFAULTS {name=value...}

디폴트 foo를 값 0x2000 으로 설정하는 경우에는, 아래의 행을 추가합니다.

DEFAULTS {foo=0x2000}

아래의 예와 같이, 개별 행에 기재하는 것으로 복수의 정수를 지정하는 것도 가능합니다.

DEFAULTS {

foo=0x2000

bar=0x4000

}

지시자 안에 선행하여 설정된 디폴트를 포함하는 DEFAULTS 지시자에서는 연산식이 사

용가능합니다.

DEFAULTS {

foo=0x2000

// Set bar to 0x4000

bar = foo + 0x2000

}

메모리의 크기를 지정할 때, 바이트 수 다음에 메가 바이트와 킬로 바이트를 의미하는 M

과 K 를 사용하는 것이 가능합니다. 크기를 16진수로 지정하기 위하여 0x를 앞에 기재하

는 것도 가능합니다.

메모리의 합계를 지정하는 경우, 바이트 수에 M를 뒤에 기재하여 메가 바이트를 나타내

거나, K 를 뒤에 기재하여 킬로 바이트를 나타내는 것이 가능합니다. 수치는 0x를 앞에 기

재하여 합계를 16진수로 나타내는 것도 가능합니다.

주의:

DEFAULTS 지시자에서 디폴트를 지정하면, -C 옵션을 전달하는 것으로 해당 값을 변

경하는 것이 가능합니다.

예 2. DEFAULT 지시자의 사용

이번 예는, 2개의 defaults를 정의 하는 DEFAULTS 지시자를 지정합니다.

DEFAULTS {

// Set heap_reserve to 1048576

heap_reserve = 1M

// Set stack_reserve to 524288

stack_reserve = 512K

}

MEMORY 지시자에 의한 메모리 맵

메모리 맵은 타겟 상의 메모리 영역에 이름을 붙여서 정의합니다. 메모리 영역을 정의 하

기 위하여서는 다음의 요소를 각각 지정하여 주십시오.

MEMORY

{

...

memname: ORIGIN=origin_expression, LENGTH=length_expression

...

}

여기서, 인수의 의미는 다음과 같습니다.

memname

메모리 영역의 이름을 지정합니다.

origin_expression

메모리 영역의 시작 어드레스를 지정합니다.

length_expression

메모리 영역의 길이를 지정합니다.

MEMORY 지시자 안의 식은 아래를 포함하는 것이 가능합니다.

DEFAULTS

지시자 안의 디폴트 설정입니다.

도트 심볼(.)

이 컨텍스트에서 도트 심볼은 직전의 메모리 영역의 다음으로 이용 가능한 첫 어드

레스를 의미합니다.

메모리 맵을 링커에 전달하는 경우, 이름을 붙여서 정의된 메모리 영역만을 섹션 맵 안에

서 참조 가능합니다.

예 3. MEMORY 지시자를 사용

이번 예에서는, MEMORY 지시자는 2개의 영역으로 메모리 맵을 정의합니다.

DEFAULTS {

heap_reserve = 1M

stack_reserve = 512K

}

MEMORY

{

dram_memory : ORIGIN = 0x80000000, LENGTH = 10M

flash_memory : ORIGIN = 0xbfc00000, LENGTH = 10M

}

이 메모리 맵은, 0x80000000 에서 시작하는 dram_memory와 0xbfc00000 에서 시작하

는 flash_memory의 메모리 영역을 정의하고 있습니다. 두가지 모두 10 메가 바이트의 크

기를 갖습니다.

예약된 메모리 블럭

디폴트의 Green Hills 링커 디렉티브 파일은 예약 메모리 블럭을 포함하는 경우가 있습니

다. 전형적으로, 이것을 통하여 모니터와 같은 구성완료된 소프트웨어에서 이미 사용되고

있는 메모리의 사용이 회피되어집니다.

예약 메모리 블럭은, 개별적으로 섹션이 할당되지 않는 것 이외에는 다른 메모리 블럭과

거의 동일합니다.

MEMORY {

// 512KB of dram starting at 0x80000000

dram_rsvd1 : ORIGIN = 0x80000000, LENGTH = 32K

dram_memory : ORIGIN = . , LENGTH = 10M – 32K

dram_rsvd2 : ORIGIN = . , LENGTH = 0

// 10MB of flash starting at 0xbcf00000

flash_rsvd1 : ORIGIN = 0xbfc00000, LENGTH = 32K

flash_memory : ORIGIN = . , LENGTH = 10M – 32K

flash_rsvd2 : ORIGIN = . , LENGTH = 0

}

SECTIONS 지시자에 의한 섹션 맵의 정의

섹션 맵은, 각 오브젝트 파일 안의 각 섹션을 프로그램 섹션에 맵핑합니다. 섹션 맵은, 프

로그램 섹션을 메모리 영역에도 맵핑합니다. 섹션 맵의 포맷은 다음과 같습니다.

SECTION

{

secname [start_expression] [attributes] : [{ contents }] [> memname, ... | >.]

...

}

secname

섹션의 이름

start_expression

섹션의 시작 어드레스를 지정합니다. start_expression과 memname를 모두 지정하면,

start_expression이 우선시됩니다.

attributes

섹션의 속성을 지정합니다. [섹션의 속성 사용]에서 설명한, 임의 수의 속성을 포함하는

것이 가능합니다.

{ contents }

섹션의 중심을 지정합니다. 이것은, 어떤 오브젝트 파일로부터 어떤 섹션을 섹션에 배치

시킬지를 지명하는 섹션의 인클루드 커맨드와 오브젝트의 작성 또는 변경을 수행하는 할

당을 포함합니다. 커맨드와 할당은 수에 제한 없이 사용 가능합니다.

> memname,... | >.

메모리 맵에 정의되어있는 memname이라는 이름의 메모리 영역에 섹션을 할당합니다.

start_expression과 memname을 모두 지정하면, start_expression이 우선시됩니다.

SECTIONS 지시자 안의 식은, 다음을 포함할 수 있습니다.

DEFAULTS 지시자에 정의된 defaults.

MEMORY 지시자 안에 정의된 메모리 영역

도트 심볼(.). 이 컨텍스트에서는, 도트 심볼은 오브젝트와 섹션의 레이아웃에 대한

링커의 현재 위치를 의미합니다.

링커에 전달되는 오브젝트 파일에 정의 되어있는 ELF 심볼.

[SECTIONS 지시자 함수]에 리스트되어 있는 함수.

예 4. SECTIONS 지시자를 사용

이번 예에서는, SECTIONS 지시자가 타겟 상의 메모리 안에 .text, .data, .bss 섹션을

어디에 배치할지를 링커에 알려주는 섹션 맵을 정의합니다.

DEFAULTS {

heap_reserve = 1M

stack_reserve = 512K

}

MEMORY

{

dram_memory : ORIGIN = 0x80000000, LENGTH = 10M

flash_memory : ORIGIN = 0xbfc00000, LENGTH = 10M

}

SECTIONS

{

// Place .text into dram_memory

.text : > dram_memory

// Place .data into dram_memory after .text, or flash_memory if it does not fit

.data :

// Place .bss after .data Fail if it does not fit in the same memory block

.bss : >.

}

섹션 위치의 지정

다음의 리스트는, start_expression과 memname을 어떻게 지정하고 있는지에따라 링커

가 어디에 섹션을 할당할지의 상태를 설명 합니다.

start_expression 만을 지정한 경우, 링커는 start_expression에서 시작하는 어드

레스에 섹션을 할당합니다.

memname 만을 지정한 경우, 링커는 memname 안의 이용가능한 첫 어드레스에

섹션을 할당합니다.

start_expression과 memname를 모두 지정한 경우, 링커는 start_expression에서

시작하는 어드레스에 섹션을 할당합니다.

start_expression도 memname도 지정하지 않은 경우, 링커는 같은 메모리 영역 안

에서의 직전 섹션의 바로 다음에 섹션을 할당합니다. 섹션이 맞지 않는 경우, 링커

는 에러를 반환합니다.

memname에 대하여 start_expression을 지정하지 않고 콤마로 끝낸 메모리 영역

의 리스트를 지정한 경우, 링커는, 그것을 유지하는데에 충분한 여지를 가진 첫 메

모리 영역에 섹션을 할당합니다.

링커가 시작 어드레스를 start_expression로 결정하든, memname으로 결정하든, 해당

내용이 요구하는 얼라이먼트를 만족하도록 어드레스가 증대됩니다. 예를 들어, 다음과 같

이 지시자를 사용한 경우,

SECTIONS {

.text 0x10001 :

}

최후의 실행 형식 파일의 .text 섹션은, 링커가 이 섹션에 배치하는 첫 오브젝트 파일의

.text 섹션이 4바이트의 얼라이먼트를 요구하고 있는 경우, 0x10001이 아닌, 0x10004에

배치됩니다.

섹션에 대하여 복수의 메모리 블럭을 지정

어떤 섹션에 대하여 하나의 메모리 블럭이 지정되어, 그 섹션이 해당 메모리 블럭에 맞지

않는 경우, 링커는 에러를 반환합니다. 메모리 블럭이 복수개 지정되어 있으면, 링커는 해

당 섹션을 유지하는데 충분한 여지를 가진 첫 메모리 블럭에 해당 섹션을 배치합니다. 예

를 들면,

SECTIONS {

...

// Place .rodata in fast_but_small_memory

.rodata : > fast_but_small_memory

// Place .text in fast_but_small_memory if there is enough remaining space

// If there is not enough space, place .text in slow_but_large_memory

.text : > fast_but_small_memory, slow_but_large_memory

...

}

스몰 데이터 영역 (SDA) 최적화를 지원하는 타겟에서는, 콤마로 끝낸 메모리 영역의 리스

트를 SDA 섹션에 사용하는 경우에 주의가 필요합니다. 예를 들어, 다음과 같이 쓰는 것은

위험합니다.

SECTIONS {

...

.sbss : > fast_but_small_memory, slow_but_large_memory

.sdata : > fast_but_small_memory, slow_but_large_memory

...

}

왜냐하면 .sdata와 .sbss는 메모리 안에서 연속하여 있을 필요가 있기 때문입니다. 이 섹

션 맵을 사용하면, 링커는 fast_but_small_memory 영역에 .sbss를,

slow_but_large_memory에 .sdata를 배치시킵니다.(.sbss가 fast_but_small_memory에

는 맞지 않으며, .sdata가 맞는 경우에는 반대의 상태가 됩니다.) 따라서, 이 문법을 SDA

섹션에 사용하지 말아 주십시오. 추가적인 정보는 [스몰 데이터 에어리어(SDA)에의한 최

적화]를 참조하여 주십시오.

섹션 인클루드 명령을 사용

섹션을 인클루드하는 명령어는 섹션 맵 안 행의 { contents } 파라메터 일환입니다. 디폴

트로, 링커는 각 오브젝트파일로부터 각 섹션을 프로그램 섹션으로서 같은 이름에 배치합

니다. 같은 이름에 의한 프로그램 섹션이 존재하지 않는 경우, 링커는 해당 오브젝트 파일

을 섹션을 프로그램에 배치하지 않습니다.

이 동작을 변경하고자 하는 경우, 링커가 프로그램의 각 섹션을 배치하는데 어떠한 오브

젝트 파일로부터 어떤 섹션을 필요로 하는가가 요구되기 때문에 섹션 인클루드 명령어를

사용하여 주십시오. 링커는 섹션 인클루드 명령어를 링커 디렉티브 파일안의 출현 순서로

실행합니다.

거기서는 문법 filename(section_name)이 사용됩니다.

// Place the .data section from foo.o into .mydata

.mydata : { foo.o(.data) }

// Then, place .data section from all remaining object files into .data

.data :

섹션 인클루드 명령어를 공백으로 분리하여 링커에 실행시키고자 하는 순서로 기재합니

다.

// Place the .data section from foo.o and bar.o into .mydata

// The foo.o .data section goes first

.mydata : { foo.o(.data) bar.o(.data) }

특정 라이브러리 안의 특정 오브젝트 파일로부터 섹션을 프로그램 섹션에 배치시키고자

하는 경우에는, library_name(filename(section_name)):의 형식으로 라이브러리를 인클

루드 합니다.

// Place the .data section from foo.o contained within lib.a into .mydata

.mydata : { lib.a(foo.o(.data)) }

주의 :

라이브러리의 전체 경로를 인클루드하지 말아 주십시오. 라이브러리 명 만을 사용하여

주십시오. 라이브러리 명은 대문자와 소문자가 엄밀하게 구별되지 않습니다.

섹션 인클루트 명령어에 와일드 카드를 사용

링커에 전달되는 오브젝트 파일을 모두 인클루드하기 위하여서는 filename 대신에 애스

터리스크(“*”)를 사용하여 주십시오.

// Place .data sections from all object files into .data

.data : { *(.data) }

프로그램 섹션과 오브젝트 파일은 동일한 이름을 가지므로, 이 경우에는 { contents } 인

수를 지정하실 필요 없이, 아래의 문법으로 충분합니다.

// Place .data sections from all object files into .data

.data

프로그램 섹션과 오브젝트 파일이 다른 이름을 가진 경우에는, { contents } 인수를 지정

하지 않으면 안됩니다.

// Place .data sections from all object files into .mydata

.mydata : { *(.data) }

와일드 카드는 filename과 section_name 중에서 사용하는 것이 가능합니다. 애스터리스

크(“*”)는 복수의 문자에 매치하여 물음표(“?”)는 임의의 1문자에 매치합니다. 이 방법에

와일드 카드를 사용할 때에는, 섹션 인클루드 명령어를 2중 인용부호(“)로 감싸주십시오.

// Place .text sections from all objec files matching “code_*.o” into .mytext

.mytext : { “code_*.o(.text)” }

동일한 이름을 포함하는 오브젝트 파일이 내부에 복수의 섹션을 가진 경우에는, 섹션 인

클루드 명령어 안에 와일드 카드를 사용하여, 모든 출력을 실행 형식 안에 동일한 섹션에

할당하는 것이 가능합니다.

// Place all sections matching “.text_*” into .mytext

.mytext :{ * (“.text_*”) }

라이브러리를 사용하는 경우에도 와일드 카드를 사용할 수 있습니다.

// Place .data sections from object files contained within lib.a into .mydata

.mydata : { lib.a(*(.data)) }

// Place .data sections from all other object files into .data

.data :

섹션 인클루드 명령어 안의 COMMON 섹션 사용

완전히 링크된 실행 형식의 .bss 섹션은 입력된 각 오브젝트 파일의 .bss 섹션으로부터의

모든 데이터를 포함하고 있습니다. COMMON 섹션으로부터의 초기화되지 않은 글로벌 데

이터도 포함합니다. 링커에 COMMON 데이터를 .bss의 데이터와는 별도의 섹션에 배치시

키고자 하는 경우에는 섹션 인클루드 명령어 안에 COMMON 키워드를 사용합니다.

// Place all COMMON data into .mybss

.mybss :{ *{COMMON) }

// Place all .bss data into .bss

.bss :

오브젝트 파일 main.o로부터의 COMMON 데이터만을 .mybss에 배치하고자 하는 경우

에는 아래의 입력을 합니다.

.mybss : { main.o(COMMON) }

이것은, .sbss 섹션과 SMALLCOMMON, .zbss 섹션과 ZEROCOMMON 각각의 조합도

동일합니다.

대입의 사용

대입 연산자에 대한 문법은 심볼 = 식; 입니다. 심볼을 절대 어드레스나 섹션의 상대 어드

레스에 설정 가능합니다.

심볼을 절대 어드레스에 설정하는 경우, SECTION 지시자 행 그 자체에 대입을 기

재하여 주십시오. 링커는 식을 어드레스와 평가하여, 심볼을 해당 어드레스에 설정

합니다. 도트 심볼(.)은, 마지막에 정의된 섹션의 후미를 가리키는 절대 어드레스를

부여합니다.

심볼을 섹션에 상대 어드레스로 설정하는 경우, 대입을 해당 섹션의 { contents }

파라메터 안에 기재하여 주십시오. 링커는 식을 오프셋 n과 평가하여, 심볼을 섹션

의 처음부터 n 바이트의 어드레스에 설정합니다. 도트 심볼은 섹션의 처음부터 현

재에 해당하는 오프셋을 부여합니다.

그것이 존재하든 하지 않든, 심볼에 어드레스를 할당하는 것은 가능합니다.

존재하지 않는 심볼에 어드레스를 할당하면, 링커는 해당 심볼을 작성합니다.

어드레스를 기존의 심볼에 할당하면, 링커는 심볼에 관련된 데이타를 움직이지 않

고 해당 심볼을 재할당 합니다. 예를들어, main의 어드레스를 할당하면, 링커는 새

로운 어드레스를 가리키는 것 처럼 main에 대한 리로케이션을 발생합니다만, main

에 대한 해당 어드레스로의 실 코드는 이동하지 않습니다.

섹션 안의 현재 위치에 패딩을 추가하는 경우에는, 도트 심볼의 값을 증가하여 주십시오.

도트의 값을 감소하려하면 링커는 에러를 발생합니다. 아래의 예에서는, 심볼 foo를

.mysection의 처음에 설정하고 foo와 bar의 사이에는 4바이트의 패딩을 추가하고 있습니

다.

.mysection : { foo = .; . += 4; bar = .; }

이 패딩이 없으면, 링커는 foo도 bar도 동일한 어드레스에 할당합니다.

예 5. 절대 / 상대 할당에서의 대처

이 예에서는 심볼을 절대 어드레스와 섹션의 상대 어드레스에 설정하는 방법을 소개하고

있습니다.

SECTIONS {

// Set alias to the same absolute address as printf

alias = printf;

// Assignments end with semicolons, but section inclusion commans do not.

.text : { alpha = 0; *(.text) beta = .; *(.text2) bad = printf; } > dram_memory

// Set gamma to address 0

gamma = 0;

// Set delta to the end of the .text section

delta = .;

}

어느 것도 섹션의 { contents } 안에서는 정의 되어있지 않으므로, alias, gamma, 그리고

delta는 절대 어드레스로 할당 됩니다. 어느 것도 { contents } 파라메터 안에 정의되어있

지 않으므로, alpha, beta, bad는 .text의 처음 부분에 상대 어드레스로 할당 됩니다.

링커는, 다음과 같이 어드레스를 .text 안에 심볼로 할당합니다.

alpha는 .text의 시작부터 오프셋 0에 위치합니다.

beta는 .text 섹션의 입력 값 후 .text 섹션에 배치 됩니다만, 이것은 .text2 섹션 입

력의 시작과 동일한 어드레스 입니다.

bad 는 .text의 처음부터 printf 바이트의 오프셋 위치에 위치합니다. 대입이 섹션

상대이므로, 이것은 printf의 어드레스와 동일 위치는 아닙니다. 예를 들어, .text가

0x4000에서 시작하고 printf가 0x4020에 배치되어있는 경우, bad는

.text+0x4020 또는 0x8020에 배치됩니다.

SECTIONS 지시자 함수

링커는 SECTION 지시자 안에서의 식 평가 중에 다음과 같은 함수를 인식합니다. 이러한

명칭에는 대문자, 소문자의 구별은 없습니다.

absolute(expr)

섹션에 관련된 오프셋 값이 지정되면, absolute는, expr에 포함되어진 섹션의 어드레스

를 추가하여 절대 어드레스를 반환합니다. 괄호로 감싸여 있는 섹션의 바깥쪽에 absolute

를 사용하면, 에러가 발생합니다.

addr(sectname)

섹션 sectname의 메모리 어드레스를 반환합니다.

align(value)

value 바이트의 경계까지 정렬된 현재의 위치(.)를 반환합니다. value는 2의 배수일 필

요가 있습니다. 이것은 아래와 등가 입니다.

(. + value – 1) & ~(value - 1)

alignof(sectname)

섹션 sectname의 얼라이먼트를 반환합니다.

endaddr(sectname)

섹션 sectname의 현재 종단 또는 메모리 블럭 sectname의 종단 메모리 어드레스를 반

환합니다.

error(“string”)

링커의 에러를 발생하여, 현재 섹션 명, 어드레스, 오프셋과 함께 string을 표시합니다.

final(finalexpression [,earlyespression=0])

마지막 레이아웃의 경우에만, 주어진 식을 평가합니다. 생략 가능한 2번째 인수는, 선행

되는 모든 패스들에서 평가됩니다.

isdefined(symbol)

symbol이 존재하면 1을 반환하고, 아니면 0을 반환합니다.

isweak(symbol)

symbol이 weak global symbol이면 1을 반환하고, 아니면 0을 반환합니다.

memaddr(sectname)

addr을 참조하여 주십시오

memendaddr(sectname)

endaddr을 첨조하여 주십시오

min(value1, value2)

max(value1, value2)

각각 주어진 2개의 값 중에 최소/최대를 반환합니다.

pack_or_align(value)

일반적으로, 섹션 맵의 start_expression으로서만 사용됩니다. 조정된 현재 위치(.)을

반환하기 때문에, 섹션은 사이즈 value의 페이지 경계를 넘는 경우는 없습니다. 이것은

다음과 등가입니다.

((. % value) + sizeof(this_section) > value?align(value) :. )

provide(name = expr)

심볼의 이름이 아직 정의되어있지 않으면 이것은 name = expr과 등가가 됩니다. 그렇

지 않은 경우에는 expr와 등가가 됩니다.

sizeof(sectname)

섹션 sectname의 현재 사이즈를 반환합니다.

예 6. 기존 심볼 어드레스의 인클루드

타겟과 유효하게 되어있는 최적화에 의존하여 링커는 프로그램의 레이아웃을 여러번 수

행하는 경우가 있습니다. 필요한 경우, final() 함수를 사용하여 링커가 마지막 레이아웃 시

에만 식을 평가하는 것을 보증하여 주십시오.

예를 들어, 심볼 func이 존재하고 있고 해당 어드레스를 1 증가하고 싶다고 하면, 아래의

대입으로 링커는 func 어드레스를 여러번 증대합니다.

// Incorrect – might increment multiple times

.text : { isdefined(func) ? (func += 1) : 0; }

그 대신에, final() 함수를 사용하면, 링커가 func의 어드레스를 1회 증가하는 것을 보증할

수 있습니다.

// Correct – only increments during the final layout

.text : { final (isdefined(func) ? (func += 1):0); }

섹션의 속성 사용

다음의 속성을 사용하는 것으로, 섹션의 동작을 설정하는 것이 가능합니다.

ABS

이 섹션에 절대 어드레스가 있고, 이동이 불가능하도록 출력 파일의 플래그를 설정합니

다. 프로그램 로더나 출력 이미지를 조작하는 그외의 유틸리티는, 위치에 의존하지 않는

코드나 데이터에 관련된 이동을 수행할 때에, 이 섹션을 인클루드 하지 않습니다.

ALIGN(n)

섹션의 시작 어드레스를 n에 주어진 바이트 경계에 맞추어 정렬시킵니다.

AT(expr)

LOAD(expr)

이 속성들은, 섹션이 로드되는 메모리 안 어드레스를 가리키는 식을 지정합니다. 이것이

관계하는 것은 섹션이 링크되는 어드레스와 섹션을 로드할 어드레스가 다른 경우에 한합

니다.

LOAD의 경우와 다르게, 섹션 맵안에는 AT를 “:”의 다음에 놓지 않으면 안됩니다. 이것

은 주로, GNU 링커 디렉티브 파일과의 호환성 향상을 위한 조치입니다.

CLEAR

NOCLEAR

이 섹션의 CLEAR 속성을 설정 또는 제거합니다. CLEAR이 존재하는 경우, 엔트리는

런타임 클리어 테이블에 생성되어, 메모리 영역을 특정 값으로 초기화하는 스타트업 코드

에 사용됩니다. ([런타임 클리어 테이블과 런타임 카피 테이블]을 참조하여 주십시오.)

CLEAR는 .bss, .zbss, .sbss로 암묵적으로 지정되어집니다. COMMON,

ZEROCOMMON, 또는 SMALLCOMMON의 각 데이터를 별도의 섹션에 인클루드하도록

링커에 지명할 때에는, 해당 섹션에 대하여 CLEAR 속성을 지정하도록 하여 주십시오.

FILL (value)

섹션을 바이트 패턴 value로 채웁니다. 대상 섹션에는 명시적으로, 또는 디폴트로

CLEAR 속성이 설정되어 있지 않으면 안됩니다. CELAR 속성이 설정되어 있지 않은 경

우, FILL 속성은 무시됩니다.

MAX_ENDADDRESS(address)

마지막 레이아웃 중에 섹션이 address를 벗어난 경우에는, 에러가 발생되는 것을 나타

냅니다.

MAX_SIZE(size)

섹션의 길이가 size 바이트를 초과하면, 에러를 발생되는 것을 나타냅니다.

MIN_ENDADDRESS(address)

필요한 경우에는, address까지 섹션을 확장하기 위하여, 패딩을 수행하도록 링커에 지

시합니다.

MIN_SIZE(size)

필요한 경우에는, 섹션의 길이를 적어도 size 바이트만큼으로 만들기 위하여, 패딩을 수

행하도록 링커에 지시합니다.

NOCHECKSUM

섹션이 체크섬을 포함하여 출력되지 않도록 지정합니다. 이 속성은 각 섹션에 대하여

-checksum 옵션 효과를 덮어쓰기 합니다.

NOLOAD

섹션이 SHT_NOBITS로서 출력되도록 지정합니다. 섹션은 타겟 이미지에 allocate됩니

다만, 내용은 모두 파기됩니다.

PAD (value)

링커는 이 섹션의 시작에 value 바이트의 패딩을 배치합니다. 이 디렉티브는, 섹션의 시

작부분에 패딩을 지정하는 것과 동일합니다.

예 : 다음의 두 정의는 동일합니다.

.stack pad(0x10000) : {}

.stack : { . += 0x10000; }

ROM (sect_name)

CROM (sect_name)

ROM_NOCOPY (sect_name)

이 속성들은 sect_name이라는 이름의 섹션 내용을 링크시에 ROM에 할당합니다만, 동

시게 RAM에 복사되는 데이터에 대한 공간이 예약됩니다. ROM과 CROM옵션은 링커에

리얼타임 ROM 카피 테이블과 압축 ROM 카피 테이블의 엔드리를 배치하도록 지명하여,

Green Hills의 스타트업 코드가 해당 섹션을 ROM으로부터 RAM에 카피 할 수 있도록 합

니다.

CROM은 이 카피를 40% 내지 50% 압축하여, 어플리케이션에 요구되는 ROM의 량을

현격하게 줄일 수 있습니다. 추가 정보는, [스타트 업시의 섹션 ROM으로부터 RAM으로

의 카피]를 참조하여 주십시오.

ROM_NOCOPY는 그것이 링커에 리얼타임 ROM 카피 테이블의 엔트리를 배치하도록

지명하지 않는 것 이외에 섹션 속성 ROM과 동일하도록 행동합니다. 그 결과, Green

Hills의 스타트 업 코드는 해당 섹션을 ROM 으로부터 RAM 에 카피하지 않습니다. 이 옵

션은, 자체 제작한 스타트 업 코드를 사용하여 섹션을 ROM으로부터 RAM에 카피하고자

하는 경우에 사용합니다.

예 7. 스택과 힙의 사이즈

이번 예에서는, 섹션 속성을 사용한 .stack과 .heap 섹션에 사이즈와 얼라이먼트를 설정

하는 방법을 소개합니다.

DEFAULTS {

heap_reserve = 1M

stack_reserve = 512K

}

MEMORY

{

dram_memory : ORIGIN = 0x80000000, LENGTH = 10M

flash_memory : ORIGIN = 0xbfc00000, LENGTH = 10M

}

SECTIONS

{

.text

.data : > dram_memory

.bss ALIGN(8) PAD(heap_reserve) : > .

.heap ALIGN(8) PAD(stack_reserve) : > .

}

.heap 섹션은, ALIGN과 PAD의 2가지 속성을 가집니다. ALIGN(8)은 링커에, 그것 이전

의 섹션 사이즈에 관계 없이 8의 배수가되는 어드레스를 .heap에 배치하도록 지시합니다.

PAD(heap_reserve)는 디폴트로 heap_reserve를 사용하여, 힙의 사이즈를 외관상 1MB

로 설정합니다.

.stack 섹션은 힙과 동일한 두가 지 속성 옵션을 가집니다.

.text 섹션에 이어지는 모든 섹션은 메모리 영역 대신 도트(.)를 사용하므로, 링커는 각각

을 dram_memory안에 .text의 다음에 연속하여 배치합니다.

예 8. CLEAR과 NOCLEAR의 사용

이번 예에서는, CLEAR과 NOCLEAR 속성을 사용하여 링커가 런타임 클리어 테이블에

섹션의 엔트리를 배치시키는지 아닌지를 제어하는 방법을 소개합니다. 테이블의 정보에

관하여 추가적인 정보과, 스타트업 코드가 그것을 사용하여 어떻게 섹션을 제로로 초기화

하는지에 관하여서는 [런타임 클리어 테이블과 런타임 카피 테이블]을 참조하여 주십시오.

다음의 행은 .bss 섹션을 지정합니다.

.bss :

디폴트로, 링커는 .bss에 대한 엔트리를 런타임 클리어 테이블 안에 작성합니다. 프로그

램이 스타트하면, 이것으로 섹션안의 모든 데이타가 제로로 초기화 됩니다.

이 행은, .mybss라는 명칭의 섹션을 의미합니다.

.mybss CLEAR : {*(COMMON) }

{*(COMMON) }은 링커에 COMMON 데이터를 이 섹션에 배치하도록 지명합니다.([섹션

인클루드 커맨드 안의 COMMON 섹션의 사용]을 참조하여 주십시오) CLEAR은 .mybss

에 대한 클리어 테이블 안에 엔트리를 만들도록 지명합니다. 프로그램이 스타트하면, 이것

으로 인하여 이 섹션 안의 모든 데이터가 제로로 초기화됩니다.

힙에도 CLEAR가 사용 가능 합니다.

.heap CLEAR PAD(0x100000) :

디폴트로, 링커는 .bss, .zbss, .sbss 이외의 섹션에 대한 런타임 클리어 테이블 안에 엔트

리를 만들지 않습니다. CLEAR는 이 동작을 무효화하므로 링커는 .heap에 대한 엔트리를

만듭니다. PAD(0x100000)는 .heap의 시작에 1MB의 패딩을 추가하여, 힙의 사이즈를 외

관상 1MB로 설정합니다. 프로그램이 스타트하면, 이것으로 인하여 1MB의 램이 할당되

며, 제로로 초기화 됩니다.

스타트업 시 섹션의 ROM 으로부터 RAM으로의 카피

링커가 런타임 카피 테이블의 어딘가에 섹션의 엔트리를 배치할지 아닌지를 제어하기위

하여 ROM과 CROM 속성을 사용합니다. 스타트 업 코드는 이 테이블을 사용하여 해당 섹

션을 스타트 업시에 RAM에 카피할지를 결정합니다. 이 테이블들에 관한 추가적인 정보는

[런타임 클리어 테이블과 런타임 카피 테이블]을 참조하여 주십시오.

ROM 또는 CROM 속성에 의해 새로운 섹션을 정의할 때에는,

새로운 섹션의 명칭은 .ROM.sect이어야만 합니다. 여기서sect는 기존 섹션의 명칭

입니다. sect에 피리오드(.)이 포함되면 안됩니다.

ROM 또는 CROM 속성도 또한 sect를 지정해야만 합니다.

새로운 섹션은 기존 섹션의 속성과 내용을 계승하며, 기존 섹션은 RAM 안에 포함되어 집

니다. 양 섹션의 오프셋과 사이즈는 카피가 정상적으로 수행되기 위하여 정확하게 매치할

필요가 있으므로, 새로운 섹션에 대하여 내용이나 그 외의 속성을 지정하지 말아주시기 바

랍니다. 동일 섹션에 대하여 복수의 ROM이나 CROM의 카피를 작성하는 것은 불가능합니

다.

스타트 업시에 RAM에 카피되도록, .data 섹션을 ROM에 배치하기 위하여서는 섹션 맵안

에 다음과 같은 복수행을 포함하도록 합니다.

.data : > RAM_memory_block

...

// Create a copy of .data in ROM and

// create an entry in the run-time ROM copy table

.ROM.data ROM(.data) : > ROM_memory_block

스타트 업시에 RAM에 카피되도록, .text 섹션을 압축 ROM에 배치하기 위하여서는 섹션

맵에 다음과 같은 복수행을 포함하도록 합니다.

.text : > RAM_memory_block

...

// Create a copy of .text, compress it in ROM, and

// create an entry in the run-time compressed ROM copy table

.CROM.text CROM(.text) : > ROM_memory_block

스타트업 코드는 .CROM.text의 ROM 이미지를 신장하여, RAM에 놓여진 .text섹션에 그

것을 카피합니다. 표준적인 ROM 카피와 동일하면서, 압축 ROM 카피는 더 작고, 해당 배

치도 표준의 ROM 카피보다 제어가 용이합니다.

ROM 카피도 압축 ROM 카피도아닌 섹션의 배치가 CROM 섹션의 사이즈에 의존하는 경

우, 링커시에 에러가 발생합니다. 추가적으로, 리로케이션은 심볼을 일절 포함하지 않습니

다.

해당 심볼에는 __ghsbegin_section 이나 __ghsend_section이 포함됩니다만, 해당 위치

는 CROM 섹션의 사이즈에 의존합니다.

커맨드 라인에 -no_crom 옵션을 전달하는 것으로 CROM 속성의 효과는 무효화 하는 것

이 가능합니다. CROM 에서 마크된 섹션은 여전히 ROM에 카피됩니다만 압축은 수행되지

않습니다.

예 9. CROM 섹션의 배치

다음의 섹션 맵은 .rodata의 배치가 .CROM.data와 .CROM.text의 사이즈에 의존하기 때

문에 에러가 됩니다.

.data : > RAM

.text :

...

.CROM.data CROM(.data) : > ROM

.CROM.text CROM(.text) :

.rodata :

이 예를 수정하기 위하여서는, .CROM.text만이 .CROM.data의 사이즈에 의존하도록 재

조정하여 주십시오.

.data : > RAM

.text :

...

.rodata : > ROM

.CROM.data CROM(.data) :

.CROM.text CROM(.text) :

고속 또는 사이즈를 개선하기 위한 섹션 맵의 수정

프로젝트 위자드에는, 여러가지 디폴트 링커 디렉티브 파일이 제공되어져 있으며, 각각

스타트 업시의 RAM에 카피되는 섹션 수를 조정하는 것으로, 속도를 최대화 하거나, 사이

즈를 최소화 하는 섹션 맵이 정의됩니다. 섹션 맵을 수동으로 편집하는 것으로, 이 기능을

제어하는 것이 가능합니다.

실행 속도의 최대화

거의 모든 하드웨어에서는 RAM의 억세스 타임 쪽이 ROM 보다 빠르므로, 통상, 프로그

램은 소속된 모든 섹션을 스타트업시에 ROM에서 RAM으로 카피되는 쪽이 빠르게 실행됩

니다. Green Hills의 스타트 업 코드는 ROM 속성으로 구별된 섹션을 ROM으로부터 RAM

에 카피합니다([스타트 업 시 섹션의 ROM에서 RAM으로 카피]를 참조하여 주십시오).

ROM에서 RAM에 섹션을 카피하기 위하여서 Green Hills의 스타트 업 코드 대신 커스터

마이즈 스타트 업 코드를 사용하시고자 하는 경우에는 [런타임 환경 프로그램 섹션의 커

스터마이즈]와 [런타임 클리어 테이블과 런타임 카피 테이블]을 참조하여 주십시오.

RAM 사용량의 최소화

RAM 사용량을 최소화하기 위하여서는, 스타트 업시에 필요 최소한의 프로그램 섹션만을

RAM에 카피할 필요가 있습니다.

섹션이 실행시에 변하지 않는 경우에는 그것을 RAM에 카피할 필요가 없습니다. 통상적

으로 .data를 RAM에 카피하지 않으면 안됩니다만, Green Hills V800 컴파일러는 실행시

에 변하지 않는 특정 데이터 항목을 결정 가능하며 그것을 ROM에 남기는 것이 가능합니

다. 이 기능을 이용하기 위하여서는 .rodata라는 섹션을 작성합니다. 링커는 유저가 정의

한 const 변수를 .rodata에 배치합니다. 키워드 const로 변수를 선언하면 해당 값은 정수

가 되며, 링커가 그것을 .rodata에 배치하는 것이 보증됩니다.

.rodata 섹션은, 프로그램의 .text섹션에 인접하는 링크 앱에 배치할 필요가 있습니다. 그

렇게 하면, 이 데이터가 프로그램 텍스트와 함께 ROM안에 배치됩니다.

SDA에의한 최적화([스몰 데이터 에어리어(SDA)에의한 최적화]를 참조)를 사용하면, 보

통은 .rodata 섹션에 놓여지는 데이터가 .rosdata 섹션에 놓여집니다.

ZDA에의한 최적화([제로 데이터 에어리어(ZDA)에의한 최적화]를 참조)를 사용하면, 보

통은 .rodata섹션에 놓여지는 데이터가 .rozdata섹션에 놓여집니다.

TDA에의한 최적화([V850의 극소 데이터 에어리어(ZDA)에의한 최적화]를 참조)를 사용

하면, 보통은 .rodata섹션에 놓여지는 데이터가 .tdata섹션에 놓여집니다.

런타임 환경 프로그램 섹션의 커스터마이즈

이 섹션에서는, Green Hills 런타임 환경 시스템(라이브러리 libsys.a그리고 libstartup.a

와 모듈 crt0.o)에의해 작선되고 관리되는, 특별한 프로그램 섹션에 관하여 설명합니다. 이

섹션들은 디스트리뷰션에 제공되고있는 모든 링커 디렉티브 파일에도 존재하고 있으며 자

동적으로 내용이 생성되기 때문에, 명시적인 추가를 할 필요는 없습니다.

주의:

다음의 섹션을 명시적인 text나 data에 배치시키려고 하면 미정의로 잠재적인 치명적 결

과를 일으킵니다. 커스텀으로 명칭을 붙인 섹션을 작성하실 때에는, 이 특별한 섹션들의

명칭을 일절 사용하지 않도록 주의하실 필요가 있습니다. 이 링커 디렉티브 들과 특별한

섹션을 사용하여 런타임 환경을 셋업하는 기능에 관한 추가 정보는, [런타임 환경 라이브

러리와 오브젝트 모듈의 커스터마이즈]를 참조하여 주십시오. src/libsys와

src/libstartup에 놓여진 커스터마이즈 가능한 소스 파일의 코맨트도 참조하여 주십시오.

.fixaddr, .fixtype

이 섹션들은 컴파일러에 의하여 작성됩니다.

이 2개의 섹션에는, Green Hills 스타트 업 코드로 데이터 변수의 PIC/PID 초기화 프로그

램을 준비하는 정보가 들어있습니다. 컴파일러는 필요한 때에, 또는 PIC 나 PID, 또는 두

가지 모두를 사용하는 경우에, .fixaddr과 .fixtype에 데이터를 자동적으로 생성합니다. 또

한, 이 라이브러리들의 대부분은, 일반적으로 PIC와 PID 용으로 작성되어 있기 때문에, 디

폴트 Green Hills 런타임 라이브러리에는 이러한 섹션들의 정보가 이미 들어있습니다.

이 2개의 섹션에는 읽기 전용 데이터가 들어있기 때문에, ROM 화가 가능합니다. 이 섹션

들을 링커 디렉티브 파일에 넣는 것을 잊으면, Green Hills 링커는 섹션 리스트의 끝에 이

섹션들을 추가합니다만, 이 경우에는 다음과 같은 경고 메시지가 표시되는 경우가 있습니

다.

[elxr] warning : section .fixaddr from libsys.a(ind_crt1.o)

isn’t included by the section map;

appending after last section.

add to section map or use -append to append without warning

프로그램이 섹션 맵의 마지막에 지정한 섹션의 끝을 초과하여 확장하는 동적 메모리에 의

존하고 있는 경우에는, 섹션 맵에 섹션을 추가하면 치명적인 결과를 발생시킬 가능성이 있

습니다. 이 섹션들은 위에 기재하는 것이 가능하기 때문입니다. 따라서, 이 섹션들은 섹션

맵에 포함될 필요가 있습니다.

.heap

이 섹션은 링커 디렉티브에 의해 작성된, 런타임 힙의 사이즈와 위치를 지정합니다. 이것

은, Green Hills 런타임 라이브러리를 사용하여, 동적 메모리를 할당할 때 필요합니다.

.heap 섹션의 시작을 나타내는 사전 정의의 링커 심볼 __ghsbegin_heap에 대한 참조는,

libsys.a라이브러리의 ind_heap.c 모듈에 있습니다.

링커 디렉티브 파일에 .heap 섹션을 포함하지 않고, 프로그램이 ind_heap.o를 생략할 경

우, 다음과 같은 링커 에러가 1개 이상 생성됩니다.

[elxr] (error) unresolved symbols : 1

‘__ghsbegin_heap’ from libsys.a(ind_heap.o)

Green Hills의 런타임 라이브러리를 사용하지 않는 경우에는 .heap 섹션을 링커 디렉티

브 파일로부터 제거할 수 있습니다.

Green Hills 런타임 라이브러리는, 동적 메모리 할당이 지정된 .heap 영역을 오버런하지

않도록 합니다. 라이브러리는 sbrk()로부터 에러 코드를 반환하며, 이를 통하여 malloc()

이나 그외의 메모리 할당 루틴에 NULL 포인터를 되돌리는 것으로, 실현 합니다. 동적 메

모리 할당 루틴을 호출할 때에는, 유저 코드는 보통 반환 값에 문제가 없는지를 검사합니

다. 또한, ind_heap.c에 있는 Green Hills sbrk() 루틴을 커스터마이즈하여, .heap 섹션을

사용하지 않도록 하는 것이 가능합니다.

.rodata

이 섹션은 컴파일러에 의하여 작성됩니다. 몇가지 Green Hills 컴파일러는, 읽기 전용 데

이터(C의 const 지시자나 문자열 정수로 선언된 데이터 등)을 .rodata라는 읽기 전용 섹션

에 넣습니다. 디폴트의 링커 디렉티브 파일에 사용되어져 있는 규칙에서는, .rodata를

ROM에 배치할 수 있는 다른 섹션과 함께 배치합니다. .rodata 섹션을 섹션 맵에 넣지 않

으면, 링커는 이 섹션을 섹션 맵의 마지막에 추가합니다. -pic 또는 -pid 옵션으로 프로그

램을 컴파일하는 경우에는 이 섹션은 사용되지 않습니다.

ROM 섹션

링커는 ROM 을 포함하는 섹션 디렉티브를 검출하면, 섹션의 읽기 전용 카피를 작성합니

다. ROM 속성을 포함하는 섹션은 .ROM.sect라는 명칭을 가질 필요가 있습니다. 여기서

.sect는 ROM으로부터 RAM에 카피되는 섹션 명입니다.([스타트 업시 섹션의 ROM으로부

터 RAM으로의 카피]를 참조하여 주십시오). Green Hills의 스타트 업 코드 ind_crt0.c는,

초기화 데이터를 ROM에서 RAM으로 카피하는 것과 동시에 데이터를 .ROM.sect 섹션에

서 .sect에 카피합니다.

자체 커스텀 코드를 사용한 스타트 업 시에 섹션을 ROM에서 RAM으로 카피하고자 하는

경우에는 ROM 섹션의 정의시에 ROM_NOCOPY 속성을 사용하여 주십시오. 이 속성을 사

용하면 링커는 카피 테이블에 엔드리를 작성하지 않고, Green Hills의 스타트 업 코드도

해당 섹션을 ROM에서 RAM으로 카피하지 않습니다. 이 속성은 ROM과 CROM 속성이 동

일하게 동작합니다.

커스텀 코드가 카피 테이블을 사용하고 있는 경우에는 ROM() 속성을 사용합니다. 그 다

음, ind_crt0.c 안의 코드를 변경하거나 제거하거나하여 섹션을 ROM에서 RAM으로 카피

하는 Green Hills 코드를 무효화하여 주십시오.

섹션을 ROM에서 RAM으로 카피할 필요가 없을 때에는 링커 디렉티브 파일에

.ROM.sect 섹션을 인클루드하거나, ROM, CROM, 또는 ROM_NOCOPY 속성을 사용하거

나 하지 말아주십시오.

.sdabase

타겟이 SDA(스몰 데이터 영역)의 최적화를 지원하고 있는지 여부와 관계 없이, .sdabase

섹션은 링커 디렉티브 파일안에 있어야만 합니다.

SDA를 실장하기 위하여서는, .sdabase 섹션이 필요합니다. .sdabase 섹션은, SDA를 구

성하는 섹션의 시작 위치 앞에 놓입니다. Green Hills 디버그 서버는, .sdabase 섹션(사이

즈 0의 더미 섹션)의 어드레스를 사용하여 SDA 베이스 레지스터를 초기화 합니다.

Green Hills 스타트 업 코드는, 새롭게 정의된 심볼 __ghsbegin_sdabase 를 참조하여

.sdabase 섹션의 위치를 얻게 되며, SDA 베이스 레지스터를 초기화 합니다.

.secinfo

이것은, Green Hills 링커 특유의 섹션 출력이며, 프로그램의 섹션 레이아웃에 관한 정보

가 들어있습니다. 스타트업 코드인 ind_crt0.c는, 이 정보를 사용하여, 프로그램의 스타트

업시에 클리어 할 필요가 있는 섹션(.bss 섹션)과, 카피를 할 필요가 있는 섹션(ROM 섹션)

을 판단합니다. 이것은, 읽기 전용이며, ROM 화 할 수 있는 섹션입니다. 링크 맵에 이 섹션

을 넣지 않으면, 링커는 이 섹션을 섹션 맵의 마지막에 추가합니다. 다음과 같이 .secinfo

섹션의 정보를 제어할 섹션 플래그가 3개 있습니다.

a

다운로드를 위한 할당

w

쓰기 가능

x

실행 가능

다음은 예 입니다.

.section “.foo”, “aw”

.section “.bar”, “ax”

동적 카피나 동적 클리어 기능에 관한 상세한 내용은, ind_crt0.c 파일 안의 코맨트를 참

조하여 주십시오.

링커는, 프로그램이, 자신이 소속된 섹션의 실행시의 배치 장소, 사이즈, 그리고 타입을

포함하는 것을 허가합니다. 심볼 __secinfo가 참조되어있지 않기 때문에 프로그램 중에 정

의되어 있지 않는 경우 링커는 .secinfo 섹션에 첨가적인 정보를 물어 심볼 __secinfo가

그것을 지지하도록 수정합니다.

.stack

이 섹션은, 프로그래머가 의도한 스택 영역과 사이즈를 지정합니다만, .stack 섹션이 지정

하는 한도 이내에 스택을 유지하는 메커니즘은 없습니다. Green Hills의 스타트 업 코드

(독립형 모드에서 실행할 때)와 디버그 서버는, 이 .stack 섹션을 기반으로 프로세스의 초

기 스택 포인터를 초기화합니다. 스택 영역의 유저 지정이 불가능한 오퍼레이팅 시스템 상

에서 실행하는 프로그램을 작성할 때, 스타트 업 코드에서 참조를 해결하기 위해서, 빈

.stack 섹션을 섹션 맵에 넣는 것이 가능합니다. Green Hills 스타트 업 코드(crt0.o)의

.stack 영역에 대한 참조는, 프로그램이 독립형 모드일 때, 즉, Green Hills 디버거를 통하

여 다운로드되지 않는 때에만 사용됩니다. 또한, 스타트 업 코드의 .stack 섹션의 사용법

도, crt0.800 어셈블리 모듈을 편집 재구축하는 것으로 커스터마이즈할 수 있습니다.

디버거에는, 특별한 변수 _INIT_SP 를 통하여 프로그램을 다운로드할 때에, 다른 초기의

스택 포인터를 지정할 수 있습니다. 초기의 스택 포인터 위치를 결정할 때에는, .stack 섹

션 대신에 _INIT_SP 가 사용됩니다.

.syscall

이 섹션에는, 시스템 콜의 Green Hills 에뮬레이션을 위한 런타임 라이브러리 코드가 들

어 있습니다. 이 섹션은, Green Hills 런타임 라이브러리를 시스템 콜 에뮬레이션에 사용

할 때에 필요합니다. 이 방법에 의하여 시스템 콜 에뮬레이션을 처리하지 않는 경우에는,

ind_dots.800을 커스터마이즈하는 것으로 .syscall 코드를 제거하는 것이 가능합니다.

심볼 정의

링커는, 몇가지의 심볼을 정의하고 있습니다. 이것을 참조하는 경우이며, 정의 되어있지

않는 경우, 마지막 이미지에 대응하여 특정 어드레스가 지정됩니다.

섹션의 시작, 종료와 사이즈의 심볼

완전히 링크된 출력에 대하여 최종적인 심볼 해결을 수행할 때, 링커는 최종적인 섹션 맵

안의 메모리 어드레스를 참조하는 특정 미정의 심볼을 확인합니다. 이 심볼들은,

__ghsbeginsection, __ghsendsection, 그리고 __ghssizesection입니다. 여기서, section

은 출력 파일 안의 각 섹션 명칭을 의미하며, 도트(.) 문자는 모든 언더 스코어(“_”)로 변경

됩니다.

예를들어, .text 라는 명칭의 섹션의 경우, 심볼 __ghsbegin_text, __ghsend_text, 그리

고 __ghssize_text가 해결되며, 이 섹션의 시작 위치, 종료 위치의 절대 어드레스, 그리고

사이즈가 됩니다.

이 섹션 맵에 대해서는 다음과 같습니다.

SECTIONS

{

.bss1 0x400000:

.bss:

}

다음의 main.c 프로그램에 대해서는 다음과 같습니다.

extern char __ghsbegin_bss1[], __ghssize_bss1[];

void foo() {

memset(__ghsbegin_bss1, 0, (int)__ghssize_bss1);

__ghsbegin_bss[0] = 0xff;

}

섹션 .bss1의 사이즈가 0x100의 경우, 링커는 __ghsbegin_bss1을 0x400000,

__ghsend_bss를 0x400100, __ghssize_bss1을 0x100, __ghsbegin_bss를 0x400100으

로 각각을 해결합니다.

함수 종료의 심볼

링커가 재배치 가능하지 않은 출력 파일의 최종적인 심볼의 해결을 실행하고 있을 때, 특

정 미정의 심볼명이 최종적인 실행 가능 파일의 함수 종료 위치 메모리 어드레스를 참조하

고 있는 것으로 인식됩니다. 이 심볼명들은, 출력 파일의 각 함수 명칭의 앞에 문자열

__ghs_eofn_을 붙인 형태가 됩니다. 예를 들면, foo 라는 함수의 경우, 심볼

__ghs_eofn_foo는 해결되어, 이 함수 종료 위치의 가상 어드레스가 됩니다.

이 프로그램에 대하여서는, 다음과 같습니다.

extern void__ghs_eofn_foo(void);

int foo(int x) { return x+1; }

int main () {

printf(“Size of foo() is %d\n”, (int)__ghs_eofn_foo- (int)foo);

return 0;

}

함수 foo() 의 어드레스가 0x100000, 사이즈가 0x20 바이트인 경우, 링커는

__ghs_eofn_foo를 0x100020 으로서 해결합니다.

링커 생성 테이블

링커가 링크를 모두 완료한 출력파일에 대하여 최종적인 심볼 해결을 수행할 때, 일정 미

정의 심볼 명은 테이블로서 인식됩니다. 특히, __ghstable_[tablename]이라는 명칭의 미

정의 심볼이 있는 경우, 링커는, 읽기 전용의 .rodata 섹션에 얼로케이트된 데이블에 대하

여 심볼 해결을 수행하는 것이 가능합니다. 이 테이블에는, __ghsentry_[tablename]

[entryname] 이라는 형으로 정의된 모든 심볼 어드레스가 격납되어, NULL 포인터로 종

료되어 있습니다. 테이블 안의 엔트리 순번은 예측 불가능합니다. 엔트리 심볼의 명칭이

링커의 채우려고하는 복수의 테이블에 일치하는 경우, 해당 엔트리는, 가장 긴 명칭의 테

이블에 추가됩니다.

주의:

__ghstable_[tablename]은, 배치 장소에 의존하지 않는 코드(PIC)나 배치 장소에 의존

하지 않는 데이터(PID)에는 지원되지 않습니다.

다음의 예에서, __ghstable_resetvectors는 함수로의 포인터 배열입니다. 이 배열에는,

__ghsentry_resetvectors_foo() 와 __ghsentry_resetvectors_bar() 의 어드레스가 격납

되어 있습니다. 함수 reset_all() 에는, 두 함수를 호출하는 효과가 있습니다.

extern void (*__ghstable_resetvectors[]) (void) ;

int foo = 5;

void __ghsentry_resetvectors_foo(void)

{

foo = 0;

}

double bar = 2.0;

void __ghsentry_resetvectors_bar(void)

{

bar = 0.0;

{

void reset_all()

{

int i;

for (i = 0; __ghstable_restvectors[i] != 0; ++i) {

(__ghstable_resetvectors[i]) ();

}

}

링커에 대한 라이브러리로부터 모듈 추출의 강제

보통, 링커는 weak가 아닌 미해결 심볼에 대한 정의가 있는 경우 라이브러리로부터 오브

젝트 파일을 추출합니다. -extractall과 -extractweak 옵션을 사용하여 이 동작을 글로벌

로 변경하는 것이 가능합니다. 하지만, 라이브러리가 커맨드 라인에 추가된 경우 등, 링커

에 라이브러리로부터 특정의 오브젝트 파일을 추출하고자 하는 경우도 있습니다. 그 경우,

링커에는 해당 라이브러리로부터 오브젝트 파일을 모두 추출시키는 것은 피하고 싶을 것

입니다.

링커는 커맨드 라인에 추가된 모든 라이브러리에 대하여 __ghsalwaysimport 또는

__ghsautoimport로 시작하는 심볼을 검사합니다. 라이브러리 안의 오브젝트 파일이

__ghsalwaysimport로 시작하는 명칭을 가진 심볼을 정의하고 있는 경우, 링커는 그 오브

젝트 파일을 언제나 추출합니다. 오브젝트 파일이 __ghsautoimport로 시작하는 명칭을 가

진 심볼을 정의하고 있는 경우, 링커는, 해당 심볼이 별도의 오브젝트 파일에 의하여 미리

정의 되어있지 않은 한, 그 오브젝트 파일을 추출합니다. __ghsalwaysimport와

__ghsautoimport의 구별은 공통 심볼을 추출할 때 편리합니다.

즉, __ghsalwaysimport_foo라는 명칭의 공통 심볼을 복수의 모듈이 정의하고 있으면 링

커는 그것들 모두를 추출합니다만, __ghsautoimport_foo 라는 명칭의 공통 심볼을 복수의

모듈이 정의하고 있다면, 링커는 최초로 만난 모듈만을 추출합니다.

사용되지 않는 함수의 제거

-delete 옵션을 사용하면, 링커는 최종적인 실행 가능 파일 안에 참조되지 않는 함수를

제거합니다. 링커는 포인트하는 재배치가 일어나지 않는 함수를 반복 검사하여 제거합니

다. 첫번째로 심볼이 재배치에 의하여 참조되어 있는 경우에도, 참조하고 있는 심볼이 제

거되면, 이어서 제거 됩니다.-delete 옵션을 사용하면, 링크에 필요한 시간과 메모리가 증

가할 가능성이 있습니다.

주의:

어셈블러의 수동 코딩으로 -delete옵션을 사용하는 경우에는, 어셈블리 라벨을 적절한

사이즈의 함수 또는 오브젝트로서 올바르게 식별하지 않으면 안됩니다.

링커는, Green Hills 어셈블러에서 생성된 어셈블리 파일에서만, -delete 옵션을 지원하

고 있습니다. 그 외의 어셈블러는, -delete 의 기능에 필요한 정보를 보존하지 않는 오브

젝트 파일을 생성하는 경우가 있습니다.

힌트:

심볼이 제거되지 않도록 하는 경우에는, -keep=funcname 컴파일러 드라이버 옵션, 또

는 .need 어셈블러 디렉티브를 사용합니다.

.need 어셈블러 디렉티브는 2개의 심볼(보통은 함수)간의 명시적인 의존 관계를 만들어,

한쪽의 함수가 사용되고 있는 경우에는 링커가 다른 한쪽의 함수를 유지하도록 합니다. 이

디렉티브는, 값을 반환하지 않고, 다음의 함수로 진행하는 어셈블리 함수에서 필요합니다.

이러한 방법으로 보호되는 심볼은, 사용되지 않는 경우에도 링커에 의하여 제거되는 일은

없습니다. 이것은, 인터럽트 테이블의 엔트리 포인트, 비표준의 엔트리 포인트, 프로그램

안의 통상적인 제어 전송에 도달하지 하지 않는 그외 코드 부분 등의 심볼을 유지하기 위

한 경우에 유효합니다.

컴파일러가 생성하는 프로파일링의 사용이나 디버그 정보는 미사용 함수로의 참조를 작

성하여, 링커에 의하여 제거되는 것을 방지합니다.