Search

1.2 ELF 바이너리 포맷

1.1 ELF 바이너리 구조

2.1 ELF File Header

ELF 파일 헤더에는
1.
ELF 파일임을 나타내는 매직 코드
2.
ELF 파일 종류
3.
파일의 다른 요소들에 대한 오프셋
을 가지고 있습니다.
typedef struct { unsigned char e_ident[16]; /* 매직코드 및 기타 정보 */ uintl6_t e_type; /* 목적 파일 형식 */ uintl6_t e_machine; /* 아키텍처 */ uint32_t e_version; /* 목적 파일 버전 */ uint64_t e_entry; /* 엔트리 포인트 가상 주소 */ uint64_t e_phoff; /* 프로그램 헤더 테이블 파일 오프셋 */ uint64_t e_shoff; /* 섹션 헤더 테이블 파일 오프셋 */ uint32_t e_flags; /* 프로세서에 따른 전용 플래그 */ uintl6_t e_ehsize; /* ELF 헤더 크기(byte 단위) */ uintl6_t e_phentsize; /* 프로그램 헤더 테이블 엔트리 크기 */ uintl6_t e_phnum; /* 프로그램 헤더 테이블 엔트리 수 */ uintl6_t e_shentsize; /* 섹션 헤더 테이블 엔트리 크기 */ uintl6_t e_shnum; /* 섹션 헤더 테이블 엔트리 수 */ uintl6_t e_shstrndx; /* 섹션 헤더 문자열 테이블 인덱스 */ } Elf64_Ehdr;
C
복사
readelf -h 명령어를 사용하여 a.out의 File Header를 확인합니다.
# readelf -h a.out ELF Header: Magic: 7f 45 4c 46 //(0x00~03 고정값 e_ident[00~03] 02 //Class 값, e_idnet[04] 01 //Data 값, e_ident[05] 01 //EI_Version, e_ident[06] 00 // OS/ABI 값 e_ident[07] 00 // ABI Version 값, e_ident[08] 00 00 00 00 00 00 00 // Reserved, e_ident[09~15] Class: ELF64 // 2:ELF64, 1:ELF32, e_ident[04] Data: 2's complement, little endian // 1: little endian, 2: big endian, e_ident[05] Version: 1 (current) // 1: current, e_ident[06] OS/ABI: UNIX - System V // e_ident[07] ABI Version: 0 // e_ident[08] Type: DYN (Shared object file) //e_type Machine: Advanced Micro Devices X86-64 //e_machine Version: 0x1 // 위의 EI_VERSION과 동일, e_version Entry point address: 0x530 // Entry Point Offset, e_entry Start of program headers: 64 (bytes into file) // Program Header File Offset, e_phoff Start of section headers: 6440 (bytes into file) // Section Header File Offset, e_shoff Flags: 0x0 // default 0, e_flags Size of this header: 64 (bytes) // x64일 경우 64bytes 고정, x86일 경우 52bytes 고정, e_ehsize Size of program headers: 56 (bytes) // Program Header Size, e_phentsize Number of program headers: 9 // Program Header Number, e_phnum Size of section headers: 64 (bytes) // Section Header Size, e_shnum Number of section headers: 29 // Section Header Number, e_shnum Section header string table index: 28 // e_shstrndx
C
복사
Section Header String Table에는 말 그대로 Section Header의 String이 포함되어 있습니다.
root@DESKTOP-2HBCL3H:~/chp1/2# readelf -x .shstrtab a.out Hex dump of section '.shstrtab': 0x00000000 002e7379 6d746162 002e7374 72746162 ..symtab..strtab 0x00000010 002e7368 73747274 6162002e 696e7465 ..shstrtab..inte 0x00000020 7270002e 6e6f7465 2e414249 2d746167 rp..note.ABI-tag 0x00000030 002e6e6f 74652e67 6e752e62 75696c64 ..note.gnu.build 0x00000040 2d696400 2e676e75 2e686173 68002e64 -id..gnu.hash..d 0x00000050 796e7379 6d002e64 796e7374 72002e67 ynsym..dynstr..g 0x00000060 6e752e76 65727369 6f6e002e 676e752e nu.version..gnu. 0x00000070 76657273 696f6e5f 72002e72 656c612e version_r..rela. 0x00000080 64796e00 2e72656c 612e706c 74002e69 dyn..rela.plt..i 0x00000090 6e697400 2e706c74 2e676f74 002e7465 nit..plt.got..te 0x000000a0 7874002e 66696e69 002e726f 64617461 xt..fini..rodata 0x000000b0 002e6568 5f667261 6d655f68 6472002e ..eh_frame_hdr.. 0x000000c0 65685f66 72616d65 002e696e 69745f61 eh_frame..init_a 0x000000d0 72726179 002e6669 6e695f61 72726179 rray..fini_array 0x000000e0 002e6479 6e616d69 63002e64 61746100 ..dynamic..data. 0x000000f0 2e627373 002e636f 6d6d656e 7400 .bss..comment.
C
복사

