ELF File Structure: Segments and Sections
An ELF (Executable and Linkable Format) file is composed a header, segments and sections, each serving a distinct purpose. not that i will use x86-64 some struct will differ in the x86 like the program header
ELF file layout
+--------------------+
| ELF Header |
+--------------------+
| Program Header |
+--------------------+
| Section 1 |
+--------------------+
| Section 2 |
+--------------------+
| ... |
+--------------------+
| Section Header |
+--------------------+ELF Header
The ELF header is at the top of the ELF file and contains metadata about the file’s structure, type, and how it should be loaded into memory. The total size of the ELF header is 64 bytes. It is composed of several fields that specify:
typedef uint16_t Elf64_Half; // 16-bit unsigned integer
typedef uint32_t Elf64_Word; // 32-bit unsigned integer
typedef uint64_t Elf64_Addr; // 64-bit unsigned integer (address)
typedef uint64_t Elf64_Off; // 64-bit unsigned integer (offset)
typedef struct {
unsigned char e_ident[16]; // EI_NIDENT is usually defined as 16
Elf64_Half e_type; // Object file type
Elf64_Half e_machine; // Architecture
Elf64_Word e_version; // Object file version
Elf64_Addr e_entry; // Entry point virtual address
Elf64_Off e_phoff; // Program header table file offset
Elf64_Off e_shoff; // Section header table file offset
Elf64_Word e_flags; // Processor-specific flags
Elf64_Half e_ehsize; // ELF header size in bytes
Elf64_Half e_phentsize; // Program header table entry size
Elf64_Half e_phnum; // Number of program header entries
Elf64_Half e_shentsize; // Section header table entry size
Elf64_Half e_shnum; // Number of section header entries
Elf64_Half e_shstrndx; // Section header string table index
} Elf64_Ehdr;
e_indent
the e_indent could be seen as a struct that look like that
typedef struct {
char ei_magic[4]; // Magic number (0x7F 'E' 'L' 'F')
uint8_t ei_class; // File class (none or 32-bit or 64-bit)
uint8_t ei_data; // Data encoding (01 little endian or 02 big endian)
uint8_t ei_version; // ELF version normaly always 1
uint8_t ei_osabi; // OS ABI (target operating system ABI) is a lot of the time set to 0 (none)
uint8_t ei_abiversion; // ABI version (almost never use)
uint8_t ei_pad[7]; // Padding (should be all 0's)
} Elf64_EIdent;e_type
typedef enum {
ET_NONE = 0, // No file type
ET_REL = 1, // Relocatable file
ET_EXEC = 2, // Executable file
ET_DYN = 3, // Shared object file
ET_CORE = 4, // Core file
ET_LOOS = 0xFE00, // Operating system-specific
ET_HIOS = 0xFEFF, // Operating system-specific
ET_LOPROC = 0xFF00, // Processor-specific
ET_HIPROC = 0xFFFF // Processor-specific
} Elf64_EType;e_machine
typedef enum {
EM_NONE = 0, // No machine
EM_M32 = 1, // AT&T WE 32100
EM_SPARC = 2, // SPARC
EM_386 = 3, // Intel 80386
EM_68K = 4, // Motorola 68000
EM_88K = 5, // Motorola 88000
EM_IAMCU = 6, // Intel MCU
EM_860 = 7, // Intel 80860
EM_MIPS = 8, // MIPS R3000
EM_ARM = 40, // ARM
EM_X86_64 = 62, // x86-64
EM_AARCH64 = 183, // ARM 64-bit (AARCH64)
EM_RISCV = 243, // RISC-V
EM_LOPROC = 0xFF00, // Processor-specific
EM_HIPROC = 0xFFFF // Processor-specific
} Elf64_EMachine;e_version
is always set to 1
e_entry
Entry point address for executable could be NULL if none
e_phoff and e_shoff
tell respectively the offset where the program header start and the offset of the section header
e_flags
is not use in x86 and x86-64
-
arm and mips
typedef enum { // ARM-specific flags EF_ARM_RELEXEC = 0x01, // Relocatable executable EF_ARM_HASENTRY = 0x02, // Entry point is present EF_ARM_INTERWORK = 0x04, // Interworking between ARM and Thumb EF_ARM_APCS_26 = 0x08, // Use APCS/26 (obsolete) EF_ARM_APCS_FLOAT = 0x10, // Floating point support EF_ARM_PIC = 0x20, // Position-independent code EF_ARM_ALIGN8 = 0x40, // 8-byte aligned data EF_ARM_NEW_ABI = 0x80, // New ABI (Application Binary Interface) EF_ARM_OLD_ABI = 0x100, // Old ABI EF_ARM_SOFT_FLOAT = 0x200, // Software floating point EF_ARM_VFP_FLOAT = 0x400, // VFP (Vector Floating Point) support EF_ARM_MAVERICK_FLOAT = 0x800, // Maverick floating point // MIPS-specific flags EF_MIPS_NOREORDER = 0x00000001, // No reorder EF_MIPS_PIC = 0x00000002, // Position-independent code EF_MIPS_CPIC = 0x00000004, // PIC using call stubs EF_MIPS_ABI2 = 0x00000020, // N32 ABI EF_MIPS_OPTIONS_FIRST = 0x00000080, // .options section first EF_MIPS_32BITMODE = 0x00000100, // 32-bit addresses EF_MIPS_FP64 = 0x00000200, // 64-bit floating point EF_MIPS_NAN2008 = 0x00000400 // IEEE 754-2008 NaN encoding } Elf64_EFlags;
e_ehsize
ELF header size to future prof the file format
help
to see a simple human readable of a ELF you can use the cmd
readelf -h realy_realy_realy_important_binarySegments vs Sections
- Segments: These are relevant during runtime. They define how and where parts of the program should be loaded into both virtual and physical memory.
- Sections: These are primarily used during the linking process, organizing code and data into meaningful units, like functions, global variables, and symbol tables.
ELF Structure in an Executable
An executable typically contains three segments:
- Data Segment: Contains initialized data, as well as uninitialized data like global variables.
- Code Segment: Holds the program’s executable instructions.
- Shared Library Segment: Specifies which shared libraries should be loaded during execution.

PROGRAM header
oh shit away go again an other header struct ! i swear that the last one !
the program header describes how sections of the file should be mapped into memory for execution. It is used by the operating system’s loader to determine which parts of the ELF file to load, where to load them in memory, and how to set their permissions (read, write, execute). Each entry in the program header corresponds to a segment, such as code, data, or dynamic linking information.
typedef struct {
uint32_t p_type; // Segment type
uint32_t p_flags; // Segment flags
uint64_t p_offset; // Offset of the segment in the file
uint64_t p_vaddr; // Virtual address of the segment in memory
uint64_t p_paddr; // Physical address (not relevant on most platforms, use same as p_vaddr)
uint64_t p_filesz; // Size of the segment in the file
uint64_t p_memsz; // Size of the segment in memory
uint64_t p_align; // Alignment of the segment
} Elf64_Phdr;p_type
typedef enum {
PT_NULL = 0, // Unused segment
PT_LOAD = 1, // Loadable segment
PT_DYNAMIC = 2, // Dynamic linking information
PT_INTERP = 3, // Interpreter path
PT_NOTE = 4, // Auxiliary information (for tool lke debuger)
PT_SHLIB = 5, // Reserved
PT_PHDR = 6, // Program header itself
PT_TLS = 7, // Thread-Local Storage
PT_LOOS = 0x60000000, // OS-specific
PT_HIOS = 0x6fffffff, // OS-specific
PT_LOPROC = 0x70000000, // Processor-specific
PT_HIPROC = 0x7fffffff // Processor-specific
} Elf64_PType;p_flags
typedef enum {
PF_X = 0x1, // Execute permission
PF_W = 0x2, // Write permission
PF_R = 0x4 // Read permission
} Elf64_PFlags;p_offset
The p_offset field specifies the offset in the file where the segment starts if it has any.
p_vaddr
The virtual address at which the segment is loaded into memory.
p_paddr
The physical address of the segment, typically not used in most systems but can be important in embedded systems. For most systems, this is the same as p_vaddr.
p_filesz
The size in bytes of the segment in the file (i.e., how much data to load from the file). if its zero the segment will only be define by the header
p_memsz
The size in memory of the segment, which may be larger than p_filesz if the segment contains uninitialized data (e.g., .bss section).
p_align
The alignment requirements of the segment in memory and in the file. For example, loadable segments are often aligned to page size (4096 bytes).
help
you can see program header with the command
readelf --segments real_programi lie…. THERE IS AN OTHER HEADER THE :
SECTION HEADER
The section header table is primarily used by the linker and debugger to describe the sections of the file (e.g., .text, .data, symbol tables). Each section has information about its type, size, and location in the file.
typedef struct {
uint32_t sh_name; // Section name (offset into the section header string table)
uint32_t sh_type; // Section type (SHT_PROGBITS, SHT_SYMTAB, etc.)
uint64_t sh_flags; // Section attributes (writable, executable, etc.)
uint64_t sh_addr; // Virtual address in memory where the section will be loaded
uint64_t sh_offset; // Offset of the section in the file
uint64_t sh_size; // Size of the section in bytes
uint32_t sh_link; // Link to another section (depends on type)
uint32_t sh_info; // Additional information (depends on type)
uint64_t sh_addralign; // Alignment of the section
uint64_t sh_entsize; // Size of entries, if the section holds a table
} Elf64_Shdr;
sh_type
This field specifies the type of the section, and its value can be one of the following:
typedef enum {
SHT_NULL = 0, // Section header is inactive
SHT_PROGBITS = 1, // Program information
SHT_SYMTAB = 2, // Symbol table
SHT_STRTAB = 3, // String table
SHT_RELA = 4, // Relocation entries with addends
SHT_HASH = 5, // Symbol hash table
SHT_DYNAMIC = 6, // Dynamic linking information
SHT_NOTE = 7, // Auxiliary information
SHT_NOBITS = 8, // Uninitialized data (e.g., .bss)
SHT_REL = 9, // Relocation entries without addends
SHT_DYNSYM = 11 // Dynamic symbol table
} Elf64_ShType;sh_flags
The sh_flags field contains attributes of the section, such as whether it is writable, executable, or allocatable in memory:
typedef enum {
SHF_WRITE = 0x1, // Section contains writable data
SHF_ALLOC = 0x2, // Section is allocated in memory
SHF_EXECINSTR = 0x4 // Section contains executable instructions
} Elf64_ShFlags;Key ELF Sections
ELF files are composed of various sections, each with a specific purpose. Here are some of the most important sections:
.text: Contains the program’s executable code (instructions)..data: Contains initialized global and static variables..bss: Contains uninitialized global and static variables..rodata: Contains read-only data, such as string literals..symtab: A symbol table, used during linking, that contains information about functions and variables..strtab: A string table containing the names of symbols referenced in the symbol table..reland.rela: Sections that contain relocation information.
Symbol Tables and Relocations
Symbol Table
.symtab(Symbol Table): This section contains the names and attributes of symbols (e.g., functions, variables) in the program. It is used by the linker to resolve addresses and is referenced by the string table..dynsym(Dynamic Symbol Table): A smaller version of the symbol table used for dynamic linking.
typedef struct {
uint32_t st_name; // Offset into the string table for the symbol name
uint8_t st_info; // Type and binding attributes of the symbol
uint8_t st_other; // Visibility of the symbol
uint16_t st_shndx; // Section index the symbol is in
uint64_t st_value; // Symbol value (e.g., address)
uint64_t st_size; // Size of the symbol
} Elf64_Sym;Relocation Sections
- Relocation Entries are used to adjust symbol references when linking or loading. Sections like
.reland.relacontain relocation information that helps the linker and loader patch addresses.
typedef struct {
uint64_t r_offset; // Offset where relocation applies
uint64_t r_info; // Symbol and type of relocation
int64_t r_addend; // Constant addend (only in RELA relocations)
} Elf64_Rela;ELF and Dynamic Linking
ELF supports dynamic linking through shared libraries. The dynamic segment (PT_DYNAMIC) contains information for the runtime linker to resolve symbols and load shared libraries.
.dynsym: The dynamic symbol table, which contains symbols that need to be dynamically resolved..dynstr: A string table for the names of symbols in.dynsym..pltand.got: The Procedure Linkage Table (PLT) and Global Offset Table (GOT) help in the process of lazy loading and resolving function addresses at runtime.
EXAMPLE
let’s start with a small example
#include <stdio.h>
void print_hello_world()
{
printf("hello world\n");
}
int main()
{
print_hello_world();
print_hello_world();
print_hello_world();
}that we will compile and and analyse with the command hexdump -C program_name or the readelf command for prettier formatting but let’s start with a raw hexdump for the e_ident part of the elf header
> hexdump -C test | head -1
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............|with the first 4 bytes 7f 45 4c 46 we now that this is a ELF
with the next byte 02 that we are on x86-64
with the next byte 01 that we use little endian formatting
with the next byte 01 Oh My Goad we are on elf version one !
with the next 2 byte 00 00 we see that we get no ABI
raw output is fun but lets have a ✨ prettier output ✨
**> readelf -h test
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Position-Independent Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x1060
Start of program headers: 64 (bytes into file)
Start of section headers: 14016 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 13
Size of section headers: 64 (bytes)
Number of section headers: 31
Section header string table index: 30**
that a lot of information but what we really want to remember is that there is 13 program header of 56 bytes each

we get the program header that we can analyse with the readelf —segments
readelf --segments test
Elf file type is DYN (Position-Independent Executable file)
Entry point 0x1060
There are 13 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040
0x00000000000002d8 0x00000000000002d8 R 0x8
INTERP 0x0000000000000318 0x0000000000000318 0x0000000000000318
0x000000000000001c 0x000000000000001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000628 0x0000000000000628 R 0x1000
LOAD 0x0000000000001000 0x0000000000001000 0x0000000000001000
0x000000000000019d 0x000000000000019d R E 0x1000
LOAD 0x0000000000002000 0x0000000000002000 0x0000000000002000
0x000000000000011c 0x000000000000011c R 0x1000
LOAD 0x0000000000002db8 0x0000000000003db8 0x0000000000003db8
0x0000000000000258 0x0000000000000260 RW 0x1000
DYNAMIC 0x0000000000002dc8 0x0000000000003dc8 0x0000000000003dc8
0x00000000000001f0 0x00000000000001f0 RW 0x8
NOTE 0x0000000000000338 0x0000000000000338 0x0000000000000338
0x0000000000000030 0x0000000000000030 R 0x8
NOTE 0x0000000000000368 0x0000000000000368 0x0000000000000368
0x0000000000000044 0x0000000000000044 R 0x4
GNU_PROPERTY 0x0000000000000338 0x0000000000000338 0x0000000000000338
0x0000000000000030 0x0000000000000030 R 0x8
GNU_EH_FRAME 0x0000000000002010 0x0000000000002010 0x0000000000002010
0x000000000000003c 0x000000000000003c R 0x4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0x10
GNU_RELRO 0x0000000000002db8 0x0000000000003db8 0x0000000000003db8
0x0000000000000248 0x0000000000000248 R 0x1
Section to Segment mapping:
Segment Sections...
00
01 .interp
02 .interp .note.gnu.property .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt
03 .init .plt .plt.got .plt.sec .text .fini
04 .rodata .eh_frame_hdr .eh_frame
05 .init_array .fini_array .dynamic .got .data .bss
06 .dynamic
07 .note.gnu.property
08 .note.gnu.build-id .note.ABI-tag
09 .note.gnu.property
10 .eh_frame_hdr
11
12 .init_array .fini_array .dynamic .got
PHDR (Program Header Table)
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
PHDR 0x0000000000000040 0x0000000000000040 0x0000000000000040
0x00000000000002d8 0x00000000000002d8 R 0x8the PHDR is the section that we are currently looking.
We can recheck that this start at 0x40 (64) bytes like we said earlier and is 0x2d8 (728) bytes like the number of header 13 and the sizeof each header 56 13 * 56 == 728
INTERP (Interpreter Path)
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
INTERP 0x0000000000000318 0x0000000000000318 0x0000000000000318
0x000000000000001c 0x000000000000001c R 0x1we see that at offset 0x318 we have a string of 0x1c bytes that we need to interpret as a path
00000310 01 00 00 00 00 00 00 00 2f 6c 69 62 36 34 2f 6c |......../lib64/l|
00000320 64 2d 6c 69 6e 75 78 2d 78 38 36 2d 36 34 2e 73 |d-linux-x86-64.s|the /lib64/ld-linux-x86-64.so is the dynamic linker file that will link all linux dependency like the libc where we could find the printf() function we use in the test code
LOAD
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000628 0x0000000000000628 R 0x1000
LOAD 0x0000000000001000 0x0000000000001000 0x0000000000001000
0x000000000000019d 0x000000000000019d R E 0x1000
LOAD 0x0000000000002000 0x0000000000002000 0x0000000000002000
0x000000000000011c 0x000000000000011c R 0x1000
LOAD 0x0000000000002db8 0x0000000000003db8 0x0000000000003db8
0x0000000000000258 0x0000000000000260 RW 0x1000LOAD segment in the ELF program headers is used to specify which parts of the ELF file should be loaded into memory and with what permissions. Each LOAD segment describes a portion of the file that will be mapped into memory, and it provides details about access permissions like read, write, or execute.
DYNAMIC (Dynamic Linking Information)
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
DYNAMIC 0x0000000000002dc8 0x0000000000003dc8 0x0000000000003dc8
0x00000000000001f0 0x00000000000001f0 RW 0x8The DYNAMIC segment contains dynamic linking information. This segment is used by the dynamic linker/loader (in this case, /lib64/ld-linux-x86-64.so.2) to resolve symbols and load shared libraries at runtime.
NOTE (Auxiliary Information)
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
NOTE 0x0000000000000338 0x0000000000000338 0x0000000000000338
0x0000000000000030 0x0000000000000030 R 0x8The NOTE segment contains auxiliary information that is typically used for things like build IDs, OS-specific metadata, and process annotations.
GNU_PROPERTY (GNU Property Notes)
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
GNU_PROPERTY 0x0000000000000338 0x0000000000000338 0x0000000000000338
0x0000000000000030 0x0000000000000030 R 0x8The GNU_PROPERTY segment stores additional metadata specific to the GNU toolchain. This metadata can include details about processor features or security properties (such as stack protection or control flow integrity).
GNU_EH_FRAME (Exception Handling Frame)
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
GNU_EH_FRAME 0x0000000000002010 0x0000000000002010 0x0000000000002010
0x000000000000003c 0x000000000000003c R 0x4The GNU_EH_FRAME segment contains exception-handling information (for C++ or other languages that support exceptions). It is used to unwind the stack when an exception is thrown.
GNU_STACK (Stack Permissions)
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RW 0x10
The GNU_STACK segment specifies the stack’s memory permissions. In this case, the stack is readable and writable (RW) but not executable (this is a security feature to prevent execution of code on the stack, known as “stack smashing protection”).
GNU_RELRO (Read-Only After Relocation)
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
GNU_RELRO 0x0000000000002db8 0x0000000000003db8 0x0000000000003db8
0x0000000000000248 0x0000000000000248 R 0x1The GNU_RELRO segment stands for “Read-Only After Relocation.” This segment is initially writable during program startup while relocations are being applied, and then it is made read-only to protect against certain types of security attacks (e.g., tampering with function pointers).
SECTION HEADER
let’s take the elf header to now how many of witch size and at witch offset we have to to analyse
> readelf -h test | grep section
Start of section headers: 14016 (bytes into file)
Size of section headers: 64 (bytes)
Number of section headers: 31we can see then stylise with the readelf -S
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.pr[...] NOTE 0000000000000338 00000338
0000000000000030 0000000000000000 A 0 0 8
[ 3] .note.gnu.bu[...] NOTE 0000000000000368 00000368
0000000000000024 0000000000000000 A 0 0 4
[ 4] .note.ABI-tag NOTE 000000000000038c 0000038c
0000000000000020 0000000000000000 A 0 0 4
[ 5] .gnu.hash GNU_HASH 00000000000003b0 000003b0
0000000000000024 0000000000000000 A 6 0 8
[ 6] .dynsym DYNSYM 00000000000003d8 000003d8
00000000000000a8 0000000000000018 A 7 1 8
[ 7] .dynstr STRTAB 0000000000000480 00000480
000000000000008d 0000000000000000 A 0 0 1
[ 8] .gnu.version VERSYM 000000000000050e 0000050e
000000000000000e 0000000000000002 A 6 0 2
[ 9] .gnu.version_r VERNEED 0000000000000520 00000520
0000000000000030 0000000000000000 A 7 1 8
[10] .rela.dyn RELA 0000000000000550 00000550
00000000000000c0 0000000000000018 A 6 0 8
[11] .rela.plt RELA 0000000000000610 00000610
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
0000000000000130 0000000000000000 AX 0 0 16
[17] .fini PROGBITS 0000000000001190 00001190
000000000000000d 0000000000000000 AX 0 0 4
[18] .rodata PROGBITS 0000000000002000 00002000
0000000000000010 0000000000000000 A 0 0 4
[19] .eh_frame_hdr PROGBITS 0000000000002010 00002010
000000000000003c 0000000000000000 A 0 0 4
[20] .eh_frame PROGBITS 0000000000002050 00002050
00000000000000cc 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
000000000000002b 0000000000000001 MS 0 0 1
[28] .symtab SYMTAB 0000000000000000 00003040
0000000000000378 0000000000000018 29 18 8
[29] .strtab STRTAB 0000000000000000 000033b8
00000000000001ec 0000000000000000 0 0 1
[30] .shstrtab STRTAB 0000000000000000 000035a4
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),
D (mbind), l (large), p (processor specific)
the scheme repeate we can parse with the struct each Section header and get the data
reminder
- PROGBITS: This is the most common type, used for program code, data, and various types of metadata.
- NOBITS: Indicates that the section does not take up space in the file but will be allocated memory when the program is loaded (like
.bss). - SYMTAB: The symbol table, which holds information about functions, variables, and their locations.
- STRTAB: The string table, which holds the names of symbols and sections.