3. Section header
ELF file에는 여러 Section이 위치하고, 각 Section 관련 정보는 Section header에 보관됩니다.
또한, 각 Section은 고유의 이름을 가질 수 있고 주요 Section으로는 .text와 .data를 들 수 있습니다.
.text section은 프로그램의 instruction을 보관하고 있고, .data section은 프로그램 시작 전 초기화되는 값들을 보관하고 있습니다.
아래는 실행 파일과 오브젝트 파일의 Section header 정보 예제입니다.
예제1) 실행 파일
hwjung@jhaewon-z01:~$ readelf -S helloworld
There are 31 section headers, starting at offset 0x3978:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .interp PROGBITS 0000000000000318 00000318
000000000000001c 0000000000000000 A 0 0 1
[ 2] .note.gnu.propert NOTE 0000000000000338 00000338
0000000000000020 0000000000000000 A 0 0 8
[ 3] .note.gnu.build-i NOTE 0000000000000358 00000358
0000000000000024 0000000000000000 A 0 0 4
[ 4] .note.ABI-tag NOTE 000000000000037c 0000037c
0000000000000020 0000000000000000 A 0 0 4
[ 5] .gnu.hash GNU_HASH 00000000000003a0 000003a0
0000000000000024 0000000000000000 A 6 0 8
[ 6] .dynsym DYNSYM 00000000000003c8 000003c8
00000000000000a8 0000000000000018 A 7 1 8
[ 7] .dynstr STRTAB 0000000000000470 00000470
0000000000000082 0000000000000000 A 0 0 1
[ 8] .gnu.version VERSYM 00000000000004f2 000004f2
000000000000000e 0000000000000002 A 6 0 2
[ 9] .gnu.version_r VERNEED 0000000000000500 00000500
0000000000000020 0000000000000000 A 7 1 8
[10] .rela.dyn RELA 0000000000000520 00000520
00000000000000c0 0000000000000018 A 6 0 8
[11] .rela.plt RELA 00000000000005e0 000005e0
0000000000000018 0000000000000018 AI 6 24 8
[12] .init PROGBITS 0000000000001000 00001000
000000000000001b 0000000000000000 AX 0 0 4
[13] .plt PROGBITS 0000000000001020 00001020
0000000000000020 0000000000000010 AX 0 0 16
[14] .plt.got PROGBITS 0000000000001040 00001040
0000000000000010 0000000000000010 AX 0 0 16
[15] .plt.sec PROGBITS 0000000000001050 00001050
0000000000000010 0000000000000010 AX 0 0 16
[16] .text PROGBITS 0000000000001060 00001060
0000000000000185 0000000000000000 AX 0 0 16
[17] .fini PROGBITS 00000000000011e8 000011e8
000000000000000d 0000000000000000 AX 0 0 4
[18] .rodata PROGBITS 0000000000002000 00002000
0000000000000010 0000000000000000 A 0 0 4
[19] .eh_frame_hdr PROGBITS 0000000000002010 00002010
0000000000000044 0000000000000000 A 0 0 4
[20] .eh_frame PROGBITS 0000000000002058 00002058
0000000000000108 0000000000000000 A 0 0 8
[21] .init_array INIT_ARRAY 0000000000003db8 00002db8
0000000000000008 0000000000000008 WA 0 0 8
[22] .fini_array FINI_ARRAY 0000000000003dc0 00002dc0
0000000000000008 0000000000000008 WA 0 0 8
[23] .dynamic DYNAMIC 0000000000003dc8 00002dc8
00000000000001f0 0000000000000010 WA 7 0 8
[24] .got PROGBITS 0000000000003fb8 00002fb8
0000000000000048 0000000000000008 WA 0 0 8
[25] .data PROGBITS 0000000000004000 00003000
0000000000000010 0000000000000000 WA 0 0 8
[26] .bss NOBITS 0000000000004010 00003010
0000000000000008 0000000000000000 WA 0 0 1
[27] .comment PROGBITS 0000000000000000 00003010
0000000000000024 0000000000000001 MS 0 0 1
[28] .symtab SYMTAB 0000000000000000 00003038
0000000000000618 0000000000000018 29 46 8
[29] .strtab STRTAB 0000000000000000 00003650
0000000000000208 0000000000000000 0 0 1
[30] .shstrtab STRTAB 0000000000000000 00003858
000000000000011a 0000000000000000 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)
예제2) 오브젝트 파일
hwjung@jhaewon-z01:~$ readelf -S functionA.o
There are 12 section headers, starting at offset 0x258:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .text PROGBITS 0000000000000000 00000040
0000000000000013 0000000000000000 AX 0 0 1
[ 2] .data PROGBITS 0000000000000000 00000053
0000000000000000 0000000000000000 WA 0 0 1
[ 3] .bss NOBITS 0000000000000000 00000053
0000000000000000 0000000000000000 WA 0 0 1
[ 4] .comment PROGBITS 0000000000000000 00000053
0000000000000025 0000000000000001 MS 0 0 1
[ 5] .note.GNU-stack PROGBITS 0000000000000000 00000078
0000000000000000 0000000000000000 0 0 1
[ 6] .note.gnu.propert NOTE 0000000000000000 00000078
0000000000000020 0000000000000000 A 0 0 8
[ 7] .eh_frame PROGBITS 0000000000000000 00000098
0000000000000038 0000000000000000 A 0 0 8
[ 8] .rela.eh_frame RELA 0000000000000000 000001d8
0000000000000018 0000000000000018 I 9 7 8
[ 9] .symtab SYMTAB 0000000000000000 000000d0
00000000000000f0 0000000000000018 10 9 8
[10] .strtab STRTAB 0000000000000000 000001c0
0000000000000017 0000000000000000 0 0 1
[11] .shstrtab STRTAB 0000000000000000 000001f0
0000000000000067 0000000000000000 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)
Section header는 다음 구조체로 정의되어 있습니다. 아래는 32bit 예제입니다.
// Section header.
struct Elf32_Shdr {
Elf32_Word sh_name;
Elf32_Word sh_type;
Elf32_Word sh_flags;
Elf32_Addr sh_addr;
Elf32_Off sh_offset;
Elf32_Word sh_size;
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign;
Elf32_Word sh_entsize;
};
위 구조체의 각 필드에 대해서 알아보겠습니다.
1) sh_name : section 이름
section 이름은 section header 중 string table section을 이용하여 표현합니다.
우선 ELF header에 있는 string table index 값을 확인합니다. 여기서는 30번째 section이 string table이라는 것을 의미합니다.
hwjung@jhaewon-z01:~$ readelf -h helloworld ELF Header: ... Section header string table index: 30 |
다음 section 중 30번째 section을 확인합니다. 30번째 section의 이름을 보면 .shstrtab으로 되어 있는 것을 알 수 있습니다.
hwjung@jhaewon-z01:~$ readelf -S helloworld There are 31 section headers, starting at offset 0x3978: Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align [ 0] NULL 0000000000000000 00000000 0000000000000000 0000000000000000 0 0 0 [ 1] .interp PROGBITS 0000000000000318 00000318 000000000000001c 0000000000000000 A 0 0 1 ... [30] .shstrtab STRTAB 0000000000000000 00003858 000000000000011a 0000000000000000 0 0 1 |
section 이름을 찾기 위해서는 이 .shstrtab section의 주소와 section의 sh_name 값을 더 해서 위치 값을 계산해야 합니다.
sh_name을 찾기 위해 section header의 starting offset 값인 0x3978 근처를 hexdump로 확인합니다.다음과 같이 sh_name 값이 0x1b 인 것을 알 수 있습니다.
00003970 74 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |t...............| 00003980 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 000039b0 00 00 00 00 00 00 00 00 1b 00 00 00 01 00 00 00 |................| ## sh_name ## sh_type 000039c0 02 00 00 00 00 00 00 00 18 03 00 00 00 00 00 00 |................| ## sh_flags ## sh_addr 000039d0 18 03 00 00 00 00 00 00 1c 00 00 00 00 00 00 00 |................| ## sh_offset ## sh_size 000039e0 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |................| ## sh_link ## sh_info ## sh_addralign 000039f0 00 00 00 00 00 00 00 00 23 00 00 00 07 00 00 00 |........#.......| ## sh_entsize |
그러면, .shstrtab section 주소인 0x3858과 sh_name 값인 0x1b를 더하면, 0x3873이므로 해당 위치의 값을 Hexdump로 확인해보면 section의 이름인 .interp를 확인할 수 있습니다.
00003860 00 2e 73 74 72 74 61 62 00 2e 73 68 73 74 72 74 |..strtab..shstrt| 00003870 61 62 00 2e 69 6e 74 65 72 70 00 2e 6e 6f 74 65 |ab..interp..note| 00003880 2e 67 6e 75 2e 70 72 6f 70 65 72 74 79 00 2e 6e |.gnu.property..n| 00003890 6f 74 65 2e 67 6e 75 2e 62 75 69 6c 64 2d 69 64 |ote.gnu.build-id| |
2) sh_type : section 유형
// Section types.
enum : unsigned {
SHT_NULL = 0, // No associated section (inactive entry).
SHT_PROGBITS = 1, // Program-defined contents.
SHT_SYMTAB = 2, // Symbol table.
SHT_STRTAB = 3, // String table.
SHT_RELA = 4, // Relocation entries; Elf32_Rela 형태
SHT_HASH = 5, // Symbol hash table. dynamic linking의 경우 hash table 필요
SHT_DYNAMIC = 6, // Information for dynamic linking. dynamic section은 오직 1개
SHT_NOTE = 7, // Information about the file.
SHT_NOBITS = 8, // Data occupies no space in the file.
SHT_REL = 9, // Relocation entries; no explicit addends.
SHT_SHLIB = 10, // Reserved.
SHT_DYNSYM = 11, // Symbol table.
...
}
3) sh_flags : section flag
// Section flags.
enum : unsigned {
SHF_WRITE = 0x1, // Section data should be writable during execution.
SHF_ALLOC = 0x2, // Section occupies memory during program execution.
SHF_EXECINSTR = 0x4, // Section contains executable machine instructions.
SHF_MERGE = 0x10, // The data in this section may be merged.
SHF_STRINGS = 0x20, // The data in this section is null-terminated strings.
SHF_INFO_LINK = 0x40U, // A field in this section holds a section header table index.
SHF_LINK_ORDER = 0x80U, // Adds special ordering requirements for link editors.
SHF_OS_NONCONFORMING = 0x100U, // This section requires special OS-specific processing to avoid incorrect behavior.
SHF_GROUP = 0x200U, // This section is a member of a section group.
SHF_TLS = 0x400U, // This section holds Thread-Local Storage.
...
}
4) sh_addr : section 시작 주소
5) sh_offset : file 내에서 section offset
6) sh_size : section 크기
7) sh_link : 다른 section으로의 포인터
symbol table(SHT_SYMTAB)과 dynamic section(SHT_DYNAMIC)의 경우, sh_link 값은 string table의 index를 제공합니다.
symbol hash table(SHT_GNU_HASH)과 relocation table(SHT_RELA)의 경우, sh_link 값은 관련된 symbol table의 index를 제공합니다.
8) sh_info : section 추가 정보
relocation table(RELA)의 경우, sh_info 값은 적용할 section의 index를 제공합니다.
9) sh_addralign : section 주소 정렬
10) sh_entsize : section에 보관된 record의 크기
Section 관련하여, 좀 더 자세히 정리해보겠습니다.
Section name | Usage |
.text | 프로그램 code instruction 저장, Text Segment에 위치 |
.data | 초기화된 전역 변수 등의 데이터 저장, Data Segment에 위치 |
.rodata | 읽기 전용 데이터, 문자열 등이 저장 |
.bss | 초기화 되지 않은 전역 데이터 저장, Data Segment에 위치 프로그램 로드 시에 0으로 초기화 |
.dynsym | 공유 라이브러리에서 import된 동적 Symbol 정보, Text Segment에 위치 |
.dynstr | 동적 Symbol String Table 정보 |
.symtab | ElfN_Sym 형식의 Symbol 정보 |
.strtab | .symtab section의 ElfN_Sym 구조체에 있는 st_name field에 의해 참조되는 Symbol String Table 정보 |
.rel.* | relocation section은 ELF 객체 또는 프로세스 이미지의 어떤 부분이 Linking 시 또는 Runtime에 relocate 되어야 하는지 알려줌 |
.got.plt | 이 section과 PLT 정보를 통해 import된 공유 라이브러리 함수에 접근 가능 Dynamic linker에 의해 Runtime에 정보 수정 가능 |
.hash | Symbol 참조 hash table |
.shstrtab | Null terminator 문자열과 각 section 이름을 나타내는 section header ELF header의 e_shstrndx 의 offset에 의해 참조 |
이상으로 ELF Format에 대한 내용을 마치겠습니다.
'Debugging > Linux' 카테고리의 다른 글
CPU Registers and Instructions - Instructions (0) | 2022.11.05 |
---|---|
CPU Registers and Instructions - Registers (0) | 2022.11.03 |
64bit Stack Walking (0) | 2022.10.14 |
ELF Format #2 - Program Header (0) | 2022.10.08 |
ELF Format #1 - ELF Header (0) | 2022.10.03 |