calc) as a building being handed to the operating system.- which parts of the file to load into memory
- what permissions each part needs (read/write/execute)
- where code lives
- where data lives
- where the dynamic linker is
- what areas must be protected
This “map” is made of Program Headers, also called segments.
.text, .data) are for humans and compilers.Now let’s decode your output.
Top-Level Info
Elf file type is DYN
Entry point 0x1050
There are 13 program headers
What this means:
- DYN = Position-Independent Executable (modern GCC default for security)
- Entry point 0x1050 = where the CPU jumps to start execution
- 13 program headers = 13 “segments” the loader must handle
Walk Through Each Segment
Let's explore them in the order shown and tie them to what they do.
Segment 0 — PHDR (Program Header Table itself)
PHDR Offset 0x40 R
Think of this as:
“This segment contains the very instructions that describe all the other segments.”
The loader loads this so it can read the rest of the map.
Segment 1 — INTERP (Interpreter)
INTERP Offset 0x318 R
[Requesting: /lib64/ld-linux-x86-64.so.2]
This tells the OS:
“I’m a dynamically linked program — please load the dynamic linker to help me.”
The interpreter (ld-linux-x86-64.so.2) handles loading shared libraries like libc.
Segment 2 — First LOAD segment (Read-Only Data)
LOAD R
Contains: .interp .note.* .gnu.hash .dynsym .dynstr .rela.*
This is the "metadata and linking info" area.
Inside are things like:
- the dynamic symbol table
- hash tables for symbol lookup
- relocation entries
Nothing executable here.
Segment 3 — LOAD (Code Segment)
LOAD R E
Contains: .init .plt .plt.got .text .fini
This is the most exciting one.
✔ This is where your actual machine code (the program logic) lives.
✔ Marked R E = readable + executable (but not writable)
This contains:
.text→ compiled instructions.plt/.got.plt→ structures for dynamic function calls (like callingprintf).init/.fini→ code run before/after main
Think of this as the “engine” of the car.
Segment 4 — LOAD (More Read-Only Data)
LOAD R
Contains: .rodata .eh_frame_hdr .eh_frame
This is the read-only data region.
.rodata→ constants (like constant strings).eh_frame→ exception/unwinding info
Nothing here should be modified at runtime.
Segment 5 — LOAD (Writable Data)
LOAD RW
Contains: .init_array .fini_array .dynamic .got .got.plt .data .bss
This is the data segment.
Anything that changes during execution lives here:
.data→ initialized global variables.bss→ uninitialized globals.got&.got.plt→ runtime addresses of functions & libraries.dynamic→ dynamic linking information- init/fini arrays → lists of constructors/destructors
Memory here is readable + writable.
Segment 6 — DYNAMIC
DYNAMIC RW
Contains: .dynamic
This is a small segment specifically for dynamic linking information:
It contains entries like:
- which libraries to load
- where the PLT/GOT are
- relocation tables
7-9 NOTE and GNU_PROPERTY segments
NOTE / GNU_PROPERTY
These are vendor or OS metadata:
- build ID
- ABI tag
- security properties (e.g., CET, stack protection)
They help tools and the kernel but are not directly “used” by your program.
Segment 10 — GNU_EH_FRAME
GNU_EH_FRAME (R)
Contains: .eh_frame_hdr
This is used by exception handling/unwinding (used by C++ and debugging tools).
Segment 11 — GNU_STACK
GNU_STACK RW
This tells the OS:
“Please create a stack for me which is writable but not executable.”
This is a security feature (prevents stack-based shellcode execution).
Segment 12 — GNU_RELRO
GNU_RELRO R
Contains: .init_array .fini_array .dynamic .got
RELRO = Relocation Read-Only
This means:
- these areas start writable during relocation
- after linking finishes, they become read-only
Stops attackers from overwriting GOT entries.
Section-to-Segment Mapping
At the bottom:
Segment Sections...
03: .init .plt .plt.got .text .fini
This is simply saying:
“These sections were merged into the same LOAD segment.”
Because loaders deal in segments, not sections.
