'링커 스크립트'에 해당되는 글 2건

  1. 2009.06.10 [ARM] elf32-littlearm.lds 파일 분석
  2. 2009.06.10 [프로그래밍 일반] 링커 스크립트
2009. 6. 10. 21:11

[ARM] elf32-littlearm.lds 파일 분석

링커 스크립트인 elf32-littlearm.lds 파일에 대한 분석이다.

링커 스크립트는 링커에게 코드배치를 이렇게 하라고 설명하는 파일이며, 더 자세한 내용은 다음의 포스트를 참조하자.



/* elf32-littlearm.lds 파일 */

//이 부분은 arm-linux-ld가 만들어 낼 최종 결과 파일의 포맷을 나타낸다.
//즉, little endian 포맷의 파일을 생성할 것인지,
//big endian 포맷의 파일을 생성할 것인지를 결정하는 역할을 한다.

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")

//이 부분은 최종 결과 파일이 동작할 CPU의 architecture를 나타낸다.
//즉, 이 파일은 ARM CPU 상에서 동작한다는 의미이다.

OUTPUT_ARCH(arm)

//최종 결과 파일의 시작 지점을 나타낸다.
//즉, 여기서 파일의 시작 지점은 reset_handler가 된다.
//reset_handler는 Cstartup.s 파일에 정의되어 있다.

ENTRY(reset_handler)

//SECTIONS{ ... }부분은 링커(arm-linux-ld)가 입력 파일들의 섹션들을
//결과 파일의 어떤 섹션들로 위치시킬지를 결정하는 역할을 한다.

SECTIONS
{
    .text : {          //프로그램의 코드영역
        _stext = .;      //코드영역의 시작주소를 makefile로 부터 가져온다.
        *(.text)        //모든 입력 파일들(*)의 .text 섹션을 결과 파일의 .text 섹션에 위치시킨다.
        *(.rodata)      //readonly 파일들을 .text 섹션에 위치시킨다.
        *(.rodata*)    //그외 모든 데이터들을 .text 섹션에 위치시킨다.
        . = ALIGN(4);  //현재의 위치에서 4 바이트 단위로 놓겠다는 의미이다.
                                 // 즉, 4바이트 단위로 메모리를 정렬한다.

         _etext = . ;    //코드영역의 끝을 현재 위치포인트로 하겠다는 의미이다.
    }

    //데이터 영역
     //코드영역 시작주소부터 코드영역의 크기만큼 더한다음 주소 즉, 코드영역 다음 주소
    .data : AT ( ADDR (.text) + SIZEOF (.text) ) { 
        _sdata = .;
        *(.vectors)    //모든 입력 파일의 벡터 테이블을 데이터 영역에 포함
        *(.data)       //모든 입력 파일의 초기화 된 데이터를 데이터 영역에 포함
        _edata = .;
    }

     //bss 영역
     //noload = 적재하지 않는다.
    .bss (NOLOAD) : {
        . = ALIGN(4);
        _sbss = .;
        *(.bss)         //모든 입력 파일의 bss영역을 출력파일의 bss영역에 포함한다.
        _ebss = .;
    }
}
end = .;


2009. 6. 10. 20:34

[프로그래밍 일반] 링커 스크립트

일반적으로 대부분의 컴파일러는 다음의 과정을 거쳐 소스파일을 실행파일로 컴파일한다.


간단하게 얘기하면 소스 파일 -> 컴파일러 -> 오브젝트 파일 ->링커 -> 실행파일 -> 로더 -> 실행 의 순으로 진행된다고 볼 수 있다.

여기서 링크과정을 살펴보면 그림에는 없지만, 모든 링크 과정에는 링커 스크립트가 조정을 한다. 오늘은 이 링커 스크립트에 대해 알아보자.

링커 스크립트

링커 스트립트는 링커 명령 언어로 쓰여진다.

링커는 항상 링커 스크립트를 사용한다. 직접 제공하지 않으면 링커는 링커 실행파일에 컴파일된 기본 스크립트를 사용한다.

링커 스크립트의 주목적은 입력파일의 섹션이 어떻게 출력파일로 대응하는지와 출력파일의 메모리 상태를 어떻게 조정하는지를 지정하는 것이다. 대부분의 링커 스크립트는 이것으로 충분하다.

링커 스크립트 형식

링커 스크립트는 일련의 명령어로 이루어져 있다. 각 명령어는 키워드로 뒤에 아규먼트를 가지거나, 심볼에 할당될 수 있다. ';'으로 각 명령어를 구분한다. 공백은 일반적으로 무시된다.

파일이나 형식 이름과 같은 문자열은 보통 직접 입력한다. 파일명이 보통 파일명을 구분하는 ',' 같은 문자를 포함한다면 파일명을 쌍따옴표 안에 두어야 한다. 파일명에 쌍따옴표를 사용할 수는 없다.

링커 스크립트는 C와 같이 '/*' 와 '*/'로 둘러싸인 주석을 포함할 수 있다.

링커 스크립트의 간단한 예

많은 링커 스크립트는 매우 간단하다.

가장 간단한 링커 스크립트는 'SECTIONS'이라는 단 하나의 명령어를 가진다. 'SECTIONS' 명령어는 강력한 명령어이며, 'SECTIONS' 명령어는 출력파일의 메모리 구조를 기술한다.

다음의 예는 프로그램이 코드, 초기화된 자료, 초기화되지 않은 자료로만 이루어진다고 가정했을 때의 링커 스크립트이다. 또한, 입력파일에도 이 섹션들만이 나온다고 가정한 스크립트이다. 그리고, 코드가 주소 0x10000에서 로드되고 자료는 0x8000000에서 시작한다고 가정하자.

SECTIONS
{
    . = 0x10000;
    .text : {*(.text)}
    . = 0x8000000;
    .data : {*(.data)}
    .bss : {*(.bss)}
}

SECTIONS 명령어는 다음에 오는 대괄호로 묶인 일련의 심볼 할당과 출력 섹션 명이 나온다.

특별한 변수인 '.' 은 항상 위치 카운터를 저장한다. '.'에 값을 대입하면 위치 카운터가 변경된다. 그래서 출력 섹션에 공백을 만들 수 있다. 위치 카운터는 절대로 뒤로 움직이지 않는다.

.text : {*(.text)} 줄을 살펴보면, 출력 섹션 '.text'가 정의될 때 현재 위치 카운터의 값으로 주소를 정한다. 현재 위치 카운터의 값은 윗줄에서 0x10000이므로 '.text' 섹션의 주소는 0x10000이 된다. '.text' 섹션은 어셈을 공부했다면 많이 본 코드 영역을 의미한다.

마찬가지로 아래쪽에 데이터 영역과 bss 영역의 주소를 정해주는 문장을 볼 수 있다.



링커 스크립트에 대한 더 자세한 문법을 알고 싶다면 아래의 페이지를 참조하자. 위의 내용은 아래 페이지의 도입부를 간략하게 정리한 것이다.

http://korea.gnu.org/manual/release/ld/ld-mahajjh/ld_3.html