read.c (50428B)
1 /* ELF reader. Parses a 64-bit little-endian ELF object back into a fresh 2 * ObjBuilder. ET_REL produces the section/symbol/reloc view; the 3 * post-finalize shape is the canonical superset doc/DESIGN.md §5.5 4 * promises: read_elf of an emit_elf output produces an ObjBuilder 5 * equivalent to the writer's input, modulo (a) section ordering and 6 * (b) STT_SECTION symbols synthesized by the writer. 7 * 8 * ET_EXEC / ET_DYN additionally attach the linked-image view via 9 * read_elf_image (program-header segments, .dynamic dependencies, 10 * .dynsym dynamic symbols, and allocatable dynamic relocations) — see 11 * doc/OBJ.md. Their section tables still parse through the same 12 * passes. The standalone read_elf_dso (below) remains the linker's 13 * exports-only DSO-input path. 14 * 15 * Scope: AArch64 little-endian. Other archs / endianness produce a 16 * compiler_panic with a diagnostic. */ 17 18 #include <string.h> 19 20 #include "core/heap.h" 21 #include "core/pool.h" 22 #include "core/slice.h" 23 #include "obj/elf/elf.h" 24 #include "obj/format.h" 25 26 /* ---- shdr scratch struct ---- */ 27 28 typedef struct ShdrRec { 29 u32 sh_name; 30 u32 sh_type; 31 u64 sh_flags; 32 u64 sh_addr; 33 u64 sh_offset; 34 u64 sh_size; 35 u32 sh_link; 36 u32 sh_info; 37 u64 sh_addralign; 38 u64 sh_entsize; 39 } ShdrRec; 40 41 static void parse_shdr(const u8* p, int is32, ShdrRec* out) { 42 /* Elf32_Shdr (40B) shares field order with Elf64_Shdr (64B); only the 43 * flags/addr/offset/size/addralign/entsize fields narrow to u32 and 44 * shift the following offsets. The ShdrRec stays u64-wide. */ 45 if (is32) { 46 out->sh_name = rd_u32_le(p + 0); 47 out->sh_type = rd_u32_le(p + 4); 48 out->sh_flags = rd_u32_le(p + 8); 49 out->sh_addr = rd_u32_le(p + 12); 50 out->sh_offset = rd_u32_le(p + 16); 51 out->sh_size = rd_u32_le(p + 20); 52 out->sh_link = rd_u32_le(p + 24); 53 out->sh_info = rd_u32_le(p + 28); 54 out->sh_addralign = rd_u32_le(p + 32); 55 out->sh_entsize = rd_u32_le(p + 36); 56 } else { 57 out->sh_name = rd_u32_le(p + 0); 58 out->sh_type = rd_u32_le(p + 4); 59 out->sh_flags = rd_u64_le(p + 8); 60 out->sh_addr = rd_u64_le(p + 16); 61 out->sh_offset = rd_u64_le(p + 24); 62 out->sh_size = rd_u64_le(p + 32); 63 out->sh_link = rd_u32_le(p + 40); 64 out->sh_info = rd_u32_le(p + 44); 65 out->sh_addralign = rd_u64_le(p + 48); 66 out->sh_entsize = rd_u64_le(p + 56); 67 } 68 } 69 70 /* ---- mappers ---- */ 71 72 /* The bits this function maps to SecFlag — anything outside this mask is 73 * treated as opaque and stashed in Section.ext_flags by the caller so the 74 * emitter can write it back unchanged. Examples of bits left over: 75 * SHF_EXCLUDE (0x80000000) on .llvm_addrsig, SHF_COMPRESSED (0x800) on 76 * compressed .debug_*, SHF_INFO_LINK (0x40) on .rela.* sections. */ 77 #define ELF_KNOWN_FLAGS_MASK \ 78 ((u64)(SHF_ALLOC | SHF_EXECINSTR | SHF_WRITE | SHF_TLS | SHF_MERGE | \ 79 SHF_STRINGS | SHF_GROUP | SHF_LINK_ORDER | SHF_GNU_RETAIN)) 80 81 static u16 elf_flags_to_obj(u64 f) { 82 u16 r = 0; 83 if (f & SHF_ALLOC) r |= SF_ALLOC; 84 if (f & SHF_EXECINSTR) r |= SF_EXEC; 85 if (f & SHF_WRITE) r |= SF_WRITE; 86 if (f & SHF_TLS) r |= SF_TLS; 87 if (f & SHF_MERGE) r |= SF_MERGE; 88 if (f & SHF_STRINGS) r |= SF_STRINGS; 89 if (f & SHF_GROUP) r |= SF_GROUP; 90 if (f & SHF_LINK_ORDER) r |= SF_LINK_ORDER; 91 if (f & SHF_GNU_RETAIN) r |= SF_RETAIN; 92 return r; 93 } 94 95 /* Map ELF sh_type -> SecSem. Sets *known to 1 if the value is one of 96 * the canonical types the kit model knows about; 0 means the caller 97 * fell through to the SSEM_PROGBITS fallback and should preserve the 98 * raw sh_type via Section.ext_type so emit_elf can write it back. */ 99 static u16 elf_type_to_sem(u32 t, int* known) { 100 *known = 1; 101 switch (t) { 102 case SHT_PROGBITS: 103 return SSEM_PROGBITS; 104 case SHT_NOBITS: 105 return SSEM_NOBITS; 106 case SHT_SYMTAB: 107 return SSEM_SYMTAB; 108 case SHT_STRTAB: 109 return SSEM_STRTAB; 110 case SHT_RELA: 111 return SSEM_RELA; 112 case SHT_REL: 113 return SSEM_REL; 114 case SHT_NOTE: 115 return SSEM_NOTE; 116 case SHT_INIT_ARRAY: 117 return SSEM_INIT_ARRAY; 118 case SHT_FINI_ARRAY: 119 return SSEM_FINI_ARRAY; 120 case SHT_PREINIT_ARRAY: 121 return SSEM_PREINIT_ARRAY; 122 case SHT_GROUP: 123 return SSEM_GROUP; 124 default: 125 *known = 0; 126 return SSEM_PROGBITS; 127 } 128 } 129 130 static u16 elf_kind_from_name(const char* name, u32 nlen, u64 sh_flags, 131 u32 sh_type) { 132 if (sh_type == SHT_NOBITS) return SEC_BSS; 133 if (nlen >= 5 && memcmp(name, ".text", 5) == 0) return SEC_TEXT; 134 if (nlen >= 7 && memcmp(name, ".rodata", 7) == 0) return SEC_RODATA; 135 if (nlen >= 5 && memcmp(name, ".data", 5) == 0) return SEC_DATA; 136 if (nlen >= 4 && memcmp(name, ".bss", 4) == 0) return SEC_BSS; 137 if (nlen >= 7 && memcmp(name, ".debug_", 7) == 0) return SEC_DEBUG; 138 /* Fallback: classify by flags. */ 139 if (sh_flags & SHF_EXECINSTR) return SEC_TEXT; 140 if (sh_flags & SHF_WRITE) return SEC_DATA; 141 if (sh_flags & SHF_ALLOC) return SEC_RODATA; 142 return SEC_OTHER; 143 } 144 145 static u16 elf_bind_to_obj(u32 b) { 146 switch (b) { 147 case STB_GLOBAL: 148 case STB_GNU_UNIQUE: 149 /* GNU-unique is a global with extra runtime uniqueness semantics; for 150 * link-time resolution it is an ordinary global definition. FreeBSD's 151 * crt1.o brands the binary with a GNU-unique `.freebsd.note*` symbol. */ 152 return SB_GLOBAL; 153 case STB_WEAK: 154 return SB_WEAK; 155 default: 156 return SB_LOCAL; 157 } 158 } 159 160 static u16 elf_type_to_kind(u32 t, u16 shndx) { 161 if (shndx == SHN_UNDEF) return SK_UNDEF; 162 if (shndx == SHN_COMMON) return SK_COMMON; 163 /* SHN_ABS is the convention for STT_FILE and a few other defined 164 * symbols whose value is not an address. Don't smother the type 165 * with SK_ABS when the type field carries real information — only 166 * fall through to SK_ABS for STT_NOTYPE-at-SHN_ABS. */ 167 if (shndx == SHN_ABS && t == STT_NOTYPE) return SK_ABS; 168 switch (t) { 169 case STT_FUNC: 170 return SK_FUNC; 171 case STT_OBJECT: 172 return SK_OBJ; 173 case STT_SECTION: 174 return SK_SECTION; 175 case STT_FILE: 176 return SK_FILE; 177 case STT_TLS: 178 return SK_TLS; 179 case STT_COMMON: 180 return SK_COMMON; 181 case STT_GNU_IFUNC: 182 return SK_IFUNC; 183 default: 184 /* STT_NOTYPE on a defined symbol (e.g. AArch64 mapping symbols 185 * `$x` / `$d`, or assembly labels) round-trips as SK_NOTYPE. 186 * The linker keeps definedness keyed on SK_UNDEF; SK_NOTYPE is 187 * "defined but typeless". */ 188 return SK_NOTYPE; 189 } 190 } 191 192 static u8 elf_other_to_vis(u32 other) { 193 switch (other & 3) { 194 case STV_HIDDEN: 195 return SV_HIDDEN; 196 case STV_PROTECTED: 197 return SV_PROTECTED; 198 case STV_INTERNAL: 199 return SV_INTERNAL; 200 default: 201 return SV_DEFAULT; 202 } 203 } 204 205 /* Bounds-checked C-string slice from a strtab section. Returns "" on 206 * out-of-range so callers don't have to special-case it. `len_out` is 207 * set to the result's byte length. */ 208 static const char* strtab_lookup(const u8* tab, u64 tab_size, u32 off, 209 u32* len_out) { 210 if (off >= tab_size) { 211 *len_out = 0; 212 return ""; 213 } 214 const char* s = (const char*)(tab + off); 215 u32 max = (u32)(tab_size - off); 216 u32 n = 0; 217 while (n < max && s[n] != '\0') ++n; 218 *len_out = n; 219 return s; 220 } 221 222 static const char* pt_type_name(u32 t) { 223 switch (t) { 224 case PT_NULL: 225 return "NULL"; 226 case PT_LOAD: 227 return "LOAD"; 228 case PT_DYNAMIC: 229 return "DYNAMIC"; 230 case PT_INTERP: 231 return "INTERP"; 232 case PT_NOTE: 233 return "NOTE"; 234 case PT_PHDR: 235 return "PHDR"; 236 case PT_TLS: 237 return "TLS"; 238 case PT_GNU_EH_FRAME: 239 return "GNU_EH_FRAME"; 240 case PT_GNU_STACK: 241 return "GNU_STACK"; 242 case PT_GNU_RELRO: 243 return "GNU_RELRO"; 244 default: 245 return "UNKNOWN"; 246 } 247 } 248 249 static Sym intern_cstr(Compiler* c, const char* s) { 250 return pool_intern_slice(c->global, (Slice){.s = s, .len = (u32)strlen(s)}); 251 } 252 253 /* ELF default-version normalization. A symbol "base@@VERSION" is the *default* 254 * version of `base`: an unversioned reference binds to it. GNU as emits the 255 * literal "@@" into a relocatable object's .symtab string (e.g. FreeBSD 256 * libc.a's openat@@FBSD_1.2 / setcontext / swapcontext). Trim to the base so 257 * kit's name-based resolution matches plain references. A single-'@' 258 * (non-default) version is left intact -- those are inert compatibility 259 * aliases (e.g. fstat@FBSD_1.0) that must NOT shadow the modern base symbol. 260 * Shared-library exports keep their version in .gnu.version_d rather than the 261 * name string, so this only fires for relocatable .symtab reads. Returns the 262 * length of the base name (== nlen when there is no "@@"). */ 263 static u32 elf_default_version_namelen(const char* nm, u32 nlen) { 264 u32 i; 265 if (!nm) return nlen; 266 for (i = 1; i + 1 < nlen; ++i) 267 if (nm[i] == '@' && nm[i + 1] == '@') return i; 268 return nlen; 269 } 270 271 /* Parse a DSO's .gnu.version_d (SHT_GNU_VERDEF) into an index->version-name 272 * table so .dynsym entries (whose version lives in the parallel .gnu.version) 273 * can be labelled. Returns an arena table indexed by version index (0/1 unused, 274 * matching VER_NDX_LOCAL/GLOBAL) and sets *out_max to the highest index seen; 275 * NULL when the input has no verdef. The Verdef/Verdaux wire layout is 276 * identical on ELFCLASS32/64 (all Half/Word fields), so this is width-agnostic. 277 */ 278 static Sym* read_elf_verdefs(Compiler* c, const u8* data, size_t len, 279 const ShdrRec* shdrs, u16 e_shnum, u32* out_max) { 280 u32 i, verdef_idx = 0, max_ndx = 0; 281 const ShdrRec* sh; 282 const ShdrRec* str_sh; 283 const u8* strtab; 284 const u8* base; 285 u64 strtab_sz, size, off; 286 Sym* tbl; 287 *out_max = 0; 288 for (i = 1; i < e_shnum; ++i) 289 if (shdrs[i].sh_type == SHT_GNU_VERDEF) { 290 verdef_idx = i; 291 break; 292 } 293 if (!verdef_idx) return NULL; 294 sh = &shdrs[verdef_idx]; 295 if (sh->sh_link >= e_shnum) return NULL; 296 str_sh = &shdrs[sh->sh_link]; 297 if (sh->sh_offset + sh->sh_size > len || 298 str_sh->sh_offset + str_sh->sh_size > len) 299 return NULL; 300 strtab = data + str_sh->sh_offset; 301 strtab_sz = str_sh->sh_size; 302 base = data + sh->sh_offset; 303 size = sh->sh_size; 304 305 /* Pass 1: highest version index, to size the table. */ 306 off = 0; 307 while (off + ELF_VERDEF_SIZE <= size) { 308 u32 ndx = (u32)(rd_u16_le(base + off + 4) & VERSYM_VERSION); 309 u32 vd_next = rd_u32_le(base + off + 16); 310 if (ndx > max_ndx) max_ndx = ndx; 311 if (!vd_next) break; 312 off += vd_next; 313 } 314 tbl = arena_zarray(c->scratch, Sym, (size_t)max_ndx + 1u); 315 316 /* Pass 2: record each non-base version's name (its first Verdaux). */ 317 off = 0; 318 while (off + ELF_VERDEF_SIZE <= size) { 319 u16 vd_flags = rd_u16_le(base + off + 2); 320 u32 ndx = (u32)(rd_u16_le(base + off + 4) & VERSYM_VERSION); 321 u32 vd_aux = rd_u32_le(base + off + 12); 322 u32 vd_next = rd_u32_le(base + off + 16); 323 if (!(vd_flags & VER_FLG_BASE) && ndx <= max_ndx && 324 off + vd_aux + ELF_VERDAUX_SIZE <= size) { 325 u32 nlen; 326 const char* nm = strtab_lookup(strtab, strtab_sz, 327 rd_u32_le(base + off + vd_aux), &nlen); 328 if (nlen) 329 tbl[ndx] = pool_intern_slice(c->global, (Slice){.s = nm, .len = nlen}); 330 } 331 if (!vd_next) break; 332 off += vd_next; 333 } 334 *out_max = max_ndx; 335 return tbl; 336 } 337 338 /* Populate the builder's ObjImage from an ET_EXEC / ET_DYN input: the 339 * program-header segment table (+ interp + image base), the .dynamic 340 * dependency view (DT_NEEDED / DT_SONAME / DT_RPATH / DT_RUNPATH), the 341 * .dynsym dynamic symbols, and the allocatable .rela.* / .rel.* dynamic 342 * relocations. The section / symbol tables are parsed by read_elf's normal 343 * passes; this adds the orthogonal image dimension. Lenient where a 344 * malformed sub-table would otherwise abort a useful inspection: a bad 345 * .dynamic / .dynsym / dyn-reloc table is skipped rather than panicked. */ 346 static void read_elf_image(Compiler* c, ObjBuilder* ob, const u8* data, 347 size_t len, u16 e_type, int is32, 348 const ShdrRec* shdrs, u16 e_shnum, 349 const u32* elf_to_obj, u32 (*reloc_from)(u32)) { 350 u32 phdr_size = is32 ? ELF32_PHDR_SIZE : ELF64_PHDR_SIZE; 351 u32 sym_size = is32 ? ELF32_SYM_SIZE : ELF64_SYM_SIZE; 352 u32 rela_size = is32 ? ELF32_RELA_SIZE : ELF64_RELA_SIZE; 353 u32 rel_size = is32 ? 8u : 16u; 354 u32 dyn_size = is32 ? ELF32_DYN_SIZE : ELF64_DYN_SIZE; 355 ObjImage* im = 356 obj_image_ensure(ob, e_type == ET_DYN ? OBJ_KIND_DYN : OBJ_KIND_EXEC); 357 if (!im) compiler_panic(c, SRCLOC_NONE, "read_elf: obj_image_ensure failed"); 358 359 /* e_entry is at offset 24 in both Ehdr32/Ehdr64, native width. */ 360 obj_image_set_entry(im, elf_rd_addr(data + 24, is32)); 361 362 /* Program headers -> segments (+ PT_INTERP string, image base). */ 363 { 364 /* e_phoff: 4B@28 on ELF32, 8B@32 on ELF64. e_phentsize/e_phnum 365 * shift accordingly (42/44 vs 54/56). */ 366 u64 e_phoff = is32 ? (u64)rd_u32_le(data + 28) : rd_u64_le(data + 32); 367 u16 e_phentsize = rd_u16_le(data + (is32 ? 42 : 54)); 368 u16 e_phnum = rd_u16_le(data + (is32 ? 44 : 56)); 369 int have_base = 0; 370 u64 image_base = 0; 371 if (e_phnum) { 372 if (e_phentsize != phdr_size) 373 compiler_panic(c, SRCLOC_NONE, "read_elf: unexpected e_phentsize %u", 374 (u32)e_phentsize); 375 if (e_phoff + (u64)e_phnum * phdr_size > len) 376 compiler_panic(c, SRCLOC_NONE, 377 "read_elf: program header table out of range"); 378 for (u16 i = 0; i < e_phnum; ++i) { 379 const u8* p = data + e_phoff + (u64)i * phdr_size; 380 /* Elf32_Phdr REORDERS p_flags AFTER the sizes: 381 * p_type@0,p_offset@4,p_vaddr@8,p_paddr@12,p_filesz@16, 382 * p_memsz@20,p_flags@24,p_align@28 (all u32). 383 * Elf64_Phdr: p_type@0,p_flags@4,p_offset@8,p_vaddr@16, 384 * p_filesz@32,p_memsz@40,p_align@48. */ 385 u32 p_type = rd_u32_le(p + 0); 386 u32 p_flags = is32 ? rd_u32_le(p + 24) : rd_u32_le(p + 4); 387 u64 p_offset = is32 ? (u64)rd_u32_le(p + 4) : rd_u64_le(p + 8); 388 u64 p_vaddr = is32 ? (u64)rd_u32_le(p + 8) : rd_u64_le(p + 16); 389 u64 p_paddr = is32 ? (u64)rd_u32_le(p + 12) : rd_u64_le(p + 24); 390 u64 p_filesz = is32 ? (u64)rd_u32_le(p + 16) : rd_u64_le(p + 32); 391 u64 p_memsz = is32 ? (u64)rd_u32_le(p + 20) : rd_u64_le(p + 40); 392 u64 p_align = is32 ? (u64)rd_u32_le(p + 28) : rd_u64_le(p + 48); 393 ObjSegment seg; 394 seg.name = intern_cstr(c, pt_type_name(p_type)); 395 seg.vaddr = p_vaddr; 396 seg.paddr = p_paddr; 397 seg.vsize = p_memsz; 398 seg.file_off = p_offset; 399 seg.file_size = p_filesz; 400 /* PF_R/W/X share bit values with OBJ_SEG_R/W/X. */ 401 seg.perms = p_flags & (PF_R | PF_W | PF_X); 402 seg.align = (u32)(p_align ? p_align : 1); 403 obj_image_add_segment(im, &seg); 404 405 if (p_type == PT_LOAD && (!have_base || p_vaddr < image_base)) { 406 image_base = p_vaddr; 407 have_base = 1; 408 } 409 if (p_type == PT_INTERP && p_filesz && p_offset + p_filesz <= len) { 410 u32 ilen = (u32)p_filesz; 411 while (ilen && data[p_offset + ilen - 1] == '\0') --ilen; 412 if (ilen) 413 obj_image_set_interp( 414 im, pool_intern_slice( 415 c->global, (Slice){.s = (const char*)(data + p_offset), 416 .len = ilen})); 417 } 418 } 419 } 420 if (have_base) obj_image_set_base(im, image_base); 421 } 422 423 /* Locate .dynamic and .dynsym. */ 424 u32 dynamic_idx = 0, dynsym_idx = 0; 425 for (u16 i = 1; i < e_shnum; ++i) { 426 if (shdrs[i].sh_type == SHT_DYNAMIC && !dynamic_idx) dynamic_idx = i; 427 if (shdrs[i].sh_type == SHT_DYNSYM && !dynsym_idx) dynsym_idx = i; 428 } 429 430 /* .dynamic -> dependency view. */ 431 if (dynamic_idx) { 432 const ShdrRec* dsh = &shdrs[dynamic_idx]; 433 if (dsh->sh_link < e_shnum) { 434 const ShdrRec* str_sh = &shdrs[dsh->sh_link]; 435 if (str_sh->sh_offset + str_sh->sh_size <= len && 436 dsh->sh_offset + dsh->sh_size <= len) { 437 const u8* dynstr = data + str_sh->sh_offset; 438 u64 dynstr_sz = str_sh->sh_size; 439 const u8* dynp = data + dsh->sh_offset; 440 u64 dynsz = dsh->sh_size; 441 /* ELF32 DT entries are 8B (d_tag:u32, d_un:u32); ELF64 16B. */ 442 for (u64 off = 0; off + dyn_size <= dynsz; off += dyn_size) { 443 u64 tag = elf_rd_addr(dynp + off, is32); 444 u64 val = elf_rd_addr(dynp + off + (is32 ? 4 : 8), is32); 445 /* Raw .dynamic view (escape hatch): one entry per DT_* tag, the 446 * terminating DT_NULL included, before the NEEDED/SONAME/RPATH 447 * filtering below. */ 448 { 449 ObjImageRaw r; 450 r.tag = (u32)tag; 451 r.value = val; 452 r.extra = 0; 453 obj_image_add_raw(im, &r); 454 } 455 if (tag == DT_NULL) break; 456 if (tag != DT_NEEDED && tag != DT_SONAME && tag != DT_RPATH && 457 tag != DT_RUNPATH) 458 continue; 459 { 460 u32 nlen; 461 const char* nm = strtab_lookup(dynstr, dynstr_sz, (u32)val, &nlen); 462 Sym s = nlen ? pool_intern_slice(c->global, 463 (Slice){.s = nm, .len = nlen}) 464 : 0; 465 if (!s) continue; 466 if (tag == DT_NEEDED) { 467 ObjImageDep d; 468 d.name = s; 469 d.imports = NULL; 470 d.nimports = 0; 471 obj_image_add_dep(im, &d); 472 } else if (tag == DT_SONAME) { 473 obj_image_set_soname(im, s); 474 } else { 475 obj_image_add_rpath(im, s); 476 } 477 } 478 } 479 } 480 } 481 } 482 483 /* .dynsym -> dynamic symbols, plus an index->name table for dyn relocs. */ 484 Sym* dynsym_names = NULL; 485 u32 ndynsym = 0; 486 if (dynsym_idx) { 487 const ShdrRec* sh = &shdrs[dynsym_idx]; 488 if (sh->sh_entsize == sym_size && (sh->sh_size % sym_size) == 0 && 489 sh->sh_link < e_shnum && sh->sh_offset + sh->sh_size <= len) { 490 const ShdrRec* str_sh = &shdrs[sh->sh_link]; 491 if (str_sh->sh_offset + str_sh->sh_size <= len) { 492 const u8* strtab = data + str_sh->sh_offset; 493 u64 strtab_sz = str_sh->sh_size; 494 const u8* base = data + sh->sh_offset; 495 ndynsym = (u32)(sh->sh_size / sym_size); 496 dynsym_names = arena_zarray(c->scratch, Sym, ndynsym ? ndynsym : 1); 497 /* Parallel symbol-version tables: .gnu.version_d names indexed by 498 * version index, and .gnu.version (one u16 per dynsym entry). A 499 * defined entry whose versym lacks VERSYM_HIDDEN is the *default* 500 * version of its name — the version a plain reference should bind. */ 501 u32 verdef_max = 0; 502 Sym* verdef_tbl = 503 read_elf_verdefs(c, data, len, shdrs, e_shnum, &verdef_max); 504 const u8* versym = NULL; 505 u32 nversym = 0; 506 for (u16 vi = 1; vi < e_shnum; ++vi) { 507 if (shdrs[vi].sh_type != SHT_GNU_VERSYM) continue; 508 if (shdrs[vi].sh_offset + shdrs[vi].sh_size <= len && 509 shdrs[vi].sh_entsize == 2) 510 versym = data + shdrs[vi].sh_offset, 511 nversym = (u32)(shdrs[vi].sh_size / 2u); 512 break; 513 } 514 for (u32 i = 1; i < ndynsym; ++i) { 515 const u8* p = base + (u64)i * sym_size; 516 /* Elf32_Sym REORDERS: st_name@0, st_value@4, st_size@8, 517 * st_info@12, st_other@13, st_shndx@14. Elf64_Sym: 518 * st_name@0, st_info@4, st_other@5, st_shndx@6, 519 * st_value@8, st_size@16. */ 520 u32 st_name = rd_u32_le(p + 0); 521 u8 st_info = is32 ? p[12] : p[4]; 522 u16 st_shndx = is32 ? rd_u16_le(p + 14) : rd_u16_le(p + 6); 523 u64 st_value = is32 ? (u64)rd_u32_le(p + 4) : rd_u64_le(p + 8); 524 u64 st_size = is32 ? (u64)rd_u32_le(p + 8) : rd_u64_le(p + 16); 525 u32 nlen; 526 const char* nm = strtab_lookup(strtab, strtab_sz, st_name, &nlen); 527 Sym sn = 528 nlen ? pool_intern_slice(c->global, (Slice){.s = nm, .len = nlen}) 529 : 0; 530 ObjImageSym ds; 531 dynsym_names[i] = sn; 532 ds.name = sn; 533 ds.bind = (SymBind)elf_bind_to_obj(ELF64_ST_BIND(st_info)); 534 ds.kind = (SymKind)elf_type_to_kind(ELF64_ST_TYPE(st_info), st_shndx); 535 ds.section = (st_shndx == SHN_UNDEF || st_shndx == SHN_ABS || 536 st_shndx == SHN_COMMON || st_shndx >= e_shnum) 537 ? OBJ_SEC_NONE 538 : elf_to_obj[st_shndx]; 539 ds.value = st_value; 540 ds.size = st_size; 541 ds.version = 0; 542 ds.version_hidden = 0; 543 if (versym && verdef_tbl && i < nversym && st_shndx != SHN_UNDEF) { 544 u16 v = rd_u16_le(versym + (u64)i * 2u); 545 u32 ndx = (u32)(v & VERSYM_VERSION); 546 if (ndx >= 2u && ndx <= verdef_max) { 547 ds.version = verdef_tbl[ndx]; 548 ds.version_hidden = (u8)((v & VERSYM_HIDDEN) != 0); 549 } 550 } 551 obj_image_add_dynsym(im, &ds); 552 } 553 } 554 } 555 } 556 557 /* Allocatable .rela.* / .rel.* -> dynamic relocations. */ 558 for (u16 i = 1; i < e_shnum; ++i) { 559 const ShdrRec* sh = &shdrs[i]; 560 int is_rela = (sh->sh_type == SHT_RELA); 561 int is_rel = (sh->sh_type == SHT_REL); 562 u32 entsize, nrec, j; 563 const u8* base; 564 if (!is_rela && !is_rel) continue; 565 if (!(sh->sh_flags & SHF_ALLOC)) 566 continue; /* link-time relocs: not dynamic */ 567 entsize = is_rela ? rela_size : rel_size; 568 if (sh->sh_entsize != entsize || (sh->sh_size % entsize) != 0) continue; 569 if (sh->sh_offset + sh->sh_size > len) continue; 570 nrec = (u32)(sh->sh_size / entsize); 571 base = data + sh->sh_offset; 572 for (j = 0; j < nrec; ++j) { 573 /* Elf32_Rela (12B): r_offset@0, r_info@4 (ELF32 packing), 574 * r_addend@8. Elf64_Rela (24B): r_offset@0, r_info@8, r_addend@16. */ 575 const u8* p = base + (u64)j * entsize; 576 u64 r_offset = elf_rd_addr(p + 0, is32); 577 u64 r_info = is32 ? (u64)rd_u32_le(p + 4) : rd_u64_le(p + 8); 578 i64 r_addend = 579 is_rela ? (is32 ? (i64)(i32)rd_u32_le(p + 8) : (i64)rd_u64_le(p + 16)) 580 : 0; 581 u32 esym = is32 ? ELF32_R_SYM(r_info) : ELF64_R_SYM(r_info); 582 u32 kind = reloc_from(is32 ? ELF32_R_TYPE(r_info) : ELF64_R_TYPE(r_info)); 583 ObjImageReloc dr; 584 if (kind == (u32)-1) continue; /* unmodeled dyn reloc type: skip */ 585 dr.section = OBJ_SEC_NONE; /* offset is a vaddr, not section-relative */ 586 dr.offset = r_offset; 587 dr.sym_name = (dynsym_names && esym < ndynsym) ? dynsym_names[esym] : 0; 588 dr.addend = r_addend; 589 dr.kind = (RelocKind)kind; 590 obj_image_add_dynreloc(im, &dr); 591 } 592 } 593 } 594 595 ObjBuilder* read_elf(Compiler* c, const char* name, const u8* data, 596 size_t len) { 597 (void)name; 598 599 /* Need at least the e_ident to read EI_CLASS; the full min-length 600 * check below uses the class-selected ehdr size. */ 601 if (len < EI_NIDENT) 602 compiler_panic(c, SRCLOC_NONE, "read_elf: input shorter than ELF header"); 603 604 if (data[EI_MAG0] != ELFMAG0 || data[EI_MAG1] != ELFMAG1 || 605 data[EI_MAG2] != ELFMAG2 || data[EI_MAG3] != ELFMAG3) 606 compiler_panic(c, SRCLOC_NONE, "read_elf: bad ELF magic"); 607 608 /* Accept both classes; is32 (EI_CLASS==ELFCLASS32) drives every 609 * stride/offset/field-order decision below. RV32 and RV64 share 610 * EM_RISCV — the reader cannot tell them apart by e_machine, only by 611 * EI_CLASS, so is32 is the single source of truth here. */ 612 if (data[EI_CLASS] != ELFCLASS64 && data[EI_CLASS] != ELFCLASS32) 613 compiler_panic(c, SRCLOC_NONE, "read_elf: not ELFCLASS32/64 (got %u)", 614 data[EI_CLASS]); 615 if (data[EI_DATA] != ELFDATA2LSB) 616 compiler_panic(c, SRCLOC_NONE, "read_elf: not ELFDATA2LSB (got %u)", 617 data[EI_DATA]); 618 619 int is32 = (data[EI_CLASS] == ELFCLASS32); 620 u32 ehdr_size = is32 ? ELF32_EHDR_SIZE : ELF64_EHDR_SIZE; 621 u32 shdr_size = is32 ? ELF32_SHDR_SIZE : ELF64_SHDR_SIZE; 622 u32 sym_size = is32 ? ELF32_SYM_SIZE : ELF64_SYM_SIZE; 623 u32 rela_size = is32 ? ELF32_RELA_SIZE : ELF64_RELA_SIZE; 624 u32 rel_size = is32 ? 8u : 16u; 625 if (len < ehdr_size) 626 compiler_panic(c, SRCLOC_NONE, "read_elf: input shorter than ELF header"); 627 628 u16 e_type = rd_u16_le(data + 16); 629 /* ET_REL parses to the section/symbol/reloc view only. ET_EXEC/ET_DYN 630 * additionally get the linked-image view (read_elf_image, below); their 631 * section tables still parse through the same passes. ET_CORE and other 632 * types are out of scope (see doc/plan/IMAGE_INSPECT.md). */ 633 if (e_type != ET_REL && e_type != ET_EXEC && e_type != ET_DYN) 634 compiler_panic(c, SRCLOC_NONE, 635 "read_elf: unsupported e_type=%u (expected ET_REL, " 636 "ET_EXEC, or ET_DYN)", 637 (u32)e_type); 638 639 u16 e_machine = rd_u16_le(data + 18); 640 /* EM_RISCV is shared by RV32/RV64; disambiguate by EI_CLASS via 641 * obj_elf_machine_class (obj_elf_machine keys on e_machine alone). */ 642 const ObjElfArchOps* arch = obj_elf_machine_class(e_machine, data[EI_CLASS]); 643 u32 (*reloc_from)(u32); 644 if (!arch || !arch->reloc_from) { 645 compiler_panic(c, SRCLOC_NONE, "read_elf: unsupported e_machine 0x%x", 646 (u32)e_machine); 647 } 648 reloc_from = arch->reloc_from; 649 650 /* Post-e_version Ehdr fields narrow + shift under ELF32: e_entry/ 651 * e_phoff/e_shoff are 4B (vs 8B), so e_flags@36, e_phentsize@42, 652 * e_phnum@44, e_shentsize@46, e_shnum@48, e_shstrndx@50 (vs 48/54/ 653 * 56/58/60/62 on ELF64). */ 654 u64 e_shoff = is32 ? (u64)rd_u32_le(data + 32) : rd_u64_le(data + 40); 655 u32 e_flags = rd_u32_le(data + (is32 ? 36 : 48)); 656 u16 e_shentsize = rd_u16_le(data + (is32 ? 46 : 58)); 657 u16 e_shnum = rd_u16_le(data + (is32 ? 48 : 60)); 658 u16 e_shstrndx = rd_u16_le(data + (is32 ? 50 : 62)); 659 660 /* A fully section-stripped image (objcopy --strip-sections, packers, 661 * some release binaries) sets e_shoff/e_shnum to zero: the section 662 * header table is gone, but the load segments still describe the file. 663 * That's valid for ET_EXEC/ET_DYN — parse the image view (segments + 664 * dynamic) and present an empty section view, matching GNU/LLVM. An 665 * ET_REL with no sections carries no model state, so still reject it. */ 666 int has_sht = (e_shoff != 0 && e_shnum != 0); 667 if (has_sht) { 668 if (e_shentsize != shdr_size) 669 compiler_panic(c, SRCLOC_NONE, "read_elf: unexpected e_shentsize %u", 670 (u32)e_shentsize); 671 if (e_shoff + (u64)e_shnum * shdr_size > len) 672 compiler_panic(c, SRCLOC_NONE, 673 "read_elf: section header table out of range"); 674 if (e_shstrndx >= e_shnum) 675 compiler_panic(c, SRCLOC_NONE, "read_elf: e_shstrndx %u >= e_shnum %u", 676 (u32)e_shstrndx, (u32)e_shnum); 677 } else { 678 if (e_type == ET_REL) 679 compiler_panic(c, SRCLOC_NONE, 680 "read_elf: ET_REL with no section header table"); 681 e_shnum = 0; /* normalize so the section/symbol/reloc passes are no-ops */ 682 } 683 684 /* Parse all shdrs into scratch. NULL when the table is absent. */ 685 ShdrRec* shdrs = NULL; 686 const u8* shstrtab = NULL; 687 u64 shstrtab_sz = 0; 688 if (has_sht) { 689 shdrs = arena_array(c->scratch, ShdrRec, e_shnum); 690 for (u32 i = 0; i < e_shnum; ++i) 691 parse_shdr(data + e_shoff + (u64)i * shdr_size, is32, &shdrs[i]); 692 693 const ShdrRec* shstr_sh = &shdrs[e_shstrndx]; 694 if (shstr_sh->sh_offset + shstr_sh->sh_size > len) 695 compiler_panic(c, SRCLOC_NONE, "read_elf: .shstrtab out of range"); 696 shstrtab = data + shstr_sh->sh_offset; 697 shstrtab_sz = shstr_sh->sh_size; 698 } 699 700 /* Build the ObjBuilder. */ 701 ObjBuilder* ob = obj_new(c); 702 if (!ob) compiler_panic(c, SRCLOC_NONE, "read_elf: obj_new failed"); 703 obj_set_elf_e_flags(ob, e_flags); 704 705 /* elf_to_obj[shndx] -> ObjSecId, OBJ_SEC_NONE for skipped sections. */ 706 u32* elf_to_obj = arena_zarray(c->scratch, u32, e_shnum ? e_shnum : 1); 707 708 /* Pass 1: create obj sections for every non-NULL shdr that carries 709 * load-bearing model state. SYMTAB / STRTAB / RELA / REL are 710 * consumed below for symbols and relocations and do NOT round-trip 711 * as obj sections — emit_elf re-synthesizes them from the 712 * ObjBuilder's symbols / strtab / relocs. The shstrtab is a STRTAB 713 * too, so it falls out the same way. */ 714 for (u32 i = 1; i < e_shnum; ++i) { 715 const ShdrRec* sh = &shdrs[i]; 716 if (sh->sh_type == SHT_NULL) continue; 717 if (sh->sh_type == SHT_SYMTAB) continue; 718 if (sh->sh_type == SHT_STRTAB) continue; 719 if (sh->sh_type == SHT_RELA) continue; 720 if (sh->sh_type == SHT_REL) continue; 721 /* SHT_GROUP is consumed below into an ObjGroup record (signature 722 * symbol + member ObjSecIds). emit_elf re-synthesizes the group 723 * section bytes from the ObjGroup, using current section indices 724 * — so the original section's raw body would be stale anyway. */ 725 if (sh->sh_type == SHT_GROUP) continue; 726 727 u32 nlen; 728 const char* nm = strtab_lookup(shstrtab, shstrtab_sz, sh->sh_name, &nlen); 729 Sym sym = pool_intern_slice(c->global, (Slice){.s = nm, .len = nlen}); 730 731 u16 sec_kind = elf_kind_from_name(nm, nlen, sh->sh_flags, sh->sh_type); 732 int type_known; 733 u16 sec_sem = elf_type_to_sem(sh->sh_type, &type_known); 734 u16 flags = elf_flags_to_obj(sh->sh_flags); 735 u32 align = sh->sh_addralign ? (u32)sh->sh_addralign : 1; 736 737 ObjSecId id = 738 obj_section_ex(ob, sym, (SecKind)sec_kind, (SecSem)sec_sem, flags, 739 align, (u32)sh->sh_entsize, sh->sh_link, sh->sh_info); 740 if (id == OBJ_SEC_NONE) 741 compiler_panic(c, SRCLOC_NONE, 742 "read_elf: obj_section_ex failed for '%.*s'", 743 SLICE_ARG(((Slice){.s = nm, .len = nlen}))); 744 elf_to_obj[i] = id; 745 746 /* Load address: 0 for ET_REL, the assigned vaddr for linked images. 747 * Lets the section view carry the load picture for execs/DSOs. */ 748 if (sh->sh_addr) obj_section_set_addr(ob, id, sh->sh_addr); 749 750 /* Preserve format-specific bits the canonical SecSem/SecFlag 751 * mapping can't represent so emit_elf can write them back 752 * verbatim. ext_type only set when the sh_type fell through 753 * to the "unknown" path. */ 754 u32 leftover = (u32)(sh->sh_flags & ~ELF_KNOWN_FLAGS_MASK); 755 if (!type_known || leftover) { 756 obj_section_set_ext(ob, id, OBJ_EXT_ELF, type_known ? 0 : sh->sh_type, 757 leftover); 758 } 759 760 /* Body bytes. */ 761 if (sh->sh_type == SHT_NOBITS) { 762 obj_reserve_bss(ob, id, (u32)sh->sh_size, align); 763 } else if (sh->sh_size) { 764 if (sh->sh_offset + sh->sh_size > len) 765 compiler_panic(c, SRCLOC_NONE, 766 "read_elf: section '%.*s' bytes out of range", 767 SLICE_ARG(((Slice){.s = nm, .len = nlen}))); 768 /* For SYMTAB/STRTAB/RELA we still copy the raw bytes — the 769 * post-finalize shape contract says these sections are 770 * present; emit_elf will regenerate them on re-emit, so the 771 * preserved bytes are informational rather than load-bearing. 772 */ 773 obj_write(ob, id, data + sh->sh_offset, (size_t)sh->sh_size); 774 } 775 } 776 777 /* Pass 2: parse the .symtab into ObjSyms, building an 778 * elf_sym_idx -> ObjSymId table. There may be zero or one SYMTAB in 779 * an ET_REL; pick the first. */ 780 u32 symtab_shndx = 0; 781 for (u32 i = 1; i < e_shnum; ++i) { 782 if (shdrs[i].sh_type == SHT_SYMTAB) { 783 symtab_shndx = i; 784 break; 785 } 786 } 787 788 u32 nsyms = 0; 789 u32* sym_elf_to_obj = NULL; 790 791 if (symtab_shndx) { 792 const ShdrRec* sh = &shdrs[symtab_shndx]; 793 if (sh->sh_entsize != sym_size) 794 compiler_panic(c, SRCLOC_NONE, "read_elf: .symtab entsize %llu != %u", 795 (unsigned long long)sh->sh_entsize, sym_size); 796 if (sh->sh_size % sym_size) 797 compiler_panic(c, SRCLOC_NONE, 798 "read_elf: .symtab size %llu not a multiple of %u", 799 (unsigned long long)sh->sh_size, sym_size); 800 if (sh->sh_link >= e_shnum) 801 compiler_panic(c, SRCLOC_NONE, 802 "read_elf: .symtab sh_link %u out of range", sh->sh_link); 803 const ShdrRec* str_sh = &shdrs[sh->sh_link]; 804 if (str_sh->sh_offset + str_sh->sh_size > len) 805 compiler_panic(c, SRCLOC_NONE, "read_elf: .strtab out of range"); 806 const u8* strtab = data + str_sh->sh_offset; 807 u64 strtab_sz = str_sh->sh_size; 808 809 nsyms = (u32)(sh->sh_size / sym_size); 810 obj_reserve_symbols(ob, nsyms); /* skip the 256->nsyms resize cascade */ 811 sym_elf_to_obj = arena_zarray(c->scratch, u32, nsyms ? nsyms : 1); 812 813 const u8* base = data + sh->sh_offset; 814 for (u32 i = 1; i < nsyms; ++i) { /* skip index 0 */ 815 const u8* p = base + (u64)i * sym_size; 816 /* Elf32_Sym REORDERS: st_name@0, st_value@4, st_size@8, st_info@12, 817 * st_other@13, st_shndx@14. Elf64_Sym: st_name@0, st_info@4, 818 * st_other@5, st_shndx@6, st_value@8, st_size@16. */ 819 u32 st_name = rd_u32_le(p + 0); 820 u8 st_info = is32 ? p[12] : p[4]; 821 u8 st_other = is32 ? p[13] : p[5]; 822 u16 st_shndx = is32 ? rd_u16_le(p + 14) : rd_u16_le(p + 6); 823 u64 st_value = is32 ? (u64)rd_u32_le(p + 4) : rd_u64_le(p + 8); 824 u64 st_size = is32 ? (u64)rd_u32_le(p + 8) : rd_u64_le(p + 16); 825 826 u32 nlen; 827 const char* nm = strtab_lookup(strtab, strtab_sz, st_name, &nlen); 828 nlen = elf_default_version_namelen(nm, nlen); 829 Sym sn = nlen 830 ? pool_intern_slice(c->global, (Slice){.s = nm, .len = nlen}) 831 : 0; 832 833 u32 e_bind = ELF64_ST_BIND(st_info); 834 u32 e_type = ELF64_ST_TYPE(st_info); 835 u16 bind = elf_bind_to_obj(e_bind); 836 u16 kind = elf_type_to_kind(e_type, st_shndx); 837 u8 vis = elf_other_to_vis(st_other); 838 839 ObjSecId sec_id; 840 u64 value; 841 u64 cmnalign = 0; 842 if (st_shndx == SHN_UNDEF) { 843 sec_id = OBJ_SEC_NONE; 844 value = st_value; 845 } else if (st_shndx == SHN_ABS || st_shndx == SHN_COMMON) { 846 sec_id = OBJ_SEC_NONE; 847 value = st_value; 848 if (st_shndx == SHN_COMMON) cmnalign = st_value; 849 } else if (st_shndx < e_shnum && shdrs[st_shndx].sh_type == SHT_GROUP) { 850 /* A COMDAT group's signature symbol is defined in its SHT_GROUP 851 * section, which we consume into an ObjGroup and never keep as an 852 * obj section (so elf_to_obj is OBJ_SEC_NONE for it). The symbol just 853 * names the group; it is not a data location and is never a reloc 854 * target. Record it as an absolute defined symbol so it doesn't look 855 * like a phantom undefined reference -- FreeBSD's crt1.o brands the 856 * binary with such a symbol (.freebsd.note*). */ 857 sec_id = OBJ_SEC_NONE; 858 value = st_value; 859 kind = SK_ABS; 860 } else if (st_shndx < e_shnum) { 861 sec_id = elf_to_obj[st_shndx]; 862 value = st_value; 863 } else { 864 compiler_panic(c, SRCLOC_NONE, "read_elf: symbol shndx %u out of range", 865 (u32)st_shndx); 866 sec_id = OBJ_SEC_NONE; 867 value = 0; /* unreachable */ 868 } 869 870 ObjSymId id = 871 obj_symbol_ex(ob, sn, (SymBind)bind, (SymVis)vis, (SymKind)kind, 872 sec_id, value, st_size, cmnalign); 873 obj_sym_mark_referenced(ob, id); 874 sym_elf_to_obj[i] = id; 875 } 876 } 877 878 /* Pass 3: parse each SHT_RELA / SHT_REL into ObjBuilder relocations 879 * targeting the section the rela header's sh_info points at. */ 880 for (u32 i = 1; i < e_shnum; ++i) { 881 const ShdrRec* sh = &shdrs[i]; 882 int is_rela = (sh->sh_type == SHT_RELA); 883 int is_rel = (sh->sh_type == SHT_REL); 884 if (!is_rela && !is_rel) continue; 885 /* Allocatable rela/rel in ET_EXEC/ET_DYN are loader (dynamic) 886 * relocations — sh_info is 0 or a .got index, not a target section. 887 * They belong to the image's dynamic-reloc view (read_elf_image), not 888 * the section-relocation table. ET_REL link-time relocs are never 889 * SHF_ALLOC, so this is a no-op for relocatable objects. */ 890 if (sh->sh_flags & SHF_ALLOC) continue; 891 892 u32 entsize = is_rela ? rela_size : rel_size; 893 if (sh->sh_entsize != entsize) 894 compiler_panic(c, SRCLOC_NONE, "read_elf: rela entsize %llu != %u", 895 (unsigned long long)sh->sh_entsize, entsize); 896 if (sh->sh_info == 0 || sh->sh_info >= e_shnum) 897 compiler_panic(c, SRCLOC_NONE, "read_elf: rela sh_info %u out of range", 898 sh->sh_info); 899 ObjSecId target = elf_to_obj[sh->sh_info]; 900 if (target == OBJ_SEC_NONE) continue; 901 902 /* For REL the addend lives in the relocated field, not an r_addend slot. 903 * Locate the target section's bytes so the per-arch decoder can recover 904 * it (matching what a field-reading linker like ld.lld does). A NOBITS 905 * target has no file bytes — its relocs keep addend 0. */ 906 const ShdrRec* tgt_sh = &shdrs[sh->sh_info]; 907 const u8* tgt_bytes = NULL; 908 u64 tgt_size = 0; 909 if (is_rel && arch && arch->reloc_field_addend && 910 tgt_sh->sh_type != SHT_NOBITS && 911 tgt_sh->sh_offset + tgt_sh->sh_size <= len) { 912 tgt_bytes = data + tgt_sh->sh_offset; 913 tgt_size = tgt_sh->sh_size; 914 } 915 916 u32 nrec = (u32)(sh->sh_size / entsize); 917 const u8* base = data + sh->sh_offset; 918 for (u32 j = 0; j < nrec; ++j) { 919 /* Elf32_Rel (8B): r_offset@0, r_info@4 — addend in-field. 920 * Elf32_Rela (12B): + r_addend@8. Elf64_Rela (24B): r_offset@0, 921 * r_info@8, r_addend@16. */ 922 const u8* p = base + (u64)j * entsize; 923 u64 r_offset = elf_rd_addr(p + 0, is32); 924 u64 r_info = is32 ? (u64)rd_u32_le(p + 4) : rd_u64_le(p + 8); 925 i64 r_addend = 926 is_rela ? (is32 ? (i64)(i32)rd_u32_le(p + 8) : (i64)rd_u64_le(p + 16)) 927 : 0; 928 u32 esym = is32 ? ELF32_R_SYM(r_info) : ELF64_R_SYM(r_info); 929 u32 etype = is32 ? ELF32_R_TYPE(r_info) : ELF64_R_TYPE(r_info); 930 931 u32 kind = reloc_from(etype); 932 if (kind == (u32)-1) 933 compiler_panic(c, SRCLOC_NONE, 934 "read_elf: unsupported reloc type %u for e_machine 0x%x", 935 etype, (u32)e_machine); 936 937 /* REL: reconstruct the implicit in-field addend (width capped to the 938 * field's remaining bytes; Thumb-2 instructions and data words are 4). */ 939 if (tgt_bytes && r_offset < tgt_size) { 940 u32 width = (u32)(tgt_size - r_offset); 941 if (width > 4) width = 4; 942 r_addend = arch->reloc_field_addend((u32)kind, tgt_bytes + r_offset, 943 width); 944 } 945 946 ObjSymId target_sym = OBJ_SYM_NONE; 947 if (esym && sym_elf_to_obj && esym < nsyms) 948 target_sym = sym_elf_to_obj[esym]; 949 950 obj_reloc_ex(ob, target, (u32)r_offset, (RelocKind)kind, target_sym, 951 r_addend, is_rela ? 1 : 0, 0); 952 } 953 } 954 955 /* Pass 4: SHT_GROUP. Each GROUP section's body is a sequence of 956 * 4-byte LE indices: [flags, shndx, shndx, ...]. The signature is 957 * the symbol named by sh_link/sh_info convention (sh_link=symtab, 958 * sh_info=symbol index in that symtab). */ 959 for (u32 i = 1; i < e_shnum; ++i) { 960 const ShdrRec* sh = &shdrs[i]; 961 if (sh->sh_type != SHT_GROUP) continue; 962 963 if (sh->sh_size < 4 || (sh->sh_size % 4)) continue; 964 const u8* p = data + sh->sh_offset; 965 u32 flags = rd_u32_le(p); 966 u32 nm_len; 967 const char* gnm = 968 strtab_lookup(shstrtab, shstrtab_sz, sh->sh_name, &nm_len); 969 Sym gname = pool_intern_slice(c->global, (Slice){.s = gnm, .len = nm_len}); 970 971 ObjSymId signature = OBJ_SYM_NONE; 972 if (sym_elf_to_obj && sh->sh_info < nsyms) 973 signature = sym_elf_to_obj[sh->sh_info]; 974 975 ObjGroupId gid = obj_group(ob, gname, signature, flags); 976 u32 n = (u32)(sh->sh_size / 4) - 1; 977 for (u32 j = 0; j < n; ++j) { 978 u32 shndx = rd_u32_le(p + 4 + j * 4); 979 if (shndx < e_shnum && elf_to_obj[shndx] != OBJ_SEC_NONE) 980 obj_group_add_section(ob, gid, elf_to_obj[shndx]); 981 } 982 } 983 984 /* ET_EXEC / ET_DYN: attach the linked-image view (segments + dynamic). */ 985 if (e_type != ET_REL) 986 read_elf_image(c, ob, data, len, e_type, is32, shdrs, e_shnum, elf_to_obj, 987 reloc_from); 988 989 obj_finalize(ob); 990 return ob; 991 } 992 993 /* ---- ET_DYN (shared object) reader ---- 994 * 995 * Produces an ObjBuilder containing only the DSO's exported symbols 996 * (parsed from .dynsym, not .symtab). The DSO's sections, relocations, 997 * and groups are skipped — DSOs contribute no bytes to the output 998 * image. The DT_SONAME (if any) is interned and returned via 999 * `*soname_out` so the caller can record DT_NEEDED at link time. 1000 * 1001 * Symbol shape: each defined dynsym entry produces an ObjSym whose 1002 * (bind, kind, vis) match the source. `section_id` is OBJ_SEC_NONE — 1003 * the symbol's value is its DSO-internal vaddr, not meaningful to the 1004 * consuming linker, so we record `value=0`. The linker layer 1005 * (resolve_undefs) only consults the name and the defined-ness flag. 1006 * 1007 * Undefined dynsym entries (st_shndx==SHN_UNDEF) are imports the DSO 1008 * itself has against other libraries; they're not relevant to a 1009 * consumer that's linking against this DSO and are dropped. */ 1010 1011 static int parse_phdr(const u8* data, size_t len, u64 e_phoff, u16 e_phentsize, 1012 u16 e_phnum, u32 want_type, u64* out_offset, 1013 u64* out_filesz) { 1014 u32 i; 1015 if (e_phentsize != ELF64_PHDR_SIZE) return 0; 1016 if (e_phoff + (u64)e_phnum * ELF64_PHDR_SIZE > len) return 0; 1017 for (i = 0; i < e_phnum; ++i) { 1018 const u8* p = data + e_phoff + (u64)i * ELF64_PHDR_SIZE; 1019 u32 p_type = rd_u32_le(p + 0); 1020 if (p_type != want_type) continue; 1021 *out_offset = rd_u64_le(p + 8); 1022 *out_filesz = rd_u64_le(p + 32); 1023 return 1; 1024 } 1025 return 0; 1026 } 1027 1028 ObjBuilder* read_elf_dso(Compiler* c, const char* name, const u8* data, 1029 size_t len, Sym* soname_out) { 1030 (void)name; 1031 if (soname_out) *soname_out = 0; 1032 1033 if (len < ELF64_EHDR_SIZE) 1034 compiler_panic(c, SRCLOC_NONE, 1035 "read_elf_dso: input shorter than ELF header"); 1036 if (data[EI_MAG0] != ELFMAG0 || data[EI_MAG1] != ELFMAG1 || 1037 data[EI_MAG2] != ELFMAG2 || data[EI_MAG3] != ELFMAG3) 1038 compiler_panic(c, SRCLOC_NONE, "read_elf_dso: bad ELF magic"); 1039 if (data[EI_CLASS] != ELFCLASS64) 1040 compiler_panic(c, SRCLOC_NONE, "read_elf_dso: not ELFCLASS64"); 1041 if (data[EI_DATA] != ELFDATA2LSB) 1042 compiler_panic(c, SRCLOC_NONE, "read_elf_dso: not ELFDATA2LSB"); 1043 1044 u16 e_type = rd_u16_le(data + 16); 1045 if (e_type != ET_DYN) 1046 compiler_panic(c, SRCLOC_NONE, 1047 "read_elf_dso: expected ET_DYN, got e_type=%u", (u32)e_type); 1048 1049 u16 e_machine = rd_u16_le(data + 18); 1050 { 1051 const ObjFormatImpl* fmt = obj_format_lookup(KIT_OBJ_ELF); 1052 const ObjElfArchOps* arch = 1053 fmt && fmt->elf_machine ? fmt->elf_machine(e_machine) : NULL; 1054 if (!arch) 1055 compiler_panic(c, SRCLOC_NONE, "read_elf_dso: unsupported e_machine 0x%x", 1056 (u32)e_machine); 1057 } 1058 1059 u64 e_phoff = rd_u64_le(data + 32); 1060 u64 e_shoff = rd_u64_le(data + 40); 1061 u16 e_phentsize = rd_u16_le(data + 54); 1062 u16 e_phnum = rd_u16_le(data + 56); 1063 u16 e_shentsize = rd_u16_le(data + 58); 1064 u16 e_shnum = rd_u16_le(data + 60); 1065 u16 e_shstrndx = rd_u16_le(data + 62); 1066 1067 if (e_shentsize != ELF64_SHDR_SIZE) 1068 compiler_panic(c, SRCLOC_NONE, "read_elf_dso: unexpected e_shentsize %u", 1069 (u32)e_shentsize); 1070 if (e_shoff + (u64)e_shnum * ELF64_SHDR_SIZE > len) 1071 compiler_panic(c, SRCLOC_NONE, 1072 "read_elf_dso: section header table out of range"); 1073 if (e_shstrndx >= e_shnum) 1074 compiler_panic(c, SRCLOC_NONE, "read_elf_dso: e_shstrndx out of range"); 1075 1076 /* read_elf_dso is ELFCLASS64-only (panics above on other classes), so 1077 * parse with the ELF64 layout (is32 = 0). */ 1078 ShdrRec* shdrs = arena_array(c->scratch, ShdrRec, e_shnum); 1079 for (u32 i = 0; i < e_shnum; ++i) 1080 parse_shdr(data + e_shoff + (u64)i * ELF64_SHDR_SIZE, 0, &shdrs[i]); 1081 1082 /* Locate .dynsym (preferred over .symtab — a stripped DSO carries 1083 * only .dynsym) and its associated strtab via sh_link. */ 1084 u32 dynsym_idx = 0, dynamic_idx = 0; 1085 for (u32 i = 1; i < e_shnum; ++i) { 1086 if (shdrs[i].sh_type == SHT_DYNSYM && !dynsym_idx) dynsym_idx = i; 1087 if (shdrs[i].sh_type == SHT_DYNAMIC && !dynamic_idx) dynamic_idx = i; 1088 } 1089 1090 if (!dynsym_idx) 1091 compiler_panic(c, SRCLOC_NONE, 1092 "read_elf_dso: no SHT_DYNSYM in shared object"); 1093 1094 /* Parse PT_DYNAMIC for DT_SONAME. The .dynamic section gives us the 1095 * dynstr to resolve the SONAME's offset; if there's no .dynamic 1096 * section we fall back to scanning the PT_DYNAMIC segment. */ 1097 Sym soname = 0; 1098 if (dynamic_idx) { 1099 const ShdrRec* dsh = &shdrs[dynamic_idx]; 1100 if (dsh->sh_link >= e_shnum) 1101 compiler_panic(c, SRCLOC_NONE, 1102 "read_elf_dso: .dynamic sh_link %u out of range", 1103 dsh->sh_link); 1104 const ShdrRec* str_sh = &shdrs[dsh->sh_link]; 1105 if (str_sh->sh_offset + str_sh->sh_size > len) 1106 compiler_panic(c, SRCLOC_NONE, 1107 "read_elf_dso: .dynamic strtab out of range"); 1108 const u8* dynstr = data + str_sh->sh_offset; 1109 u64 dynstr_sz = str_sh->sh_size; 1110 1111 if (dsh->sh_offset + dsh->sh_size > len) 1112 compiler_panic(c, SRCLOC_NONE, 1113 "read_elf_dso: .dynamic body out of range"); 1114 const u8* dynp = data + dsh->sh_offset; 1115 u64 dynsz = dsh->sh_size; 1116 /* DT entries are 16 bytes: (d_tag: u64, d_un: u64). */ 1117 for (u64 off = 0; off + 16 <= dynsz; off += 16) { 1118 u64 tag = rd_u64_le(dynp + off); 1119 u64 val = rd_u64_le(dynp + off + 8); 1120 if (tag == DT_NULL) break; 1121 if (tag == DT_SONAME) { 1122 u32 nlen; 1123 const char* nm = strtab_lookup(dynstr, dynstr_sz, (u32)val, &nlen); 1124 if (nlen) 1125 soname = pool_intern_slice(c->global, (Slice){.s = nm, .len = nlen}); 1126 break; 1127 } 1128 } 1129 } else if (e_phnum) { 1130 /* Fallback: walk PT_DYNAMIC straight from program headers. We 1131 * only need DT_SONAME, so skip if we can't find a strtab pointer 1132 * inline (DT_STRTAB carries a vaddr, not a file offset — stripped 1133 * DSOs without SHT_DYNAMIC are exceedingly rare in practice). */ 1134 u64 dyn_off, dyn_sz; 1135 (void)parse_phdr(data, len, e_phoff, e_phentsize, e_phnum, PT_DYNAMIC, 1136 &dyn_off, &dyn_sz); 1137 } 1138 if (soname_out) *soname_out = soname; 1139 1140 /* Now parse .dynsym. */ 1141 const ShdrRec* sh = &shdrs[dynsym_idx]; 1142 if (sh->sh_entsize != ELF64_SYM_SIZE) 1143 compiler_panic(c, SRCLOC_NONE, "read_elf_dso: .dynsym entsize %llu != %u", 1144 (unsigned long long)sh->sh_entsize, (u32)ELF64_SYM_SIZE); 1145 if (sh->sh_size % ELF64_SYM_SIZE) 1146 compiler_panic(c, SRCLOC_NONE, 1147 "read_elf_dso: .dynsym size not multiple of entry size"); 1148 if (sh->sh_link >= e_shnum) 1149 compiler_panic(c, SRCLOC_NONE, 1150 "read_elf_dso: .dynsym sh_link out of range"); 1151 const ShdrRec* str_sh = &shdrs[sh->sh_link]; 1152 if (str_sh->sh_offset + str_sh->sh_size > len) 1153 compiler_panic(c, SRCLOC_NONE, "read_elf_dso: .dynstr out of range"); 1154 const u8* strtab = data + str_sh->sh_offset; 1155 u64 strtab_sz = str_sh->sh_size; 1156 1157 ObjBuilder* ob = obj_new(c); 1158 if (!ob) compiler_panic(c, SRCLOC_NONE, "read_elf_dso: obj_new failed"); 1159 1160 /* The DSO always gets an ObjImage: its dynsyms record each export's default 1161 * version (so the linker can emit a matching .gnu.version_r — see 1162 * build_versions in link_dyn.c, harmless/empty for unversioned DSOs like 1163 * musl), and its undef list records the symbols this DSO references so 1164 * --gc-sections keeps the executable's definitions of them alive. */ 1165 u32 verdef_max = 0; 1166 Sym* verdef_tbl = read_elf_verdefs(c, data, len, shdrs, e_shnum, &verdef_max); 1167 const u8* versym = NULL; 1168 u32 nversym = 0; 1169 for (u32 i = 1; i < e_shnum; ++i) { 1170 if (shdrs[i].sh_type != SHT_GNU_VERSYM) continue; 1171 if (shdrs[i].sh_offset + shdrs[i].sh_size <= len && 1172 shdrs[i].sh_entsize == 2) 1173 versym = data + shdrs[i].sh_offset, 1174 nversym = (u32)(shdrs[i].sh_size / 2u); 1175 break; 1176 } 1177 ObjImage* im = obj_image_ensure(ob, OBJ_KIND_DYN); 1178 if (im && soname) obj_image_set_soname(im, soname); 1179 1180 u32 nsyms = (u32)(sh->sh_size / ELF64_SYM_SIZE); 1181 const u8* base = data + sh->sh_offset; 1182 for (u32 i = 1; i < nsyms; ++i) { /* skip index 0 */ 1183 const u8* p = base + (u64)i * ELF64_SYM_SIZE; 1184 u32 st_name = rd_u32_le(p + 0); 1185 u8 st_info = p[4]; 1186 u8 st_other = p[5]; 1187 u16 st_shndx = rd_u16_le(p + 6); 1188 u32 e_bind = ELF64_ST_BIND(st_info); 1189 u32 nlen; 1190 const char* nm; 1191 Sym sn; 1192 1193 /* Locals are neither exports nor reference dependencies we track. */ 1194 if (e_bind == STB_LOCAL) continue; 1195 nm = strtab_lookup(strtab, strtab_sz, st_name, &nlen); 1196 if (!nlen) continue; 1197 sn = pool_intern_slice(c->global, (Slice){.s = nm, .len = nlen}); 1198 1199 /* The DSO's own undefined references: not exports, but if the executable 1200 * defines one (e.g. libc.so.7's `environ` / `__progname`, defined by the 1201 * crt) the static linker must keep that definition under --gc-sections. */ 1202 if (st_shndx == SHN_UNDEF) { 1203 obj_image_add_undef(im, sn); 1204 continue; 1205 } 1206 1207 u32 e_type_field = ELF64_ST_TYPE(st_info); 1208 u16 bind = elf_bind_to_obj(e_bind); 1209 u16 kind = elf_type_to_kind(e_type_field, st_shndx); 1210 u8 vis = elf_other_to_vis(st_other); 1211 1212 /* DSO exports land as defined symbols in OBJ_SEC_NONE with 1213 * value=0. The consumer treats them as imports — see 1214 * resolve_undefs in src/link/link_layout.c. */ 1215 { 1216 ObjSymId did = obj_symbol_ex(ob, sn, (SymBind)bind, (SymVis)vis, 1217 (SymKind)kind, OBJ_SEC_NONE, 0, 0, 0); 1218 obj_sym_mark_referenced(ob, did); 1219 } 1220 if (im) { 1221 ObjImageSym ds; 1222 ds.name = sn; 1223 ds.bind = (SymBind)bind; 1224 ds.kind = (SymKind)kind; 1225 ds.section = OBJ_SEC_NONE; 1226 ds.value = 0; 1227 ds.size = 0; 1228 ds.version = 0; 1229 ds.version_hidden = 0; 1230 if (i < nversym) { 1231 u16 v = rd_u16_le(versym + (u64)i * 2u); 1232 u32 ndx = (u32)(v & VERSYM_VERSION); 1233 if (ndx >= 2u && ndx <= verdef_max) { 1234 ds.version = verdef_tbl[ndx]; 1235 ds.version_hidden = (u8)((v & VERSYM_HIDDEN) != 0); 1236 } 1237 } 1238 obj_image_add_dynsym(im, &ds); 1239 } 1240 } 1241 1242 obj_finalize(ob); 1243 return ob; 1244 }