2.2 Section Header

Section이란
ELF 바이너리의 코드와 데이터가 연속적이지만 겹치지 않는 조각의 형태로 논리적으로 분리되어 있는것을 Section 이라고 한다
또한 모든 Section은
1.
Section Header 에서 Section과 관련된 모든 정보를 찾을수 있으며
2.
Section Header Table 에서 모든 Section에 대한 해더 정보를 찾을 수 있다.
그리고 Section을 구분하는 목적은
1.
링커가 바이너리를 해석할 때 편리한 단위로 나눈 것이다.
2.
그래서 링킹 작업이 필요 없는 경우 Section Header가 불필요하다.
a.
외부 링킹을 하지 않는, 모든 함수가 하나의 C 파일에 짜져 있는 경우는 불필요 할 듯..?
Segment란
바이너리를 실행해 메모리상에 프로세스 형태로 불러올 때 실행 가능한 ELF 바이너리 내부의 코드와 데이터를 논리적인 영역으로 구분하는 것을 Segment라고 한다.
typedef struct { uint32_t sh_name; /* 섹션 이름(문자열 테이블 인덱스 번호) */ uint32_t sh_type; /* 섹션 타입 */ uint64_t sh_flags; /* 섹션 플래그 */ uint64_t sh_addr; /* 실행시점의 섹션 가상 주소 */ uint64_t sh_offset; /* 섹션 파일 오프셋 */ uint64_t sh_size; /* 바이트 단위의 섹션 크기 */ uint32_t sh_link; /* 다른 참조 섹션 */ uint32_t sh_info; /* 추가적인 섹션 정보 */ uint64_t sh_addralign; /* 섹션 배치 규칙 */ uint64_t sh_entsize; /* 섹션 테이블이 존재하는 경우 엔트리 크기 */ } Elf64_Shdr;
C
복사

2.2.1 sh_name

앞에서 본 .shstrtab의 인덱스 번호를 지칭하며, 없을 경우 Section 이름이 null인 경우입니다.

2.2.2 sh_type

해당 필드에 표기된 숫자로 Section의 타입을 구분합니다.
1.
SHT_PROGBITS
기계어 명령어, 상수값 등의 프로그램 데이터를 포함하고 있는 Section
링커가 따로 분석해야 할 별도의 특별한 구조를 갖지 않음
2.
Symbol Table 관련 Section
정적 심벌 테이블 타입인 SHT_SYMTAB
동적 링킹 심벌 테이블 타입인 SHT_DYNSYM
문자열 테이블 SHT_STRTAB
3.
Relocation 관련 Section
정적 링킹에 관련된 SHT_REL, SHT_RELA
동적 링킹에 관련된 SHT_DYNAMIC
4.
그 외의 Section Type의 경우 해당 링크에서 확인 할 수 있습니다.

2.2.3 sh_flags

해당 플래그는 Section과 관련한 추가 정보를 담고 있으며
중요 플래그로는 세가지가 있습니다
1.
SHF_WRITE
해당 플래그는 실행 시점에 Section이 쓰기 가능한 상태임을 의미합니다.
2.
SHF_ALLOC
주어진 바이너리가 실행될 때 해당 Section의 정보가 가상 메모리에 적재됨을 의미합니다.
여기서 설명하는 가상 메모리는 Swap File System. 즉 하드디스크의 일부를 메모리처럼 이용하는 방법을 말합니다. 가상 메모리 주소(Virtual Address) 와 혼동하지 않도록 주의!
3.
SHF_EXECINSTR
해당 Section이 실행 가능한 명령어들을 담고 있는 Section임을 의미합니다.

