ELF file format

ELF ELF는 Executable and Linkable Format의 약자로 executables, object code, shared libraries, core dumps를 위한 일반적인 파일포멧이다.
x86 시스템에서 Unix, Unix-like 운영체제에서의 기본파일 포멧이다.
ELF는 매우 유연하게 디자인되어서 프로세서나 아키첵터에 영향을 받지않고 여러 플랫폼과 운영체제에서 사용할 수 있다.

linux상에서 코드를 컴파일 할 때 생성 할 수 있는 a.o(gcc -c a.c, object code)파일과 a(gcc -o a a.c, executables)파일 모두 ELF파일 포멧을 갖고 있다.

ELF파일의 구조를 살펴보자.



아래쪽에 Section header table이 있다는 것 말고는 PE파일와 상당히 비슷하게 생겼다.
파일시스템이나 메모리 관리 같은 부분도 운영체제마다 다르긴 하지만 크게 다르지 않다
아마도 어짜피 폰노이만구조의 컴퓨터를 사용하기 때문에 최적화를 하다보면 비슷해 지는것 같다.

각 영역에는

ELF header
Program header table    //segments에 대한 정보
.text    //기계어
.rodata    //문자열
.data    //변수
Section header table    //sention에 대한 정보

의 정보가 들어 있다.

리눅스에서 gcc로 컴파일된 실행가능한 파일의 elf헤더를 뒤져보자.



readelf 의 -h옵션을 이용하면 ELF파일의 헤더를 보기좋게 파싱하여 보여준다.
각각의 정보는 readelf가 이름을 잘붙여주어 elf파일의 정보를 쉽게 볼 수 있다.

elf 헤더에 대한 typedef는 elf.h에 선언되어 있다.



elf.h의 구조체의 변수와 a파일의 ELF 헤더의 헥사값을 직접 비교해 보고 싶었는데
readelf를 사용해서는 보기가 불편하여 보기좋게 직접 넣어보았다.(클릭)



이제 ELF헤더의 각각의 값들이 어떤 정보를 의미하는지 알아보자.

첫 4바이트는 매직넘버로 "0x7f 0x45 0x4c 0x46(\177ELF)"의 값을 갖고 있다.
다음 1바이트는 1일 경우 32bit format, 2일 경우 64bit format임을 알려준다.
다음 1바이트는 1일 경우 little endianness, 2일 경우 big endianness로 사용되는 엔디언을 알려준다.
다음 1바이트는 ELF의 버젼으로 1이 오리지널 버젼이다.
다음 1바이트는 OS,ABI의 정보를 담고 있다.
다음 1바이트는 ABI의 버젼정보를 담고 있다. 리눅스의 경우 정의되어있지 않다.
다음 7바이트(리눅스일경우 ABI버젼이 없기때문에 8바이트)는 패딩으로 0으로 셋되있다.
다음 2바이트는 elf파일의 타입을 알려준다.(1=relocatable, 2=executable, 3=shared, 4=core)
다음 2바이트는 어떤 아키텍처의 인스트럭션을 사용하는지 알려준다.
다음 4바이트는 버젼으로 오리지날 elf는 1로 셋되어있다.
다음 4바이트는 ELF의 프로세스가 실행시 처음 시작되는 엔트리포인트이다.(VA)
다음 4바이트는 program header table의 시작을 알 수 있는 오프셋 값이다.
다음 4바이트는 section header table의 시작을 알 수 있는 오프셋 값이다.
다음 4바이트는 flags
다음 2바이트는 헤더의 사이즈로 일반적으로 32비트는 52의 값을 갖고있다.
다음 2바이트는 program header table의 사이즈 값이다.
다음 2바이트는 program header table의 갯수를 갖고있다.
다음 2바이트는 section header table의 사이즈를 갖고 있다.
다음 2바이트는 section header table의 갯수를 갖고 있다.
다음 2바이트는 섹션이름을 갖고있는 section header table의 인덱스를 갖고 있다.

ELF파일이 executable파일일 경우 elf헤더중 e_shnum값이나 e_shstrndx값 같이 실행시 필요 없는 부분은 값이 손상되어도 파일을 실행 할 수 있다.
하지만 readelf같이 파일헤더를 파싱해오는 프로그램은 executable파일이어도 모든 헤더 영역을 다 읽기 때문에 정보를 읽어오는데 문제가 발생 할 수 있다.

ELF파일의 program header table은 readelf -l 을 사용하여 볼 수 있다.



Program header를 보면 프로그램 헤더의 타입과 주소,오프셋등의 정보가 들어 있다.
elf.h에 정의되어있는 p_type의 정보들이다.

#define PT_NULL  0  /* Program header table entry unused */
#define PT_LOAD  1  /* Loadable program segment */
#define PT_DYNAMIC 2  /* Dynamic linking information */
#define PT_INTERP 3  /* Program interpreter */
#define PT_NOTE  4  /* Auxiliary information */
#define PT_SHLIB 5  /* Reserved */
#define PT_PHDR  6  /* Entry for header table itself */
#define PT_NUM  7  /* Number of defined types.  */
#define PT_LOOS  0x60000000 /* Start of OS-specific */
#define PT_HIOS  0x6fffffff /* End of OS-specific */
#define PT_LOPROC 0x70000000 /* Start of processor-specific */
#define PT_HIPROC 0x7fffffff /* End of processor-specific */

그 밑으로 보이는 Section to Segment mapping 은 위의 Program header의 영역에 포함되는 섹션들의 이름이 쓰여져 있다.
(줄단위로 매핑해서 보면 된다.)

ELF파일의 Section header table은 readelf -S로 볼 수 있다.


elf.h에 정의되어있는 section 타입을 알아보자.

#define SHT_NULL  0  /* Section header table entry unused */
#define SHT_PROGBITS  1  /* Program data */
#define SHT_SYMTAB  2  /* Symbol table */
#define SHT_STRTAB  3  /* String table */
#define SHT_RELA  4  /* Relocation entries with addends */
#define SHT_HASH  5  /* Symbol hash table */
#define SHT_DYNAMIC  6  /* Dynamic linking information */
#define SHT_NOTE  7  /* Notes */
#define SHT_NOBITS  8  /* Program space with no data (bss) */
#define SHT_REL   9  /* Relocation entries, no addends */
#define SHT_SHLIB  10  /* Reserved */
#define SHT_DYNSYM  11  /* Dynamic linker symbol table */
#define SHT_NUM   12  /* Number of defined types.  */
#define SHT_LOOS  0x60000000 /* Start OS-specific */
#define SHT_LOSUNW  0x6ffffffb /* Sun-specific low bound.  */
#define SHT_SUNW_COMDAT  0x6ffffffb
#define SHT_SUNW_syminfo 0x6ffffffc
#define SHT_GNU_verdef  0x6ffffffd /* Version definition section.  */
#define SHT_GNU_verneed  0x6ffffffe /* Version needs section.  */
#define SHT_GNU_versym  0x6fffffff /* Version symbol table.  */
#define SHT_HISUNW  0x6fffffff /* Sun-specific high bound.  */
#define SHT_HIOS  0x6fffffff /* End OS-specific type */
#define SHT_LOPROC  0x70000000 /* Start of processor-specific */
#define SHT_HIPROC  0x7fffffff /* End of processor-specific */
#define SHT_LOUSER  0x80000000 /* Start of application-specific */
#define SHT_HIUSER  0x8fffffff /* End of application-specific */

참고링크의 elf.h를 보면 elf의 더 많은 구조체들을 만날 수 있다.

참고
1. elf.h
2. wikipedia

댓글 1개: