XIP 살펴보기
|
eXecute In Place (XIP) 살펴보기
저자: Phil Wilshire <philwil AT earthlink.net>
번역: 김남형 <namhyung AT gmail.com> 1. XIP (eXecute In Place) ¶XIP 는 uClinux 상에서 활용할 수 있는 유용한 옵션 중의 하나이다. XIP 의 장점은 동일한 프로그램을 여러번 실행할 때 텍스트 세그먼트를 복사할 필요가 없다는 것이다. 실제로 텍스트 세그먼트는 플래시 메모리 상에 존재할 수 있기 때문에 시스템의 RAM 에 복사될 필요가 전혀 없다. 이것은 커다란 코드 영역을 가지는 프로그램이 시스템 상에 여러 개의 인스턴스로 실행되는 태스크에서 유용하다.
이 경우 각각의 프로세스에 대해서 오직 스택, BSS, 데이터 세그먼트만이 새로 생성될 필요가 있다. 그리고 텍스트 세그먼트 영역은 플래시 메모리에 존재하거나, 성능이 문제가 되는 경우 파일 시스템의 내용을 RAM 에 복사한 후에 램 디스크로 마운트될 수 있다. 만약 파일 시스템 내의 실행 파일이 XIP 를 지원하도록 컴파일 되었고 헤더 파일에서 XIP 플래그를 설정하였으면 오직 하나의 텍스트 세그먼트만이 로드되어 실행된다.
2. XIP 와 커널 ¶커널은 항상 "XIP" 로 동작한다. 여기서 가질 수 있는 단 한가지 의문점은 만약 커널이 실행되기 전에 RAM 으로 복사되는 경우에 대한 것이다. 이것은 다음과 같은 여러가지 일들에 의존한다:
68K (Dragonball) 와 Coldfire 커널은 ROM 에서 실행될 수 있어야 한다. 모든 초기화 코드는 나중에 여기에 사용된 메모리를 다시 사용할 수 있게 하기 위해서 RAM 상에 존재하도록 해야 한다 (아니면 메모리를 해제하지 않도록 한다).
3. XIP 와 사용자 태스크 ¶사용자 태스크도 XIP 로 동작하도록 정의할 수 있다. 이 경우 오직 데이터, BSS, 재배치 정보와 스택 만이 각 태스크 고유의 RAM 영역에 존재한다. 스택 영역의 크기가 증가될 수 없음에 주의하라. 이 크기는
elf2flt 가 동작할 때 고정된다. 이것은 elf2flt 프로그램을 다시 실행하거나 flthdr (아래 참조)를 사용해서 변경할 수 있다.
주의: 이 플래그?를 이용해서 XIP 가 아닌 코드를 XIP 코드로 변경할 수는 없다. 하지만 XIP 코드가 (여러 인스턴스가 실행될 때) 텍스트 섹션을 강제로 로드하도록 할 수는 있다.
linux-2.04.x/fs/binfmt_flat.c
그 중 필요한 RAM 영역을 할당하는 부분의 코드는 다음과 같다.
extra = MAX(bss_len + stack_len, relocs * sizeof(unsigned long));
down_write(&t->mm->mmap_sem);
realdatastart = do_mmap(0, 0, data_len + extra +
MAX_SHARED_LIBS * sizeof(unsigned long),
PROT_READ|PROT_WRITE|PROT_EXEC, 0, 0);
up_write(&t->mm->mmap_sem);
4. Flat 파일 재배치 ¶로더 프로세스는 데이터 세그먼트가 할당된 영역이 변경됨에 따라 필요한 작업들을 처리해야 한다. 이것은 MMU 가 없기 때문에 발생하는 문제이다. 우리는 단순히 "적절한 곳에 메모리가 존재하도록" 할 수 없다. 재배치 목록은 elf 파일이 flat 파일로 변환될 때
elf2flt 프로그램에 의해 정해진다.
고려해 볼 만한 두가지 종류의 재배치 방법이 있다.
4.1. Global Offset Table (GOT) ¶이것은 사실 이 문서에서 다룰 내용은 아니지만 언급할 가치가 있으므로 얘기하고자 한다. 만일 컴파일시 옵션으로 GOT를 활성화 시켰다면 데이터 세그먼트는 GOT 영역에서 시작하게 된다. 이 테이블에 있는 주소 값들은 데이터 섹션의 실제 주소를 반영하여 재배치될 필요가 있다. GOT 테이블의 마지막은 (존재하는 경우) -1 (0xFFFFFFFF) 값을 가진다.
아래의 코드는
binfmt_flat.c 의 내용으로 GOT 테이블을 업데이트하는 부분이다.
if (flags & FLAT_FLAG_GOTPIC) {
for (rp = (unsigned long *)datapos; *rp != 0xffffffff;rp++) {
unsigned long addr;
if (*rp) {
addr = calc_reloc(*rp, libinfo, id, 0);
if (addr == RELOC_FAILED)
return -ENOEXEC;
*rp = addr;
}
}
}
4.2. 코드 재배치 (Code RELOCS) ¶이 방법은
elf2flt 프로세스에 의해 생성된 재배치 테이블을 사용한다. 주의할 점은, 만약 파일이 XIP 로 동작하도록 되어 있다면 여러 개의 실행 파일에서 공유되기 위해 텍스트 세그먼트 영역은 영향을 주지 않는다는 것이다.
테이블의 각 엔트리는 재배치될 필요가 있는 영역의 주소를 나타낸다. 재배치할 영역 자체가 재배치되기 때문에 이 영역의 주소가 먼저 수정되어야 한다. 일단 변경된 주소가 계산되면 그 주소가 가리키는 영역의 내용은 결정되며 해당 영역에는 새로운 주소가 적용된다.
주소들간에 다른 바이트 오더링 형식 (little/big endian) 이 사용된다면 복잡한 문제가 발생되며 재배치되는 실제 주소는 정렬되지 않을 수 있다.
다시 한번
binfmt_flat.c 파일을 살펴 보자. 아래의 코드는 재배치를 수행하는 부분을 나타낸다.
for (i=0; i < relocs; i++) {
unsigned long addr;
/* 재배치될 포인터의 주소를 얻어온다.
(물론 먼저 이 주소를 재배치 해야 한다) */
rp = (unsigned long *)calc_reloc(ntohl(reloc[i]), libinfo, id, 1);
if (rp == (unsigned long *)RELOC_FAILED)
return -ENOEXEC;
/* 포인터가 가리키는 내용을 가져 온다. */
addr = get_unaligned (rp);
if (addr != 0) {
/*
* 재배치를 수행한다.
* 데이터 섹션의 PIC 재배치는 이미 타겟의 바이트 오더로 되어 있다.
*/
addr = calc_reloc( (flags & FLAT_FLAG_GOTPIC) ? addr : ntohl(addr),
libinfo, id, 0);
if (addr == RELOC_FAILED)
return -ENOEXEC;
/* 재배치된 포인터를 기록한다(write back). */
put_unaligned (addr, rp);
}
}
5. 연결 ¶위에 살펴보았듯이 이것이 동작하기 위해서는 여러 시스템들이 함께 적절히 동작해야 한다.
6. Flathdr - flat 파일 매니저 ¶이 프로그램은
elf2flt 에 의해 생성된 flat 파일 내의 flat 헤더의 내용을 조사하거나 변경하기 위해 사용된다.
사용 방법은 아래와 같다
/usr/local/bin/flthdr romfs/bin/boa
romfs/bin/boa
Magic: bFLT
Rev: 4
Entry: 0x50
Data Start: 0x11980
Data End: 0x13d40
BSS End: 0x15604
Stack Size: 0x2000
Reloc Start: 0x13d40
Reloc Count: 0x4f
Flags: 0x2 ( Has-PIC-GOT )flt.
사용할 수 있는 옵션은 아래와 같다.
-p : print current settings
-z : compressed flat file
-d : compressed data-only flat file
-Z : un-compressed flat file
-r : ram load
-R : do not RAM load
-s size : stack size
-o file : output-file
(default is to modify input file)
아래는
flthdr 을 사용하여 압축된 flat 파일을 생성하는 예제이다.
/usr/local/bin/flthdr -z romfs/bin/boa -o romfs/bin/boaz
그리고 그 결과는 아래와 같다
/usr/local/bin/flthdr -p romfs/bin/boaz
romfs/bin/boaz
Magic: bFLT
Rev: 4
Entry: 0x50
Data Start: 0x11980
Data End: 0x13d40
BSS End: 0x15604
Stack Size: 0x2000
Reloc Start: 0x13d40
Reloc Count: 0x4f
Flags: 0x6 ( Has-PIC-GOT Gzip-Compressed )
ls -l romfs/bin/boa*
-rwxr--r-- 1 philw philw 81532 Jul 18 04:22 romfs/bin/boa
-rw-rw-r-- 1 philw philw 40261 Jul 18 04:16 romfs/bin/boaz
load to ram 비트는 -r 혹은 -R 옵션에 의해 변경될 수 있다.
/usr/local/bin/flthdr -r romfs/bin/boa
결과는 아래와 같다
/usr/local/bin/flthdr -p romfs/bin/boa
romfs/bin/boa
Magic: bFLT
Rev: 4
Entry: 0x50
Data Start: 0x11980
Data End: 0x13d40
BSS End: 0x15604
Stack Size: 0x2000
Reloc Start: 0x13d40
Reloc Count: 0x4f
Flags: 0x3 ( Load-to-Ram Has-PIC-GOT )
스택의 크기는 -s 옵션을 이용하여 변경할 수 있다.
/usr/local/bin/flthdr -s 16384 romfs/bin/boa
결과는 아래와 같다
usr/local/bin/flthdr -p romfs/bin/boa
romfs/bin/boa
Magic: bFLT
Rev: 4
Entry: 0x50
Data Start: 0x11980
Data End: 0x13d40
BSS End: 0x15604
Stack Size: 0x4000
Reloc Start: 0x13d40
Reloc Count: 0x4f
Flags: 0x2 ( Has-PIC-GOT )
7. 컴파일 플래그 ¶이 부분이 이 문서의 핵심이다. 각각의 시스템에서 XIP 로 동작시키기 위한 컴파일 플래그는 무엇일까? 다음 테이블을 살펴보면 도움을 얻을 수 있을 것이다. (TODO: 확인하고 테이블 완성하기) GOT 옵션은..??
8. 저자 ¶이 문서의 저자는 Phil Wilshire 이며
System Design & Consulting Services (SDCS) 의 트레이닝 프로그램의 일부로 사용되었다.
Please see: uClinux
|
How sharper than a hound's tooth it is to have a thankless serpent. |











주의: 이 플래그?를 이용해서 XIP 가 아닌 코드를 XIP 코드로 변경할 수는 없다. 하지만 XIP 코드가 (여러 인스턴스가 실행될 때) 텍스트 섹션을 강제로 로드하도록 할 수는 있다.
![[http]](/imgs/http.png)