link.c (50334B)
1 /* Public link API entries. 2 * 3 * Thin orchestrators over the Linker primitives in link.c / link_resolve.c / 4 * link_layout.c / link_jit.c. Each entry: 5 * - allocates a Linker against the caller's Compiler, 6 * - feeds in the KitLinkInputs, 7 * - configures lane-specific flags (pie, shared, jit), 8 * - calls link_resolve, 9 * - dispatches to the emit (writer) or JIT-map (kit_jit_from_image) tail. 10 * 11 * The driver's job ends at populating KitLinkInputs; everything below this 12 * line is libkit-internal. */ 13 14 #include "link/link.h" 15 16 #include <kit/core.h> 17 #include <kit/jit.h> 18 #include <kit/link.h> 19 #include <kit/target.h> 20 #include <setjmp.h> 21 #include <stdarg.h> 22 #include <stdio.h> 23 #include <string.h> 24 25 #include "cg/internal.h" 26 #include "cg/ir_recorder.h" 27 #include "core/core.h" 28 #include "core/diag.h" 29 #include "link/link_internal.h" 30 31 KitJit* kit_jit_from_image(LinkImage*); 32 33 static KitStatus link_session_guard(KitLinkSession* s, 34 void (*fn)(KitLinkSession*, void*), 35 void* arg) { 36 PanicFrame panic; 37 if (!s || !s->c || !s->linker || !fn) return KIT_INVALID; 38 compiler_panic_push(s->c, &panic); 39 if (setjmp(panic.env)) { 40 compiler_run_cleanups(s->c); 41 s->linker = NULL; 42 s->image = NULL; 43 compiler_panic_pop(s->c, &panic); 44 return KIT_ERR; 45 } 46 fn(s, arg); 47 compiler_panic_pop(s->c, &panic); 48 return KIT_OK; 49 } 50 51 static KitStatus link_session_remember_publish_obj(KitLinkSession* s, 52 KitObjBuilder* ob) { 53 Heap* h; 54 KitObjBuilder** nb; 55 u32 new_cap; 56 if (!s || !ob) return KIT_INVALID; 57 if (s->npublish_objs < s->publish_objs_cap) { 58 s->publish_objs[s->npublish_objs++] = ob; 59 return KIT_OK; 60 } 61 h = s->c->ctx->heap; 62 new_cap = s->publish_objs_cap ? s->publish_objs_cap * 2u : 8u; 63 nb = (KitObjBuilder**)h->realloc( 64 h, s->publish_objs, sizeof(*s->publish_objs) * s->publish_objs_cap, 65 sizeof(*s->publish_objs) * new_cap, _Alignof(KitObjBuilder*)); 66 if (!nb) return KIT_NOMEM; 67 s->publish_objs = nb; 68 s->publish_objs_cap = new_cap; 69 s->publish_objs[s->npublish_objs++] = ob; 70 return KIT_OK; 71 } 72 73 /* These KitLinkSessionOptions fields have no plumbing into the Linker yet: 74 * the shared-library DT_* knobs (soname/rpaths/runpaths/exports) and the 75 * build-id selector (build_id_mode/bytes/len; the 76 * ELF writer currently emits a fixed image-hash note regardless of mode). 77 * Until they are wired through, warn rather than silently honor the default 78 * instead of the caller's request. */ 79 static void link_warn_ignored_opt(Compiler* c, const char* name) { 80 DiagSink* diag = (c && c->ctx) ? c->ctx->diag : NULL; 81 if (!diag) return; 82 diag_emit(diag, DIAG_WARN, SRCLOC_NONE, 83 "link: option '%s' is not yet supported and is ignored", name); 84 } 85 86 /* -l<name> suffix search order. libkit owns only this policy table + walk 87 * order; the host probe does all path composition and filesystem access. */ 88 typedef struct LibVariant { 89 const char* prefix; 90 const char* suffix; 91 uint8_t kind; /* KitLibResolveKind */ 92 } LibVariant; 93 94 bool kit_lib_resolve(uint8_t os, uint8_t mode, const char* name, 95 const char* const* search_dirs, uint32_t nsearch_dirs, 96 KitLibResolveProbe probe, void* user) { 97 /* POSIX dynamic: Apple .tbd/.dylib first (the macOS SDK ships .tbd stubs), 98 * then .so, then the .a fallback. DYNAMIC_ONLY drops the trailing .a. */ 99 static const LibVariant posix_dyn[] = { 100 {"lib", ".tbd", KIT_LIB_RESOLVE_KIND_TBD}, 101 {"lib", ".dylib", KIT_LIB_RESOLVE_KIND_SHARED}, 102 {"lib", ".so", KIT_LIB_RESOLVE_KIND_SHARED}, 103 {"lib", ".a", KIT_LIB_RESOLVE_KIND_ARCHIVE}, 104 }; 105 static const LibVariant posix_static[] = { 106 {"lib", ".a", KIT_LIB_RESOLVE_KIND_ARCHIVE}, 107 }; 108 /* Windows / mingw: mingw-canonical names first (lib<n>.dll.a, lib<n>.a), 109 * then the MSVC <n>.lib / <n>.dll.a variants. Every match feeds the linker 110 * as an archive input (short-form import libs are AR archives). */ 111 static const LibVariant win_variants[] = { 112 {"lib", ".dll.a", KIT_LIB_RESOLVE_KIND_ARCHIVE}, 113 {"lib", ".a", KIT_LIB_RESOLVE_KIND_ARCHIVE}, 114 {"", ".lib", KIT_LIB_RESOLVE_KIND_ARCHIVE}, 115 {"", ".dll.a", KIT_LIB_RESOLVE_KIND_ARCHIVE}, 116 }; 117 const LibVariant* variants; 118 uint32_t nvariants, vi, di; 119 120 if (!name || !probe) return false; 121 122 if (os == KIT_LIB_RESOLVE_OS_WINDOWS) { 123 variants = win_variants; 124 nvariants = (uint32_t)(sizeof win_variants / sizeof win_variants[0]); 125 } else if (mode == KIT_LIB_RESOLVE_STATIC_ONLY) { 126 variants = posix_static; 127 nvariants = (uint32_t)(sizeof posix_static / sizeof posix_static[0]); 128 } else { 129 variants = posix_dyn; 130 nvariants = (uint32_t)(sizeof posix_dyn / sizeof posix_dyn[0]); 131 if (mode == KIT_LIB_RESOLVE_DYNAMIC_ONLY) nvariants -= 1u; /* drop .a */ 132 } 133 134 for (vi = 0; vi < nvariants; ++vi) { 135 for (di = 0; di < nsearch_dirs; ++di) { 136 if (probe(user, search_dirs[di], variants[vi].prefix, name, 137 variants[vi].suffix, variants[vi].kind)) 138 return true; 139 } 140 } 141 return false; 142 } 143 144 KitStatus kit_link_session_new(KitCompiler* c, 145 const KitLinkSessionOptions* opts, 146 KitLinkSession** out) { 147 Heap* h; 148 KitLinkSession* s; 149 Linker* l; 150 if (!out) return KIT_INVALID; 151 *out = NULL; 152 if (!c || !opts) return KIT_INVALID; 153 h = c->ctx->heap; 154 l = link_new(c); 155 if (!l) return KIT_NOMEM; 156 s = (KitLinkSession*)h->alloc(h, sizeof(*s), _Alignof(KitLinkSession)); 157 if (!s) { 158 link_free(l); 159 return KIT_NOMEM; 160 } 161 memset(s, 0, sizeof(*s)); 162 s->c = (Compiler*)c; 163 s->linker = l; 164 s->opts = *opts; 165 if (opts->output_kind > KIT_LINK_OUTPUT_JIT) { 166 h->free(h, s, sizeof(*s)); 167 link_free(l); 168 return KIT_INVALID; 169 } 170 if (opts->pe_subsystem != KIT_PE_SUBSYSTEM_DEFAULT && 171 opts->pe_subsystem != KIT_PE_SUBSYSTEM_WINDOWS_GUI && 172 opts->pe_subsystem != KIT_PE_SUBSYSTEM_WINDOWS_CUI) { 173 h->free(h, s, sizeof(*s)); 174 link_free(l); 175 return KIT_INVALID; 176 } 177 link_set_pe_subsystem(l, opts->pe_subsystem); 178 179 switch ((KitLinkOutputKind)opts->output_kind) { 180 case KIT_LINK_OUTPUT_EXE: 181 link_set_emit_static_exe(l, 1); 182 link_set_gc_sections(l, opts->gc_sections); 183 link_set_strip_debug(l, opts->strip_debug); 184 link_set_allow_undefined(l, opts->allow_undefined); 185 link_set_pie(l, opts->pie); 186 link_set_interp_path(l, opts->interp_path); 187 break; 188 case KIT_LINK_OUTPUT_SHARED: 189 link_set_gc_sections(l, opts->gc_sections); 190 link_set_strip_debug(l, opts->strip_debug); 191 link_set_allow_undefined(l, 0); 192 link_set_shared(l, 1); 193 link_set_pie(l, 0); 194 if (opts->exports && opts->nexports) 195 link_warn_ignored_opt(s->c, "--export-symbol"); 196 break; 197 case KIT_LINK_OUTPUT_RELOCATABLE: 198 break; 199 case KIT_LINK_OUTPUT_JIT: 200 if (!opts->jit_host) { 201 h->free(h, s, sizeof(*s)); 202 link_free(l); 203 return KIT_INVALID; 204 } 205 link_set_jit_host(l, opts->jit_host); 206 link_set_jit_mode(l, 1); 207 link_set_gc_sections(l, opts->gc_sections); 208 if (!opts->entry.s || opts->entry.len == 0) link_clear_entry(l); 209 if (opts->extern_resolver) { 210 link_set_extern_resolver(l, opts->extern_resolver, 211 opts->extern_resolver_user); 212 } 213 break; 214 } 215 if (opts->linker_script) link_set_script(l, opts->linker_script); 216 if (opts->text_base_set) link_set_text_base(l, opts->text_base); 217 /* Linker-flags/policy plumbing (kernel-C work). The Linker struct lives in 218 * link_internal.h; these fields have no dedicated setter, so the public API 219 * composition layer assigns them directly. The arrays are borrowed from the 220 * caller (the driver keeps them alive for the session's lifetime). */ 221 l->defsyms = opts->defsyms; 222 l->ndefsyms = opts->ndefsyms; 223 l->section_starts = opts->section_starts; 224 l->nsection_starts = opts->nsection_starts; 225 l->soname = opts->soname; 226 l->rpaths = opts->rpaths; 227 l->nrpaths = opts->nrpaths; 228 l->runpaths = opts->runpaths; 229 l->nrunpaths = opts->nrunpaths; 230 l->orphan_handling = opts->orphan_handling; 231 l->fatal_warnings = opts->fatal_warnings ? 1 : 0; 232 l->freestanding_strict = opts->freestanding_strict ? 1 : 0; 233 if (opts->entry.s && opts->entry.len) { 234 link_set_entry(l, opts->entry); 235 } else if (opts->pe_subsystem == KIT_PE_SUBSYSTEM_WINDOWS_GUI && 236 !(opts->linker_script && opts->linker_script->entry.s && 237 opts->linker_script->entry.len)) { 238 link_set_entry(l, KIT_SLICE_LIT("WinMainCRTStartup")); 239 } 240 /* TODO(build-id): the ELF writer (src/obj/elf/link.c) emits a fixed 241 * image-hash build-id note unconditionally for non-scripted layouts; the 242 * caller's mode selection is not threaded through, so a note is emitted 243 * even for KIT_BUILDID_NONE and uuid/user-bytes modes get the default hash. 244 * Honoring the mode means carrying it into LinkImage + the ELF/Mach-O 245 * writers (and is a no-op for the common default), so it is left as a known 246 * gap rather than warned about on the default path. */ 247 (void)opts->build_id_mode; 248 (void)opts->build_id_bytes; 249 (void)opts->build_id_len; 250 *out = s; 251 return KIT_OK; 252 } 253 254 typedef struct LinkAddObjArg { 255 KitObjBuilder* ob; 256 } LinkAddObjArg; 257 258 static void link_session_add_obj_inner(KitLinkSession* s, void* arg) { 259 LinkAddObjArg* a = (LinkAddObjArg*)arg; 260 link_add_obj(s->linker, (ObjBuilder*)a->ob); 261 } 262 263 KitStatus kit_link_session_add_obj(KitLinkSession* s, KitObjBuilder* ob) { 264 LinkAddObjArg arg; 265 KitStatus st; 266 if (!s || !ob || s->resolved) return KIT_INVALID; 267 arg.ob = ob; 268 st = link_session_guard(s, link_session_add_obj_inner, &arg); 269 if (st != KIT_OK) return st; 270 return link_session_remember_publish_obj(s, ob); 271 } 272 273 typedef struct LinkAddBytesArg { 274 KitSlice name; 275 const KitSlice* bytes; 276 const KitLinkArchiveInput* archive; 277 } LinkAddBytesArg; 278 279 static void link_session_add_obj_bytes_inner(KitLinkSession* s, void* arg) { 280 LinkAddBytesArg* a = (LinkAddBytesArg*)arg; 281 link_add_obj_bytes(s->linker, a->name.s, a->bytes->data, a->bytes->len); 282 } 283 284 KitStatus kit_link_session_add_obj_bytes(KitLinkSession* s, KitSlice name, 285 const KitSlice* bytes) { 286 LinkAddBytesArg arg; 287 if (!s || !bytes || s->resolved) return KIT_INVALID; 288 arg.name = name; 289 arg.bytes = bytes; 290 arg.archive = NULL; 291 s->non_obj_inputs++; 292 return link_session_guard(s, link_session_add_obj_bytes_inner, &arg); 293 } 294 295 static void link_session_add_archive_bytes_inner(KitLinkSession* s, void* arg) { 296 const KitLinkArchiveInput* a = ((LinkAddBytesArg*)arg)->archive; 297 link_add_archive_bytes(s->linker, a->name.s, a->bytes.data, a->bytes.len, 298 a->whole_archive, a->link_mode, a->group_id); 299 } 300 301 KitStatus kit_link_session_add_archive_bytes( 302 KitLinkSession* s, const KitLinkArchiveInput* archive) { 303 LinkAddBytesArg arg; 304 if (!s || !archive || s->resolved) return KIT_INVALID; 305 arg.bytes = NULL; 306 arg.archive = archive; 307 s->non_obj_inputs++; 308 return link_session_guard(s, link_session_add_archive_bytes_inner, &arg); 309 } 310 311 static void link_session_add_dso_bytes_inner(KitLinkSession* s, void* arg) { 312 LinkAddBytesArg* a = (LinkAddBytesArg*)arg; 313 link_add_dso_bytes(s->linker, a->name.s, a->bytes->data, a->bytes->len); 314 } 315 316 KitStatus kit_link_session_add_dso_bytes(KitLinkSession* s, KitSlice name, 317 const KitSlice* bytes) { 318 LinkAddBytesArg arg; 319 if (!s || !bytes || s->resolved) return KIT_INVALID; 320 arg.name = name; 321 arg.bytes = bytes; 322 arg.archive = NULL; 323 s->non_obj_inputs++; 324 return link_session_guard(s, link_session_add_dso_bytes_inner, &arg); 325 } 326 327 typedef struct LinkLtoPreserveArg { 328 KitObjBuilder* lto_obj; 329 KitCg* lto_cg; 330 KitLinkLtoPreservedCallback cb; 331 void* user; 332 } LinkLtoPreserveArg; 333 334 typedef struct LinkLtoRefMark { 335 ObjSymId sym; 336 u8 referenced; 337 u8 pad[3]; 338 } LinkLtoRefMark; 339 340 typedef struct LinkLtoRefMarks { 341 Compiler* c; 342 ObjBuilder* ob; 343 LinkLtoRefMark* marks; 344 u32 nmarks; 345 u32 cap; 346 } LinkLtoRefMarks; 347 348 static int link_lto_sym_is_logical_undef(const ObjSym* s) { 349 return s && s->section_id == OBJ_SEC_NONE && s->kind != SK_ABS && 350 s->kind != SK_COMMON; 351 } 352 353 static int link_lto_sym_is_preservable_def(const ObjSym* s) { 354 return s && !s->removed && s->name != 0 && s->bind != SB_LOCAL && 355 link_sym_is_def(s); 356 } 357 358 static void link_lto_preserve_name(LinkLtoPreserveArg* a, Sym name) { 359 ObjSymIter* it; 360 ObjSymEntry e; 361 if (!a || !name) return; 362 it = obj_symiter_new((ObjBuilder*)a->lto_obj); 363 while (it && obj_symiter_next(it, &e)) { 364 const ObjSym* s = e.sym; 365 if (!s || s->name != name) continue; 366 if (link_lto_sym_is_preservable_def(s)) a->cb(a->user, (KitCgSym)e.id); 367 } 368 if (it) obj_symiter_free(it); 369 } 370 371 static int link_lto_sym_in_preserved_section(ObjBuilder* ob, ObjSymId sym, 372 const ObjSym* s) { 373 const Section* sec; 374 const ObjAtom* atom; 375 ObjAtomId aid; 376 if (!ob || !s) return 0; 377 if (s->section_id == OBJ_SEC_NONE) return 0; 378 sec = obj_section_get(ob, s->section_id); 379 if (sec && ((sec->flags & SF_RETAIN) || sec->sem == SSEM_INIT_ARRAY || 380 sec->sem == SSEM_FINI_ARRAY || sec->sem == SSEM_PREINIT_ARRAY)) 381 return 1; 382 aid = obj_atom_find_symbol(ob, sym); 383 atom = obj_atom_get(ob, aid); 384 return atom && (atom->flags & OBJ_ATOM_RETAIN); 385 } 386 387 static void link_lto_refmarks_add(LinkLtoRefMarks* marks, ObjSymId sym, 388 const ObjSym* s) { 389 Heap* h; 390 LinkLtoRefMark* nm; 391 u32 ncap; 392 if (!marks || sym == OBJ_SYM_NONE || !s) return; 393 for (u32 i = 0; i < marks->nmarks; ++i) 394 if (marks->marks[i].sym == sym) return; 395 if (marks->nmarks == marks->cap) { 396 h = marks->c->ctx->heap; 397 ncap = marks->cap ? marks->cap * 2u : 32u; 398 nm = (LinkLtoRefMark*)h->realloc( 399 h, marks->marks, sizeof(*marks->marks) * marks->cap, 400 sizeof(*marks->marks) * ncap, _Alignof(LinkLtoRefMark)); 401 if (!nm) 402 compiler_panic(marks->c, SRCLOC_NONE, 403 "link: oom on LTO semantic-ref marks"); 404 marks->marks = nm; 405 marks->cap = ncap; 406 } 407 marks->marks[marks->nmarks].sym = sym; 408 marks->marks[marks->nmarks].referenced = s->referenced ? 1u : 0u; 409 marks->nmarks++; 410 } 411 412 static void link_lto_mark_refset(ObjBuilder* ob, const ObjSymSet* refs, 413 LinkLtoRefMarks* marks) { 414 if (!ob || !refs || !refs->cap) return; 415 for (u32 i = 0; i < refs->cap; ++i) { 416 ObjSymId sym = refs->slots[i].k; 417 const ObjSym* s; 418 if (sym == OBJ_SYM_NONE) continue; 419 s = obj_symbol_get(ob, sym); 420 if (link_lto_sym_is_logical_undef(s)) { 421 link_lto_refmarks_add(marks, sym, s); 422 obj_sym_mark_referenced(ob, sym); 423 } 424 } 425 } 426 427 static int link_lto_module_has_asm(const CgIrModule* module) { 428 if (!module) return 0; 429 if (module->nfile_scope_asms) return 1; 430 for (u32 i = 0; i < module->nfuncs; ++i) { 431 const CgIrFunc* f = module->funcs[i]; 432 if (!f || f->removed) continue; 433 for (u32 k = 0; k < f->ninsts; ++k) 434 if (f->insts[k].op == CG_IR_ASM_BLOCK) return 1; 435 } 436 return 0; 437 } 438 439 static void link_lto_mark_semantic_refs(LinkLtoPreserveArg* a, 440 LinkLtoRefMarks* marks) { 441 ObjBuilder* ob = (ObjBuilder*)a->lto_obj; 442 const CgIrModule* module; 443 if (!a->lto_cg || !a->lto_cg->target) return; 444 module = cg_ir_recorder_module(a->lto_cg->target); 445 if (!module) return; 446 for (u32 i = 0; i < module->nfuncs; ++i) { 447 const CgIrFunc* f = module->funcs[i]; 448 if (!f || f->removed) continue; 449 link_lto_mark_refset(ob, &f->call_refs, marks); 450 link_lto_mark_refset(ob, &f->global_refs, marks); 451 } 452 } 453 454 static void link_lto_refmarks_restore(LinkLtoRefMarks* marks) { 455 if (!marks || !marks->ob) return; 456 for (u32 i = 0; i < marks->nmarks; ++i) { 457 obj_sym_set_referenced(marks->ob, marks->marks[i].sym, 458 marks->marks[i].referenced); 459 } 460 } 461 462 static void link_lto_refmarks_fini(LinkLtoRefMarks* marks) { 463 Heap* h; 464 if (!marks || !marks->marks) return; 465 h = marks->c->ctx->heap; 466 h->free(h, marks->marks, sizeof(*marks->marks) * marks->cap); 467 memset(marks, 0, sizeof(*marks)); 468 } 469 470 static void link_lto_preserve_intrinsic_roots(KitLinkSession* s, 471 LinkLtoPreserveArg* a) { 472 ObjBuilder* ob = (ObjBuilder*)a->lto_obj; 473 const CgIrModule* module = NULL; 474 int preserve_all_nonlocal = 0; 475 ObjSymIter* it; 476 ObjSymEntry e; 477 478 if (a->lto_cg && a->lto_cg->target) 479 module = cg_ir_recorder_module(a->lto_cg->target); 480 481 preserve_all_nonlocal = s->opts.output_kind != KIT_LINK_OUTPUT_EXE || 482 link_lto_module_has_asm(module); 483 if (s->opts.output_kind == KIT_LINK_OUTPUT_SHARED) preserve_all_nonlocal = 1; 484 485 it = obj_symiter_new(ob); 486 while (it && obj_symiter_next(it, &e)) { 487 const ObjSym* os = e.sym; 488 if (!link_lto_sym_is_preservable_def(os)) continue; 489 if (preserve_all_nonlocal || os->bind == SB_WEAK || os->kind == SK_IFUNC || 490 (os->flags & KIT_CG_SYM_USED) || 491 link_lto_sym_in_preserved_section(ob, e.id, os)) { 492 a->cb(a->user, (KitCgSym)e.id); 493 } 494 } 495 if (it) obj_symiter_free(it); 496 497 if (s->linker->entry_name) link_lto_preserve_name(a, s->linker->entry_name); 498 for (u32 i = 0; i < s->opts.nexports; ++i) { 499 const KitSlice* ex = &s->opts.exports[i]; 500 if (ex->s && ex->len) 501 link_lto_preserve_name( 502 a, 503 pool_intern_slice(s->c->global, (Slice){.s = ex->s, .len = ex->len})); 504 } 505 } 506 507 static void link_lto_preserve_opaque_undef_refs(KitLinkSession* s, 508 LinkLtoPreserveArg* a) { 509 u32 ninputs = LinkInputs_count(&s->linker->inputs); 510 for (u32 ii = 0; ii < ninputs; ++ii) { 511 LinkInput* in = LinkInputs_at(&s->linker->inputs, ii); 512 ObjSymIter* it; 513 ObjSymEntry e; 514 if (!in || !in->obj || in->obj == (ObjBuilder*)a->lto_obj) continue; 515 it = obj_symiter_new(in->obj); 516 while (it && obj_symiter_next(it, &e)) { 517 const ObjSym* os = e.sym; 518 if (!os || os->name == 0 || os->bind == SB_LOCAL) continue; 519 if (link_sym_is_spurious_undef(os)) continue; 520 if (!link_lto_sym_is_logical_undef(os)) continue; 521 link_lto_preserve_name(a, os->name); 522 } 523 if (it) obj_symiter_free(it); 524 } 525 } 526 527 static void link_session_visit_lto_preserved_inner(KitLinkSession* s, 528 void* arg) { 529 LinkLtoPreserveArg* a = (LinkLtoPreserveArg*)arg; 530 LinkLtoRefMarks marks; 531 memset(&marks, 0, sizeof marks); 532 marks.c = s->c; 533 marks.ob = (ObjBuilder*)a->lto_obj; 534 if (s->opts.output_kind != KIT_LINK_OUTPUT_RELOCATABLE) { 535 /* Archive selection needs pre-finish semantic refs, but those refs may 536 * disappear after LTO internalization/DCE. Borrow ObjSym::referenced only 537 * for archive ingestion, then restore it before CG finish. */ 538 link_lto_mark_semantic_refs(a, &marks); 539 link_ingest_archives(s->linker); 540 link_lto_refmarks_restore(&marks); 541 link_lto_refmarks_fini(&marks); 542 } 543 link_lto_preserve_intrinsic_roots(s, a); 544 link_lto_preserve_opaque_undef_refs(s, a); 545 } 546 547 KitStatus kit_link_session_visit_lto_preserved(KitLinkSession* s, 548 KitObjBuilder* lto_obj, 549 KitCg* lto_cg, 550 KitLinkLtoPreservedCallback cb, 551 void* user) { 552 LinkLtoPreserveArg arg; 553 if (!s || !lto_obj || !lto_cg || !cb || s->resolved) return KIT_INVALID; 554 memset(&arg, 0, sizeof arg); 555 arg.lto_obj = lto_obj; 556 arg.lto_cg = lto_cg; 557 arg.cb = cb; 558 arg.user = user; 559 return link_session_guard(s, link_session_visit_lto_preserved_inner, &arg); 560 } 561 562 static void link_session_resolve_inner(KitLinkSession* s, void* arg) { 563 (void)arg; 564 if ((KitLinkOutputKind)s->opts.output_kind == KIT_LINK_OUTPUT_RELOCATABLE) { 565 s->resolved = 1; 566 return; 567 } 568 s->image = link_resolve(s->linker); 569 s->resolved = 1; 570 } 571 572 KitStatus kit_link_session_resolve(KitLinkSession* s) { 573 if (!s || s->resolved) return KIT_INVALID; 574 return link_session_guard(s, link_session_resolve_inner, NULL); 575 } 576 577 static KitStatus link_report_write(KitWriter* out, const char* s, size_t n) { 578 return n ? kit_writer_write(out, s, n) : KIT_OK; 579 } 580 581 static KitStatus link_report_cstr(KitWriter* out, const char* s) { 582 return link_report_write(out, s, s ? strlen(s) : 0); 583 } 584 585 static KitStatus link_report_slice(KitWriter* out, KitSlice s) { 586 return link_report_write(out, s.s, s.s ? s.len : 0); 587 } 588 589 static KitStatus link_reportf(KitWriter* out, const char* fmt, ...) { 590 char buf[512]; 591 va_list ap; 592 int n; 593 va_start(ap, fmt); 594 n = vsnprintf(buf, sizeof(buf), fmt, ap); 595 va_end(ap); 596 if (n < 0) return KIT_ERR; 597 if ((size_t)n >= sizeof(buf)) return KIT_UNSUPPORTED; 598 return link_report_write(out, buf, (size_t)n); 599 } 600 601 static const char* link_report_output_kind(uint8_t kind) { 602 switch ((KitLinkOutputKind)kind) { 603 case KIT_LINK_OUTPUT_EXE: 604 return "exe"; 605 case KIT_LINK_OUTPUT_SHARED: 606 return "shared"; 607 case KIT_LINK_OUTPUT_RELOCATABLE: 608 return "relocatable"; 609 case KIT_LINK_OUTPUT_JIT: 610 return "jit"; 611 } 612 return "unknown"; 613 } 614 615 static KitSlice link_report_sym_name(LinkImage* img, Sym name) { 616 return name ? pool_slice(img->c->global, name) : KIT_SLICE_NULL; 617 } 618 619 static int link_report_slice_cmp(KitSlice a, KitSlice b) { 620 size_t n = a.len < b.len ? a.len : b.len; 621 int c = n ? memcmp(a.s, b.s, n) : 0; 622 if (c) return c; 623 if (a.len < b.len) return -1; 624 if (a.len > b.len) return 1; 625 return 0; 626 } 627 628 static int link_report_symbol_include(const LinkImage* img, 629 const LinkSymbol* s) { 630 if (!s || !s->name || !s->defined || s->imported) return 0; 631 if (s->kind == SK_FILE || s->kind == SK_SECTION) return 0; 632 if (s->bind != SB_LOCAL && !link_symbol_is_canonical_global(img, s)) return 0; 633 return 1; 634 } 635 636 typedef struct LinkReportSymbols { 637 LinkSymId* ids; 638 u32 n; 639 u32 cap; 640 } LinkReportSymbols; 641 642 static int link_report_symbol_cmp(LinkImage* img, LinkSymId a, LinkSymId b) { 643 const LinkSymbol* sa = LinkSyms_at(&img->syms, a - 1u); 644 const LinkSymbol* sb = LinkSyms_at(&img->syms, b - 1u); 645 KitSlice na; 646 KitSlice nb; 647 if (sa->vaddr < sb->vaddr) return -1; 648 if (sa->vaddr > sb->vaddr) return 1; 649 na = link_report_sym_name(img, sa->name); 650 nb = link_report_sym_name(img, sb->name); 651 return link_report_slice_cmp(na, nb); 652 } 653 654 static KitStatus link_report_collect_symbols(LinkImage* img, 655 LinkReportSymbols* out) { 656 Heap* h = img->heap; 657 u32 i; 658 memset(out, 0, sizeof(*out)); 659 out->cap = LinkSyms_count(&img->syms); 660 if (!out->cap) return KIT_OK; 661 out->ids = 662 (LinkSymId*)h->alloc(h, sizeof(*out->ids) * out->cap, _Alignof(LinkSymId)); 663 if (!out->ids) return KIT_NOMEM; 664 for (i = 0; i < out->cap; ++i) { 665 const LinkSymbol* s = LinkSyms_at(&img->syms, i); 666 if (link_report_symbol_include(img, s)) out->ids[out->n++] = s->id; 667 } 668 for (i = 1; i < out->n; ++i) { 669 LinkSymId key = out->ids[i]; 670 u32 j = i; 671 while (j > 0 && link_report_symbol_cmp(img, key, out->ids[j - 1u]) < 0) { 672 out->ids[j] = out->ids[j - 1u]; 673 --j; 674 } 675 out->ids[j] = key; 676 } 677 return KIT_OK; 678 } 679 680 static void link_report_free_symbols(LinkImage* img, LinkReportSymbols* syms) { 681 if (syms->ids) 682 img->heap->free(img->heap, syms->ids, 683 sizeof(*syms->ids) * syms->cap); 684 memset(syms, 0, sizeof(*syms)); 685 } 686 687 static char link_report_symbol_type(const LinkImage* img, 688 const LinkSymbol* s) { 689 char t = 'N'; 690 const LinkSection* sec = NULL; 691 if (!s->defined) { 692 t = 'U'; 693 } else if (s->kind == SK_ABS) { 694 t = 'A'; 695 } else if (s->kind == SK_COMMON) { 696 t = 'C'; 697 } else if (s->kind == SK_FUNC || s->kind == SK_IFUNC) { 698 t = 'T'; 699 } else { 700 if (s->section_id != LINK_SEC_NONE && s->section_id <= img->nsections) 701 sec = &img->sections[s->section_id - 1u]; 702 if (s->kind == SK_TLS) { 703 t = 'D'; 704 } else if (sec && sec->sem == SSEM_NOBITS) { 705 t = 'B'; 706 } else if (sec && (sec->flags & SF_EXEC)) { 707 t = 'T'; 708 } else if (sec && (sec->flags & SF_WRITE)) { 709 t = 'D'; 710 } else if (sec && (sec->flags & SF_ALLOC)) { 711 t = 'R'; 712 } 713 } 714 if (s->bind == SB_WEAK) { 715 if (t == 'D' || t == 'B' || t == 'R') 716 t = 'V'; 717 else if (t != 'U') 718 t = 'W'; 719 } else if (s->bind == SB_LOCAL && t >= 'A' && t <= 'Z') { 720 t = (char)(t - 'A' + 'a'); 721 } 722 return t; 723 } 724 725 /* Final runtime address of a symbol, mirroring the ELF emitter's st_value 726 * rule: SK_FILE / undefined carry 0; SK_ABS carries its own value verbatim; 727 * every other defined symbol is image-relative and gets img->load_base added 728 * (0 for PIE/scripted, the static base or -Ttext override otherwise). Keeps 729 * the side-files consistent with the produced binary's symbol table. */ 730 static u64 link_report_final_addr(const LinkImage* img, const LinkSymbol* s) { 731 if (s->kind == SK_FILE || !s->defined) return 0; 732 if (s->kind == SK_ABS) return s->vaddr; 733 return img->load_base + s->vaddr; 734 } 735 736 static KitStatus link_report_write_symbol_line(LinkImage* img, KitWriter* out, 737 const LinkSymbol* s) { 738 KitSlice name = link_report_sym_name(img, s->name); 739 KitStatus st = link_reportf(out, "%016llx %c ", 740 (unsigned long long)link_report_final_addr(img, s), 741 link_report_symbol_type(img, s)); 742 if (st != KIT_OK) return st; 743 st = link_report_slice(out, name); 744 if (st != KIT_OK) return st; 745 return link_report_cstr(out, "\n"); 746 } 747 748 static KitStatus link_report_write_symbols_nm(LinkImage* img, KitWriter* out) { 749 LinkReportSymbols syms; 750 KitStatus st; 751 u32 i; 752 st = link_report_collect_symbols(img, &syms); 753 if (st != KIT_OK) return st; 754 for (i = 0; i < syms.n; ++i) { 755 const LinkSymbol* s = LinkSyms_at(&img->syms, syms.ids[i] - 1u); 756 st = link_report_write_symbol_line(img, out, s); 757 if (st != KIT_OK) break; 758 } 759 link_report_free_symbols(img, &syms); 760 return st == KIT_OK ? kit_writer_status(out) : st; 761 } 762 763 /* Normalize a (possibly absolute) input path to its basename so map/side files 764 * stay byte-identical regardless of where the inputs live on disk (an absolute 765 * host path would leak the build directory and break determinism). */ 766 static KitSlice link_report_normalize_path(KitSlice raw) { 767 size_t i; 768 size_t base = 0; 769 if (!raw.s || raw.len == 0) return raw; 770 for (i = 0; i < raw.len; ++i) 771 if (raw.s[i] == '/' || raw.s[i] == '\\') base = i + 1u; 772 if (base >= raw.len) return raw; /* trailing separator: keep as-is */ 773 raw.s += base; 774 raw.len -= base; 775 return raw; 776 } 777 778 static KitSlice link_report_input_name(LinkImage* img, LinkInputId id) { 779 LinkInput* in; 780 KitSlice raw; 781 if (!img || !img->linker || id == LINK_INPUT_NONE || 782 id > LinkInputs_count(&img->linker->inputs)) 783 return KIT_SLICE_NULL; 784 in = LinkInputs_at(&img->linker->inputs, id - 1u); 785 if (!in || !in->name) return KIT_SLICE_NULL; 786 raw = pool_slice(img->c->global, in->name); 787 return link_report_normalize_path(raw); 788 } 789 790 /* Discarded sections: input sections that are layout candidates 791 * (link_section_kept) but did not land in the final image — dropped by 792 * --gc-sections, retired as a COMDAT duplicate, or otherwise unplaced. Walks 793 * the per-input maps in input/section order for determinism, and reports the 794 * normalized input name so no absolute host path leaks. */ 795 static KitStatus link_report_write_discarded(LinkImage* img, KitWriter* out) { 796 KitStatus st; 797 u32 ii; 798 if (!img || !img->linker) return KIT_OK; 799 st = link_report_cstr(out, "\ndiscarded\n"); 800 if (st != KIT_OK) return st; 801 for (ii = 0; ii < LinkInputs_count(&img->linker->inputs); ++ii) { 802 LinkInput* in = LinkInputs_at(&img->linker->inputs, ii); 803 InputMap* m = (ii < img->ninput_maps) ? &img->input_maps[ii] : NULL; 804 ObjBuilder* ob = in ? in->obj : NULL; 805 KitSlice input; 806 u32 j, n; 807 if (!ob || !m) continue; 808 if (in->kind == LINK_INPUT_DSO_BYTES) continue; 809 input = link_report_input_name(img, in->id); 810 n = obj_section_count(ob); 811 for (j = 1; j < n; ++j) { 812 const Section* sec = obj_section_get(ob, j); 813 int dropped; 814 if (!sec || sec->removed || !link_section_kept(sec)) continue; 815 dropped = (m->comdat_discarded && j < m->nsection && m->comdat_discarded[j]) || 816 (m->section && j < m->nsection && m->section[j] == LINK_SEC_NONE); 817 if (!dropped) continue; 818 st = link_report_cstr(out, " "); 819 if (st != KIT_OK) return st; 820 { 821 KitSlice nm = sec->name ? link_report_sym_name(img, sec->name) 822 : KIT_SLICE_NULL; 823 st = nm.s ? link_report_slice(out, nm) : link_report_cstr(out, "-"); 824 if (st != KIT_OK) return st; 825 } 826 if (input.s && input.len) { 827 st = link_report_cstr(out, " input="); 828 if (st != KIT_OK) return st; 829 st = link_report_slice(out, input); 830 if (st != KIT_OK) return st; 831 } 832 st = link_report_cstr(out, "\n"); 833 if (st != KIT_OK) return st; 834 } 835 } 836 return KIT_OK; 837 } 838 839 /* Unresolved symbols: image symbols that remain undefined and unimported 840 * after resolution (only reachable when the link is permissive, e.g. 841 * --allow-undefined; a strict link panics instead). Sorted by name for a 842 * deterministic listing. */ 843 static KitStatus link_report_write_unresolved(LinkImage* img, KitWriter* out) { 844 KitStatus st; 845 Heap* h = img->heap; 846 LinkSymId* ids = NULL; 847 u32 n = 0, cap, i; 848 if (!img) return KIT_OK; 849 st = link_report_cstr(out, "\nunresolved\n"); 850 if (st != KIT_OK) return st; 851 cap = LinkSyms_count(&img->syms); 852 if (!cap) return KIT_OK; 853 ids = (LinkSymId*)h->alloc(h, sizeof(*ids) * cap, _Alignof(LinkSymId)); 854 if (!ids) return KIT_NOMEM; 855 for (i = 0; i < cap; ++i) { 856 const LinkSymbol* s = LinkSyms_at(&img->syms, i); 857 if (!s || s->name == 0) continue; 858 if (s->defined || s->imported) continue; 859 if (s->kind == SK_FILE || s->kind == SK_SECTION) continue; 860 ids[n++] = s->id; 861 } 862 /* Insertion sort by name (small lists; deterministic). */ 863 for (i = 1; i < n; ++i) { 864 LinkSymId key = ids[i]; 865 KitSlice kn = link_report_sym_name( 866 img, LinkSyms_at(&img->syms, key - 1u)->name); 867 u32 j = i; 868 while (j > 0) { 869 KitSlice pn = link_report_sym_name( 870 img, LinkSyms_at(&img->syms, ids[j - 1u] - 1u)->name); 871 if (link_report_slice_cmp(pn, kn) <= 0) break; 872 ids[j] = ids[j - 1u]; 873 --j; 874 } 875 ids[j] = key; 876 } 877 for (i = 0; i < n; ++i) { 878 const LinkSymbol* s = LinkSyms_at(&img->syms, ids[i] - 1u); 879 KitSlice nm = link_report_sym_name(img, s->name); 880 st = link_report_cstr(out, " "); 881 if (st == KIT_OK) st = link_report_slice(out, nm); 882 if (st == KIT_OK) st = link_report_cstr(out, "\n"); 883 if (st != KIT_OK) break; 884 } 885 h->free(h, ids, sizeof(*ids) * cap); 886 return st; 887 } 888 889 static KitStatus link_report_write_map_image(KitLinkSession* s, 890 KitWriter* out) { 891 LinkImage* img = s->image; 892 char triple[96]; 893 KitStatus st; 894 u32 i; 895 if (!img) return KIT_INVALID; 896 if (!kit_target_to_triple(img->c->target, triple, sizeof(triple))) 897 strcpy(triple, "unknown"); 898 st = link_reportf(out, 899 "target %s\n" 900 "output %s\n", 901 triple, link_report_output_kind(s->opts.output_kind)); 902 if (st != KIT_OK) return st; 903 if (img->entry_sym != LINK_SYM_NONE) { 904 const LinkSymbol* es = LinkSyms_at(&img->syms, img->entry_sym - 1u); 905 KitSlice name = link_report_sym_name(img, es->name); 906 st = link_report_cstr(out, "entry "); 907 if (st != KIT_OK) return st; 908 st = link_report_slice(out, name); 909 if (st != KIT_OK) return st; 910 st = link_reportf(out, " 0x%llx\n", 911 (unsigned long long)link_report_final_addr(img, es)); 912 if (st != KIT_OK) return st; 913 } else { 914 st = link_report_cstr(out, "entry -\n"); 915 if (st != KIT_OK) return st; 916 } 917 918 st = link_report_cstr(out, "\nsegments\n"); 919 if (st != KIT_OK) return st; 920 /* The synthesized read-only headers load segment (ehdr+phdrs) maps at the 921 * image base ahead of the content segments; the format emitter records it 922 * so the map shows where the image actually loads (e.g. a -Ttext base). */ 923 if (img->headers_present) { 924 st = link_reportf(out, 925 " [0] r-- off=0x0 vaddr=0x%llx " 926 "filesz=0x%llx memsz=0x%llx align=0x%x\n", 927 (unsigned long long)img->load_base, 928 (unsigned long long)img->headers_filesz, 929 (unsigned long long)img->headers_memsz, 930 img->headers_align); 931 if (st != KIT_OK) return st; 932 } 933 for (i = 0; i < img->nsegments; ++i) { 934 const LinkSegment* seg = &img->segments[i]; 935 char w = (seg->flags & SF_WRITE) ? 'w' : '-'; 936 char x = (seg->flags & SF_EXEC) ? 'x' : '-'; 937 st = link_reportf(out, 938 " [%u] r%c%c off=0x%llx vaddr=0x%llx " 939 "filesz=0x%llx memsz=0x%llx align=0x%x\n", 940 seg->id, w, x, (unsigned long long)seg->file_offset, 941 (unsigned long long)(img->load_base + seg->vaddr), 942 (unsigned long long)seg->file_size, 943 (unsigned long long)seg->mem_size, seg->align); 944 if (st != KIT_OK) return st; 945 } 946 947 st = link_report_cstr(out, "\nsections\n"); 948 if (st != KIT_OK) return st; 949 for (i = 0; i < img->nsections; ++i) { 950 const LinkSection* sec = &img->sections[i]; 951 KitSlice name = link_report_sym_name(img, sec->name); 952 KitSlice input = link_report_input_name(img, sec->input_id); 953 int loaded = !(sec->file_only || sec->segment_id == LINK_SEG_NONE); 954 /* Loaded sections report their final runtime address; file-only debug 955 * sections aren't mapped (sh_addr 0), so leave their image-relative 956 * bookkeeping vaddr untouched rather than biasing it by the load base. */ 957 u64 sec_vaddr = loaded ? img->load_base + sec->vaddr : sec->vaddr; 958 /* LMA (load-memory address): where the section's initialized bytes load. 959 * Equals the VMA for the common case; differs only when the section's 960 * segment declares a distinct load region (a script `AT>` clause, which 961 * sets the segment paddr apart from its vaddr). */ 962 u64 sec_lma = sec_vaddr; 963 if (loaded && sec->segment_id <= img->nsegments) { 964 const LinkSegment* seg = &img->segments[sec->segment_id - 1u]; 965 if (seg->paddr != seg->vaddr) 966 sec_lma = img->load_base + seg->paddr + (sec->vaddr - seg->vaddr); 967 } 968 st = link_reportf(out, 969 " [%u] ", sec->id); 970 if (st != KIT_OK) return st; 971 st = name.s ? link_report_slice(out, name) : link_report_cstr(out, "-"); 972 if (st != KIT_OK) return st; 973 st = link_reportf(out, 974 " seg=%u off=0x%llx vaddr=0x%llx lma=0x%llx size=0x%llx " 975 "align=0x%x", 976 sec->segment_id, (unsigned long long)sec->file_offset, 977 (unsigned long long)sec_vaddr, 978 (unsigned long long)sec_lma, 979 (unsigned long long)sec->size, sec->align); 980 if (st != KIT_OK) return st; 981 if (input.s && input.len) { 982 st = link_report_cstr(out, " input="); 983 if (st != KIT_OK) return st; 984 st = link_report_slice(out, input); 985 if (st != KIT_OK) return st; 986 } 987 st = link_report_cstr(out, "\n"); 988 if (st != KIT_OK) return st; 989 } 990 991 st = link_report_write_discarded(img, out); 992 if (st != KIT_OK) return st; 993 st = link_report_write_unresolved(img, out); 994 if (st != KIT_OK) return st; 995 996 st = link_report_cstr(out, "\nsymbols\n"); 997 if (st != KIT_OK) return st; 998 return link_report_write_symbols_nm(img, out); 999 } 1000 1001 /* --cref predicate: a symbol participates in the cross-reference table when it 1002 * is a named non-FILE/non-SECTION global that is either locally defined OR 1003 * imported from a DSO. Imported (DSO-resolved) externals are exactly the 1004 * cross-references a cref table exists to show, so — unlike the nm-style 1005 * "symbols" listing's link_report_symbol_include — they are NOT dropped. */ 1006 static int link_report_cref_include(const LinkSymbol* s) { 1007 if (!s || !s->name) return 0; 1008 if (s->kind == SK_FILE || s->kind == SK_SECTION) return 0; 1009 return (s->defined && !s->imported) || s->imported; 1010 } 1011 1012 /* --cref: cross-reference table. For each defined-or-imported global/weak 1013 * symbol (deduped by name, sorted by name for determinism) emit the defining 1014 * file — the providing DSO basename for an imported symbol, the defining object 1015 * otherwise — then the set of distinct input files that reference it via a 1016 * relocation. Input names are normalized to basenames. The symbol set is built 1017 * INDEPENDENTLY of the nm-style "symbols" listing so imports are included. */ 1018 static KitStatus link_report_write_cref_image(KitLinkSession* s, 1019 KitWriter* out) { 1020 LinkImage* img = s->image; 1021 Heap* h; 1022 LinkSymId* ids = NULL; 1023 u32 n = 0, cap, i; 1024 KitStatus st; 1025 if (!img) return KIT_INVALID; 1026 h = img->heap; 1027 st = link_report_cstr(out, "cross reference table\n"); 1028 if (st != KIT_OK) return st; 1029 cap = LinkSyms_count(&img->syms); 1030 if (!cap) return kit_writer_status(out); 1031 ids = (LinkSymId*)h->alloc(h, sizeof(*ids) * cap, _Alignof(LinkSymId)); 1032 if (!ids) return KIT_NOMEM; 1033 /* Collect one canonical slot per qualifying name, deduped by Sym (the 1034 * interned name handle): a name's first qualifying slot wins. Prefer a 1035 * locally-defined slot over an imported one when both exist (so a symbol that 1036 * is both defined and referenced through a DSO reports its real def). */ 1037 for (i = 0; i < cap; ++i) { 1038 const LinkSymbol* sy = LinkSyms_at(&img->syms, i); 1039 u32 k; 1040 int seen = 0; 1041 if (!link_report_cref_include(sy)) continue; 1042 for (k = 0; k < n; ++k) { 1043 LinkSymbol* prev = LinkSyms_at(&img->syms, ids[k] - 1u); 1044 if (prev->name != sy->name) continue; 1045 seen = 1; 1046 /* Upgrade a previously-recorded imported slot to a real definition. */ 1047 if (sy->defined && !sy->imported && (!prev->defined || prev->imported)) 1048 ids[k] = sy->id; 1049 break; 1050 } 1051 if (!seen) ids[n++] = sy->id; 1052 } 1053 /* Insertion sort by name (small lists; deterministic). */ 1054 for (i = 1; i < n; ++i) { 1055 LinkSymId key = ids[i]; 1056 KitSlice kn = 1057 link_report_sym_name(img, LinkSyms_at(&img->syms, key - 1u)->name); 1058 u32 j = i; 1059 while (j > 0) { 1060 KitSlice pn = link_report_sym_name( 1061 img, LinkSyms_at(&img->syms, ids[j - 1u] - 1u)->name); 1062 if (link_report_slice_cmp(pn, kn) <= 0) break; 1063 ids[j] = ids[j - 1u]; 1064 --j; 1065 } 1066 ids[j] = key; 1067 } 1068 for (i = 0; i < n; ++i) { 1069 const LinkSymbol* sym = LinkSyms_at(&img->syms, ids[i] - 1u); 1070 KitSlice name = link_report_sym_name(img, sym->name); 1071 KitSlice deffile; 1072 LinkInputId defining_input = LINK_INPUT_NONE; 1073 u32 r, k; 1074 LinkInputId last = LINK_INPUT_NONE; 1075 if (sym->imported) { 1076 /* Imported symbol: the "definition" is the providing DSO input. */ 1077 defining_input = sym->dso_input_id; 1078 } else { 1079 /* Find the defining file: the canonical global slot (img->globals) is the 1080 * real definition; resolution copies its value into per-input reference 1081 * slots, so scanning slots by `defined` alone would mis-attribute. Fall 1082 * back to any defined same-name slot for locals (never in globals). */ 1083 LinkSymId canon = symhash_get(&img->globals, sym->name); 1084 if (canon != LINK_SYM_NONE) { 1085 const LinkSymbol* c = LinkSyms_at(&img->syms, canon - 1u); 1086 if (c->defined && !c->imported) defining_input = c->input_id; 1087 } 1088 if (defining_input == LINK_INPUT_NONE) { 1089 for (k = 0; k < cap; ++k) { 1090 const LinkSymbol* c = LinkSyms_at(&img->syms, k); 1091 if (c->name != sym->name) continue; 1092 if (c->defined && !c->imported && c->input_id != LINK_INPUT_NONE) { 1093 defining_input = c->input_id; 1094 break; 1095 } 1096 } 1097 } 1098 } 1099 deffile = link_report_input_name(img, defining_input); 1100 st = link_report_slice(out, name); 1101 if (st == KIT_OK) st = link_report_cstr(out, "\n"); 1102 if (st != KIT_OK) break; 1103 /* Defining file. */ 1104 st = link_report_cstr(out, " def "); 1105 if (st == KIT_OK) 1106 st = (deffile.s && deffile.len) ? link_report_slice(out, deffile) 1107 : link_report_cstr(out, "-"); 1108 if (st == KIT_OK) st = link_report_cstr(out, "\n"); 1109 if (st != KIT_OK) break; 1110 /* Referencing files: scan relocs targeting any same-name slot. The reloc 1111 * list is already in a deterministic input/section/offset order, so 1112 * consecutive dedup of input ids gives a stable per-symbol reference set. */ 1113 for (r = 0; r < LinkRelocs_count(&img->relocs); ++r) { 1114 const LinkRelocApply* ra = LinkRelocs_at(&img->relocs, r); 1115 const LinkSymbol* tsym; 1116 KitSlice reffile; 1117 if (!ra || ra->target == LINK_SYM_NONE) continue; 1118 tsym = LinkSyms_at(&img->syms, ra->target - 1u); 1119 if (!tsym || tsym->name != sym->name) continue; 1120 if (ra->input_id == last) continue; 1121 last = ra->input_id; 1122 reffile = link_report_input_name(img, ra->input_id); 1123 st = link_report_cstr(out, " ref "); 1124 if (st == KIT_OK) 1125 st = (reffile.s && reffile.len) ? link_report_slice(out, reffile) 1126 : link_report_cstr(out, "-"); 1127 if (st == KIT_OK) st = link_report_cstr(out, "\n"); 1128 if (st != KIT_OK) break; 1129 } 1130 if (st != KIT_OK) break; 1131 } 1132 h->free(h, ids, sizeof(*ids) * cap); 1133 return st == KIT_OK ? kit_writer_status(out) : st; 1134 } 1135 1136 /* --print-memory-usage: GNU-ld-style per-MEMORY-region used/free/total. The 1137 * regions come from the linker script; usage is the total size of placed 1138 * sections (and BSS zero-fill) whose runtime address falls inside a region's 1139 * [origin, origin+length) window. */ 1140 static KitStatus link_report_write_memory_usage_image(KitLinkSession* s, 1141 KitWriter* out) { 1142 LinkImage* img = s->image; 1143 const KitLinkScript* script = s->opts.linker_script; 1144 KitStatus st; 1145 u32 ri; 1146 if (!img) return KIT_INVALID; 1147 st = link_report_cstr(out, "Memory region Used Size Region Size " 1148 "%age Used\n"); 1149 if (st != KIT_OK) return st; 1150 if (!script || script->nregions == 0) return kit_writer_status(out); 1151 for (ri = 0; ri < script->nregions; ++ri) { 1152 const KitLinkRegion* rg = &script->regions[ri]; 1153 u64 used = 0; 1154 u64 free_bytes; 1155 unsigned pct_int = 0, pct_frac = 0; 1156 u32 j; 1157 for (j = 0; j < img->nsegments; ++j) { 1158 const LinkSegment* seg = &img->segments[j]; 1159 u64 base = img->load_base + seg->vaddr; 1160 /* Alias / program-header-only segments (nsections==0) describe the SAME 1161 * bytes as a primary segment under an additional :phdr; charging them 1162 * would double-count a section placed into multiple PT_LOADs. Real 1163 * primaries (incl. BSS/COMMON zero-fill) carry nsections>=1, so genuine 1164 * mem_size stays counted exactly once. */ 1165 if (seg->nsections == 0) continue; 1166 /* A segment belongs to a region when its load address sits within the 1167 * [origin, origin+length) window. Count memsz (covers BSS). The end of 1168 * the window is computed overflow-safe via a subtract — a region that 1169 * touches the top of the address space (origin+length wraps to 0) would 1170 * otherwise mis-test `base < 0` and attribute nothing. */ 1171 if (base >= rg->origin && 1172 (rg->length == 0 ? 0 : base - rg->origin < rg->length)) 1173 used += seg->mem_size; 1174 } 1175 free_bytes = (rg->length > used) ? rg->length - used : 0; 1176 if (rg->length) { 1177 /* Two-decimal percentage without floating point: used*10000/length. */ 1178 u64 scaled = (used * 10000ull) / rg->length; 1179 pct_int = (unsigned)(scaled / 100ull); 1180 pct_frac = (unsigned)(scaled % 100ull); 1181 } 1182 st = link_report_slice(out, 1183 rg->name.s ? rg->name : KIT_SLICE_LIT("<unnamed>")); 1184 if (st == KIT_OK) 1185 st = link_reportf(out, " used=0x%llx free=0x%llx total=0x%llx %u.%02u%%\n", 1186 (unsigned long long)used, 1187 (unsigned long long)free_bytes, 1188 (unsigned long long)rg->length, pct_int, pct_frac); 1189 if (st != KIT_OK) return st; 1190 } 1191 return kit_writer_status(out); 1192 } 1193 1194 typedef struct LinkReportArg { 1195 KitWriter* out; 1196 uint8_t format; 1197 KitStatus st; 1198 } LinkReportArg; 1199 1200 static void link_session_map_inner(KitLinkSession* s, void* arg) { 1201 LinkReportArg* a = (LinkReportArg*)arg; 1202 a->st = link_report_write_map_image(s, a->out); 1203 } 1204 1205 static void link_session_symbols_inner(KitLinkSession* s, void* arg) { 1206 LinkReportArg* a = (LinkReportArg*)arg; 1207 if (a->format != KIT_LINK_SYMBOLS_NM) { 1208 a->st = KIT_UNSUPPORTED; 1209 return; 1210 } 1211 a->st = link_report_write_symbols_nm(s->image, a->out); 1212 } 1213 1214 KitStatus kit_link_session_write_map(KitLinkSession* s, KitWriter* out) { 1215 LinkReportArg arg; 1216 KitStatus st; 1217 if (!s || !out) return KIT_INVALID; 1218 if ((KitLinkOutputKind)s->opts.output_kind == KIT_LINK_OUTPUT_RELOCATABLE || 1219 (KitLinkOutputKind)s->opts.output_kind == KIT_LINK_OUTPUT_JIT) 1220 return KIT_INVALID; 1221 if (!s->resolved) { 1222 st = kit_link_session_resolve(s); 1223 if (st != KIT_OK) return st; 1224 } 1225 arg.out = out; 1226 arg.format = KIT_LINK_SYMBOLS_NM; 1227 arg.st = KIT_OK; 1228 st = link_session_guard(s, link_session_map_inner, &arg); 1229 if (st != KIT_OK) return st; 1230 return arg.st == KIT_OK ? kit_writer_status(out) : arg.st; 1231 } 1232 1233 KitStatus kit_link_session_write_symbols(KitLinkSession* s, uint8_t format, 1234 KitWriter* out) { 1235 LinkReportArg arg; 1236 KitStatus st; 1237 if (!s || !out) return KIT_INVALID; 1238 if ((KitLinkOutputKind)s->opts.output_kind == KIT_LINK_OUTPUT_RELOCATABLE || 1239 (KitLinkOutputKind)s->opts.output_kind == KIT_LINK_OUTPUT_JIT) 1240 return KIT_INVALID; 1241 if (!s->resolved) { 1242 st = kit_link_session_resolve(s); 1243 if (st != KIT_OK) return st; 1244 } 1245 arg.out = out; 1246 arg.format = format; 1247 arg.st = KIT_OK; 1248 st = link_session_guard(s, link_session_symbols_inner, &arg); 1249 if (st != KIT_OK) return st; 1250 return arg.st == KIT_OK ? kit_writer_status(out) : arg.st; 1251 } 1252 1253 static void link_session_cref_inner(KitLinkSession* s, void* arg) { 1254 LinkReportArg* a = (LinkReportArg*)arg; 1255 a->st = link_report_write_cref_image(s, a->out); 1256 } 1257 1258 static void link_session_memusage_inner(KitLinkSession* s, void* arg) { 1259 LinkReportArg* a = (LinkReportArg*)arg; 1260 a->st = link_report_write_memory_usage_image(s, a->out); 1261 } 1262 1263 KitStatus kit_link_session_write_cref(KitLinkSession* s, KitWriter* out) { 1264 LinkReportArg arg; 1265 KitStatus st; 1266 if (!s || !out) return KIT_INVALID; 1267 if ((KitLinkOutputKind)s->opts.output_kind == KIT_LINK_OUTPUT_RELOCATABLE || 1268 (KitLinkOutputKind)s->opts.output_kind == KIT_LINK_OUTPUT_JIT) 1269 return KIT_INVALID; 1270 if (!s->resolved) { 1271 st = kit_link_session_resolve(s); 1272 if (st != KIT_OK) return st; 1273 } 1274 arg.out = out; 1275 arg.format = KIT_LINK_SYMBOLS_NM; 1276 arg.st = KIT_OK; 1277 st = link_session_guard(s, link_session_cref_inner, &arg); 1278 if (st != KIT_OK) return st; 1279 return arg.st == KIT_OK ? kit_writer_status(out) : arg.st; 1280 } 1281 1282 KitStatus kit_link_session_write_memory_usage(KitLinkSession* s, 1283 KitWriter* out) { 1284 LinkReportArg arg; 1285 KitStatus st; 1286 if (!s || !out) return KIT_INVALID; 1287 if ((KitLinkOutputKind)s->opts.output_kind == KIT_LINK_OUTPUT_RELOCATABLE || 1288 (KitLinkOutputKind)s->opts.output_kind == KIT_LINK_OUTPUT_JIT) 1289 return KIT_INVALID; 1290 if (!s->resolved) { 1291 st = kit_link_session_resolve(s); 1292 if (st != KIT_OK) return st; 1293 } 1294 arg.out = out; 1295 arg.format = KIT_LINK_SYMBOLS_NM; 1296 arg.st = KIT_OK; 1297 st = link_session_guard(s, link_session_memusage_inner, &arg); 1298 if (st != KIT_OK) return st; 1299 return arg.st == KIT_OK ? kit_writer_status(out) : arg.st; 1300 } 1301 1302 typedef struct LinkEmitArg { 1303 KitWriter* out; 1304 } LinkEmitArg; 1305 1306 static void link_session_emit_inner(KitLinkSession* s, void* arg) { 1307 KitWriter* out = ((LinkEmitArg*)arg)->out; 1308 if ((KitLinkOutputKind)s->opts.output_kind == KIT_LINK_OUTPUT_RELOCATABLE) { 1309 link_emit_relocatable_writer(s->linker, out); 1310 } else { 1311 link_emit_image_writer(s->image, out); 1312 } 1313 } 1314 1315 KitStatus kit_link_session_emit(KitLinkSession* s, KitWriter* out) { 1316 LinkEmitArg arg; 1317 KitStatus st; 1318 if (!s || !out) return KIT_INVALID; 1319 if (!s->resolved) { 1320 st = kit_link_session_resolve(s); 1321 if (st != KIT_OK) return st; 1322 } 1323 if ((KitLinkOutputKind)s->opts.output_kind == KIT_LINK_OUTPUT_JIT) 1324 return KIT_INVALID; 1325 arg.out = out; 1326 return link_session_guard(s, link_session_emit_inner, &arg); 1327 } 1328 1329 typedef struct LinkJitArg { 1330 KitJit* jit; 1331 } LinkJitArg; 1332 1333 static void link_session_jit_inner(KitLinkSession* s, void* arg) { 1334 LinkJitArg* a = (LinkJitArg*)arg; 1335 a->jit = kit_jit_from_image(s->image); 1336 if (a->jit) { 1337 s->image = NULL; 1338 s->linker_transferred = 1; 1339 s->linker = NULL; 1340 } 1341 } 1342 1343 KitStatus kit_link_session_jit(KitLinkSession* s, KitJit** out_jit) { 1344 LinkJitArg arg; 1345 KitStatus st; 1346 if (!out_jit) return KIT_INVALID; 1347 *out_jit = NULL; 1348 if (!s || (KitLinkOutputKind)s->opts.output_kind != KIT_LINK_OUTPUT_JIT) 1349 return KIT_INVALID; 1350 if (!s->resolved) { 1351 st = kit_link_session_resolve(s); 1352 if (st != KIT_OK) return st; 1353 } 1354 arg.jit = NULL; 1355 st = link_session_guard(s, link_session_jit_inner, &arg); 1356 if (st != KIT_OK) return st; 1357 if (!arg.jit) return KIT_ERR; 1358 *out_jit = arg.jit; 1359 return KIT_OK; 1360 } 1361 1362 void kit_link_session_free(KitLinkSession* s) { 1363 Heap* h; 1364 if (!s) return; 1365 h = s->c->ctx->heap; 1366 if (s->image) link_image_free(s->image); 1367 if (s->linker) link_free(s->linker); 1368 if (s->publish_objs) { 1369 h->free(h, s->publish_objs, sizeof(*s->publish_objs) * s->publish_objs_cap); 1370 } 1371 h->free(h, s, sizeof(*s)); 1372 }