-
ELF 파일 포맷(1)Linux System 2019. 3. 11. 03:48
ELF(Excutable and Linkable Format)
단순하게 말하면 그냥 리눅스/유닉스에서의 실행파일
디스크에 저장되어 있던 프로그램이 메모리 영역에 올라가서 컴퓨팅 자원을 사용하여 서비스를 제공해주는 것.
ELF에서는 프로그램이 실행될 때 메모리에 올라가야 할 각각의 부분들을 미리 정리하여 관리하다가 실행을 하게 되면 정리된 부분들(코드, 전역데이터, 읽기 전용 데이터 등등)을 메모리에 올리게 된다. (이 때 며가지 영역이 덧 붙게 된다.)
이렇게 메모리에 올라온 주소 공간의 .text 섹션(코드 영역)의 Instruction을 한 라인씩 실행하며 프로세스가 진행된다.
Linkable이란?
라이브러리 예를 가지고 살펴보면,
foo와 my_data의 정의가 main에 존재하지 않는다. 이 때, main.c를 컴파일 해도 완벽한 프로그램이 될 수 없다. 두 symbol을 알려줘야지 제대로 된 완벽한 프로그램이 될 수 있다.
이 때 이 알려주는 시점은 다양하지만(컴파일 시, 메모리에 로드 시, 런타임 중),
ELF는 "나 아직 foo와 my_data에 대해서 몰라! 언젠지 몰라도 나 완벽해져야 되니까 알려줘!"라고 하면서 .rel 섹션에다가 symbol들을 적어두고 알려달라고, 즉, relocatable symbol들을 reference resolving 해달라고 적어둔다.
이후에 링커 스크립터가 돌면서 모르는 relocatable symbol들을 다른 ELF나 라이브러리에서 알아내 연결(Link)을 해주게 된다.
좀 더 포맷 관점에서 알아보자!
ELF 포맷은 리눅스와 BSD게열 및 그 외의 OS엣서 실행파일(Executables), 공유 라이브러리(Shared Libraries), 오브젝트 파일(Obejct Files), 코어 덤프 파일(Coredump Files) 및 커널 부트 이미지에서 사용을 한다.
ELF 파일 포맷은 readelf 명령어를 통해 확인이 가능하다.
ex) readelf -a example
1. ELF 파일 형식
1) ET_NONE (ELF type none) (0x 0000)
: 알 수 없는 형식 -> 아직 정의되지 않았거나 알 수 없다는 의미
2) ET_REL (ELF type relocatable) (0x 0001) - 링킹 가능한 포맷
: 재배열이 가능한 파일 형식 -> 아직 실행파일에 링킹되지 않은 상태
(*.o 파일로 컴파일만 진행된 상태)
- relocatable symbol들을 symbol resolving reference 해야하는 바이너리
3) ET_EXEC (ELF type executable) (0x0002) - 실행 가능한 포맷
: 실행 파일 형식(= 프로그램) -> 프로세스의 시작 지점인 엔트리 포인트가 존재
- relocatable symbol들을 모두 symbol resolving reference 해서 실행 가능한 바이너리
4) ET_DYN (ELF type dynamic) (0x0003) - 실행 가능하면서 링킹 가능한 포맷
: 공유 오브젝트 파일 형식 -> 동적 링킹이 가능한 오브젝트 파일 (= 공유 라이브러리)
(런타임 중에 프로그램의 프로세스 이미지로 로드되고 링크 됨)
- relocatable symbol들을 symbol resolving reference 해서 실행 가능하지만, 공유 혹은 동적 라이브러리를 실행 시에 혹은 런타임에 링킹시켜야 하는 바이너리
5) ET_CORE (ELF type core) (0x0004)
: 코어 파일 형식 -> 프로세스 이미지의 전체 덤프
주로 프로그램이 비정상 종료되거나 SIGSEGV 시그널(세그멘테이션 폴트)로 인해 프로세스가 종료된 경우 생성
GDB로 코어파일을 읽어 분석해 비정상 종료된 시점의 원인 분석이 가능
Ex)
2. ELF는 2가지 View를 가진다.
- Linking View가 relocatable file의 형식. (즉, Link 하기 전의 object file(*.o)은 Linking View)
(나중에 Link 과정을 위해 다른 Object file하고 연결하려고 여러가지 정보들을 심어놓은 것)
- Link가 끝난 후에 완전히 실행 가능한 형태가 된 ELF 형식을 Execution View라고 한다.
3. ELF 파일 헤더 (ELF Header)
- 이 헤더는 Linking View이던 Execution View이던 무조건 가지고 있다.
- ELF header는 현재의 ELF 파일에 대한 정의를 한다.
- Program header table과 Section header table의 위치를 결정한다.
- Zero offset에서 시작.
- 구조체
#define EI_NIDENT 16
typedef struct {
unsigned char e_ident[EI_NIDENT];uint16_t e_type; // ELF 파일 형식 (위에서 언급)
uint16_t e_machine; // CPU 아키텍쳐 타입
uint32_t e_version; // ELF 파일 버전 (거의 무조건 0x1)
ElfN_Addr e_entry; // Virtual Memory상의 엔트리 포인트
ElfN_Off e_phoff; // program header table 파일 오프셋
ElfN_Off e_shoff; // section header table 파일 오프셋
uint32_t e_flags; // processor specific flags
uint16_t e_ehsize; // ELF header 사이즈 (bytes)
uint16_t e_phentsize; // program header table entry 사이즈
uint16_t e_phnum; // program header table entry의 갯수
uint16_t e_shentsize; // section header table entry 사이즈
uint16_t e_shnum; // section header table entry의 갯수
uint16_t e_shstrndx; // section header string table의 인덱스
}ElfN_Ehdr;
- e_ident는 또 몇가지 영역으로 나눠서 볼 수 있다.
0x00 (4bytes) - 7F 45 4C 46 (ELF) : ELF 파일의 Magic Number
0x04 (1bytes) e_ident[EI_CLASS] : 32bit format인 경우 1, 64bit format인 경우 2를 세팅.
0x05 (1bytes) e_ident[EI_DATA] : Little Endian인 경우 1, Big Endian인 경우 2를 세팅
0x06 (1bytes) e_ident[EI_VERSION] : ELF 파일의 버전, 1로 세팅
0x07 (1bytes) e_ident[EI_OSABI] : OS 식별자
0x08 (1bytes) e_ident[EI_ABIVERSION]
0x09 (7bytes) e_ident[EI_PAD] : 사용하지 않음. - 0x00으로 채움.
Ex) Execution 파일을 헥스에디터와 readelf로 비교해보았다.
'Linux System' 카테고리의 다른 글
ELF 파일 포맷(3) (0) 2019.03.14 ELF 파일 포맷(2) (0) 2019.03.11 라이브러리 (0) 2019.03.11 파일 디스크립터 (0) 2019.03.10 댓글