2.2.4 sh_addr, sh_offset, sh_size

1.
sh_addr
Section이 적재 될 가상 메모리 주소
2.
sh_offset
Section의 파일 오프셋
3.
sh_size
Section의 사이즈

2.2.5 sh_link

Section 사이의 연관 정보를 가지고 있는 필드이며, 관련된 Section의 인덱스 정보(Section Header Table의 Index)를 명시적으로 해당 필드에 표기합니다.

2.2.6 sh_info

섹션과 관련된 추가 정보를 제공하는 필드입니다.

2.2.7 sh_addralign

해당 Section의 align 유무를 설정하는 필드입니다.

2.2.8 sh_entsize

자료 구조 형태로 테이블을 가지는 Section(Symbol Table, Reloc Table)들의 table entry size를 가지는 필드입니다.

2.3 Section

readelf 명령어를 이용하여 본 샘플 파일입니다.
# readelf --sections --wide a.out There are 29 section headers, starting at offset 0x1928: Section Headers: [Nr] Name Type Address Off Size ES Flg Lk Inf Al [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 [ 1] .interp PROGBITS 0000000000000238 000238 00001c 00 A 0 0 1 [ 2] .note.ABI-tag NOTE 0000000000000254 000254 000020 00 A 0 0 4 [ 3] .note.gnu.build-id NOTE 0000000000000274 000274 000024 00 A 0 0 4 [ 4] .gnu.hash GNU_HASH 0000000000000298 000298 00001c 00 A 5 0 8 [ 5] .dynsym DYNSYM 00000000000002b8 0002b8 0000a8 18 A 6 1 8 [ 6] .dynstr STRTAB 0000000000000360 000360 000082 00 A 0 0 1 [ 7] .gnu.version VERSYM 00000000000003e2 0003e2 00000e 02 A 5 0 2 [ 8] .gnu.version_r VERNEED 00000000000003f0 0003f0 000020 00 A 6 1 8 [ 9] .rela.dyn RELA 0000000000000410 000410 0000c0 18 A 5 0 8 [10] .rela.plt RELA 00000000000004d0 0004d0 000018 18 AI 5 22 8 [11] .init PROGBITS 00000000000004e8 0004e8 000017 00 AX 0 0 4 [12] .plt PROGBITS 0000000000000500 000500 000020 10 AX 0 0 16 [13] .plt.got PROGBITS 0000000000000520 000520 000008 08 AX 0 0 8 [14] .text PROGBITS 0000000000000530 000530 0001a2 00 AX 0 0 16 [15] .fini PROGBITS 00000000000006d4 0006d4 000009 00 AX 0 0 4 [16] .rodata PROGBITS 00000000000006e0 0006e0 000012 00 A 0 0 4 [17] .eh_frame_hdr PROGBITS 00000000000006f4 0006f4 00003c 00 A 0 0 4 [18] .eh_frame PROGBITS 0000000000000730 000730 000108 00 A 0 0 8 [19] .init_array INIT_ARRAY 0000000000200db8 000db8 000008 08 WA 0 0 8 [20] .fini_array FINI_ARRAY 0000000000200dc0 000dc0 000008 08 WA 0 0 8 [21] .dynamic DYNAMIC 0000000000200dc8 000dc8 0001f0 10 WA 6 0 8 [22] .got PROGBITS 0000000000200fb8 000fb8 000048 08 WA 0 0 8 [23] .data PROGBITS 0000000000201000 001000 000010 00 WA 0 0 8 [24] .bss NOBITS 0000000000201010 001010 000008 00 WA 0 0 1 [25] .comment PROGBITS 0000000000000000 001010 000029 01 MS 0 0 1 [26] .symtab SYMTAB 0000000000000000 001040 0005e8 18 27 43 8 [27] .strtab STRTAB 0000000000000000 001628 000202 00 0 0 1 [28] .shstrtab STRTAB 0000000000000000 00182a 0000fe 00 0 0 1 Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings), I (info), L (link order), O (extra OS processing required), G (group), T (TLS), C (compressed), x (unknown), o (OS specific), E (exclude), l (large), p (processor specific)
C
복사
결과에서 샘플 파일에 대한 Section Name, Type, Address, Offset, Size, Type, Flag, Link, Info, Align 정보를 확인할 수 있습니다.

