link_resolve.c (56423B)
1 /* link_resolve.c — archive ingest, symbol resolution, --gc-sections liveness. 2 * 3 * Phase 1 of the link pipeline: 4 * link_ingest_archives — pull archive members into l->inputs 5 * link_resolve_symbols — register every ObjSym, build img->globals 6 * link_resolve_undefs — satisfy remaining undefs (globals/DSOs/resolver) 7 * link_gc_compute — mark live sections (or mark all live if disabled) 8 * link_gc_drop_dead_globals — clear `defined` on syms in dropped sections 9 */ 10 11 #include <kit/core.h> 12 #include <stdlib.h> 13 #include <string.h> 14 15 #include "core/buf.h" 16 #include "core/bytes.h" 17 #include "core/heap.h" 18 #include "core/pool.h" 19 #include "core/slice.h" 20 #include "core/util.h" 21 #include "core/vec.h" 22 #include "link/link.h" 23 #include "link/link_arch.h" 24 #include "link/link_internal.h" 25 26 /* ---- per-input symbol/section maps ---- */ 27 28 typedef struct AtomSortRec { 29 ObjAtomId id; 30 ObjSecId section_id; 31 u32 offset; 32 } AtomSortRec; 33 34 static int atom_sort_rec_cmp(const void* av, const void* bv) { 35 const AtomSortRec* a = (const AtomSortRec*)av; 36 const AtomSortRec* b = (const AtomSortRec*)bv; 37 if (a->section_id < b->section_id) return -1; 38 if (a->section_id > b->section_id) return 1; 39 if (a->offset < b->offset) return -1; 40 if (a->offset > b->offset) return 1; 41 if (a->id < b->id) return -1; 42 if (a->id > b->id) return 1; 43 return 0; 44 } 45 46 static ObjAtomId input_map_find_atom(const InputMap* m, ObjBuilder* ob, 47 ObjSecId sid, u32 offset) { 48 u32 first, count, i; 49 if (!link_input_section_has_atoms(m, sid)) return OBJ_ATOM_NONE; 50 link_input_section_atoms(m, sid, &first, &count); 51 for (i = 0; i < count; ++i) { 52 ObjAtomId aid = m->section_atom_ids[first + i]; 53 const ObjAtom* a = obj_atom_get(ob, aid); 54 u64 begin, end; 55 if (!a || a->removed) continue; 56 begin = a->offset; 57 end = begin + a->size; 58 if (a->size != 0 && (u64)offset >= begin && (u64)offset < end) return aid; 59 } 60 for (i = 0; i < count; ++i) { 61 ObjAtomId aid = m->section_atom_ids[first + i]; 62 const ObjAtom* a = obj_atom_get(ob, aid); 63 if (!a || a->removed) continue; 64 if (a->size == 0 && offset == a->offset) return aid; 65 } 66 return OBJ_ATOM_NONE; 67 } 68 69 static ObjAtomId input_map_find_symbol_atom(const InputMap* m, ObjBuilder* ob, 70 ObjSymId sym) { 71 const ObjSym* s; 72 ObjAtomId aid; 73 u32 i; 74 if (!ob || sym == OBJ_SYM_NONE) return OBJ_ATOM_NONE; 75 s = obj_symbol_get(ob, sym); 76 if (!s || s->section_id == OBJ_SEC_NONE) return OBJ_ATOM_NONE; 77 aid = input_map_find_atom(m, ob, s->section_id, (u32)s->value); 78 if (aid != OBJ_ATOM_NONE) return aid; 79 for (i = 0; i < m->nsection_atom_ids; ++i) { 80 const ObjAtom* a = obj_atom_get(ob, m->section_atom_ids[i]); 81 if (a && !a->removed && a->signature == sym) return m->section_atom_ids[i]; 82 } 83 return OBJ_ATOM_NONE; 84 } 85 86 void link_input_map_alloc(LinkImage* img, InputMap* m, ObjBuilder* ob, 87 u32 nsym) { 88 Heap* h = img->heap; 89 u32 nsection = obj_section_count(ob); 90 u32 natom = obj_atom_count(ob); 91 u32 nreloc = obj_reloc_total(ob); 92 AtomSortRec* atoms = NULL; 93 u32 nactive = 0; 94 u32 i; 95 96 memset(m, 0, sizeof(*m)); 97 m->nsym = nsym; 98 m->sym = (LinkSymId*)h->alloc(h, sizeof(*m->sym) * nsym, _Alignof(LinkSymId)); 99 if (!m->sym) 100 compiler_panic(img->c, SRCLOC_NONE, "link: oom on input symbol map"); 101 memset(m->sym, 0, sizeof(*m->sym) * nsym); 102 m->nsection = nsection; 103 m->section = (LinkSectionId*)h->alloc(h, sizeof(*m->section) * nsection, 104 _Alignof(LinkSectionId)); 105 if (!m->section) 106 compiler_panic(img->c, SRCLOC_NONE, "link: oom on input section map"); 107 memset(m->section, 0, sizeof(*m->section) * nsection); 108 m->natom = natom; 109 m->atom = (LinkSectionId*)h->alloc(h, sizeof(*m->atom) * (natom ? natom : 1u), 110 _Alignof(LinkSectionId)); 111 if (!m->atom) 112 compiler_panic(img->c, SRCLOC_NONE, "link: oom on input atom map"); 113 memset(m->atom, 0, sizeof(*m->atom) * (natom ? natom : 1u)); 114 m->sym_atom = (ObjAtomId*)h->alloc( 115 h, sizeof(*m->sym_atom) * (nsym ? nsym : 1u), _Alignof(ObjAtomId)); 116 if (!m->sym_atom) 117 compiler_panic(img->c, SRCLOC_NONE, "link: oom on input symbol atom map"); 118 memset(m->sym_atom, 0, sizeof(*m->sym_atom) * (nsym ? nsym : 1u)); 119 m->nreloc = nreloc; 120 m->reloc_atom = (ObjAtomId*)h->alloc( 121 h, sizeof(*m->reloc_atom) * (nreloc ? nreloc : 1u), _Alignof(ObjAtomId)); 122 if (!m->reloc_atom) 123 compiler_panic(img->c, SRCLOC_NONE, "link: oom on input reloc atom map"); 124 memset(m->reloc_atom, 0, sizeof(*m->reloc_atom) * (nreloc ? nreloc : 1u)); 125 m->section_has_atoms = (u8*)h->alloc(h, nsection ? nsection : 1u, 1); 126 if (!m->section_has_atoms) 127 compiler_panic(img->c, SRCLOC_NONE, "link: oom on input section atom map"); 128 memset(m->section_has_atoms, 0, nsection ? nsection : 1u); 129 m->section_atom_first = (u32*)h->alloc( 130 h, sizeof(*m->section_atom_first) * (nsection ? nsection : 1u), 131 _Alignof(u32)); 132 m->section_atom_count = (u32*)h->alloc( 133 h, sizeof(*m->section_atom_count) * (nsection ? nsection : 1u), 134 _Alignof(u32)); 135 if (!m->section_atom_first || !m->section_atom_count) 136 compiler_panic(img->c, SRCLOC_NONE, 137 "link: oom on input section atom ranges"); 138 memset(m->section_atom_first, 0, 139 sizeof(*m->section_atom_first) * (nsection ? nsection : 1u)); 140 memset(m->section_atom_count, 0, 141 sizeof(*m->section_atom_count) * (nsection ? nsection : 1u)); 142 m->comdat_discarded = (u8*)h->alloc(h, nsection ? nsection : 1u, 1); 143 if (!m->comdat_discarded) 144 compiler_panic(img->c, SRCLOC_NONE, "link: oom on input comdat map"); 145 memset(m->comdat_discarded, 0, nsection ? nsection : 1u); 146 147 if (natom > 1u) { 148 atoms = (AtomSortRec*)h->alloc(h, sizeof(*atoms) * natom, 149 _Alignof(AtomSortRec)); 150 if (!atoms) 151 compiler_panic(img->c, SRCLOC_NONE, "link: oom on atom sort map"); 152 for (i = 1; i < natom; ++i) { 153 const ObjAtom* a = obj_atom_get(ob, (ObjAtomId)i); 154 if (!a || a->removed || a->section_id == OBJ_SEC_NONE || 155 a->section_id >= nsection) 156 continue; 157 atoms[nactive].id = (ObjAtomId)i; 158 atoms[nactive].section_id = a->section_id; 159 atoms[nactive].offset = a->offset; 160 ++nactive; 161 } 162 if (nactive > 1u) qsort(atoms, nactive, sizeof(*atoms), atom_sort_rec_cmp); 163 } 164 165 m->nsection_atom_ids = nactive; 166 if (nactive) { 167 ObjSecId cur = OBJ_SEC_NONE; 168 m->section_atom_ids = (ObjAtomId*)h->alloc( 169 h, sizeof(*m->section_atom_ids) * nactive, _Alignof(ObjAtomId)); 170 if (!m->section_atom_ids) 171 compiler_panic(img->c, SRCLOC_NONE, "link: oom on section atom ids"); 172 for (i = 0; i < nactive; ++i) { 173 ObjSecId sid = atoms[i].section_id; 174 m->section_atom_ids[i] = atoms[i].id; 175 if (sid != cur) { 176 m->section_has_atoms[sid] = 1; 177 m->section_atom_first[sid] = i; 178 cur = sid; 179 } 180 m->section_atom_count[sid]++; 181 } 182 } 183 if (atoms) h->free(h, atoms, sizeof(*atoms) * natom); 184 185 for (i = 1; i < nsym; ++i) 186 m->sym_atom[i] = input_map_find_symbol_atom(m, ob, (ObjSymId)i); 187 for (i = 0; i < nreloc; ++i) { 188 const Reloc* r = obj_reloc_at(ob, i); 189 if (!r || r->section_id == OBJ_SEC_NONE) continue; 190 m->reloc_atom[i] = input_map_find_atom(m, ob, r->section_id, r->offset); 191 } 192 } 193 194 /* ---- pass 1: collect symbols ---- */ 195 196 /* A symbol with no home section and no absolute/common pseudo-value: the 197 * importer's view of an undefined reference (or a DSO export). Distinct 198 * from link_sym_is_def — SK_FILE symbols are logical undefs here but 199 * defs there. Used only by scan_presence_before to split logical undefs 200 * from logical defs; the spurious-undef prune routes through the shared 201 * link_sym_is_spurious_undef. */ 202 static int obj_sym_is_logical_undef(const ObjSym* s) { 203 return s && s->section_id == OBJ_SEC_NONE && s->kind != SK_ABS && 204 s->kind != SK_COMMON; 205 } 206 207 /* COFF/PE SELECTANY: a duplicate strong global is acceptable iff both 208 * definitions live in COMDAT (SF_GROUP-tagged) sections. When that 209 * holds, the earlier-processed definition wins and the new section is 210 * marked for discard so its bytes never reach layout. */ 211 static int obj_sym_defined_in_comdat(ObjBuilder* ob, const ObjSym* s) { 212 const Section* sec; 213 if (!s || s->section_id == OBJ_SEC_NONE) return 0; 214 sec = obj_section_get(ob, s->section_id); 215 return sec && (sec->flags & SF_GROUP); 216 } 217 218 void link_resolve_symbols(Linker* l, LinkImage* img) { 219 u32 ii; 220 for (ii = 0; ii < LinkInputs_count(&l->inputs); ++ii) { 221 LinkInput* in = LinkInputs_at(&l->inputs, ii); 222 ObjBuilder* ob = in->obj; 223 InputMap* m = &img->input_maps[ii]; 224 u32 nsym = obj_section_count(ob); 225 (void)nsym; 226 ObjSymIter* it; 227 ObjSymEntry e; 228 229 if (in->kind == LINK_INPUT_DSO_BYTES) continue; 230 231 u32 nsyms_in_input = 0; 232 it = obj_symiter_new(ob); 233 while (obj_symiter_next(it, &e)) ++nsyms_in_input; 234 obj_symiter_free(it); 235 236 link_input_map_alloc(img, m, ob, 237 nsyms_in_input + 1u /* +1 for id-0 slot */); 238 239 /* Pre-size the global symbol map for this input's symbols so the bulk 240 * insert below never rehashes mid-stream. Only globals/weaks actually land 241 * in img->globals, so this slightly over-reserves; it kills the resize 242 * cascade (256 -> N) on symbol-heavy inputs (e.g. a large linked object). */ 243 symhash_reserve(&img->globals, img->globals.used + nsyms_in_input); 244 245 it = obj_symiter_new(ob); 246 while (obj_symiter_next(it, &e)) { 247 const ObjSym* s = e.sym; 248 LinkSymbol rec; 249 LinkSymId existing; 250 /* Tombstoned symbols are deleted, not just undefined: a file-format 251 * emitter (which runs obj_sweep_dead, then `if (s->removed) continue`) 252 * never writes them, so a serialized-then-re-read input carries none. 253 * An in-memory ObjBuilder linked directly (the one-shot compile+link 254 * path) still holds them, so honor the same `removed` contract here. 255 * Without this, a deferred-but-never-materialized local rodata constant 256 * (`obj_symbol_defer` leaves `.Lkit_ro.N` as a removed local SK_OBJ when 257 * its function is optimized away at -O1) survives as an undefined local 258 * and trips the "undefined reference to '.Lkit_ro.N'" panic below. 259 * Leaving such a symbol unregistered (m->sym stays LINK_SYM_NONE); a 260 * reloc that still targets it is dead and is dropped in the reloc passes 261 * (matching obj_sweep_dead pass 3, which retires those relocs on write). */ 262 if (s->removed) continue; 263 if (link_sym_is_spurious_undef(s)) continue; 264 int is_def = link_sym_is_def(s); 265 266 memset(&rec, 0, sizeof(rec)); 267 rec.name = s->name; 268 rec.input_id = in->id; 269 rec.obj_sym = e.id; 270 rec.section_id = LINK_SEC_NONE; 271 rec.atom_id = is_def ? link_input_sym_atom(m, e.id) : OBJ_ATOM_NONE; 272 rec.value = s->value; 273 rec.size = s->size; 274 rec.common_align = (s->kind == SK_COMMON) ? (u32)s->common_align : 0u; 275 rec.bind = (u8)s->bind; 276 rec.kind = (u8)s->kind; 277 rec.vis = (u8)s->vis; 278 rec.defined = (u8)is_def; 279 rec.vaddr = 0; 280 281 if (is_def && (s->bind == SB_GLOBAL || s->bind == SB_WEAK) && 282 s->name != 0) { 283 LinkSymId fresh = (LinkSymId)(LinkSyms_count(&img->syms) + 1u); 284 if (symhash_insert(&img->globals, s->name, fresh, &existing)) { 285 m->sym[e.id] = link_append_symbol(img, &rec); 286 } else { 287 /* A second definition of an existing global/weak name: hand the 288 * binding-precedence decision to the shared policy module. The 289 * COMDAT lookup (does prev's section carry SF_GROUP?) is the 290 * caller-side bookkeeping symresolve deliberately leaves out. */ 291 LinkSymbol* prev = LinkSyms_at(&img->syms, existing - 1); 292 ObjBuilder* prev_ob = 293 (prev->input_id != LINK_INPUT_NONE) 294 ? LinkInputs_at(&l->inputs, prev->input_id - 1)->obj 295 : NULL; 296 const ObjSym* prev_os = 297 prev_ob ? obj_symbol_get(prev_ob, prev->obj_sym) : NULL; 298 SymAttrs ex_a = {0}; 299 SymAttrs inc_a = {0}; 300 SymMergeResult mr; 301 ex_a.bind = prev->bind; 302 ex_a.kind = prev->kind; 303 ex_a.size = prev->size; 304 ex_a.common_align = prev->common_align; 305 ex_a.in_comdat = (prev_ob && prev_os) 306 ? (u8)obj_sym_defined_in_comdat(prev_ob, prev_os) 307 : 0u; 308 inc_a.bind = rec.bind; 309 inc_a.kind = rec.kind; 310 inc_a.size = rec.size; 311 inc_a.common_align = rec.common_align; 312 inc_a.in_comdat = (u8)obj_sym_defined_in_comdat(ob, s); 313 mr = symresolve_merge(ex_a, inc_a); 314 switch (mr.kind) { 315 case SYM_MERGE_REPLACE: 316 rec.id = existing; 317 *prev = rec; 318 m->sym[e.id] = existing; 319 break; 320 case SYM_MERGE_COMMON: 321 rec.id = existing; 322 rec.common_align = mr.merged_align; 323 *prev = rec; 324 m->sym[e.id] = existing; 325 break; 326 case SYM_MERGE_COMDAT_DISCARD: 327 m->sym[e.id] = existing; 328 if (s->section_id < m->nsection) 329 m->comdat_discarded[s->section_id] = 1; 330 break; 331 case SYM_MERGE_ODR_ERROR: { 332 Slice nm_s = pool_slice(l->c->global, s->name); 333 compiler_panic(l->c, SRCLOC_NONE, 334 "link: duplicate definition of " 335 "global symbol '%.*s'", 336 (int)nm_s.len, nm_s.s); 337 break; 338 } 339 case SYM_MERGE_KEEP_EXISTING: 340 default: 341 m->sym[e.id] = existing; 342 break; 343 } 344 } 345 } else { 346 m->sym[e.id] = link_append_symbol(img, &rec); 347 } 348 } 349 obj_symiter_free(it); 350 } 351 } 352 353 static int obj_sym_is_dso_export(const ObjSym* s) { 354 return s && s->name != 0 && s->kind != SK_UNDEF && s->bind != SB_LOCAL; 355 } 356 357 static void dso_exports_build(Linker* l, SymHash* exports) { 358 u32 ii; 359 u32 nexports = 0; 360 symhash_init(exports, l->heap); 361 for (ii = 0; ii < LinkInputs_count(&l->inputs); ++ii) { 362 LinkInput* in = LinkInputs_at(&l->inputs, ii); 363 ObjSymIter* it; 364 ObjSymEntry e; 365 if (in->kind != LINK_INPUT_DSO_BYTES) continue; 366 it = obj_symiter_new(in->obj); 367 while (obj_symiter_next(it, &e)) { 368 if (obj_sym_is_dso_export(e.sym)) ++nexports; 369 } 370 obj_symiter_free(it); 371 } 372 symhash_reserve(exports, nexports); 373 for (ii = 0; ii < LinkInputs_count(&l->inputs); ++ii) { 374 LinkInput* in = LinkInputs_at(&l->inputs, ii); 375 ObjSymIter* it; 376 ObjSymEntry e; 377 if (in->kind != LINK_INPUT_DSO_BYTES) continue; 378 it = obj_symiter_new(in->obj); 379 while (obj_symiter_next(it, &e)) { 380 LinkSymId existing; 381 if (!obj_sym_is_dso_export(e.sym)) continue; 382 /* Preserve command-line order: the old lookup returned the first DSO 383 * exporting a name, so duplicate exports keep the earliest provider. */ 384 (void)symhash_insert(exports, e.sym->name, in->id, &existing); 385 } 386 obj_symiter_free(it); 387 } 388 } 389 390 static int elf_split_versioned_undef(Compiler* c, Sym full, Sym* base_out, 391 Sym* version_out) { 392 Slice nm; 393 u32 i; 394 if (!c || full == 0 || !base_out || !version_out) return 0; 395 nm = pool_slice(c->global, full); 396 if (!nm.s || nm.len < 3u) return 0; 397 for (i = 1u; i + 1u < nm.len; ++i) { 398 u32 j; 399 if (nm.s[i] != '@') continue; 400 if (nm.s[i + 1u] == '@') return 0; 401 for (j = i + 1u; j < nm.len; ++j) 402 if (nm.s[j] == '@') return 0; 403 *base_out = 404 pool_intern_slice(c->global, (Slice){.s = nm.s, .len = i}); 405 *version_out = pool_intern_slice( 406 c->global, (Slice){.s = nm.s + i + 1u, .len = nm.len - i - 1u}); 407 return *base_out != 0 && *version_out != 0; 408 } 409 return 0; 410 } 411 412 static const ObjImageSym* dso_dynsym_version(LinkInput* in, Sym name, 413 Sym version) { 414 const ObjImage* im; 415 u32 i, n; 416 if (!in || !in->obj || name == 0 || version == 0) return NULL; 417 im = obj_image(in->obj); 418 n = obj_image_ndynsyms(im); 419 for (i = 0; i < n; ++i) { 420 const ObjImageSym* s = obj_image_dynsym(im, i); 421 if (!s || s->name != name) continue; 422 if (s->section == OBJ_SEC_NONE && s->kind == SK_UNDEF) continue; 423 if (s->bind == SB_LOCAL) continue; 424 if (s->version == version) return s; 425 } 426 return NULL; 427 } 428 429 static LinkInputId find_dso_export_version(Linker* l, Sym name, Sym version, 430 const ObjImageSym** sym_out) { 431 u32 ii; 432 if (sym_out) *sym_out = NULL; 433 if (name == 0 || version == 0) return LINK_INPUT_NONE; 434 for (ii = 0; ii < LinkInputs_count(&l->inputs); ++ii) { 435 LinkInput* in = LinkInputs_at(&l->inputs, ii); 436 const ObjImageSym* s; 437 if (in->kind != LINK_INPUT_DSO_BYTES) continue; 438 s = dso_dynsym_version(in, name, version); 439 if (!s) continue; 440 if (sym_out) *sym_out = s; 441 return in->id; 442 } 443 return LINK_INPUT_NONE; 444 } 445 446 static int resolve_elf_versioned_dso_undef(Linker* l, LinkSymbol* s) { 447 Sym base = 0; 448 Sym version = 0; 449 const ObjImageSym* ds = NULL; 450 LinkInputId dso; 451 if (!l || !s || s->name == 0) return 0; 452 if (l->c->target.obj != KIT_OBJ_ELF) return 0; 453 if (!elf_split_versioned_undef(l->c, s->name, &base, &version)) return 0; 454 dso = find_dso_export_version(l, base, version, &ds); 455 if (dso == LINK_INPUT_NONE) return 0; 456 s->name = base; 457 s->kind = ds ? (u8)ds->kind : s->kind; 458 s->imported = 1; 459 s->dso_input_id = dso; 460 s->elf_version = version; 461 return 1; 462 } 463 464 /* Resolve undefined symbol `s` to the symbol named `alias` (a defined image 465 * global or a DSO export), copying the target's binding into `s`. Returns 1 on 466 * success. Shared by the recorded-alias path and the underscore heuristic. */ 467 static int resolve_to_alias(LinkImage* img, const SymHash* dso_exports, 468 LinkSymbol* s, Sym alias) { 469 if (alias == 0) return 0; 470 LinkSymId hit = symhash_get(&img->globals, alias); 471 if (hit != LINK_SYM_NONE) { 472 LinkSymbol* def = LinkSyms_at(&img->syms, hit - 1); 473 if (def->defined || def->imported) { 474 s->name = def->name; 475 s->section_id = def->section_id; 476 s->value = def->value; 477 s->vaddr = def->vaddr; 478 s->kind = def->kind; 479 s->defined = def->defined; 480 s->imported = def->imported; 481 s->dso_input_id = def->dso_input_id; 482 s->elf_version = def->elf_version; 483 if (!s->defined && !s->imported) { 484 s->kind = SK_ABS; 485 s->vaddr = 0; 486 s->defined = 1; 487 } 488 return 1; 489 } 490 } 491 LinkInputId dso = symhash_get(dso_exports, alias); 492 if (dso != LINK_INPUT_NONE) { 493 s->name = alias; 494 s->imported = 1; 495 s->dso_input_id = dso; 496 s->elf_version = 0; 497 return 1; 498 } 499 return 0; 500 } 501 502 static int resolve_elf_loader_owned_undef(Linker* l, LinkSymbol* s) { 503 Slice nm; 504 if (!l || !s || !s->name) return 0; 505 if (!l->emit_pie || l->c->target.obj != KIT_OBJ_ELF) return 0; 506 nm = pool_slice(l->c->global, s->name); 507 if (slice_eq_cstr(nm, "__tls_get_addr")) { 508 if (l->c->target.arch != KIT_ARCH_X86_64 && 509 l->c->target.arch != KIT_ARCH_RV64 && 510 l->c->target.arch != KIT_ARCH_RV32) 511 return 0; 512 /* Some glibc dynamic TLS helpers are provided by the ELF interpreter 513 * itself (ld-linux), not by a regular DT_NEEDED DSO. GNU ld permits this 514 * unresolved-looking reference in dynamic executables; model it as a 515 * function import with no provider DSO so the PLT/dynsym machinery can 516 * emit any needed JUMP_SLOT without adding the interpreter as DT_NEEDED. 517 * RISC-V TLS-GD references that relax fully to local-exec will skip their 518 * call relocations later, leaving this dynsym entry harmlessly unused. */ 519 s->kind = SK_FUNC; 520 } else if (slice_eq_cstr(nm, "__stack_chk_guard")) { 521 /* glibc's AArch64 and RISC-V ABIs expose the process canary from 522 * ld-linux, while libc only carries an undefined versioned reference to 523 * it. Treat the guard as an interpreter-owned object import. This keeps 524 * the loader out of DT_NEEDED (it is already PT_INTERP) and lets the 525 * ordinary GOT/dynsym machinery bind the address at startup. x86-64 reads 526 * its guard directly from fs:0x28 and never reaches this path. */ 527 if (l->c->target.os != KIT_OS_LINUX || 528 (l->c->target.arch != KIT_ARCH_ARM_64 && 529 l->c->target.arch != KIT_ARCH_RV64 && 530 l->c->target.arch != KIT_ARCH_RV32)) 531 return 0; 532 s->kind = SK_OBJ; 533 } else { 534 return 0; 535 } 536 s->imported = 1; 537 s->dso_input_id = LINK_INPUT_NONE; 538 s->elf_version = 0; 539 return 1; 540 } 541 542 void link_resolve_undefs(Linker* l, LinkImage* img) { 543 u32 i; 544 545 /* Cross-input COFF WEAK_EXTERNAL alias map: alias-declarator name -> target 546 * name (SymHash's value slot holds an interned Sym, never a real LinkSymId 547 * here; 0 = absent). Populated from every input's recorded aliases so a 548 * reference to the aliased name resolves to the target regardless of which 549 * input the reference vs. the declarator came from. Empty for non-COFF. */ 550 SymHash alias_map; 551 symhash_init(&alias_map, l->heap); 552 if (l->c->target.obj == KIT_OBJ_COFF) { 553 for (u32 ii = 0; ii < LinkInputs_count(&l->inputs); ++ii) { 554 LinkInput* in = LinkInputs_at(&l->inputs, ii); 555 if (!in->obj || in->kind == LINK_INPUT_DSO_BYTES) continue; 556 u32 na = obj_weak_alias_count(in->obj); 557 for (u32 ai = 0; ai < na; ++ai) { 558 ObjSymId asym = OBJ_SYM_NONE; 559 Sym target = 0; 560 if (!obj_weak_alias_at(in->obj, ai, &asym, &target) || target == 0) 561 continue; 562 const ObjSym* os = obj_symbol_get(in->obj, asym); 563 if (os && os->name != 0) symhash_set(&alias_map, os->name, target); 564 } 565 } 566 } 567 SymHash dso_exports; 568 dso_exports_build(l, &dso_exports); 569 570 for (i = 0; i < LinkSyms_count(&img->syms); ++i) { 571 LinkSymbol* s = LinkSyms_at(&img->syms, i); 572 if (s->defined) continue; 573 if (s->name != 0) { 574 LinkSymId hit = symhash_get(&img->globals, s->name); 575 if (hit != LINK_SYM_NONE && hit != s->id) { 576 LinkSymbol* def = LinkSyms_at(&img->syms, hit - 1); 577 if (def->defined) { 578 s->section_id = def->section_id; 579 s->value = def->value; 580 s->vaddr = def->vaddr; 581 s->kind = def->kind; 582 s->bind = def->bind; 583 s->vis = def->vis; 584 s->defined = 1; 585 continue; 586 } 587 } 588 } 589 if (s->name != 0) { 590 if (resolve_elf_versioned_dso_undef(l, s)) { 591 continue; 592 } 593 LinkInputId dso = symhash_get(&dso_exports, s->name); 594 if (dso != LINK_INPUT_NONE) { 595 s->imported = 1; 596 s->dso_input_id = dso; 597 s->elf_version = 0; 598 continue; 599 } 600 if (resolve_elf_loader_owned_undef(l, s)) continue; 601 } 602 if (l->resolver && s->name != 0) { 603 Slice nm_s = pool_slice(l->c->global, s->name); 604 void* p = l->resolver(l->resolver_user, nm_s); 605 if (p) { 606 s->kind = SK_ABS; 607 s->vaddr = (u64)(uintptr_t)p; 608 s->defined = 1; 609 continue; 610 } 611 } 612 /* COFF WEAK_EXTERNAL alias: resolve to the recorded fall-back symbol (the 613 * aux TagIndex target captured by read_coff, collected into `alias_map` 614 * keyed by the alias-declarator's name). This is the precise relationship — 615 * e.g. mingw x86_64's `_setjmp` aliasing `__intrinsic_setjmp`, which the 616 * single-underscore heuristic below cannot derive. It applies to ANY undef 617 * of the aliased name, not just the declarator symbol itself: the strong 618 * reference (sj.o's `_setjmp`) and the weak declarator are distinct undefs, 619 * and the reference is what needs redirecting. The declarator member is 620 * pulled by member_satisfies (weak undef under PE/COMDAT semantics), which 621 * brings in the target's own undef and pulls its short-import DSO, so the 622 * target is resolvable by now. Follow a short chain in case the target is 623 * itself an alias. */ 624 if (s->name != 0) { 625 int resolved = 0; 626 Sym cur = s->name; 627 for (u32 hop = 0; hop < 8u; ++hop) { 628 Sym target = symhash_get(&alias_map, cur); 629 if (target == 0) break; 630 if (resolve_to_alias(img, &dso_exports, s, target)) { 631 resolved = 1; 632 break; 633 } 634 cur = target; 635 } 636 if (resolved) continue; 637 } 638 /* COFF WEAK_EXTERNAL alias fallback for references that carry no recorded 639 * aux TagIndex (GLOBAL undefs like crt2.o's call to `__set_app_type`, or 640 * inputs read before alias capture): recover the relationship via the mingw 641 * single-underscore naming convention. e.g. `__set_app_type` aliases to 642 * `_set_app_type`; `__imp___set_app_type` aliases to `__imp__set_app_type`. 643 * Try the de-underscored variant first, then the re-underscored one. */ 644 if (obj_format_weak_extern_underscore_alias(l->c) && s->name != 0) { 645 Slice nm_s = pool_slice(l->c->global, s->name); 646 const char* nm = nm_s.s; 647 size_t nlen = nm_s.len; 648 Sym candidates[2] = {0, 0}; 649 u32 ncand = 0; 650 if (nm && nlen >= 2 && nm[0] == '_') { 651 candidates[ncand++] = pool_intern_slice( 652 l->c->global, (Slice){.s = nm + 1, .len = (u32)(nlen - 1u)}); 653 } 654 if (nm && nlen > 0) { 655 char* buf = (char*)arena_array(l->c->scratch, char, nlen + 1u); 656 buf[0] = '_'; 657 memcpy(buf + 1, nm, nlen); 658 candidates[ncand++] = pool_intern_slice( 659 l->c->global, (Slice){.s = buf, .len = (u32)(nlen + 1u)}); 660 } 661 int resolved = 0; 662 for (u32 ci = 0; !resolved && ci < ncand; ++ci) { 663 if (resolve_to_alias(img, &dso_exports, s, candidates[ci])) 664 resolved = 1; 665 } 666 if (resolved) continue; 667 } 668 if (s->bind == SB_WEAK) { 669 s->kind = SK_ABS; 670 s->vaddr = 0; 671 s->defined = 1; 672 continue; 673 } 674 /* JIT lane: format pseudo-symbols the JIT image satisfies internally. 675 * Mach-O inputs (including clang-produced .o files) carry a non-weak undef 676 * `__tlv_bootstrap` on every TLV var; kit_jit_from_image rewrites every 677 * descriptor's slot[0] to our thunk, so the resolved value never gets read. 678 * Windows COFF inputs carry `_tls_index` (normally supplied by the OS 679 * loader via the TLS directory); the JIT relaxes every TLS access to 680 * in-image addressing, so it is never read. Treat such a symbol as 681 * weak-undef (vaddr = 0, SK_ABS) in JIT mode only; AOT lanes keep the 682 * strict "undefined external" semantics. The obj layer is the single 683 * arbiter (shared with link_jit.c), so src/link names no pseudo-symbol. */ 684 if (l->jit_mode && obj_format_jit_undef_internal(l->c, s->name)) { 685 s->kind = SK_ABS; 686 s->vaddr = 0; 687 s->defined = 1; 688 continue; 689 } 690 if (l->allow_undefined) { 691 s->kind = SK_ABS; 692 s->vaddr = 0; 693 s->defined = 1; 694 continue; 695 } 696 if (l->emit_shared && s->name != 0 && s->bind != SB_LOCAL) { 697 s->imported = 1; 698 s->dso_input_id = LINK_INPUT_NONE; 699 s->elf_version = 0; 700 continue; 701 } 702 /* --defsym NAME=EXPR: a defsym whose NAME matches this undef satisfies the 703 * reference. Defsyms are applied AFTER undef resolution (link_apply_defsyms 704 * runs in link_resolve, once the alias target's vaddr is settled), so we 705 * cannot define it here; instead, skip the panic and leave the record 706 * undefined-for-now. link_apply_defsyms then UPDATES this same record in 707 * place (its `existing != LINK_SYM_NONE` branch) — leaving s->defined=0 708 * avoids the duplicate-symbol artifact a synthetic definition would add. */ 709 if (s->name != 0 && l->ndefsyms) { 710 int is_defsym = 0; 711 u32 k; 712 for (k = 0; k < l->ndefsyms; ++k) { 713 const KitLinkDefsym* d = &l->defsyms[k]; 714 Sym dn; 715 if (!d->name.s || d->name.len == 0) continue; 716 dn = pool_intern_slice(l->c->global, 717 (Slice){.s = d->name.s, .len = d->name.len}); 718 if (dn == s->name) { 719 is_defsym = 1; 720 break; 721 } 722 } 723 if (is_defsym) continue; 724 } 725 { 726 Slice nm_s = s->name ? pool_slice(l->c->global, s->name) : SLICE_NULL; 727 const char* nm = nm_s.s ? nm_s.s : ""; 728 size_t namelen = nm_s.len; 729 obj_format_demangle_c(l->c, &nm, &namelen); 730 compiler_panic(l->c, SRCLOC_NONE, "link: undefined reference to '%.*s'", 731 (int)namelen, nm); 732 } 733 } 734 symhash_fini(&dso_exports); 735 symhash_fini(&alias_map); 736 } 737 738 /* ---- pass 1b: --gc-sections liveness ---- */ 739 740 #define GC_ATOM_BIT 0x80000000u 741 #define GC_PACK(ii, j, is_atom) \ 742 (((u64)(u32)(ii) << 32) | ((is_atom) ? GC_ATOM_BIT : 0u) | (u32)(j)) 743 #define GC_II(p) ((u32)((p) >> 32)) 744 #define GC_IS_ATOM(p) (((u32)(p) & GC_ATOM_BIT) != 0) 745 #define GC_J(p) ((u32)((p) & ~GC_ATOM_BIT)) 746 747 static void gc_queue_push(GcQueue* q, Heap* h, u32 ii, u32 j, int is_atom) { 748 if (VEC_GROW(h, q->items, q->cap, q->n + 1u)) return; 749 q->items[q->n++] = GC_PACK(ii, j, is_atom); 750 } 751 752 void link_gc_live_alloc(GcLive* g, Linker* l, Heap* h) { 753 u32 ii; 754 g->ninputs = LinkInputs_count(&l->inputs); 755 g->marks = 756 LinkInputs_count(&l->inputs) 757 ? (u8**)h->alloc(h, sizeof(*g->marks) * LinkInputs_count(&l->inputs), 758 _Alignof(u8*)) 759 : NULL; 760 g->atom_marks = 761 LinkInputs_count(&l->inputs) 762 ? (u8**)h->alloc( 763 h, sizeof(*g->atom_marks) * LinkInputs_count(&l->inputs), 764 _Alignof(u8*)) 765 : NULL; 766 g->nsec = 767 LinkInputs_count(&l->inputs) 768 ? (u32*)h->alloc(h, sizeof(*g->nsec) * LinkInputs_count(&l->inputs), 769 _Alignof(u32)) 770 : NULL; 771 g->natom = 772 LinkInputs_count(&l->inputs) 773 ? (u32*)h->alloc(h, sizeof(*g->natom) * LinkInputs_count(&l->inputs), 774 _Alignof(u32)) 775 : NULL; 776 if (LinkInputs_count(&l->inputs) && 777 (!g->marks || !g->atom_marks || !g->nsec || !g->natom)) 778 compiler_panic(l->c, SRCLOC_NONE, "link: oom on gc live map"); 779 for (ii = 0; ii < LinkInputs_count(&l->inputs); ++ii) { 780 u32 nsec = obj_section_count(LinkInputs_at(&l->inputs, ii)->obj); 781 u32 natom = obj_atom_count(LinkInputs_at(&l->inputs, ii)->obj); 782 g->nsec[ii] = nsec; 783 g->natom[ii] = natom; 784 g->marks[ii] = (u8*)h->alloc(h, nsec ? nsec : 1u, 1); 785 if (!g->marks[ii]) 786 compiler_panic(l->c, SRCLOC_NONE, "link: oom on gc marks"); 787 memset(g->marks[ii], 0, nsec); 788 g->atom_marks[ii] = (u8*)h->alloc(h, natom ? natom : 1u, 1); 789 if (!g->atom_marks[ii]) 790 compiler_panic(l->c, SRCLOC_NONE, "link: oom on gc atom marks"); 791 memset(g->atom_marks[ii], 0, natom); 792 } 793 } 794 795 void link_gc_live_free(GcLive* g, Heap* h) { 796 u32 ii; 797 if (g->marks) { 798 for (ii = 0; ii < g->ninputs; ++ii) 799 if (g->marks[ii]) 800 h->free(h, g->marks[ii], g->nsec[ii] ? g->nsec[ii] : 1u); 801 h->free(h, g->marks, sizeof(*g->marks) * g->ninputs); 802 } 803 if (g->atom_marks) { 804 for (ii = 0; ii < g->ninputs; ++ii) 805 if (g->atom_marks[ii]) 806 h->free(h, g->atom_marks[ii], g->natom[ii] ? g->natom[ii] : 1u); 807 h->free(h, g->atom_marks, sizeof(*g->atom_marks) * g->ninputs); 808 } 809 if (g->nsec) h->free(h, g->nsec, sizeof(*g->nsec) * g->ninputs); 810 if (g->natom) h->free(h, g->natom, sizeof(*g->natom) * g->ninputs); 811 } 812 813 int link_gc_live_get(const GcLive* g, u32 ii, ObjSecId j) { 814 if (ii >= g->ninputs || j == OBJ_SEC_NONE || j >= g->nsec[ii]) return 0; 815 return g->marks[ii][j]; 816 } 817 818 int link_gc_atom_live_get(const GcLive* g, u32 ii, ObjAtomId j) { 819 if (ii >= g->ninputs || j == OBJ_ATOM_NONE || j >= g->natom[ii]) return 0; 820 return g->atom_marks[ii][j]; 821 } 822 823 static void gc_mark(GcLive* g, GcQueue* q, Heap* h, u32 ii, ObjSecId j) { 824 if (ii >= g->ninputs || j == OBJ_SEC_NONE || j >= g->nsec[ii]) return; 825 if (g->marks[ii][j]) return; 826 g->marks[ii][j] = 1; 827 if (q) gc_queue_push(q, h, ii, j, 0); 828 } 829 830 static void gc_mark_atom(GcLive* g, GcQueue* q, Heap* h, u32 ii, ObjAtomId j) { 831 if (ii >= g->ninputs || j == OBJ_ATOM_NONE || j >= g->natom[ii]) return; 832 if (g->atom_marks[ii][j]) return; 833 g->atom_marks[ii][j] = 1; 834 if (q) gc_queue_push(q, h, ii, j, 1); 835 } 836 837 static void gc_mark_section_or_atoms(GcLive* g, GcQueue* q, Heap* h, 838 ObjBuilder* ob, const InputMap* m, u32 ii, 839 ObjSecId sid) { 840 u32 first, count, i; 841 int marked = 0; 842 if (!link_input_section_has_atoms(m, sid)) { 843 gc_mark(g, q, h, ii, sid); 844 return; 845 } 846 link_input_section_atoms(m, sid, &first, &count); 847 for (i = 0; i < count; ++i) { 848 ObjAtomId aid = m->section_atom_ids[first + i]; 849 const ObjAtom* a = obj_atom_get(ob, aid); 850 if (!a || a->removed) continue; 851 gc_mark_atom(g, q, h, ii, aid); 852 marked = 1; 853 } 854 if (!marked) gc_mark(g, q, h, ii, sid); 855 } 856 857 /* From a LinkSymId, find the (input_idx, obj_sec_id) of its defining section. 858 * Returns 1 on hit. */ 859 static int gc_def_site(LinkImage* img, Linker* l, LinkSymId id, u32* out_ii, 860 ObjSecId* out_sid, ObjAtomId* out_aid) { 861 const LinkSymbol* s; 862 ObjBuilder* ob; 863 const ObjSym* osym; 864 if (id == LINK_SYM_NONE || id > LinkSyms_count(&img->syms)) return 0; 865 s = LinkSyms_at(&img->syms, id - 1); 866 if (!s->defined) { 867 LinkSymId hit; 868 if (s->name == 0) return 0; 869 hit = symhash_get(&img->globals, s->name); 870 if (hit == LINK_SYM_NONE || hit == s->id) return 0; 871 return gc_def_site(img, l, hit, out_ii, out_sid, out_aid); 872 } 873 if (s->kind == SK_ABS || s->kind == SK_COMMON) return 0; 874 if (s->input_id == LINK_INPUT_NONE) return 0; 875 ob = LinkInputs_at(&l->inputs, s->input_id - 1)->obj; 876 osym = obj_symbol_get(ob, s->obj_sym); 877 if (!osym || osym->section_id == OBJ_SEC_NONE) return 0; 878 *out_ii = (u32)(s->input_id - 1u); 879 *out_sid = osym->section_id; 880 *out_aid = link_input_sym_atom(&img->input_maps[*out_ii], s->obj_sym); 881 return 1; 882 } 883 884 /* Detect __start_<X> / __stop_<X> with <X> a valid C identifier. */ 885 int link_gc_split_start_stop(const char* s, size_t n, size_t* out_off, 886 size_t* out_len, int* out_is_start) { 887 static const char START[] = "__start_"; 888 static const char STOP[] = "__stop_"; 889 size_t off, len, i; 890 int is_start; 891 if (n > sizeof(START) - 1u && memcmp(s, START, sizeof(START) - 1u) == 0) { 892 off = sizeof(START) - 1u; 893 is_start = 1; 894 } else if (n > sizeof(STOP) - 1u && memcmp(s, STOP, sizeof(STOP) - 1u) == 0) { 895 off = sizeof(STOP) - 1u; 896 is_start = 0; 897 } else { 898 return 0; 899 } 900 len = n - off; 901 if (len == 0) return 0; 902 { 903 char c = s[off]; 904 if (!(c == '_' || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))) 905 return 0; 906 } 907 for (i = 1; i < len; ++i) { 908 char c = s[off + i]; 909 if (!(c == '_' || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || 910 (c >= '0' && c <= '9'))) 911 return 0; 912 } 913 *out_off = off; 914 *out_len = len; 915 if (out_is_start) *out_is_start = is_start; 916 return 1; 917 } 918 919 static void gc_promote_by_section_name(Linker* l, LinkImage* img, GcLive* g, 920 GcQueue* q, Heap* h, Sym section_name) { 921 u32 ii, j; 922 for (ii = 0; ii < LinkInputs_count(&l->inputs); ++ii) { 923 ObjBuilder* ob = LinkInputs_at(&l->inputs, ii)->obj; 924 u32 nsec = obj_section_count(ob); 925 for (j = 1; j < nsec; ++j) { 926 const Section* s = obj_section_get(ob, j); 927 if (!s || !link_section_kept(s)) continue; 928 if (s->name != section_name) continue; 929 gc_mark_section_or_atoms(g, q, h, ob, &img->input_maps[ii], ii, j); 930 } 931 } 932 } 933 934 static int gc_match_glob(const char* pat, const char* name) { 935 size_t plen, nlen; 936 if (!pat || !name) return 0; 937 plen = slice_from_cstr(pat).len; 938 nlen = slice_from_cstr(name).len; 939 if (plen == 1 && pat[0] == '*') return 1; 940 if (plen >= 2 && pat[plen - 1] == '*') { 941 if (nlen + 1 < plen) return 0; 942 return memcmp(pat, name, plen - 1) == 0; 943 } 944 if (plen >= 2 && pat[0] == '*') { 945 if (nlen + 1 < plen) return 0; 946 return memcmp(pat + 1, name + (nlen - (plen - 1)), plen - 1) == 0; 947 } 948 return plen == nlen && memcmp(pat, name, plen) == 0; 949 } 950 951 static const char* gc_basename(const char* s) { 952 const char* base = s; 953 if (!s) return NULL; 954 for (; *s; ++s) 955 if (*s == '/' || *s == '\\') base = s + 1; 956 return base; 957 } 958 959 static int gc_match_input_name(Linker* l, u32 ii, 960 const KitLinkInputMatch* m) { 961 const LinkInput* in; 962 Slice nm = SLICE_NULL; 963 const char* full; 964 const char* base; 965 u32 i; 966 if (!m->file_pattern.s && m->nexclude_file_patterns == 0) return 1; 967 in = LinkInputs_at(&l->inputs, ii); 968 if (in->name) nm = pool_slice(l->c->global, in->name); 969 full = nm.s; 970 base = gc_basename(full); 971 if (m->file_pattern.s) { 972 if (!full) return 0; 973 if (!gc_match_glob(m->file_pattern.s, full) && 974 !gc_match_glob(m->file_pattern.s, base)) 975 return 0; 976 } 977 for (i = 0; i < m->nexclude_file_patterns; ++i) { 978 const char* pat = m->exclude_file_patterns[i].s; 979 if (!pat || !full) continue; 980 if (gc_match_glob(pat, full) || gc_match_glob(pat, base)) return 0; 981 } 982 return 1; 983 } 984 985 static void gc_mark_script_keep_roots(Linker* l, LinkImage* img, GcLive* g, 986 GcQueue* q, Heap* h) { 987 u32 si, mi, ii, j; 988 if (!l->script) return; 989 for (si = 0; si < l->script->nsections; ++si) { 990 const KitLinkOutputSection* os = &l->script->sections[si]; 991 for (mi = 0; mi < os->ninputs; ++mi) { 992 const KitLinkInputMatch* im = &os->inputs[mi]; 993 if (!im->keep) continue; 994 for (ii = 0; ii < LinkInputs_count(&l->inputs); ++ii) { 995 ObjBuilder* ob = LinkInputs_at(&l->inputs, ii)->obj; 996 InputMap* m = &img->input_maps[ii]; 997 if (!gc_match_input_name(l, ii, im)) continue; 998 for (j = 1; j < obj_section_count(ob); ++j) { 999 const Section* s = obj_section_get(ob, j); 1000 Slice sn; 1001 if (!s || !link_section_kept(s)) continue; 1002 if (m->comdat_discarded[j]) continue; 1003 sn = pool_slice(l->c->global, s->name); 1004 if (!gc_match_glob(im->section_pattern.s, sn.s)) continue; 1005 gc_mark_section_or_atoms(g, q, h, ob, m, ii, j); 1006 } 1007 } 1008 } 1009 } 1010 } 1011 1012 static void gc_mark_script_extern_roots(Linker* l, LinkImage* img, GcLive* g, 1013 GcQueue* q, Heap* h) { 1014 u32 i; 1015 if (!l->script) return; 1016 for (i = 0; i < l->script->nexterns; ++i) { 1017 Sym name = pool_intern_slice(l->c->global, l->script->externs[i]); 1018 LinkSymId id = symhash_get(&img->globals, name); 1019 u32 tii; 1020 ObjSecId tsid; 1021 ObjAtomId taid; 1022 if (gc_def_site(img, l, id, &tii, &tsid, &taid)) { 1023 if (taid != OBJ_ATOM_NONE) 1024 gc_mark_atom(g, q, h, tii, taid); 1025 else 1026 gc_mark(g, q, h, tii, tsid); 1027 } 1028 } 1029 } 1030 1031 void link_gc_compute(Linker* l, LinkImage* img, GcLive* g) { 1032 u32 ii, j, k; 1033 GcQueue q; 1034 Heap* h = img->heap; 1035 1036 if (!l->gc_sections) { 1037 for (ii = 0; ii < LinkInputs_count(&l->inputs); ++ii) { 1038 ObjBuilder* ob = LinkInputs_at(&l->inputs, ii)->obj; 1039 InputMap* m = &img->input_maps[ii]; 1040 u32 nsec = obj_section_count(ob); 1041 for (j = 1; j < nsec; ++j) { 1042 const Section* s = obj_section_get(ob, j); 1043 if (s && link_section_kept(s) && !m->comdat_discarded[j]) 1044 gc_mark_section_or_atoms(g, NULL, h, ob, m, ii, j); 1045 } 1046 } 1047 return; 1048 } 1049 1050 memset(&q, 0, sizeof(q)); 1051 1052 for (ii = 0; ii < LinkInputs_count(&l->inputs); ++ii) { 1053 ObjBuilder* ob = LinkInputs_at(&l->inputs, ii)->obj; 1054 InputMap* m = &img->input_maps[ii]; 1055 u32 nsec = obj_section_count(ob); 1056 for (j = 1; j < nsec; ++j) { 1057 const Section* s = obj_section_get(ob, j); 1058 int root; 1059 if (!s || !link_section_kept(s)) continue; 1060 if (m->comdat_discarded[j]) continue; 1061 root = (s->flags & SF_RETAIN) || s->sem == SSEM_INIT_ARRAY || 1062 s->sem == SSEM_FINI_ARRAY || s->sem == SSEM_PREINIT_ARRAY; 1063 if (root) gc_mark_section_or_atoms(g, &q, h, ob, m, ii, j); 1064 if (link_input_section_has_atoms(m, j)) { 1065 u32 first, count, ai; 1066 link_input_section_atoms(m, j, &first, &count); 1067 for (ai = 0; ai < count; ++ai) { 1068 ObjAtomId aid = m->section_atom_ids[first + ai]; 1069 const ObjAtom* a = obj_atom_get(ob, aid); 1070 if (!a || a->removed) continue; 1071 if (a->flags & OBJ_ATOM_RETAIN) gc_mark_atom(g, &q, h, ii, aid); 1072 } 1073 } 1074 } 1075 } 1076 1077 if (l->entry_name != 0) { 1078 LinkSymId id = symhash_get(&img->globals, l->entry_name); 1079 u32 tii; 1080 ObjSecId tsid; 1081 ObjAtomId taid; 1082 if (gc_def_site(img, l, id, &tii, &tsid, &taid)) { 1083 if (taid != OBJ_ATOM_NONE) 1084 gc_mark_atom(g, &q, h, tii, taid); 1085 else 1086 gc_mark(g, &q, h, tii, tsid); 1087 } 1088 } 1089 1090 gc_mark_script_extern_roots(l, img, g, &q, h); 1091 gc_mark_script_keep_roots(l, img, g, &q, h); 1092 1093 /* Keep executable definitions that a linked shared library references but 1094 * nothing in the executable does (e.g. FreeBSD libc.so.7's back-references 1095 * to crt-defined `environ` / `__progname`). Without rooting these, GC drops 1096 * the defining section and the resulting dynamic exe fails to load 1097 * ("Undefined symbol"). read_elf_dso records each DSO's undef names. */ 1098 for (ii = 0; ii < LinkInputs_count(&l->inputs); ++ii) { 1099 LinkInput* in = LinkInputs_at(&l->inputs, ii); 1100 const ObjImage* dim; 1101 u32 u, nu; 1102 if (in->kind != LINK_INPUT_DSO_BYTES || !in->obj) continue; 1103 dim = obj_image(in->obj); 1104 nu = obj_image_nundefs(dim); 1105 for (u = 0; u < nu; ++u) { 1106 LinkSymId id = symhash_get(&img->globals, obj_image_undef(dim, u)); 1107 u32 tii; 1108 ObjSecId tsid; 1109 ObjAtomId taid; 1110 if (id == LINK_SYM_NONE) continue; 1111 if (gc_def_site(img, l, id, &tii, &tsid, &taid)) { 1112 if (taid != OBJ_ATOM_NONE) 1113 gc_mark_atom(g, &q, h, tii, taid); 1114 else 1115 gc_mark(g, &q, h, tii, tsid); 1116 } 1117 } 1118 } 1119 1120 while (q.n > 0) { 1121 u64 v = q.items[--q.n]; 1122 u32 cii = GC_II(v); 1123 int c_is_atom = GC_IS_ATOM(v); 1124 ObjSecId cj = (ObjSecId)GC_J(v); 1125 ObjBuilder* ob = LinkInputs_at(&l->inputs, cii)->obj; 1126 InputMap* m = &img->input_maps[cii]; 1127 const ObjAtom* src_atom = 1128 c_is_atom ? obj_atom_get(ob, (ObjAtomId)cj) : NULL; 1129 ObjSecId src_sec = src_atom ? src_atom->section_id : cj; 1130 u32 total = obj_reloc_total(ob); 1131 (void)obj_section_count; 1132 if (!total) continue; 1133 for (k = 0; k < total; ++k) { 1134 const Reloc* r = obj_reloc_at(ob, k); 1135 LinkSymId target; 1136 const LinkSymbol* tsym; 1137 u32 tii; 1138 ObjSecId tsid; 1139 ObjAtomId taid; 1140 if (r->section_id != src_sec) continue; 1141 if (src_atom) { 1142 u64 begin = src_atom->offset; 1143 u64 end = begin + src_atom->size; 1144 if ((u64)r->offset < begin || (u64)r->offset >= end) continue; 1145 } 1146 if (r->sym == OBJ_SYM_NONE || r->sym >= m->nsym) continue; 1147 target = m->sym[r->sym]; 1148 if (target == LINK_SYM_NONE) continue; 1149 tsym = LinkSyms_at(&img->syms, target - 1); 1150 1151 if (tsym->name != 0) { 1152 size_t off, ilen; 1153 Slice nm_s = pool_slice(l->c->global, tsym->name); 1154 const char* nm = nm_s.s; 1155 size_t namelen = nm_s.len; 1156 if (link_gc_split_start_stop(nm, namelen, &off, &ilen, NULL)) { 1157 Sym secname = pool_intern_slice(l->c->global, 1158 (Slice){.s = nm + off, .len = ilen}); 1159 gc_promote_by_section_name(l, img, g, &q, h, secname); 1160 } 1161 } 1162 1163 if (gc_def_site(img, l, target, &tii, &tsid, &taid)) { 1164 if (taid != OBJ_ATOM_NONE) 1165 gc_mark_atom(g, &q, h, tii, taid); 1166 else 1167 gc_mark(g, &q, h, tii, tsid); 1168 } 1169 } 1170 } 1171 1172 if (q.items) h->free(h, q.items, sizeof(*q.items) * q.cap); 1173 } 1174 1175 void link_gc_drop_dead_globals(Linker* l, LinkImage* img, const GcLive* g) { 1176 u32 i; 1177 if (!l->gc_sections) return; 1178 for (i = 0; i < LinkSyms_count(&img->syms); ++i) { 1179 LinkSymbol* s = LinkSyms_at(&img->syms, i); 1180 ObjBuilder* ob; 1181 const ObjSym* osym; 1182 ObjSecId osid; 1183 ObjAtomId aid; 1184 if (!s->defined) continue; 1185 if (s->kind == SK_ABS || s->kind == SK_COMMON) continue; 1186 if (s->input_id == LINK_INPUT_NONE) continue; 1187 ob = LinkInputs_at(&l->inputs, s->input_id - 1)->obj; 1188 osym = obj_symbol_get(ob, s->obj_sym); 1189 if (!osym) continue; 1190 osid = osym->section_id; 1191 if (osid == OBJ_SEC_NONE) continue; 1192 aid = link_input_sym_atom(&img->input_maps[s->input_id - 1u], s->obj_sym); 1193 if (aid != OBJ_ATOM_NONE) { 1194 if (link_gc_atom_live_get(g, (u32)(s->input_id - 1u), aid)) continue; 1195 s->defined = 0; 1196 s->vaddr = 0; 1197 s->section_id = LINK_SEC_NONE; 1198 continue; 1199 } 1200 if (link_gc_live_get(g, (u32)(s->input_id - 1u), osid)) continue; 1201 s->defined = 0; 1202 s->vaddr = 0; 1203 s->section_id = LINK_SEC_NONE; 1204 } 1205 } 1206 1207 /* ---- archive ingestion ---- */ 1208 1209 static void include_archive_member(Linker* l, const LinkArchive* ar, 1210 LinkArchiveMember* mem) { 1211 LinkInput* in; 1212 LinkInputId id; 1213 u32 idx; 1214 Sym coff_dll = 0; 1215 if (mem->included) return; 1216 if (mem->obj) 1217 link_merge_elf_e_flags( 1218 l, mem->obj, 1219 mem->name ? pool_slice(l->c->global, mem->name) 1220 : SLICE_LIT("<unnamed archive member>")); 1221 in = LinkInputs_push(&l->inputs, &idx); 1222 if (!in) 1223 compiler_panic(l->c, SRCLOC_NONE, 1224 "link: oom growing inputs (archive member)"); 1225 id = (LinkInputId)(idx + 1u); 1226 in->id = id; 1227 /* PE/COFF short-import shim: read_coff_short_import stashes the 1228 * providing DLL name on the ObjBuilder. Such members behave like 1229 * DSO inputs — symbols are exports, not local definitions — so route 1230 * through LINK_INPUT_DSO_BYTES with the DLL name as the soname. */ 1231 if (mem->obj && obj_get_coff_import_dll(mem->obj, &coff_dll) && coff_dll) { 1232 in->kind = LINK_INPUT_DSO_BYTES; 1233 in->soname = coff_dll; 1234 /* Short-import NameType may make the DLL export name differ from the 1235 * local symbol name (EXPORTAS etc.); carry it for import-table synthesis. 1236 */ 1237 { 1238 Sym coff_imp_name = 0; 1239 if (obj_get_coff_import_name(mem->obj, &coff_imp_name)) 1240 in->coff_import_name = coff_imp_name; 1241 } 1242 } else { 1243 in->kind = LINK_INPUT_OBJ_BYTES; 1244 } 1245 in->order = ar->order; 1246 in->obj = mem->obj; 1247 in->name = mem->name; 1248 mem->included = 1; 1249 mem->obj = NULL; 1250 } 1251 1252 static void scan_presence_before(Linker* l, u32 max_order, SymHash* defined, 1253 SymHash* undefs) { 1254 u32 ii; 1255 ObjSymIter* it; 1256 ObjSymEntry e; 1257 for (ii = 0; ii < LinkInputs_count(&l->inputs); ++ii) { 1258 LinkInput* in = LinkInputs_at(&l->inputs, ii); 1259 ObjBuilder* ob = in->obj; 1260 int is_dso = (in->kind == LINK_INPUT_DSO_BYTES); 1261 if (!ob || in->order > max_order) continue; 1262 it = obj_symiter_new(ob); 1263 while (obj_symiter_next(it, &e)) { 1264 const ObjSym* s = e.sym; 1265 if (s->name == 0) continue; 1266 if (s->bind == SB_LOCAL) continue; 1267 if (is_dso) { 1268 /* A DSO's exported symbols satisfy undefined references, so a later 1269 * static-archive member must NOT be pulled to redefine them. kit 1270 * records DSO exports as OBJ_SEC_NONE globals (the importer's view), 1271 * which obj_sym_is_logical_undef would otherwise misclassify as 1272 * undefined — leaving e.g. a real libc's atoi looking unsatisfied and 1273 * letting the freestanding rt's atoi shadow it. The DSO's own undefs 1274 * (SK_UNDEF) are not exports and stay out of `defined`. */ 1275 if (s->kind != SK_UNDEF) symhash_set(defined, s->name, 1u); 1276 continue; 1277 } 1278 /* An unreferenced global/weak extern declaration is a header 1279 * artifact, not a real demand to pull from an archive. Without 1280 * this prune the C frontend's per-extern undef synthesis (e.g. 1281 * every prototype in <math.h>) drags in matching archive members 1282 * even when the user's source never references them. Matches the 1283 * spurious-UNDEF prune in link_resolve_symbols and obj_sweep_dead 1284 * at .o emit (obj.c). */ 1285 if (link_sym_is_spurious_undef(s)) continue; 1286 if (obj_sym_is_logical_undef(s)) 1287 symhash_set(undefs, s->name, 1u); 1288 else 1289 symhash_set(defined, s->name, 1u); 1290 } 1291 obj_symiter_free(it); 1292 } 1293 } 1294 1295 static int inputs_have_defined_ifunc_before(Linker* l, u32 max_order) { 1296 u32 ii; 1297 ObjSymIter* it; 1298 ObjSymEntry e; 1299 for (ii = 0; ii < LinkInputs_count(&l->inputs); ++ii) { 1300 LinkInput* in = LinkInputs_at(&l->inputs, ii); 1301 ObjBuilder* ob = in->obj; 1302 if (!ob || in->order > max_order) continue; 1303 it = obj_symiter_new(ob); 1304 while (obj_symiter_next(it, &e)) { 1305 const ObjSym* s = e.sym; 1306 if (s->kind == SK_IFUNC) { 1307 obj_symiter_free(it); 1308 return 1; 1309 } 1310 } 1311 obj_symiter_free(it); 1312 } 1313 return 0; 1314 } 1315 1316 static int member_satisfies(LinkArchiveMember* mem, const SymHash* defined, 1317 const SymHash* wanted, int weak_undef_pulls) { 1318 ObjSymIter* it; 1319 ObjSymEntry e; 1320 int hit = 0; 1321 it = obj_symiter_new(mem->obj); 1322 while (obj_symiter_next(it, &e)) { 1323 const ObjSym* s = e.sym; 1324 if (s->name == 0) continue; 1325 /* In COFF archives, WEAK_EXTERNAL alias declarations are read as 1326 * SB_WEAK + SK_UNDEF (kit has no native alias model — see 1327 * coff_read.c step "WEAK_EXTERNAL primary"). The archive's symbol 1328 * map still lists the member as the canonical provider of that 1329 * name, so treat such weak undefs as defining for the archive-pull 1330 * decision (formats whose COMDAT semantics pull on a weak undef — 1331 * obj_format_weak_undef_pulls_archive_member). The actual 1332 * alias-to-target resolution happens later in link_resolve_undefs. */ 1333 if (s->kind == SK_UNDEF) { 1334 if (!(weak_undef_pulls && s->bind == SB_WEAK)) continue; 1335 } 1336 if (s->bind != SB_GLOBAL && s->bind != SB_WEAK) continue; 1337 if (symhash_get(wanted, s->name) == LINK_SYM_NONE) continue; 1338 if (symhash_get(defined, s->name) != LINK_SYM_NONE) continue; 1339 hit = 1; 1340 break; 1341 } 1342 obj_symiter_free(it); 1343 return hit; 1344 } 1345 1346 static int scan_archive_once(Linker* l, LinkArchive* ar, u32 max_order, 1347 Sym want_ifunc_init, int weak_undef_pulls) { 1348 SymHash defined, undefs; 1349 int changed = 0; 1350 u32 m; 1351 symhash_init(&defined, l->heap); 1352 symhash_init(&undefs, l->heap); 1353 scan_presence_before(l, max_order, &defined, &undefs); 1354 if (want_ifunc_init != 0 && 1355 symhash_get(&defined, want_ifunc_init) == LINK_SYM_NONE) 1356 symhash_set(&undefs, want_ifunc_init, 1u); 1357 if (l->script && l->script->externs) { 1358 u32 ei; 1359 for (ei = 0; ei < l->script->nexterns; ++ei) { 1360 Sym ex = pool_intern_slice(l->c->global, l->script->externs[ei]); 1361 if (symhash_get(&defined, ex) == LINK_SYM_NONE) 1362 symhash_set(&undefs, ex, 1u); 1363 } 1364 } 1365 1366 for (m = 0; m < ar->nmembers; ++m) { 1367 LinkArchiveMember* mem = &ar->members[m]; 1368 if (mem->included) continue; 1369 if (!mem->obj) continue; /* long-form skip (head/trailer) */ 1370 if (!member_satisfies(mem, &defined, &undefs, weak_undef_pulls)) continue; 1371 include_archive_member(l, ar, mem); 1372 changed = 1; 1373 } 1374 symhash_fini(&defined); 1375 symhash_fini(&undefs); 1376 return changed; 1377 } 1378 1379 /* Synthesize an ObjBuilder providing the mingw CRT ctor/dtor list 1380 * boundary symbols (`__CTOR_LIST__`, `__CTOR_END__`, `__DTOR_LIST__`, 1381 * `__DTOR_END__`) backed by a 16-byte zero blob. mingw's gccmain.o 1382 * references these and walks them at program startup; lld/binutils 1383 * generate them via the linker script's `.ctors` / `.dtors` rules. 1384 * kit has no script for PE, so we inject an equivalent here. 1385 * 1386 * Zero contents are intentional for the empty-list case: 1387 * - __do_global_ctors loads `*(u32*)__CTOR_LIST__`; sees 0; cbz 1388 * short-circuit returns without iterating. 1389 * - __do_global_dtors loads `*(u64*)__DTOR_LIST__`; sees 0; cbz 1390 * short-circuit returns. 1391 * 1392 * For programs that emit real ctor/dtor sections this synth would 1393 * need to coordinate with .ctors/.dtors layout; v1 covers the empty 1394 * case (hello-world through mingw CRT). */ 1395 /* Registered as the COFF format's synth_inputs hook (src/obj/registry.c), so 1396 * it is only ever invoked for COFF targets — no obj==COFF guard needed. */ 1397 void link_synth_coff_ctor_dtor_list(Linker* l) { 1398 ObjBuilder* ob; 1399 ObjSecId sid; 1400 static const u8 kZeros[16] = {0}; 1401 LinkInput* in; 1402 u32 idx; 1403 if (!l) return; 1404 ob = obj_new(l->c); 1405 if (!ob) return; 1406 sid = obj_section_ex( 1407 ob, pool_intern_slice(l->c->global, SLICE_LIT(".rdata$ctors")), 1408 SEC_RODATA, SSEM_PROGBITS, SF_ALLOC | SF_RETAIN, 16, 0u, 0u, 0u); 1409 obj_section_replace_bytes(ob, sid, kZeros, sizeof(kZeros)); 1410 obj_symbol_ex(ob, pool_intern_slice(l->c->global, SLICE_LIT("__CTOR_LIST__")), 1411 SB_GLOBAL, SV_DEFAULT, SK_OBJ, sid, 0, 0, 0); 1412 obj_symbol_ex(ob, pool_intern_slice(l->c->global, SLICE_LIT("__CTOR_END__")), 1413 SB_GLOBAL, SV_DEFAULT, SK_OBJ, sid, 0, 0, 0); 1414 obj_symbol_ex(ob, pool_intern_slice(l->c->global, SLICE_LIT("__DTOR_LIST__")), 1415 SB_GLOBAL, SV_DEFAULT, SK_OBJ, sid, 0, 0, 0); 1416 obj_symbol_ex(ob, pool_intern_slice(l->c->global, SLICE_LIT("__DTOR_END__")), 1417 SB_GLOBAL, SV_DEFAULT, SK_OBJ, sid, 0, 0, 0); 1418 /* __chkstk: synthesized only for arches whose link descriptor carries the 1419 * stub bytes (aarch64). x64 needs none — its codegen emits inline probes (or 1420 * links libmingwex's plain-object __chkstk). Driven by the descriptor, so no 1421 * arch identity is consulted here. */ 1422 { 1423 const LinkArchDesc* la = link_arch_desc_for(l->c); 1424 if (la && la->coff_chkstk_bytes && la->coff_chkstk_len) { 1425 ObjSecId tsid = obj_section_ex( 1426 ob, pool_intern_slice(l->c->global, SLICE_LIT(".text$chkstk")), 1427 SEC_TEXT, SSEM_PROGBITS, SF_ALLOC | SF_EXEC | SF_RETAIN, 4, 0u, 0u, 1428 0u); 1429 obj_section_replace_bytes(ob, tsid, la->coff_chkstk_bytes, 1430 la->coff_chkstk_len); 1431 obj_symbol_ex(ob, pool_intern_slice(l->c->global, SLICE_LIT("__chkstk")), 1432 SB_GLOBAL, SV_DEFAULT, SK_FUNC, tsid, 0, 1433 la->coff_chkstk_len, 0); 1434 } 1435 } 1436 obj_finalize(ob); 1437 in = LinkInputs_push(&l->inputs, &idx); 1438 if (!in) 1439 compiler_panic(l->c, SRCLOC_NONE, "link: oom growing inputs (synth)"); 1440 in->id = (LinkInputId)(idx + 1u); 1441 in->kind = LINK_INPUT_OBJ_BYTES; 1442 in->order = l->next_input_order++; 1443 in->obj = ob; 1444 in->name = 1445 pool_intern_slice(l->c->global, SLICE_LIT("<kit-synth-coff-runtime>")); 1446 in->soname = 0; 1447 } 1448 1449 void link_ingest_archives(Linker* l) { 1450 u32 a, m; 1451 int weak_undef_pulls; 1452 if (LinkArchives_count(&l->archives) == 0) return; 1453 weak_undef_pulls = obj_format_weak_undef_pulls_archive_member(l->c); 1454 1455 for (a = 0; a < LinkArchives_count(&l->archives); ++a) { 1456 LinkArchive* ar = LinkArchives_at(&l->archives, a); 1457 if (!ar->whole_archive) continue; 1458 for (m = 0; m < ar->nmembers; ++m) { 1459 /* obj==NULL is the long-form COFF head/trailer skip path 1460 * (set by link_add_archive_bytes). Drop them silently. */ 1461 if (!ar->members[m].obj) continue; 1462 include_archive_member(l, ar, &ar->members[m]); 1463 } 1464 } 1465 1466 if (obj_format_global_archive_fixpoint(l->c)) { 1467 for (;;) { 1468 int changed = 0; 1469 for (a = 0; a < LinkArchives_count(&l->archives); ++a) { 1470 LinkArchive* ar = LinkArchives_at(&l->archives, a); 1471 if (ar->whole_archive) continue; 1472 changed |= scan_archive_once(l, ar, ~0u, 0, weak_undef_pulls); 1473 } 1474 if (!changed) break; 1475 } 1476 return; 1477 } 1478 1479 for (a = 0; a < LinkArchives_count(&l->archives); ++a) { 1480 LinkArchive* ar = LinkArchives_at(&l->archives, a); 1481 Sym want_ifunc_init = 0; 1482 if (ar->whole_archive) continue; 1483 if (l->emit_static_exe && inputs_have_defined_ifunc_before(l, ar->order)) 1484 want_ifunc_init = 1485 pool_intern_slice(l->c->global, SLICE_LIT("__kit_ifunc_init")); 1486 for (;;) { 1487 if (!scan_archive_once(l, ar, ar->order, want_ifunc_init, 1488 weak_undef_pulls)) 1489 break; 1490 } 1491 } 1492 }