Reading — step 1 of 5
Read
~1 min readStatic Loading
Loading a Static ELF
Static executable: all symbols resolved; no shared libraries (except potentially compiled in).
Loading process:
int load_elf(int fd) {
ElfHeader hdr;
pread(fd, &hdr, sizeof hdr, 0);
// Validate
if (memcmp(hdr.ident, "\x7fELF", 4) != 0) return -1;
if (hdr.ident[4] != 2) return -1; // require 64-bit
// Map all PT_LOAD segments
for (int i = 0; i < hdr.phnum; i++) {
ProgramHeader ph;
pread(fd, &ph, sizeof ph, hdr.phoff + i * hdr.phentsize);
if (ph.type != PT_LOAD) continue;
int prot = 0;
if (ph.flags & PF_R) prot |= PROT_READ;
if (ph.flags & PF_W) prot |= PROT_WRITE;
if (ph.flags & PF_X) prot |= PROT_EXEC;
void *addr = mmap((void*)ph.vaddr, ph.memsz,
prot, MAP_PRIVATE | MAP_FIXED,
fd, ph.offset & ~(PAGE_SIZE - 1));
if (addr == MAP_FAILED) return -1;
// Zero BSS (if memsz > filesz)
if (ph.memsz > ph.filesz) {
memset((char*)ph.vaddr + ph.filesz, 0, ph.memsz - ph.filesz);
}
}
// Set up stack
void *stack = mmap(NULL, STACK_SIZE,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
// Push argv, envp, auxv onto stack
setup_initial_stack(stack, argv, envp);
// Jump to entry
((void(*)(void))hdr.entry)();
return 0;
}
Stack layout (System V ABI):
high addr
[NULL]
[envp[N], envp[N-1], ..., envp[0]]
[argv[N], argv[N-1], ..., argv[0]]
[argc]
low addr <- rsp
Auxiliary vector (auxv): kernel-provided info (page size, hwcap flags, random bytes, executable path).
Entry point (_start):
- Sets up TLS (thread-local storage).
- Calls __libc_start_main:
- Run constructors.
- Call main(argc, argv).
- Run destructors.
- exit() with main's return value.
Static binaries: large, but no runtime deps. Go binaries are static by default.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…