2.3.1 .init, .fini Section

1장에서 잠깐 설명한 것처럼 바이너리 실행, 종료 시 실행되는 루틴이 저장되어 있는 섹션입니다.

2.3.2 .text Section

.text Section은 일반적인 바이너리에서 실행 코드들이 존재하는 섹션입니다.
당연히 Type은 PROGBITS로 설정되어 있으며, Flags 또한 AX로 설정되어 있습니다.
일반적으로 gcc 컴파일러를 이용하여 컴파일 하는 경우
_start, _registertm_clones, frame_dummy와 같은 표준 함수가 자동으로 해당 섹션안에 포함됩니다.
_start 함수의 경우 메인 함수를 호출하는데 Disassemble한 결과를 보면 아래와 같습니다.
0000000000000530 <_start>: 530: 31 ed xor ebp,ebp 532: 49 89 d1 mov r9,rdx 535: 5e pop rsi 536: 48 89 e2 mov rdx,rsp 539: 48 83 e4 f0 and rsp,0xfffffffffffffff0 53d: 50 push rax 53e: 54 push rsp 53f: 4c 8d 05 8a 01 00 00 lea r8,[rip+0x18a] # 6d0 <__libc_csu_fini> 546: 48 8d 0d 13 01 00 00 lea rcx,[rip+0x113] # 660 <__libc_csu_init> 54d: 48 8d 3d e6 00 00 00 lea rdi,[rip+0xe6] # 63a <main> 554: ff 15 86 0a 20 00 call QWORD PTR [rip+0x200a86] # 200fe0 <__libc_start_main@GLIBC_2.2.5> 55a: f4 hlt 55b: 0f 1f 44 00 00 nop DWORD PTR [rax+rax*1+0x0] 000000000000063a <main>: 63a: 55 push rbp 63b: 48 89 e5 mov rbp,rsp 63e: 48 83 ec 10 sub rsp,0x10 642: 89 7d fc mov DWORD PTR [rbp-0x4],edi 645: 48 89 75 f0 mov QWORD PTR [rbp-0x10],rsi 649: 48 8d 3d 94 00 00 00 lea rdi,[rip+0x94] # 6e4 <_IO_stdin_used+0x4> 650: e8 bb fe ff ff call 510 <puts@plt> 655: b8 00 00 00 00 mov eax,0x0 65a: c9 leave 65b: c3 ret 65c: 0f 1f 40 00 nop DWORD PTR [rax+0x0]
C
복사
__libc_start_main@plt 함수를 호출하며, rdi 레지스터에 main 함수의 address를 전달합니다.
전달받은 함수는 해당 바이너리의 메인 함수를 호출하게 됩니다.

2.3.3 .rodata, .data, .bss

해당 Section에 대해서는 해당 문서(추가3. 메모리의 구조.데이터 영역)를 참고하시길 바랍니다.

2.3.4 지연바인딩과 .plt, .got, .got.plt

지연바인딩(Lazy Binding)이란
컴파일시 공유 라이브러리 함수의 링킹을 실행하지 않고, 런타임에서 해당 함수를 처음 참조하여 실행했을 때 링킹하는 것을 지연바인딩이라고 한다.
해당 기능은 동적 바인딩 시 시간 낭비를 줄일려고 하는 기법이며, LD_BIND_NOW를 이용하여 해당 기능을 Disable 할 수 있습니다. (bash shell에서 LD_BIND_NOW=1 입력)
호출 순서
1.
메인함수에서 공유 라이브러리 함수(.plt section) 호출
2.
함수@plt 함수로 jmp되어 .got section 의 함수 주소 참조
3.
.got section에서 참조한 함수 포인터로 jmp
4.
해당 함수 포인터에는 extern으로 함수가 선언되어 있음.
지연 바인딩을 쓰는 이유
1.
데이터 영역에 존재하기 때문에 쓰기가 불가능하여 보안성 강화
2.
공유 라이브러리의 코드 공유를 위해 사용

2.3.5 .rel, .rela section

