link_dyn.c (53975B)
1 /* Phase 4 of dynamic linking: synthesize the dyn-link tables and 2 * sections an ET_DYN ELF exe needs to be loadable by a real runtime 3 * loader (musl ld-musl-aarch64.so.1). 4 * 5 * Inputs (computed by earlier passes): 6 * - LinkSymbol entries with `imported = 1` (set by resolve_undefs's 7 * DSO-search path; their dso_input_id names the providing DSO). 8 * - LinkInputs of kind LINK_INPUT_DSO_BYTES carrying SONAMEs. 9 * 10 * Outputs (deposited on LinkImage.dyn): 11 * - .interp PT_INTERP target string 12 * - .dynsym + .dynstr symbol table + name pool 13 * - .gnu.hash GNU-style hash for the loader 14 * - .rela.dyn GLOB_DAT (data imports) + space for 15 * R_AARCH64_RELATIVE records that 16 * Phase 6 emit fills in 17 * - .rela.plt JUMP_SLOT records (one per imported func) 18 * - .plt allocated, body NOT emitted (Phase 5) 19 * - .got.plt 3 reserved slots + 1 per PLT slot, 20 * allocated, body NOT emitted 21 * - .dynamic PT_DYNAMIC body, populated 22 * 23 * The .plt body / GOT-slot fill / CALL26 reloc rewriting are Phase 5; 24 * they're called out at the relevant allocation site so the missing 25 * pieces are obvious to anyone reading the output. The static-exe path 26 * is unaffected — layout_dyn early-outs when emit_pie is 0. 27 * 28 * Allocator pattern follows layout_iplt (link_layout.c): grow segments 29 * + sections via realloc, then page-align each new segment after the 30 * existing image span. Synthetic sections carry input_id == LINK_INPUT_NONE 31 * so downstream passes (emit_reloc_records, GC) leave them alone. 32 */ 33 34 #include "obj/elf/link_dyn.h" 35 36 #include <string.h> 37 38 #include "core/bytes.h" 39 #include "core/heap.h" 40 #include "core/pool.h" 41 #include "core/slice.h" 42 #include "core/util.h" 43 #include "core/vec.h" 44 #include "link/link.h" 45 #include "link/link_arch.h" 46 #include "link/link_internal.h" 47 #include "link/link_reloc_desc.h" 48 #include "obj/bytebuf.h" 49 #include "obj/elf/elf.h" 50 #include "obj/format.h" 51 52 /* ---- small allocators (mirror layout_iplt's helpers) ---- */ 53 54 static u32 dyn_alloc_segments(LinkImage* img, u32 nseg) { 55 Heap* h = img->heap; 56 u32 base = img->nsegments; 57 u32 new_nseg = base + nseg; 58 LinkSegment* nsegs = (LinkSegment*)h->realloc( 59 h, img->segments, sizeof(*img->segments) * img->nsegments, 60 sizeof(*img->segments) * new_nseg, _Alignof(LinkSegment)); 61 u8** nsbufs = (u8**)h->realloc( 62 h, img->segment_bytes, sizeof(*img->segment_bytes) * img->nsegments, 63 sizeof(*img->segment_bytes) * new_nseg, _Alignof(u8*)); 64 size_t* nscaps = (size_t*)h->realloc( 65 h, img->segment_bytes_cap, 66 sizeof(*img->segment_bytes_cap) * img->nsegments, 67 sizeof(*img->segment_bytes_cap) * new_nseg, _Alignof(size_t)); 68 if (!nsegs || !nsbufs || !nscaps) 69 compiler_panic(img->c, SRCLOC_NONE, "link: oom on dyn segments"); 70 img->segments = nsegs; 71 img->segment_bytes = nsbufs; 72 img->segment_bytes_cap = nscaps; 73 return base; 74 } 75 76 static u32 dyn_alloc_sections(LinkImage* img, u32 nsec) { 77 Heap* h = img->heap; 78 u32 base = img->nsections; 79 u32 new_nsec = base + nsec; 80 LinkSection* nsections = (LinkSection*)h->realloc( 81 h, img->sections, sizeof(*img->sections) * img->nsections, 82 sizeof(*img->sections) * new_nsec, _Alignof(LinkSection)); 83 if (!nsections) 84 compiler_panic(img->c, SRCLOC_NONE, "link: oom on dyn sections"); 85 img->sections = nsections; 86 return base; 87 } 88 89 /* The .dynstr / .gnu.hash byte-builder is the shared ObjByteBuf (objbb_*). */ 90 91 /* ---- GNU-hash computation (psABI v1 hash) ---- 92 * Body layout: 93 * u32 nbuckets 94 * u32 symoffset (first hashed dynsym index) 95 * u32 bloom_size (in 64-bit words) 96 * u32 bloom_shift 97 * u64 bloom[bloom_size] 98 * u32 buckets[nbuckets] 99 * u32 chains[ndynsym - symoffset] 100 * 101 * For Phase 4 we keep this very small: nbuckets = max(1, n/2), 102 * bloom_size = 1, bloom_shift = 6 (64-bit ELFCLASS64). All hashed 103 * symbols (sym_offset..ndynsym-1) participate in bloom + buckets + 104 * chains. Slot 0..symoffset-1 are STN_UNDEF + locals, which the 105 * loader doesn't hash. */ 106 107 static u32 gnu_hash_name(const char* s, u32 n) { 108 /* h = 5381; for c in s: h = h * 33 + c */ 109 u32 h = 5381u; 110 u32 i; 111 for (i = 0; i < n; ++i) h = (h * 33u) + (u8)s[i]; 112 return h; 113 } 114 115 /* ---- partition: enumerate imports ---- 116 * 117 * Walks LinkSyms and collects each `imported` symbol that's the 118 * canonical entry in img->globals (resolve_undefs may stamp `imported` 119 * onto multiple shadow slots of the same name; only the canonical one 120 * lands in dynsym). The two output arrays are LinkSymIds: funcs first 121 * (PLT-bound), then data (GOT-bound via GLOB_DAT). */ 122 123 typedef struct ImportLists { 124 LinkSymId* exports; 125 LinkSymId* funcs; 126 u32 nfuncs; 127 LinkSymId* datas; 128 u32 ndatas; 129 u32 nexports; 130 } ImportLists; 131 132 static int sym_is_func_import(const LinkSymbol* s) { 133 /* Most undef shadows have kind = SK_UNDEF (the obj reader keys kind 134 * off shndx, not STT_*). Only useful when the canonical entry 135 * carried a real type — fall through to the DSO lookup otherwise. */ 136 return s->kind == SK_FUNC || s->kind == SK_IFUNC; 137 } 138 139 /* Resolve an import's classifier kind by consulting its providing 140 * DSO's dynsym. read_elf_dso preserves STT_FUNC / STT_OBJECT / etc. 141 * on each defined export; the consumer's undef may have arrived as 142 * SK_UNDEF (clang emits external refs as SHN_UNDEF, which the reader 143 * collapses to SK_UNDEF regardless of STT_*). Returns 1 for func / 144 * ifunc, 0 for everything else (or if the DSO export is missing). */ 145 static int dso_export_is_func(Linker* l, const LinkSymbol* s) { 146 if (s->dso_input_id == LINK_INPUT_NONE) return 0; 147 if (s->dso_input_id - 1u >= LinkInputs_count(&l->inputs)) return 0; 148 LinkInput* in = LinkInputs_at(&l->inputs, s->dso_input_id - 1u); 149 if (!in->obj) return 0; 150 ObjSymIter* it = obj_symiter_new(in->obj); 151 ObjSymEntry e; 152 int is_func = 0; 153 while (obj_symiter_next(it, &e)) { 154 const ObjSym* es = e.sym; 155 if (!es || es->name != s->name) continue; 156 if (es->kind == SK_UNDEF) continue; 157 is_func = (es->kind == SK_FUNC || es->kind == SK_IFUNC); 158 break; 159 } 160 obj_symiter_free(it); 161 return is_func; 162 } 163 164 static int import_has_branch_reloc(Linker* l, LinkImage* img, 165 const LinkSymbol* s) { 166 u32 i; 167 if (!l || !img || !s || s->name == 0) return 0; 168 for (i = 0; i < LinkRelocs_count(&img->relocs); ++i) { 169 const LinkRelocApply* r = LinkRelocs_at(&img->relocs, i); 170 const LinkSymbol* tgt; 171 if (!reloc_kind_is_branch(l->c, r->kind)) continue; 172 if (r->target == LINK_SYM_NONE) continue; 173 tgt = LinkSyms_at(&img->syms, r->target - 1); 174 if (!tgt || !tgt->imported || tgt->name != s->name) continue; 175 return 1; 176 } 177 return 0; 178 } 179 180 static void collect_imports(Linker* l, LinkImage* img, Heap* h, 181 ImportLists* il) { 182 u32 i; 183 u32 cap_e = 0, cap_f = 0, cap_d = 0; 184 il->exports = NULL; 185 il->funcs = NULL; 186 il->datas = NULL; 187 il->nexports = il->nfuncs = il->ndatas = 0; 188 for (i = 0; i < LinkSyms_count(&img->syms); ++i) { 189 LinkSymbol* s = LinkSyms_at(&img->syms, i); 190 if (s->name == 0) continue; 191 /* Only the canonical (img->globals) entry per name. */ 192 LinkSymId canonical = symhash_get(&img->globals, s->name); 193 if (canonical != LINK_SYM_NONE && canonical != s->id) continue; 194 if (s->defined && !s->imported && 195 (s->bind == SB_GLOBAL || s->bind == SB_WEAK) && s->kind != SK_FILE && 196 s->kind != SK_SECTION && s->vis != SV_HIDDEN && 197 s->vis != SV_INTERNAL) { 198 if (VEC_GROW(h, il->exports, cap_e, il->nexports + 1u)) 199 compiler_panic(img->c, SRCLOC_NONE, "link: oom on exports"); 200 il->exports[il->nexports++] = s->id; 201 continue; 202 } 203 if (!s->imported) continue; 204 int is_func = sym_is_func_import(s) || dso_export_is_func(l, s) || 205 import_has_branch_reloc(l, img, s); 206 if (is_func) { 207 if (VEC_GROW(h, il->funcs, cap_f, il->nfuncs + 1u)) 208 compiler_panic(img->c, SRCLOC_NONE, "link: oom on import-funcs"); 209 il->funcs[il->nfuncs++] = s->id; 210 } else { 211 if (VEC_GROW(h, il->datas, cap_d, il->ndatas + 1u)) 212 compiler_panic(img->c, SRCLOC_NONE, "link: oom on import-datas"); 213 il->datas[il->ndatas++] = s->id; 214 } 215 } 216 } 217 218 static void free_imports(Heap* h, ImportLists* il) { 219 if (il->exports) h->free(h, il->exports, sizeof(*il->exports) * il->nexports); 220 if (il->funcs) h->free(h, il->funcs, sizeof(*il->funcs) * il->nfuncs); 221 if (il->datas) h->free(h, il->datas, sizeof(*il->datas) * il->ndatas); 222 } 223 224 /* ---- DT_NEEDED set: each DSO input that contributed at least one 225 * import. Order is input order so the loader sees deps in declaration 226 * order. */ 227 static void collect_needed(Linker* l, LinkImage* img, LinkDynState* dyn) { 228 Heap* h = img->heap; 229 u8* used; 230 u32 ninputs = LinkInputs_count(&l->inputs); 231 u32 i, nused = 0; 232 233 used = (u8*)h->alloc(h, ninputs ? ninputs : 1u, 1); 234 if (!used) compiler_panic(img->c, SRCLOC_NONE, "link: oom on needed map"); 235 memset(used, 0, ninputs ? ninputs : 1u); 236 237 /* Mark every DSO that ended up satisfying at least one import. */ 238 for (i = 0; i < LinkSyms_count(&img->syms); ++i) { 239 LinkSymbol* s = LinkSyms_at(&img->syms, i); 240 if (!s->imported) continue; 241 if (s->dso_input_id == LINK_INPUT_NONE) continue; 242 if (s->dso_input_id - 1u >= ninputs) continue; 243 used[s->dso_input_id - 1u] = 1; 244 } 245 /* Always pull every explicitly-supplied DSO into DT_NEEDED, even if 246 * no import landed on it — matches GNU ld without --as-needed. 247 * Phase 4 doesn't plumb --as-needed through to the resolver, so the 248 * default "needed" behavior is the right baseline. */ 249 for (i = 0; i < ninputs; ++i) { 250 LinkInput* in = LinkInputs_at(&l->inputs, i); 251 if (in->kind == LINK_INPUT_DSO_BYTES && in->soname != 0) used[i] = 1; 252 } 253 for (i = 0; i < ninputs; ++i) 254 if (used[i]) ++nused; 255 256 dyn->needed = 257 nused ? (Sym*)h->alloc(h, sizeof(Sym) * nused, _Alignof(Sym)) : NULL; 258 if (nused && !dyn->needed) 259 compiler_panic(img->c, SRCLOC_NONE, "link: oom on needed list"); 260 dyn->nneeded = 0; 261 for (i = 0; i < ninputs; ++i) { 262 LinkInput* in = LinkInputs_at(&l->inputs, i); 263 if (!used[i]) continue; 264 if (in->soname == 0) continue; 265 dyn->needed[dyn->nneeded++] = in->soname; 266 } 267 h->free(h, used, ninputs ? ninputs : 1u); 268 } 269 270 /* ---- dynsym + dynstr build ---- 271 * 272 * Slot 0: STN_UNDEF (zero entry). The loader ignores names with index 273 * 0; we still emit a dynstr entry at offset 0 (the leading NUL). 274 * 275 * Slots 1..nexports: executable-defined globals exported for DSO lookup. 276 * Slots after exports: imported symbols (functions first, then data). 277 * st_shndx = SHN_UNDEF; the loader fills in the value at bind time. 278 * st_value/size are zero — the static linker has no value for an 279 * imported symbol. 280 * 281 * Defined executable globals must be present too: ELF DSOs can resolve 282 * references back to the main executable, and FreeBSD libc depends on that 283 * for Scrt1.o's `environ` and `__progname` definitions. */ 284 285 static void build_dynsym(LinkImage* img, LinkDynState* dyn, 286 const ImportLists* il, ObjByteBuf* dynstr) { 287 Heap* h = img->heap; 288 u32 nimports = il->nfuncs + il->ndatas; 289 u32 ndynsym = 1u + il->nexports + nimports; /* +1 for null slot */ 290 u32 i; 291 292 dyn->ndynsym = ndynsym; 293 dyn->dynsym = (DynSymRec*)h->alloc(h, sizeof(*dyn->dynsym) * ndynsym, 294 _Alignof(DynSymRec)); 295 if (!dyn->dynsym) compiler_panic(img->c, SRCLOC_NONE, "link: oom on dynsym"); 296 memset(dyn->dynsym, 0, sizeof(*dyn->dynsym) * ndynsym); 297 298 /* Slot 0: STN_UNDEF. dynstr leads with a NUL so st_name=0 reads as 299 * the empty string. */ 300 { 301 u8 z = 0; 302 objbb_append(dynstr, &z, 1); 303 } 304 305 /* Per-symbol: dedupe `sym_dynidx` lookup table. Sized to LinkSymId 306 * upper bound. Clean (zero-filled) by alloc convention; we set 307 * indices for imports below. */ 308 dyn->sym_dynidx_size = LinkSyms_count(&img->syms) + 1u; 309 dyn->sym_dynidx = (u32*)h->alloc( 310 h, sizeof(*dyn->sym_dynidx) * dyn->sym_dynidx_size, _Alignof(u32)); 311 if (!dyn->sym_dynidx) 312 compiler_panic(img->c, SRCLOC_NONE, "link: oom on sym_dynidx"); 313 memset(dyn->sym_dynidx, 0, sizeof(*dyn->sym_dynidx) * dyn->sym_dynidx_size); 314 /* sym_plt_vaddr is populated alongside the PLT body emit below; here 315 * we only allocate the parallel array. */ 316 dyn->sym_plt_vaddr = (u64*)h->alloc( 317 h, sizeof(*dyn->sym_plt_vaddr) * dyn->sym_dynidx_size, _Alignof(u64)); 318 if (!dyn->sym_plt_vaddr) 319 compiler_panic(img->c, SRCLOC_NONE, "link: oom on sym_plt_vaddr"); 320 memset(dyn->sym_plt_vaddr, 0, 321 sizeof(*dyn->sym_plt_vaddr) * dyn->sym_dynidx_size); 322 323 /* All dynamic entries we emit today are non-local, so first_global is 324 * right after the single STN_UNDEF slot. */ 325 dyn->first_global = 1u; 326 327 u32 idx = 1u; 328 for (i = 0; i < il->nexports; ++i) { 329 LinkSymId lsid = il->exports[i]; 330 LinkSymbol* s = LinkSyms_at(&img->syms, lsid - 1); 331 DynSymRec* r = &dyn->dynsym[idx]; 332 Slice nm_s = pool_slice(img->c->global, s->name); 333 const char* nm = nm_s.s; 334 size_t namelen = nm_s.len; 335 u8 elf_type = elf_st_type(s->kind); 336 u8 elf_bind = elf_st_bind(s->bind); 337 r->st_name = objbb_append_str(dynstr, nm, (u32)namelen); 338 r->st_info = ELF64_ST_INFO(elf_bind, elf_type); 339 r->st_other = elf_st_other(s->vis); 340 /* The emitter refreshes defined-symbol values after the final header 341 * shift. Any nonzero, non-special section index is enough for rtld to 342 * treat the symbol as defined; section headers are not part of runtime 343 * loading. */ 344 r->st_shndx = 1; 345 r->st_value = s->vaddr; 346 r->st_size = s->size; 347 dyn->sym_dynidx[lsid] = idx; 348 ++idx; 349 } 350 for (i = 0; i < il->nfuncs; ++i) { 351 LinkSymId lsid = il->funcs[i]; 352 LinkSymbol* s = LinkSyms_at(&img->syms, lsid - 1); 353 DynSymRec* r = &dyn->dynsym[idx]; 354 Slice nm_s = pool_slice(img->c->global, s->name); 355 const char* nm = nm_s.s; 356 size_t namelen = nm_s.len; 357 r->st_name = objbb_append_str(dynstr, nm, (u32)namelen); 358 r->st_info = ELF64_ST_INFO(STB_GLOBAL, STT_FUNC); 359 r->st_other = elf_st_other(s->vis); 360 r->st_shndx = SHN_UNDEF; 361 r->st_value = 0; 362 r->st_size = 0; 363 dyn->sym_dynidx[lsid] = idx; 364 ++idx; 365 } 366 for (i = 0; i < il->ndatas; ++i) { 367 LinkSymId lsid = il->datas[i]; 368 LinkSymbol* s = LinkSyms_at(&img->syms, lsid - 1); 369 DynSymRec* r = &dyn->dynsym[idx]; 370 Slice nm_s = pool_slice(img->c->global, s->name); 371 const char* nm = nm_s.s; 372 size_t namelen = nm_s.len; 373 u8 elf_type = STT_OBJECT; 374 if (s->kind == SK_TLS) 375 elf_type = STT_TLS; 376 else if (s->kind == SK_NOTYPE) 377 elf_type = STT_NOTYPE; 378 r->st_name = objbb_append_str(dynstr, nm, (u32)namelen); 379 r->st_info = ELF64_ST_INFO(STB_GLOBAL, elf_type); 380 r->st_other = elf_st_other(s->vis); 381 r->st_shndx = SHN_UNDEF; 382 r->st_value = 0; 383 r->st_size = 0; 384 dyn->sym_dynidx[lsid] = idx; 385 ++idx; 386 } 387 } 388 389 /* ---- GNU symbol versioning (.gnu.version + .gnu.version_r) ---- 390 * 391 * For each imported symbol that binds to a versioned DSO export, require that 392 * export's *default* version (read into ObjImageSym.version at input time) so 393 * the runtime binds the right one. On FreeBSD this is mandatory: the INO64 394 * transition left `stat`/`fstat`/... as two incompatible struct-stat ABIs, the 395 * compat behind a hidden FBSD_1.0 and the modern one as the default FBSD_1.5; 396 * an unversioned reference binds the compat and reads st_size at the wrong 397 * offset. We emit: 398 * .gnu.version — one u16 per .dynsym entry: 0 (null/unversioned import), 399 * 1 (defined export), or >=2 (a version requirement index). 400 * .gnu.version_r — Verneed per DT_NEEDED soname + Vernaux per required 401 * version, numbered 2.. in first-seen order. 402 * Both reference only .dynstr offsets and indices (no vaddrs), so the bytes are 403 * final at layout time. Nothing is emitted when no import is versioned, leaving 404 * musl/glibc-without-version and static links byte-for-byte unchanged. */ 405 406 static u32 elf_sysv_hash(const char* s, u32 n) { 407 u32 h = 0, g, i; 408 for (i = 0; i < n; ++i) { 409 h = (h << 4) + (u8)s[i]; 410 g = h & 0xf0000000u; 411 if (g) h ^= g >> 24; 412 h &= ~g; 413 } 414 return h; 415 } 416 417 /* Default version name the DSO `in` exports for `name`, or 0 if `in` carries no 418 * versioning / doesn't export `name` with a default version. */ 419 static Sym dso_default_version(LinkInput* in, Sym name) { 420 const ObjImage* im = in->obj ? obj_image(in->obj) : NULL; 421 u32 i, n; 422 if (!im) return 0; 423 n = obj_image_ndynsyms(im); 424 for (i = 0; i < n; ++i) { 425 const ObjImageSym* s = obj_image_dynsym(im, i); 426 if (s->name == name && s->version != 0 && !s->version_hidden) 427 return s->version; 428 } 429 return 0; 430 } 431 432 typedef struct VerReq { 433 Sym soname; 434 Sym version; 435 u16 index; 436 } VerReq; 437 438 typedef struct VerBuild { 439 Heap* h; 440 Linker* l; 441 LinkImage* img; 442 LinkDynState* dyn; 443 u8* vs; /* versym bytes being filled */ 444 VerReq* reqs; 445 u32 nreq; 446 u32 capreq; 447 } VerBuild; 448 449 /* Resolve one imported symbol's version requirement: explicit name@VERSION 450 * imports keep that requested version on LinkSymbol; plain imports use the 451 * providing DSO's default version for the name. The chosen (soname, version) 452 * pair is interned as a requirement and stamped into the symbol's versym slot. */ 453 static void ver_process_import(VerBuild* vb, LinkSymId lsid) { 454 LinkSymbol* s = LinkSyms_at(&vb->img->syms, lsid - 1); 455 u32 di = vb->dyn->sym_dynidx[lsid]; 456 LinkInput* in; 457 Sym ver; 458 u16 vidx = 0; 459 u32 r; 460 if (!di || s->dso_input_id == LINK_INPUT_NONE) return; 461 if (s->dso_input_id - 1u >= LinkInputs_count(&vb->l->inputs)) return; 462 in = LinkInputs_at(&vb->l->inputs, s->dso_input_id - 1u); 463 if (in->soname == 0) return; 464 ver = s->elf_version ? s->elf_version : dso_default_version(in, s->name); 465 if (ver == 0) return; 466 for (r = 0; r < vb->nreq; ++r) 467 if (vb->reqs[r].soname == in->soname && vb->reqs[r].version == ver) { 468 vidx = vb->reqs[r].index; 469 break; 470 } 471 if (!vidx) { 472 if (VEC_GROW(vb->h, vb->reqs, vb->capreq, vb->nreq + 1u)) 473 compiler_panic(vb->img->c, SRCLOC_NONE, "link: oom on version reqs"); 474 vidx = (u16)(2u + vb->nreq); 475 vb->reqs[vb->nreq].soname = in->soname; 476 vb->reqs[vb->nreq].version = ver; 477 vb->reqs[vb->nreq].index = vidx; 478 vb->nreq++; 479 } 480 wr_u16_le(vb->vs + (u64)di * 2u, vidx); 481 } 482 483 static void build_versions(Linker* l, LinkImage* img, LinkDynState* dyn, 484 const ImportLists* il, ObjByteBuf* dynstr) { 485 Heap* h = img->heap; 486 VerBuild vb; 487 u32 i; 488 489 dyn->versym = NULL; 490 dyn->versym_len = 0; 491 dyn->verneed = NULL; 492 dyn->verneed_len = 0; 493 dyn->nverneed = 0; 494 if (dyn->ndynsym == 0) return; 495 496 /* versym: default 0 (local/unversioned); defined exports -> GLOBAL. */ 497 vb.h = h; 498 vb.l = l; 499 vb.img = img; 500 vb.dyn = dyn; 501 vb.reqs = NULL; 502 vb.nreq = 0; 503 vb.capreq = 0; 504 vb.vs = (u8*)h->alloc(h, (size_t)dyn->ndynsym * 2u, 2); 505 if (!vb.vs) compiler_panic(img->c, SRCLOC_NONE, "link: oom on versym"); 506 memset(vb.vs, 0, (size_t)dyn->ndynsym * 2u); 507 for (i = 0; i < il->nexports; ++i) { 508 u32 di = dyn->sym_dynidx[il->exports[i]]; 509 if (di) wr_u16_le(vb.vs + (u64)di * 2u, (u16)VER_NDX_GLOBAL); 510 } 511 for (i = 0; i < il->nfuncs; ++i) ver_process_import(&vb, il->funcs[i]); 512 for (i = 0; i < il->ndatas; ++i) ver_process_import(&vb, il->datas[i]); 513 514 if (vb.nreq == 0) { 515 /* No versioned imports: emit nothing, keep the link unchanged. */ 516 h->free(h, vb.vs, (size_t)dyn->ndynsym * 2u); 517 if (vb.reqs) h->free(h, vb.reqs, sizeof(*vb.reqs) * vb.capreq); 518 return; 519 } 520 dyn->versym = vb.vs; 521 dyn->versym_len = dyn->ndynsym * 2u; 522 523 /* Group requirements by soname (first-seen order) into Verneed/Vernaux. */ 524 { 525 Sym* sonames = NULL; 526 u32 nson = 0, capson = 0; 527 u32 r; 528 for (r = 0; r < vb.nreq; ++r) { 529 u32 k; 530 int seen = 0; 531 for (k = 0; k < nson; ++k) 532 if (sonames[k] == vb.reqs[r].soname) { 533 seen = 1; 534 break; 535 } 536 if (!seen) { 537 if (VEC_GROW(h, sonames, capson, nson + 1u)) 538 compiler_panic(img->c, SRCLOC_NONE, "link: oom on verneed sonames"); 539 sonames[nson++] = vb.reqs[r].soname; 540 } 541 } 542 { 543 u32 total = 544 nson * (u32)ELF_VERNEED_SIZE + vb.nreq * (u32)ELF_VERNAUX_SIZE; 545 u8* vn = (u8*)h->alloc(h, total, 4); 546 u8* p; 547 u32 si; 548 if (!vn) compiler_panic(img->c, SRCLOC_NONE, "link: oom on verneed"); 549 memset(vn, 0, total); 550 p = vn; 551 for (si = 0; si < nson; ++si) { 552 Slice so_s = pool_slice(l->c->global, sonames[si]); 553 u32 file_off = objbb_append_str(dynstr, so_s.s, (u32)so_s.len); 554 u8* vn_rec = p; 555 u32 cnt = 0; 556 u8* aux; 557 p += ELF_VERNEED_SIZE; 558 aux = p; 559 for (r = 0; r < vb.nreq; ++r) { 560 Slice ver_s; 561 u32 name_off; 562 if (vb.reqs[r].soname != sonames[si]) continue; 563 ver_s = pool_slice(l->c->global, vb.reqs[r].version); 564 name_off = objbb_append_str(dynstr, ver_s.s, (u32)ver_s.len); 565 wr_u32_le(p + 0, 566 elf_sysv_hash(ver_s.s, (u32)ver_s.len)); /* vna_hash */ 567 wr_u16_le(p + 4, 0); /* vna_flags */ 568 wr_u16_le(p + 6, vb.reqs[r].index); /* vna_other */ 569 wr_u32_le(p + 8, name_off); /* vna_name */ 570 /* vna_next: filled after we know if another aux follows. */ 571 p += ELF_VERNAUX_SIZE; 572 ++cnt; 573 } 574 /* Verneed header. vn_aux is the byte offset to the first Vernaux. */ 575 wr_u16_le(vn_rec + 0, 1); /* vn_version */ 576 wr_u16_le(vn_rec + 2, (u16)cnt); /* vn_cnt */ 577 wr_u32_le(vn_rec + 4, file_off); /* vn_file */ 578 wr_u32_le(vn_rec + 8, (u32)(aux - vn_rec)); /* vn_aux */ 579 wr_u32_le(vn_rec + 12, 580 si + 1u < nson ? (u32)(p - vn_rec) : 0u); /* vn_next */ 581 /* Link the Vernaux chain (each entry -> next, last -> 0). */ 582 { 583 u8* a = aux; 584 u32 j; 585 for (j = 0; j < cnt; ++j) { 586 wr_u32_le(a + 12, j + 1u < cnt ? (u32)ELF_VERNAUX_SIZE : 0u); 587 a += ELF_VERNAUX_SIZE; 588 } 589 } 590 } 591 dyn->verneed = vn; 592 dyn->verneed_len = total; 593 dyn->nverneed = nson; 594 } 595 if (sonames) h->free(h, sonames, sizeof(*sonames) * capson); 596 } 597 if (vb.reqs) h->free(h, vb.reqs, sizeof(*vb.reqs) * vb.capreq); 598 } 599 600 /* ---- .gnu.hash builder ---- 601 * 602 * Hashed range is [first_global, ndynsym) — slot 0 (STN_UNDEF) is 603 * unhashed. Layout matches loader expectations (musl, glibc, FreeBSD). 604 * 605 * Bucket count: one. That keeps the required chain ordering trivial even as 606 * we mix executable exports and imports without sorting the dynsym table by 607 * hash bucket. Bloom is 1 word for Phase 4 — a real implementation would 608 * scale with hashed_count, but 1 word with shift=6 still satisfies the 609 * loader's correctness check (false positives only cost a chain scan). */ 610 611 static void build_gnu_hash(Heap* h, LinkImage* img, LinkDynState* dyn, 612 const ObjByteBuf* dynstr) { 613 u32 hashed = (dyn->ndynsym > dyn->first_global) 614 ? (dyn->ndynsym - dyn->first_global) 615 : 0u; 616 u32 nbuckets = 1u; 617 u32 bloom_size = 1u; /* 64-bit word */ 618 u32 bloom_shift = 6u; 619 u32 sym_offset = dyn->first_global; 620 u32 hdr_bytes = 16u; /* nbuckets/symoff/bloomsz/bloomshift */ 621 u32 bloom_bytes = bloom_size * 8u; 622 u32 buckets_bytes = nbuckets * 4u; 623 u32 chains_bytes = hashed * 4u; 624 u32 total = hdr_bytes + bloom_bytes + buckets_bytes + chains_bytes; 625 626 u8* buf = (u8*)h->alloc(h, total ? total : 1u, 4); 627 if (!buf) compiler_panic(img->c, SRCLOC_NONE, "link: oom on .gnu.hash"); 628 memset(buf, 0, total); 629 630 wr_u32_le(buf + 0, nbuckets); 631 wr_u32_le(buf + 4, sym_offset); 632 wr_u32_le(buf + 8, bloom_size); 633 wr_u32_le(buf + 12, bloom_shift); 634 635 /* Bloom + buckets + chains. We need each hashed symbol's hash. */ 636 if (hashed) { 637 u32 i; 638 u32* hashes = (u32*)h->alloc(h, sizeof(u32) * hashed, _Alignof(u32)); 639 if (!hashes) 640 compiler_panic(img->c, SRCLOC_NONE, "link: oom on .gnu.hash hashes"); 641 for (i = 0; i < hashed; ++i) { 642 const DynSymRec* r = &dyn->dynsym[sym_offset + i]; 643 const char* name = (const char*)dynstr->data + r->st_name; 644 size_t n = name ? slice_from_cstr(name).len : 0; 645 hashes[i] = gnu_hash_name(name, (u32)n); 646 } 647 648 /* Bloom filter: H[i] / H[i] >> shift */ 649 u64 bloom = 0; 650 for (i = 0; i < hashed; ++i) { 651 u32 h1 = hashes[i] % 64u; 652 u32 h2 = (hashes[i] >> bloom_shift) % 64u; 653 bloom |= ((u64)1 << h1) | ((u64)1 << h2); 654 } 655 wr_u64_le(buf + hdr_bytes, bloom); 656 657 /* Buckets/chains: for each hashed sym, append to its bucket's 658 * chain. The chain encodes (hash & ~1) per entry; the LSB is set 659 * on the LAST entry in a bucket to terminate. Buckets are filled 660 * with the first chain index that hashes there (1-based into the 661 * dynsym, i.e. `sym_offset + i`). */ 662 u32* buckets = (u32*)(buf + hdr_bytes + bloom_bytes); 663 u32* chains = (u32*)(buf + hdr_bytes + bloom_bytes + buckets_bytes); 664 /* First pass: bucket = first sym index that hashes there. */ 665 for (i = 0; i < hashed; ++i) { 666 u32 b = hashes[i] % nbuckets; 667 if (buckets[b] == 0) buckets[b] = sym_offset + i; 668 } 669 /* Second pass: chain[i] = hash with LSB cleared; LSB set if next 670 * sym is in a different bucket. Walk symbols in order; LSB on 671 * chain[i] when sym i+1 is in a different bucket OR is the end. */ 672 for (i = 0; i < hashed; ++i) { 673 u32 v = hashes[i] & ~1u; 674 int last = (i + 1 == hashed) || 675 ((hashes[i + 1] % nbuckets) != (hashes[i] % nbuckets)); 676 if (last) v |= 1u; 677 chains[i] = v; 678 } 679 h->free(h, hashes, sizeof(u32) * hashed); 680 } 681 682 dyn->gnu_hash = buf; 683 dyn->gnu_hash_len = total; 684 } 685 686 /* ---- .dynamic body builder ---- 687 * 688 * Computed at layout time so the size is known before segments are 689 * placed. Each entry is two u64s (d_tag, d_un.d_val|d_un.d_ptr). 690 * Final entry is DT_NULL. The d_ptr fields that point at other 691 * synthetic sections are filled with image-relative vaddrs; the emit 692 * pass adds load-base / IMAGE_BASE only when ET_EXEC. */ 693 694 typedef struct DynEntry { 695 u64 tag; 696 u64 val; /* either d_val or d_ptr; emit just writes 8 bytes */ 697 } DynEntry; 698 699 static u32 count_dynamic_entries(const LinkDynState* dyn) { 700 /* Required: DT_STRTAB DT_STRSZ DT_SYMTAB DT_SYMENT DT_GNU_HASH 701 * DT_FLAGS_1 (DF_1_NOW for eager binding) 702 * DT_NULL terminator 703 * Optional (only when there are .rela.dyn records): 704 * DT_RELA DT_RELASZ DT_RELAENT 705 * Optional (only when there are imported functions / a PLT): 706 * DT_PLTGOT DT_PLTRELSZ DT_PLTREL DT_JMPREL 707 * Plus DT_NEEDED per dependency. */ 708 u32 n = dyn->nneeded; 709 n += 7; /* 5 fixed + DT_FLAGS_1 + DT_NULL */ 710 if (dyn->soname) n += 1; 711 n += dyn->nrpaths + dyn->nrunpaths; 712 if (dyn->cap_rela_dyn) n += 3; /* DT_RELA + DT_RELASZ + DT_RELAENT */ 713 if (dyn->nrela_plt) n += 4; /* PLT-only entries */ 714 if (dyn->nverneed) n += 3; /* DT_VERSYM + DT_VERNEED + DT_VERNEEDNUM */ 715 return n; 716 } 717 718 /* ---- main entry ---- */ 719 720 void layout_dyn(Linker* l, LinkImage* img) { 721 Heap* h = img->heap; 722 LinkDynState* dyn; 723 LinkDynState dyn_probe; 724 ImportLists imports; 725 ObjByteBuf dynstr; 726 u64 page; 727 const LinkArchDesc* arch; 728 const ObjElfArchOps* elf_arch; 729 730 if (!l->emit_pie && !l->emit_shared) return; 731 732 /* The dynamic-section layout below is ELF64-only (Elf64_Sym/Dyn/Rela wire 733 * sizes, 8-byte GOT slots). rv32 is a static-only v1 target, so a dynamic / 734 * PIE rv32 link is unsupported — fail with a clear diagnostic instead of 735 * crashing on the ELF64 assumptions. Link rv32 images statically (kit ld 736 * -no-pie, or a -T script for bare-metal section placement). */ 737 if (img->c->target.ptr_size == 4u) { 738 compiler_panic(img->c, SRCLOC_NONE, 739 "link: dynamic/PIE linking is not supported for 32-bit " 740 "RISC-V (ELFCLASS32); link statically (kit ld -no-pie)"); 741 } 742 743 arch = link_arch_desc_for(l->c); 744 if (!arch) 745 compiler_panic(img->c, SRCLOC_NONE, "link: layout_dyn: no arch descriptor"); 746 { 747 const ObjFormatImpl* fmt = obj_format_lookup(KIT_OBJ_ELF); 748 elf_arch = fmt && fmt->elf_arch ? fmt->elf_arch(l->c->target.arch) : NULL; 749 if (!elf_arch) 750 compiler_panic(img->c, SRCLOC_NONE, 751 "link: layout_dyn: no ELF arch descriptor"); 752 } 753 754 /* Step 1: enumerate imports + DT_NEEDED. A PIE with no imports and no 755 * DSO inputs is effectively static; keep ET_DYN output but do not stamp 756 * PT_INTERP/PT_DYNAMIC or an empty .dynamic section. */ 757 memset(&dyn_probe, 0, sizeof dyn_probe); 758 collect_imports(l, img, h, &imports); 759 collect_needed(l, img, &dyn_probe); 760 if (!l->emit_shared && l->emit_static_exe && imports.nfuncs == 0 && 761 imports.ndatas == 0 && 762 dyn_probe.nneeded == 0) { 763 img->pie = 1; 764 free_imports(h, &imports); 765 return; 766 } 767 768 dyn = (LinkDynState*)h->alloc(h, sizeof(*dyn), _Alignof(LinkDynState)); 769 if (!dyn) compiler_panic(img->c, SRCLOC_NONE, "link: oom on dyn state"); 770 *dyn = dyn_probe; 771 img->dyn = dyn; 772 img->pie = l->emit_pie ? 1 : 0; 773 img->shared = l->emit_shared ? 1 : 0; 774 775 /* PT_INTERP path. Default to the canonical musl loader matching the 776 * target arch (per-arch table in src/arch/<arch>/link.c) when the caller 777 * didn't set one. Drivers like kit-cc always override via 778 * link_set_interp_path; this default is correctness for direct 779 * libkit consumers. glibc users have to set their interp 780 * explicitly — we don't pick a default for them. */ 781 if (!l->emit_shared) { 782 dyn->interp_path = 783 l->interp_path 784 ? l->interp_path 785 : pool_intern_slice(l->c->global, 786 slice_from_cstr(elf_arch->default_musl_interp)); 787 } 788 if (l->soname.s && l->soname.len) 789 dyn->soname = pool_intern_slice(l->c->global, l->soname); 790 if (l->nrpaths) { 791 u32 ri; 792 dyn->rpaths = 793 (Sym*)h->alloc(h, sizeof(*dyn->rpaths) * l->nrpaths, _Alignof(Sym)); 794 if (!dyn->rpaths) compiler_panic(img->c, SRCLOC_NONE, "link: oom on rpaths"); 795 dyn->nrpaths = l->nrpaths; 796 for (ri = 0; ri < l->nrpaths; ++ri) 797 dyn->rpaths[ri] = pool_intern_slice(l->c->global, l->rpaths[ri]); 798 } 799 if (l->nrunpaths) { 800 u32 ri; 801 dyn->runpaths = (Sym*)h->alloc(h, sizeof(*dyn->runpaths) * l->nrunpaths, 802 _Alignof(Sym)); 803 if (!dyn->runpaths) 804 compiler_panic(img->c, SRCLOC_NONE, "link: oom on runpaths"); 805 dyn->nrunpaths = l->nrunpaths; 806 for (ri = 0; ri < l->nrunpaths; ++ri) 807 dyn->runpaths[ri] = pool_intern_slice(l->c->global, l->runpaths[ri]); 808 } 809 810 /* Step 2: build .dynstr + .dynsym. .dynstr must also carry the 811 * DT_NEEDED soname strings the .dynamic body references; intern 812 * them after the import names so build_dynsym's de-dup also covers 813 * any name that happens to collide with a soname. */ 814 objbb_init(&dynstr, h); 815 build_dynsym(img, dyn, &imports, &dynstr); 816 { 817 u32 ni; 818 for (ni = 0; ni < dyn->nneeded; ++ni) { 819 Slice s_s = pool_slice(l->c->global, dyn->needed[ni]); 820 const char* s = s_s.s; 821 size_t slen = s_s.len; 822 if (s && slen) (void)objbb_append_str(&dynstr, s, (u32)slen); 823 } 824 if (dyn->soname) { 825 Slice s_s = pool_slice(l->c->global, dyn->soname); 826 if (s_s.s && s_s.len) 827 (void)objbb_append_str(&dynstr, s_s.s, (u32)s_s.len); 828 } 829 for (ni = 0; ni < dyn->nrpaths; ++ni) { 830 Slice s_s = pool_slice(l->c->global, dyn->rpaths[ni]); 831 if (s_s.s && s_s.len) 832 (void)objbb_append_str(&dynstr, s_s.s, (u32)s_s.len); 833 } 834 for (ni = 0; ni < dyn->nrunpaths; ++ni) { 835 Slice s_s = pool_slice(l->c->global, dyn->runpaths[ni]); 836 if (s_s.s && s_s.len) 837 (void)objbb_append_str(&dynstr, s_s.s, (u32)s_s.len); 838 } 839 } 840 /* Symbol versioning: assign per-import version requirements and append the 841 * version strings ("FBSD_1.5", ...) to .dynstr. Must run before .dynstr is 842 * finalized below; emits nothing when no import is versioned. */ 843 build_versions(l, img, dyn, &imports, &dynstr); 844 dyn->dynstr = dynstr.data; 845 dyn->dynstr_len = dynstr.len; 846 847 /* Step 3: .gnu.hash. */ 848 build_gnu_hash(h, img, dyn, &dynstr); 849 850 /* Step 4: pre-size all the synthetic sections. 851 * .interp: strlen + 1 852 * .dynsym: 24 * ndynsym 853 * .dynstr: dynstr_len 854 * .gnu.hash: gnu_hash_len 855 * .rela.dyn: 24 * (runtime GLOB_DAT + RELATIVE records) 856 * .rela.plt: 24 * nfuncs 857 * .plt: 32 + 16 * nfuncs (PLT0 + per-slot) 858 * .got.plt: 8 * (3 + nfuncs) 859 * .dynamic: 16 * count_dynamic_entries 860 */ 861 dyn->nplt = imports.nfuncs; 862 dyn->nrela_plt = imports.nfuncs; 863 dyn->rela_plt = imports.nfuncs 864 ? (DynRela*)h->alloc(h, sizeof(DynRela) * imports.nfuncs, 865 _Alignof(DynRela)) 866 : NULL; 867 if (imports.nfuncs && !dyn->rela_plt) 868 compiler_panic(img->c, SRCLOC_NONE, "link: oom on rela_plt"); 869 870 /* RELA dyn: GLOB_DAT (one per imported abs-relocated symbol) + 871 * RELATIVE (one per PIE internal abs reloc against a defined sym). 872 * Phase 5 emits these dynamically during reloc-apply; pre-count the 873 * exact total here (img->relocs and the resolve-time `imported` flags 874 * are already settled by the time layout_dyn runs) so the section 875 * isn't padded with hundreds of trailing R_*_NONE records. */ 876 u32 cap_rel = 0; 877 { 878 u32 ri; 879 for (ri = 0; ri < LinkRelocs_count(&img->relocs); ++ri) { 880 const LinkRelocApply* r = LinkRelocs_at(&img->relocs, ri); 881 const LinkSymbol* tgt = LinkSyms_at(&img->syms, r->target - 1); 882 const LinkSection* sec; 883 if (r->kind != R_ABS32 && r->kind != R_ABS64) continue; 884 if (r->link_section_id == LINK_SEC_NONE || 885 r->link_section_id > img->nsections) 886 continue; 887 sec = &img->sections[r->link_section_id - 1]; 888 if (sec->segment_id == LINK_SEG_NONE || sec->file_only) continue; 889 if (tgt->imported) { 890 cap_rel++; /* GLOB_DAT */ 891 } else if (tgt->defined && tgt->kind != SK_ABS) { 892 cap_rel++; /* RELATIVE */ 893 } 894 } 895 } 896 dyn->cap_rela_dyn = cap_rel; 897 dyn->rela_dyn = 898 dyn->cap_rela_dyn 899 ? (DynRela*)h->alloc(h, sizeof(DynRela) * dyn->cap_rela_dyn, 900 _Alignof(DynRela)) 901 : NULL; 902 if (dyn->cap_rela_dyn && !dyn->rela_dyn) 903 compiler_panic(img->c, SRCLOC_NONE, "link: oom on rela_dyn"); 904 dyn->nrela_dyn = 0; 905 906 Slice interp_s = l->emit_shared ? SLICE_NULL 907 : pool_slice(l->c->global, dyn->interp_path); 908 const char* interp_str = interp_s.s; 909 size_t namelen = interp_s.len; 910 u64 interp_bytes = l->emit_shared ? 0u : (u64)namelen + 1u; 911 u64 dynsym_bytes = (u64)dyn->ndynsym * ELF64_SYM_SIZE; 912 u64 dynstr_bytes = (u64)dyn->dynstr_len; 913 u64 gnuhash_bytes = (u64)dyn->gnu_hash_len; 914 int has_ver = dyn->nverneed > 0; 915 u64 versym_bytes = (u64)dyn->versym_len; 916 u64 verneed_bytes = (u64)dyn->verneed_len; 917 /* rela.dyn is pre-counted exactly; rela.plt is one record per PLT slot. */ 918 u64 rela_dyn_bytes = (u64)dyn->cap_rela_dyn * ELF64_RELA_SIZE; 919 u64 rela_plt_bytes = (u64)dyn->nrela_plt * ELF64_RELA_SIZE; 920 u64 plt_bytes = 921 (u64)(imports.nfuncs 922 ? arch->plt0_size + arch->plt_entry_size * imports.nfuncs 923 : 0u); 924 u64 gotplt_bytes = (u64)(imports.nfuncs ? 8u * (3u + imports.nfuncs) : 0u); 925 dyn->ndyn_entries = count_dynamic_entries(dyn); 926 u64 dynamic_bytes = (u64)dyn->ndyn_entries * ELF64_DYN_SIZE; 927 928 /* Step 5: place segments, page-aligned after the existing image 929 * span. New segments: 930 * ro_seg (PF_R) — .interp + .dynsym + .dynstr + .gnu.hash + 931 * .rela.dyn + .rela.plt 932 * rx_seg (PF_R+X)— .plt (only when imports.nfuncs > 0) 933 * rw_seg (PF_R+W)— .got.plt + .dynamic 934 * 935 * .dynamic lives in rw_seg because glibc's loader patches DT_* 936 * d_un.d_ptr fields in-place at startup (elf_get_dynamic_info 937 * adjusts STRTAB/SYMTAB/etc. by l_addr); a PF_R-only segment 938 * causes SEGV_ACCERR. musl's loader doesn't do this rewrite, but 939 * the RW placement is conventional and works for both. 940 */ 941 page = 0x4000u; /* keep aligned with layout_page_size default */ 942 { 943 /* Read the page size from layout_page_size by re-using the 944 * configured execmem if present — duplicates the helper rather 945 * than expose it; the value is only used for alignment. */ 946 const KitExecMem* m = (l && l->jit_host) ? l->jit_host->execmem : NULL; 947 if (m && m->page_size) page = (u64)m->page_size; 948 } 949 950 u64 base_vaddr = 0; 951 u32 i; 952 for (i = 0; i < img->nsegments; ++i) { 953 u64 end = img->segments[i].vaddr + img->segments[i].mem_size; 954 if (end > base_vaddr) base_vaddr = end; 955 } 956 base_vaddr = ALIGN_UP(base_vaddr, page); 957 958 /* Pack ro section offsets (relative to ro_seg.vaddr). 8-byte 959 * alignment for tables; 4-byte for .interp string. */ 960 u64 off = 0; 961 u64 interp_off = off; 962 off = ALIGN_UP(off + interp_bytes, 8u); 963 u64 dynsym_off = off; 964 off = ALIGN_UP(off + dynsym_bytes, 8u); 965 u64 dynstr_off = off; 966 off = ALIGN_UP(off + dynstr_bytes, 8u); 967 u64 gnuhash_off = off; 968 off = ALIGN_UP(off + gnuhash_bytes, 8u); 969 u64 rela_dyn_off = off; 970 off = ALIGN_UP(off + rela_dyn_bytes, 8u); 971 u64 rela_plt_off = off; 972 off = ALIGN_UP(off + rela_plt_bytes, 8u); 973 /* .gnu.version + .gnu.version_r (zero-sized and skipped when no import is 974 * versioned, so the ro segment is unchanged for unversioned links). */ 975 u64 versym_off = off; 976 off = ALIGN_UP(off + versym_bytes, 8u); 977 u64 verneed_off = off; 978 off = ALIGN_UP(off + verneed_bytes, 8u); 979 u64 ro_seg_size = off; 980 981 /* When no PLT is needed, suppress the RX/.plt segment entirely. */ 982 int has_plt = imports.nfuncs > 0; 983 984 /* Pack rw_seg offsets: .got.plt (when has_plt) followed by .dynamic. */ 985 u64 rw_off = 0; 986 u64 gotplt_off = rw_off; 987 if (has_plt) rw_off = ALIGN_UP(rw_off + gotplt_bytes, 8u); 988 u64 dynamic_off = rw_off; 989 rw_off = ALIGN_UP(rw_off + dynamic_bytes, 8u); 990 u64 rw_seg_size = rw_off; 991 992 u64 ro_vaddr = base_vaddr; 993 u64 rx_vaddr = ALIGN_UP(ro_vaddr + ro_seg_size, page); 994 u64 rw_vaddr = ALIGN_UP(rx_vaddr + (has_plt ? plt_bytes : 0u), page); 995 996 /* rw_seg always exists (it carries .dynamic). */ 997 u32 nseg = 2u + (has_plt ? 1u : 0u); 998 u32 seg_base = dyn_alloc_segments(img, nseg); 999 u32 ro_seg_idx = seg_base + 0u; 1000 u32 rx_seg_idx = has_plt ? seg_base + 1u : 0u; 1001 u32 rw_seg_idx = seg_base + (has_plt ? 2u : 1u); 1002 1003 LinkSegment* ro_seg = &img->segments[ro_seg_idx]; 1004 memset(ro_seg, 0, sizeof(*ro_seg)); 1005 ro_seg->id = (LinkSegmentId)(ro_seg_idx + 1u); 1006 ro_seg->flags = SF_ALLOC; /* PF_R */ 1007 ro_seg->file_offset = ro_vaddr; 1008 ro_seg->vaddr = ro_vaddr; 1009 ro_seg->paddr = ro_vaddr; 1010 ro_seg->file_size = ro_seg_size; 1011 ro_seg->mem_size = ro_seg_size; 1012 ro_seg->align = (u32)page; 1013 ro_seg->nsections = (l->emit_shared ? 5u : 6u) + (has_ver ? 2u : 0u); 1014 img->segment_bytes[ro_seg_idx] = 1015 ro_seg_size ? (u8*)h->alloc(h, (size_t)ro_seg_size, 16) : NULL; 1016 img->segment_bytes_cap[ro_seg_idx] = (size_t)ro_seg_size; 1017 if (ro_seg_size && !img->segment_bytes[ro_seg_idx]) 1018 compiler_panic(img->c, SRCLOC_NONE, "link: oom on ro dyn segment"); 1019 if (ro_seg_size) 1020 memset(img->segment_bytes[ro_seg_idx], 0, (size_t)ro_seg_size); 1021 1022 if (has_plt) { 1023 LinkSegment* rx_seg = &img->segments[rx_seg_idx]; 1024 memset(rx_seg, 0, sizeof(*rx_seg)); 1025 rx_seg->id = (LinkSegmentId)(rx_seg_idx + 1u); 1026 rx_seg->flags = SF_ALLOC | SF_EXEC; 1027 rx_seg->file_offset = rx_vaddr; 1028 rx_seg->vaddr = rx_vaddr; 1029 rx_seg->paddr = rx_vaddr; 1030 rx_seg->file_size = plt_bytes; 1031 rx_seg->mem_size = plt_bytes; 1032 rx_seg->align = (u32)page; 1033 rx_seg->nsections = 1; 1034 img->segment_bytes[rx_seg_idx] = (u8*)h->alloc(h, (size_t)plt_bytes, 16); 1035 img->segment_bytes_cap[rx_seg_idx] = (size_t)plt_bytes; 1036 if (!img->segment_bytes[rx_seg_idx]) 1037 compiler_panic(img->c, SRCLOC_NONE, "link: oom on .plt segment"); 1038 memset(img->segment_bytes[rx_seg_idx], 0, (size_t)plt_bytes); 1039 /* Stash plt / got.plt vaddrs now — the PLT body emit just below 1040 * reads them, and the post-shift fixup in shift_image_addresses 1041 * (link_elf.c) keys on these fields too. */ 1042 dyn->plt_vaddr = rx_vaddr; 1043 dyn->plt_size = plt_bytes; 1044 dyn->got_plt_vaddr = rw_vaddr; 1045 dyn->got_plt_size = gotplt_bytes; 1046 /* PLT body emit: the descriptor owns the psABI-specific bytes. */ 1047 if (!arch->emit_plt0 || !arch->emit_plt_entry) 1048 compiler_panic(l->c, SRCLOC_NONE, "link: PLT emit not configured"); 1049 { 1050 u8* plt_b = img->segment_bytes[rx_seg_idx]; 1051 u32 ki; 1052 arch->emit_plt0(plt_b, dyn->plt_vaddr, dyn->got_plt_vaddr); 1053 for (ki = 0; ki < imports.nfuncs; ++ki) { 1054 u64 entry_vaddr = dyn->plt_vaddr + arch->plt0_size + 1055 (u64)arch->plt_entry_size * (u64)ki; 1056 u64 slot_vaddr = dyn->got_plt_vaddr + 8u * (3u + ki); 1057 u8* p = 1058 plt_b + arch->plt0_size + (size_t)arch->plt_entry_size * (size_t)ki; 1059 arch->emit_plt_entry(p, entry_vaddr, slot_vaddr); 1060 } 1061 } 1062 } 1063 /* rw_seg always exists — it carries .dynamic, plus .got.plt when 1064 * imports are present. */ 1065 { 1066 LinkSegment* rw_seg = &img->segments[rw_seg_idx]; 1067 memset(rw_seg, 0, sizeof(*rw_seg)); 1068 rw_seg->id = (LinkSegmentId)(rw_seg_idx + 1u); 1069 rw_seg->flags = SF_ALLOC | SF_WRITE; 1070 rw_seg->file_offset = rw_vaddr; 1071 rw_seg->vaddr = rw_vaddr; 1072 rw_seg->paddr = rw_vaddr; 1073 rw_seg->file_size = rw_seg_size; 1074 rw_seg->mem_size = rw_seg_size; 1075 rw_seg->align = (u32)page; 1076 rw_seg->nsections = has_plt ? 2u : 1u; 1077 img->segment_bytes[rw_seg_idx] = (u8*)h->alloc(h, (size_t)rw_seg_size, 16); 1078 img->segment_bytes_cap[rw_seg_idx] = (size_t)rw_seg_size; 1079 if (!img->segment_bytes[rw_seg_idx]) 1080 compiler_panic(img->c, SRCLOC_NONE, "link: oom on rw dyn segment"); 1081 /* Zero-initialize. .got.plt[0] (&.dynamic) is filled later, after 1082 * shift_image_addresses has bumped dyn->dynamic_vaddr. .dynamic 1083 * body is built post-shift in link_emit_elf. Loader 1084 * patches all .got.plt slots from .rela.plt before user code 1085 * under DF_1_NOW. */ 1086 memset(img->segment_bytes[rw_seg_idx], 0, (size_t)rw_seg_size); 1087 } 1088 img->nsegments += nseg; 1089 1090 /* Step 6: synthetic LinkSection entries. Order in img->sections 1091 * matches the loader-friendly file order and feeds emit's 1092 * outshdr-merge pass. */ 1093 u32 nsec = (l->emit_shared ? 6u : 7u) + (has_plt ? 2u : 0u) + 1094 (has_ver ? 2u : 0u); 1095 u32 sec_base = dyn_alloc_sections(img, nsec); 1096 1097 /* helper: populate a fresh LinkSection for a segment-internal range */ 1098 /* Inline because the args differ enough (sem, name) per slot. */ 1099 Sym name_interp = pool_intern_slice(l->c->global, SLICE_LIT(".interp")); 1100 Sym name_dynsym = pool_intern_slice(l->c->global, SLICE_LIT(".dynsym")); 1101 Sym name_dynstr = pool_intern_slice(l->c->global, SLICE_LIT(".dynstr")); 1102 Sym name_gnu_hash = pool_intern_slice(l->c->global, SLICE_LIT(".gnu.hash")); 1103 Sym name_rela_dyn = pool_intern_slice(l->c->global, SLICE_LIT(".rela.dyn")); 1104 Sym name_rela_plt = pool_intern_slice(l->c->global, SLICE_LIT(".rela.plt")); 1105 Sym name_dynamic = pool_intern_slice(l->c->global, SLICE_LIT(".dynamic")); 1106 Sym name_plt = pool_intern_slice(l->c->global, SLICE_LIT(".plt")); 1107 Sym name_got_plt = pool_intern_slice(l->c->global, SLICE_LIT(".got.plt")); 1108 Sym name_gnu_version = 1109 pool_intern_slice(l->c->global, SLICE_LIT(".gnu.version")); 1110 Sym name_gnu_version_r = 1111 pool_intern_slice(l->c->global, SLICE_LIT(".gnu.version_r")); 1112 1113 #define INIT_SEC(IDX, NAME, SEG_IDX, OFF_IN_SEG, SIZE, ALIGN, FLAGS, SEM) \ 1114 do { \ 1115 LinkSection* ls = &img->sections[sec_base + (IDX)]; \ 1116 memset(ls, 0, sizeof(*ls)); \ 1117 ls->id = (LinkSectionId)(sec_base + (IDX) + 1u); \ 1118 ls->input_id = LINK_INPUT_NONE; \ 1119 ls->obj_section_id = OBJ_SEC_NONE; \ 1120 ls->segment_id = img->segments[(SEG_IDX)].id; \ 1121 ls->input_offset = (OFF_IN_SEG); \ 1122 ls->file_offset = img->segments[(SEG_IDX)].file_offset + (OFF_IN_SEG); \ 1123 ls->vaddr = img->segments[(SEG_IDX)].vaddr + (OFF_IN_SEG); \ 1124 ls->size = (SIZE); \ 1125 ls->flags = (FLAGS); \ 1126 ls->align = (ALIGN); \ 1127 ls->name = (NAME); \ 1128 ls->sem = (SEM); \ 1129 } while (0) 1130 1131 u32 si_base = 0; 1132 if (!l->emit_shared) { 1133 INIT_SEC(0, name_interp, ro_seg_idx, interp_off, interp_bytes, 1, SF_ALLOC, 1134 SSEM_PROGBITS); 1135 dyn->sec_interp = (LinkSectionId)(sec_base + 0 + 1u); 1136 si_base = 1u; 1137 } 1138 INIT_SEC(si_base + 0u, name_dynsym, ro_seg_idx, dynsym_off, dynsym_bytes, 8, SF_ALLOC, 1139 SSEM_PROGBITS); 1140 INIT_SEC(si_base + 1u, name_dynstr, ro_seg_idx, dynstr_off, dynstr_bytes, 1, SF_ALLOC, 1141 SSEM_PROGBITS); 1142 INIT_SEC(si_base + 2u, name_gnu_hash, ro_seg_idx, gnuhash_off, gnuhash_bytes, 8, 1143 SF_ALLOC, SSEM_PROGBITS); 1144 INIT_SEC(si_base + 3u, name_rela_dyn, ro_seg_idx, rela_dyn_off, rela_dyn_bytes, 8, 1145 SF_ALLOC, SSEM_PROGBITS); 1146 INIT_SEC(si_base + 4u, name_rela_plt, ro_seg_idx, rela_plt_off, rela_plt_bytes, 8, 1147 SF_ALLOC, SSEM_PROGBITS); 1148 INIT_SEC(si_base + 5u, name_dynamic, rw_seg_idx, dynamic_off, dynamic_bytes, 8, 1149 SF_ALLOC | SF_WRITE, SSEM_PROGBITS); 1150 1151 dyn->sec_dynsym = (LinkSectionId)(sec_base + si_base + 0u + 1u); 1152 dyn->sec_dynstr = (LinkSectionId)(sec_base + si_base + 1u + 1u); 1153 dyn->sec_gnu_hash = (LinkSectionId)(sec_base + si_base + 2u + 1u); 1154 dyn->sec_rela_dyn = (LinkSectionId)(sec_base + si_base + 3u + 1u); 1155 dyn->sec_rela_plt = (LinkSectionId)(sec_base + si_base + 4u + 1u); 1156 dyn->sec_dynamic = (LinkSectionId)(sec_base + si_base + 5u + 1u); 1157 dyn->dynamic_vaddr = img->segments[rw_seg_idx].vaddr + dynamic_off; 1158 dyn->dynamic_size = dynamic_bytes; 1159 1160 if (has_plt) { 1161 u32 plt0 = si_base + 6u; 1162 INIT_SEC(plt0, name_plt, rx_seg_idx, 0, plt_bytes, 16, SF_ALLOC | SF_EXEC, 1163 SSEM_PROGBITS); 1164 INIT_SEC(plt0 + 1u, name_got_plt, rw_seg_idx, gotplt_off, gotplt_bytes, 8, 1165 SF_ALLOC | SF_WRITE, SSEM_PROGBITS); 1166 dyn->sec_plt = (LinkSectionId)(sec_base + plt0 + 1u); 1167 dyn->sec_got_plt = (LinkSectionId)(sec_base + plt0 + 1u + 1u); 1168 } 1169 if (has_ver) { 1170 /* Appended after the optional PLT slots; emit sorts the section-header 1171 * table by (segment, vaddr), so array order here is not load-bearing. The 1172 * SSEM_PROGBITS sem just parks the bytes in the ro segment — the runtime 1173 * reads them via DT_VERSYM/DT_VERNEED, not the section headers. */ 1174 u32 vb0 = si_base + 6u + (has_plt ? 2u : 0u); 1175 INIT_SEC(vb0, name_gnu_version, ro_seg_idx, versym_off, versym_bytes, 2, 1176 SF_ALLOC, SSEM_PROGBITS); 1177 INIT_SEC(vb0 + 1u, name_gnu_version_r, ro_seg_idx, verneed_off, 1178 verneed_bytes, 4, SF_ALLOC, SSEM_PROGBITS); 1179 dyn->sec_gnu_version = (LinkSectionId)(sec_base + vb0 + 1u); 1180 dyn->sec_gnu_version_r = (LinkSectionId)(sec_base + vb0 + 1u + 1u); 1181 } 1182 #undef INIT_SEC 1183 1184 img->nsections += nsec; 1185 1186 /* Step 7: copy .interp / .dynsym / .dynstr / .gnu.hash bytes into 1187 * the ro segment. .dynamic body is built during emit (it embeds 1188 * runtime vaddrs that PIE keeps image-relative; emit just reads 1189 * the section ids' final vaddrs). */ 1190 u8* ro_bytes = img->segment_bytes[ro_seg_idx]; 1191 1192 /* .interp */ 1193 if (interp_bytes && ro_bytes) 1194 memcpy(ro_bytes + interp_off, interp_str, (size_t)interp_bytes); 1195 1196 /* .dynsym: serialize DynSymRec to ELF64 wire layout. */ 1197 { 1198 u32 si; 1199 for (si = 0; si < dyn->ndynsym; ++si) { 1200 u8* p = ro_bytes + dynsym_off + (u64)si * ELF64_SYM_SIZE; 1201 const DynSymRec* r = &dyn->dynsym[si]; 1202 wr_u32_le(p + 0, r->st_name); 1203 p[4] = r->st_info; 1204 p[5] = r->st_other; 1205 wr_u16_le(p + 6, r->st_shndx); 1206 wr_u64_le(p + 8, r->st_value); 1207 wr_u64_le(p + 16, r->st_size); 1208 } 1209 } 1210 1211 /* .dynstr */ 1212 if (dynstr_bytes && ro_bytes && dyn->dynstr) 1213 memcpy(ro_bytes + dynstr_off, dyn->dynstr, dyn->dynstr_len); 1214 1215 /* .gnu.hash */ 1216 if (gnuhash_bytes && ro_bytes && dyn->gnu_hash) 1217 memcpy(ro_bytes + gnuhash_off, dyn->gnu_hash, dyn->gnu_hash_len); 1218 1219 /* .gnu.version + .gnu.version_r (no vaddrs inside; copied verbatim). */ 1220 if (has_ver && ro_bytes) { 1221 if (versym_bytes && dyn->versym) 1222 memcpy(ro_bytes + versym_off, dyn->versym, dyn->versym_len); 1223 if (verneed_bytes && dyn->verneed) 1224 memcpy(ro_bytes + verneed_off, dyn->verneed, dyn->verneed_len); 1225 } 1226 1227 /* .rela.plt: emit JUMP_SLOT records, one per imported function, and 1228 * stash each import's PLT-entry vaddr in `sym_plt_vaddr` so the 1229 * apply pass can redirect CALL26/JUMP26 against the import. The 1230 * record's r_offset addresses the .got.plt slot the PLT stub reads 1231 * through; the loader patches that slot to the resolved runtime 1232 * address before user code runs (DF_1_NOW, BIND_NOW). Bytes are 1233 * written here at pre-shift vaddrs; link_emit re-serializes them 1234 * after shift_image_addresses bumps the dyn vaddrs by headers_load. */ 1235 { 1236 u32 ki; 1237 for (ki = 0; ki < imports.nfuncs; ++ki) { 1238 LinkSymId lsid = imports.funcs[ki]; 1239 u32 dynidx = dyn->sym_dynidx[lsid]; 1240 u64 slot_vaddr = dyn->got_plt_vaddr + 8u * (3u + ki); 1241 u64 plt_entry_vaddr = dyn->plt_vaddr + arch->plt0_size + 1242 (u64)arch->plt_entry_size * (u64)ki; 1243 DynRela* r = &dyn->rela_plt[ki]; 1244 r->r_offset = slot_vaddr; 1245 r->r_info = ELF64_R_INFO((u64)dynidx, elf_arch->r_jump_slot); 1246 r->r_addend = 0; 1247 /* Serialize into segment bytes (will be re-serialized post-shift). */ 1248 u8* p = ro_bytes + rela_plt_off + (u64)ki * ELF64_RELA_SIZE; 1249 wr_u64_le(p + 0, r->r_offset); 1250 wr_u64_le(p + 8, r->r_info); 1251 wr_u64_le(p + 16, (u64)r->r_addend); 1252 /* sym_plt_vaddr is consulted by apply_all_relocs. */ 1253 dyn->sym_plt_vaddr[lsid] = plt_entry_vaddr; 1254 } 1255 } 1256 1257 /* .rela.dyn entries (GLOB_DAT for imports referenced via .got, and 1258 * RELATIVE for PIE internal abs fixups) are emitted by 1259 * apply_all_relocs as it walks every relocation. layout_dyn 1260 * leaves .rela.dyn empty here; the bytes are written post-shift in 1261 * link_emit_elf. */ 1262 1263 /* .got.plt prelude: for BIND_NOW we leave the body zero — the 1264 * loader patches every slot from .rela.plt before user code. Some 1265 * loaders still inspect slot 0 (&.dynamic) at startup; provide it 1266 * so glibc-style loaders don't fault. The loader writes the link_map 1267 * cookie into slot 1 at load time. */ 1268 if (has_plt) { 1269 u8* gp_bytes = img->segment_bytes[rw_seg_idx]; 1270 if (gp_bytes && gotplt_bytes >= 8u) { 1271 wr_u64_le(gp_bytes, dyn->dynamic_vaddr); 1272 /* Slots 1, 2, and per-PLT slots stay zero until the loader 1273 * fills them. Phase 5 would prefill the per-PLT slots with 1274 * the address of PLT0 to support lazy binding. */ 1275 } 1276 } 1277 1278 /* The .dynamic body is built later, after segment shifts are 1279 * applied during emit. link_emit_elf (src/obj/elf/link.c) takes the 1280 * post-shift vaddrs of every other dyn section and writes one 1281 * DT_* entry per index. */ 1282 1283 /* Synthesize linker-defined symbols that reference the .dynamic 1284 * vaddr. Scrt1.o on Linux loads `_DYNAMIC` via ADRP+ADD, and 1285 * libc_nonshared.a's atexit shim takes `__dso_handle` as the 1286 * per-image identity (we use the .dynamic vaddr — any stable 1287 * per-image address satisfies the contract since the shim only 1288 * passes it through to __cxa_atexit, which the program-side glibc 1289 * just stashes). */ 1290 link_define_boundary(l, img, "_DYNAMIC", dyn->dynamic_vaddr); 1291 link_define_boundary(l, img, "__dso_handle", dyn->dynamic_vaddr); 1292 1293 free_imports(h, &imports); 1294 } 1295 1296 /* ---- cleanup ---- */ 1297 1298 void link_dyn_state_free(LinkImage* img) { 1299 Heap* h = img->heap; 1300 LinkDynState* dyn = img->dyn; 1301 if (!dyn) return; 1302 if (dyn->dynsym) h->free(h, dyn->dynsym, sizeof(*dyn->dynsym) * dyn->ndynsym); 1303 if (dyn->dynstr) h->free(h, dyn->dynstr, dyn->dynstr_len); 1304 if (dyn->gnu_hash) h->free(h, dyn->gnu_hash, dyn->gnu_hash_len); 1305 if (dyn->versym) h->free(h, dyn->versym, dyn->versym_len); 1306 if (dyn->verneed) h->free(h, dyn->verneed, dyn->verneed_len); 1307 if (dyn->rela_dyn) 1308 h->free(h, dyn->rela_dyn, sizeof(*dyn->rela_dyn) * dyn->cap_rela_dyn); 1309 if (dyn->rela_plt) 1310 h->free(h, dyn->rela_plt, sizeof(*dyn->rela_plt) * dyn->nrela_plt); 1311 if (dyn->needed) h->free(h, dyn->needed, sizeof(*dyn->needed) * dyn->nneeded); 1312 if (dyn->rpaths) h->free(h, dyn->rpaths, sizeof(*dyn->rpaths) * dyn->nrpaths); 1313 if (dyn->runpaths) 1314 h->free(h, dyn->runpaths, sizeof(*dyn->runpaths) * dyn->nrunpaths); 1315 if (dyn->sym_dynidx) 1316 h->free(h, dyn->sym_dynidx, 1317 sizeof(*dyn->sym_dynidx) * dyn->sym_dynidx_size); 1318 if (dyn->sym_plt_vaddr) 1319 h->free(h, dyn->sym_plt_vaddr, 1320 sizeof(*dyn->sym_plt_vaddr) * dyn->sym_dynidx_size); 1321 h->free(h, dyn, sizeof(*dyn)); 1322 img->dyn = NULL; 1323 }