두 Section 모두 재배치 과정에서 링커가 활용할 정보를 담고 있습니다.
root@DESKTOP-2HBCL3H:~/chp1/2# readelf --relocs a.out Relocation section '.rela.dyn' at offset 0x410 contains 8 entries: Offset Info Type Sym. Value Sym. Name + Addend 000000200db8 000000000008 R_X86_64_RELATIVE 630 000000200dc0 000000000008 R_X86_64_RELATIVE 5f0 000000201008 000000000008 R_X86_64_RELATIVE 201008 000000200fd8 000100000006 R_X86_64_GLOB_DAT 0000000000000000 _ITM_deregisterTMClone + 0 000000200fe0 000300000006 R_X86_64_GLOB_DAT 0000000000000000 __libc_start_main@GLIBC_2.2.5 + 0 000000200fe8 000400000006 R_X86_64_GLOB_DAT 0000000000000000 __gmon_start__ + 0 000000200ff0 000500000006 R_X86_64_GLOB_DAT 0000000000000000 _ITM_registerTMCloneTa + 0 000000200ff8 000600000006 R_X86_64_GLOB_DAT 0000000000000000 __cxa_finalize@GLIBC_2.2.5 + 0 Relocation section '.rela.plt' at offset 0x4d0 contains 1 entry: Offset Info Type Sym. Value Sym. Name + Addend 000000200fd0 000200000007 R_X86_64_JUMP_SLO 0000000000000000 puts@GLIBC_2.2.5 + 0
C
복사
해당 결과에는 Reloc Type이 2가지가 존재합니다.
1.
R_X86_64_GLOB_DAT
2.
R_X86_64_JUMP_SLO
1번의 경우 Data Symbol의 올바른 주소를 계산하고 올바른 오프셋에 연결하는데 사용됩니다.
2번의 경우 Jump Slot으로 오프셋에는 해당 라이브러리의 함수 주소를 담는데 사용됩니다.

2.3.6 .dynamic Section

.dynamic Section의 경우 바이너리를 로드 할 때 운영체제와 동적 링커에게 로드맵을 제시하는 역할을 합니다.
.dynamic Section은 Elf64_Dyn 구조의 테이블을 포함하며, 태그라고 표현되기도 합니다.
root@DESKTOP-2HBCL3H:~/chp1/2# readelf --dynamic a.out Dynamic section at offset 0xdc8 contains 27 entries: Tag Type Name/Value 0x0000000000000001 (NEEDED) Shared library: [libc.so.6] 0x000000000000000c (INIT) 0x4e8 0x000000000000000d (FINI) 0x6d4 0x0000000000000019 (INIT_ARRAY) 0x200db8 0x000000000000001b (INIT_ARRAYSZ) 8 (bytes) 0x000000000000001a (FINI_ARRAY) 0x200dc0 0x000000000000001c (FINI_ARRAYSZ) 8 (bytes) 0x000000006ffffef5 (GNU_HASH) 0x298 0x0000000000000005 (STRTAB) 0x360 0x0000000000000006 (SYMTAB) 0x2b8 0x000000000000000a (STRSZ) 130 (bytes) 0x000000000000000b (SYMENT) 24 (bytes) 0x0000000000000015 (DEBUG) 0x0 0x0000000000000003 (PLTGOT) 0x200fb8 0x0000000000000002 (PLTRELSZ) 24 (bytes) 0x0000000000000014 (PLTREL) RELA 0x0000000000000017 (JMPREL) 0x4d0 0x0000000000000007 (RELA) 0x410 0x0000000000000008 (RELASZ) 192 (bytes) 0x0000000000000009 (RELAENT) 24 (bytes) 0x000000000000001e (FLAGS) BIND_NOW 0x000000006ffffffb (FLAGS_1) Flags: NOW PIE 0x000000006ffffffe (VERNEED) 0x3f0 0x000000006fffffff (VERNEEDNUM) 1 0x000000006ffffff0 (VERSYM) 0x3e2 0x000000006ffffff9 (RELACOUNT) 3 0x0000000000000000 (NULL) 0x0
C
복사
결과를 보면 각 태그와, 태그의 타입, Name과 Value를 볼 수 있습니다.
DT_NEEDED의 경우 동적 링커에게 해당 바이너리와 의존성 관계를 알려주는 역할을 합니다.
DT_VERNEED, DT_VERNEEDNUM 태그는 버전 의존성 테이블의 시작 주소와 엔트리 수를 가르킵니다.

2.3.7 .init_array, .fini_array Section

.init_array Section의 경우 main 함수가 시작되기 전 필요한 생성자 함수들이 연결되어 있는 포인터들의 배열입니다 (vtable)
.fini_array의 경우 .init_array와 동일하지만 소멸자 함수들이 연결되어 있는 VTable입니다.

2.3.8 .shstrtab, .symtab, .strtab, .dynsym, .dynstr Section

1.
.shstrtab
바이너리에서 사용되는 모든 Section의 이름을 문자열로 담고있는 Section.
숫자로 된 Index 를 가지고 있습니다.
2.
.symtab
심볼 테이블 정보를 가지고 있는 Section.
링킹시 해당 이름을 가지고 있는 함수와 변수들과 연결된다
strip 적용 시 사라진다
3.
.strtab
심볼들의 실제 이름을 가지고 있는 Section
strip 적용 시 사라진다
4.
.dynsym
동적 링킹 시 필요한 심볼 테이블 정보를 가지고 있는 Section
동적 링킹에 필요한 Section이기 때문에 Strip을 적용해도 사라지지 않는다
5.
.dyntab
동적 링킹 시 필요한 심볼들의 실제 이름을 가지고 있다.
동적 링킹에 필요한 Section이기 때문에 Strip을 적용해도 사라지지 않는다

4. 프로그램 헤더

프로그램 해더는 바이너리를 Segment 관점에서 해석할 수 있도록 하는 구조체이다.
Segment의 경우 0개, 그 이상의 Section을 포함하며, 본질적으로 Section을 하나의 단일 조각으로 묶어서 처리한다.
# readelf --wide --segments a.out Elf file type is DYN (Shared object file) Entry point 0x530 There are 9 program headers, starting at offset 64 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align PHDR 0x000040 0x0000000000000040 0x0000000000000040 0x0001f8 0x0001f8 R 0x8 INTERP 0x000238 0x0000000000000238 0x0000000000000238 0x00001c 0x00001c R 0x1 [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2] LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000838 0x000838 R E 0x200000 LOAD 0x000db8 0x0000000000200db8 0x0000000000200db8 0x000258 0x000260 RW 0x200000 DYNAMIC 0x000dc8 0x0000000000200dc8 0x0000000000200dc8 0x0001f0 0x0001f0 RW 0x8 NOTE 0x000254 0x0000000000000254 0x0000000000000254 0x000044 0x000044 R 0x4 GNU_EH_FRAME 0x0006f4 0x00000000000006f4 0x00000000000006f4 0x00003c 0x00003c R 0x4 GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10 GNU_RELRO 0x000db8 0x0000000000200db8 0x0000000000200db8 0x000248 0x000248 R 0x1 Section to Segment mapping: Segment Sections... 00 01 .interp 02 .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame 03 .init_array .fini_array .dynamic .got .data .bss 04 .dynamic 05 .note.ABI-tag .note.gnu.build-id 06 .eh_frame_hdr 07 08 .init_array .fini_array .dynamic .got
C
복사

2.4.1 p_type 필드

p_type 필드는 Segment의 유형을 식별하는 역할을 하며, 여기서 중요한 값은 PT_LOAD, PT_DYNAMIC, PT_INTERP이다
1.
PT_LOAD
프로세스가 초기에 생성되고 메모리에서 로드되는 과정에서 사용됨
첫번째 LOAD Segment의 경우 코드 영역, 두번째 LOAD Segment의 경우 데이터 영역
2.
PT_INTERP
바이너리 로드 할 때 사용할 인터프리터의 이름을 지정 (동적 라이브러리 로드)
3.
PT_DYNAMIC
.dynamic Section이 포함되어 있으며, 바이너리 로드 시 인터프리터가 수행해야 할 구문 분석 등의 준비작업을 명시

2.4.2 p_flags

해당 Segment에 대한 실행 권한을 명시합니다.
PF_X = 실행 권한
PF_W = 쓰기 권한
PF_R = 읽기 권한

2.4.3 p_offset, p_vaddr, p_paddr, p_filesz, p_memsz

각각 Segment의 파일 오프셋, 가상 메모리 주소, 물리 메모리 주소, 파일 사이즈, 메모리 사이즈를 뜻합니다.

2.4.4 p_align

정렬에 필요한 메모리 양(바이트 단위)를 뜻합니다.