kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

link.c (31151B)


      1 /* Linker: lifecycle, input registration, and LinkImage accessors.
      2  *
      3  * Resolution and layout live in link_layout.c; relocation application
      4  * in link_reloc.c; format-specific emit in link_elf.c; JIT mapping in
      5  * link_jit.c.
      6  *
      7  * Discipline (see link.h:136): inputs are never destroyed by
      8  * link_resolve, LinkInputId / ObjBuilder* mappings are stable for the
      9  * Linker's lifetime, and resolution produces a fresh LinkImage rather
     10  * than mutating the Linker. The single-shot implementation must keep
     11  * those invariants so a future incremental re-resolve can plug in. */
     12 
     13 #include "link/link.h"
     14 
     15 #include <kit/archive.h>
     16 #include <kit/core.h>
     17 #include <kit/object.h>
     18 #include <kit/target.h>
     19 #include <string.h>
     20 
     21 #include "core/heap.h"
     22 #include "core/pool.h"
     23 #include "core/slice.h"
     24 #include "core/vec.h"
     25 #include "link/link_internal.h"
     26 #include "obj/elf/elf.h"
     27 #include "obj/format.h"
     28 
     29 static const char* link_float_abi_name(KitFloatAbi abi) {
     30   switch (abi) {
     31     case KIT_FLOAT_ABI_DEFAULT:
     32       return "default";
     33     case KIT_FLOAT_ABI_SOFT:
     34       return "soft";
     35     case KIT_FLOAT_ABI_SINGLE:
     36       return "single";
     37     case KIT_FLOAT_ABI_DOUBLE:
     38       return "double";
     39   }
     40   return "unknown";
     41 }
     42 
     43 /* OS compatibility is deliberately directional: an ELF object carrying the
     44  * generic/Linux OSABI may be consumed by Linux, Android, or a freestanding
     45  * image, because that header value is what assemblers use for otherwise
     46  * platform-neutral relocatables. A FreeBSD object or a Mach-O platform stamp
     47  * is never borrowed across operating systems. */
     48 static int link_target_os_compatible(KitTargetSpec expected,
     49                                      KitTargetSpec actual) {
     50   if (expected.os == actual.os) return 1;
     51   if (expected.obj != KIT_OBJ_ELF || actual.os != KIT_OS_LINUX) return 0;
     52   return expected.os == KIT_OS_ANDROID ||
     53          expected.os == KIT_OS_FREESTANDING;
     54 }
     55 
     56 static const char* link_target_mismatch(KitTargetSpec expected,
     57                                         KitTargetSpec actual) {
     58   if (expected.arch != actual.arch) return "architecture";
     59   if (expected.obj != actual.obj) return "object format";
     60   if (expected.ptr_size != actual.ptr_size) return "pointer size";
     61   if (expected.big_endian != actual.big_endian) return "endianness";
     62   if (!link_target_os_compatible(expected, actual)) return "operating system";
     63   if ((expected.arch == KIT_ARCH_RV32 || expected.arch == KIT_ARCH_RV64) &&
     64       expected.float_abi != KIT_FLOAT_ABI_DEFAULT &&
     65       actual.float_abi != KIT_FLOAT_ABI_DEFAULT &&
     66       expected.float_abi != actual.float_abi)
     67     return "float ABI";
     68   return NULL;
     69 }
     70 
     71 static void link_target_panic(Linker* l, Slice name, Slice container,
     72                               KitTargetSpec actual, const char* reason) {
     73   KitTargetSpec expected = l->c->target;
     74   if (container.s) {
     75     compiler_panic(
     76         l->c, SRCLOC_NONE,
     77         "link: incompatible input '%.*s(%.*s)': %s mismatch; expected "
     78         "arch=%s os=%s format=%s ptr=%u endian=%s float=%s, got "
     79         "arch=%s os=%s format=%s ptr=%u endian=%s float=%s",
     80         SLICE_ARG(container), SLICE_ARG(name), reason,
     81         kit_target_arch_name(expected.arch), kit_target_os_name(expected.os),
     82         kit_target_obj_name(expected.obj), (u32)expected.ptr_size,
     83         expected.big_endian ? "big" : "little",
     84         link_float_abi_name((KitFloatAbi)expected.float_abi),
     85         kit_target_arch_name(actual.arch), kit_target_os_name(actual.os),
     86         kit_target_obj_name(actual.obj), (u32)actual.ptr_size,
     87         actual.big_endian ? "big" : "little",
     88         link_float_abi_name((KitFloatAbi)actual.float_abi));
     89   }
     90   compiler_panic(
     91       l->c, SRCLOC_NONE,
     92       "link: incompatible input '%.*s': %s mismatch; expected "
     93       "arch=%s os=%s format=%s ptr=%u endian=%s float=%s, got "
     94       "arch=%s os=%s format=%s ptr=%u endian=%s float=%s",
     95       SLICE_ARG(name), reason, kit_target_arch_name(expected.arch),
     96       kit_target_os_name(expected.os), kit_target_obj_name(expected.obj),
     97       (u32)expected.ptr_size, expected.big_endian ? "big" : "little",
     98       link_float_abi_name((KitFloatAbi)expected.float_abi),
     99       kit_target_arch_name(actual.arch), kit_target_os_name(actual.os),
    100       kit_target_obj_name(actual.obj), (u32)actual.ptr_size,
    101       actual.big_endian ? "big" : "little",
    102       link_float_abi_name((KitFloatAbi)actual.float_abi));
    103 }
    104 
    105 static void link_validate_target(Linker* l, Slice name, Slice container,
    106                                  KitTargetSpec actual) {
    107   const char* reason = link_target_mismatch(l->c->target, actual);
    108   if (reason) link_target_panic(l, name, container, actual, reason);
    109 }
    110 
    111 static void link_validate_obj_target(Linker* l, Slice name, ObjBuilder* ob) {
    112   Compiler* source = obj_compiler(ob);
    113   if (!source)
    114     compiler_panic(l->c, SRCLOC_NONE,
    115                    "link: input '%.*s' has no target-owning compiler",
    116                    SLICE_ARG(name));
    117   link_validate_target(l, name, SLICE_NULL, source->target);
    118 }
    119 
    120 static void link_validate_bytes_target(Linker* l, Slice name, Slice container,
    121                                        const u8* data, size_t len,
    122                                        int allow_text_dso) {
    123   KitTargetSpec actual;
    124   KitStatus st = kit_detect_target(data, len, &actual);
    125   if (st == KIT_OK) {
    126     link_validate_target(l, name, container, actual);
    127     return;
    128   }
    129   if (allow_text_dso && kit_detect_fmt(data, len) == KIT_BIN_UNKNOWN) return;
    130   if (container.s)
    131     compiler_panic(l->c, SRCLOC_NONE,
    132                    "link: cannot determine target of input '%.*s(%.*s)'",
    133                    SLICE_ARG(container), SLICE_ARG(name));
    134   compiler_panic(l->c, SRCLOC_NONE,
    135                  "link: cannot determine target of input '%.*s'",
    136                  SLICE_ARG(name));
    137 }
    138 
    139 void link_merge_elf_e_flags(Linker* l, ObjBuilder* ob, KitSlice label) {
    140   u32 incoming;
    141   u32 known = EF_RISCV_RVC | EF_RISCV_FLOAT_ABI_MASK | EF_RISCV_RVE |
    142               EF_RISCV_TSO;
    143   u32 must_match = EF_RISCV_FLOAT_ABI_MASK | EF_RISCV_RVE | ~known;
    144   u32 merge_bits = EF_RISCV_RVC | EF_RISCV_TSO;
    145   KitFloatAbi incoming_abi;
    146   KitFloatAbi target_abi;
    147   Slice first;
    148   if (!l || !ob || l->c->target.obj != KIT_OBJ_ELF ||
    149       (l->c->target.arch != KIT_ARCH_RV32 &&
    150        l->c->target.arch != KIT_ARCH_RV64) ||
    151       !obj_get_elf_e_flags(ob, &incoming))
    152     return;
    153   incoming_abi = elf_riscv_float_abi_from_e_flags(incoming);
    154   target_abi = (KitFloatAbi)l->c->target.float_abi;
    155   if (target_abi != KIT_FLOAT_ABI_DEFAULT && incoming_abi != target_abi) {
    156     compiler_panic(l->c, SRCLOC_NONE,
    157                    "link: incompatible input '%.*s': RISC-V float ABI is %s, "
    158                    "link target requires %s (e_flags=0x%x)",
    159                    SLICE_ARG(label), link_float_abi_name(incoming_abi),
    160                    link_float_abi_name(target_abi), incoming);
    161   }
    162   if (!l->have_elf_e_flags) {
    163     l->elf_e_flags = incoming;
    164     l->elf_e_flags_source = pool_intern_slice(l->c->global, label);
    165     l->have_elf_e_flags = 1;
    166     return;
    167   }
    168   if ((l->elf_e_flags & must_match) != (incoming & must_match)) {
    169     first = l->elf_e_flags_source
    170                 ? pool_slice(l->c->global, l->elf_e_flags_source)
    171                 : SLICE_LIT("<first input>");
    172     compiler_panic(l->c, SRCLOC_NONE,
    173                    "link: incompatible RISC-V ELF e_flags: input '%.*s' has "
    174                    "0x%x, input '%.*s' has 0x%x (float ABI, RVE, and reserved "
    175                    "bits must agree)",
    176                    SLICE_ARG(label), incoming, SLICE_ARG(first),
    177                    l->elf_e_flags);
    178   }
    179   l->elf_e_flags |= incoming & merge_bits;
    180 }
    181 
    182 /* ---- SrcLoc helper ---- */
    183 
    184 /* SymHash is a HASHMAP_DEFINE instance — see link_internal.h. The thin
    185  * symhash_* wrappers there preserve the historic insert-if-absent / by-
    186  * value get API. */
    187 
    188 /* ---- Linker lifecycle ---- */
    189 
    190 static void linker_release(Linker* l) {
    191   u32 i, j;
    192   if (!l) return;
    193   /* Free the ObjBuilders we own (the ones we read from bytes inputs).
    194    * link_add_obj inputs are caller-owned and stay alive. */
    195   for (i = 0; i < LinkInputs_count(&l->inputs); ++i) {
    196     LinkInput* in = LinkInputs_at(&l->inputs, i);
    197     if ((in->kind == LINK_INPUT_OBJ_BYTES ||
    198          in->kind == LINK_INPUT_DSO_BYTES) &&
    199         in->obj)
    200       obj_free(in->obj);
    201   }
    202   /* Free archive member ObjBuilders that were never pulled into inputs.
    203    * Pulled members had their `obj` pointer transferred and nulled, so
    204    * obj_free(NULL) is safe regardless. */
    205   for (i = 0; i < LinkArchives_count(&l->archives); ++i) {
    206     LinkArchive* ar = LinkArchives_at(&l->archives, i);
    207     for (j = 0; j < ar->nmembers; ++j) {
    208       if (ar->members[j].obj) obj_free(ar->members[j].obj);
    209     }
    210     if (ar->members)
    211       l->heap->free(l->heap, ar->members, sizeof(*ar->members) * ar->nmembers);
    212   }
    213   LinkArchives_fini(&l->archives);
    214   LinkInputs_fini(&l->inputs);
    215   l->heap->free(l->heap, l, sizeof(*l));
    216 }
    217 
    218 static void linker_cleanup(void* arg) { linker_release((Linker*)arg); }
    219 
    220 Linker* link_new(Compiler* c) {
    221   Heap* h = (Heap*)c->ctx->heap;
    222   Linker* l = (Linker*)h->alloc(h, sizeof(*l), _Alignof(Linker));
    223   if (!l) return NULL;
    224   memset(l, 0, sizeof(*l));
    225   l->c = c;
    226   l->heap = h;
    227   LinkInputs_init(&l->inputs, h);
    228   LinkArchives_init(&l->archives, h);
    229   /* Default entry: ELF/static convention uses `_start`.  Mach-O's
    230    * LC_MAIN names main directly (dyld owns the C runtime startup),
    231    * so the on-disk symbol is `_main` (the mangled form of `main`).
    232    * Format choice lives in obj_format_default_entry_name. */
    233   l->entry_name = pool_intern_slice(
    234       c->global, slice_from_cstr(obj_format_default_entry_name(c)));
    235   /* Match the rest of libkit's lifetime story: the new'd Linker is
    236    * registered for cleanup in case a panic fires before link_free. */
    237   l->deferred = compiler_defer(c, linker_cleanup, l);
    238   return l;
    239 }
    240 
    241 void link_free(Linker* l) {
    242   Compiler* c;
    243   CompilerCleanup* d;
    244   if (!l) return;
    245   c = l->c;
    246   d = l->deferred;
    247   linker_release(l);
    248   if (d) compiler_undefer(c, d);
    249 }
    250 
    251 /* ---- input registration ---- */
    252 
    253 static LinkInput* inputs_push(Linker* l, LinkInputId* id_out) {
    254   u32 idx;
    255   LinkInput* in = LinkInputs_push(&l->inputs, &idx);
    256   if (!in)
    257     compiler_panic(l->c, SRCLOC_NONE, "link: out of memory growing inputs");
    258   *id_out = (LinkInputId)(idx + 1u);
    259   in->id = *id_out;
    260   return in;
    261 }
    262 
    263 LinkInputId link_add_obj(Linker* l, ObjBuilder* ob) {
    264   LinkInputId id;
    265   LinkInput* in;
    266   if (!l || !ob) return LINK_INPUT_NONE;
    267   link_validate_obj_target(l, SLICE_LIT("<in-memory object>"), ob);
    268   link_merge_elf_e_flags(l, ob, SLICE_LIT("<in-memory object>"));
    269   in = inputs_push(l, &id);
    270   in->kind = LINK_INPUT_OBJ;
    271   in->order = l->next_input_order++;
    272   in->obj = ob;
    273   return id;
    274 }
    275 
    276 LinkInputId link_add_obj_bytes(Linker* l, const char* name, const u8* data,
    277                                size_t len) {
    278   ObjBuilder* ob;
    279   LinkInput* in;
    280   LinkInputId id;
    281   KitBinFmt fmt;
    282   const ObjFormatImpl* impl;
    283   const char* reader_name;
    284   Slice label;
    285   if (!l || !data || !len) return LINK_INPUT_NONE;
    286   label = name ? slice_from_cstr(name) : SLICE_LIT("(unnamed)");
    287   link_validate_bytes_target(l, label, SLICE_NULL, data, len, 0);
    288   fmt = kit_detect_fmt(data, len);
    289   impl = obj_format_lookup_bin(fmt);
    290   if (!impl || !impl->read)
    291     compiler_panic(
    292         l->c, SRCLOC_NONE,
    293         "link_add_obj_bytes: unsupported object format "
    294         "(fmt=%u) for '%.*s'",
    295         (u32)fmt,
    296         SLICE_ARG(name ? slice_from_cstr(name) : SLICE_LIT("(unnamed)")));
    297   reader_name = impl->read_name;
    298   ob = impl->read(l->c, name, data, len);
    299   if (!ob)
    300     compiler_panic(
    301         l->c, SRCLOC_NONE, "link_add_obj_bytes: %.*s returned NULL for '%.*s'",
    302         SLICE_ARG(slice_from_cstr(reader_name)),
    303         SLICE_ARG(name ? slice_from_cstr(name) : SLICE_LIT("(unnamed)")));
    304   link_merge_elf_e_flags(l, ob, label);
    305   in = inputs_push(l, &id);
    306   in->order = l->next_input_order++;
    307   in->obj = ob; /* re-uses the ObjBuilder slot for ownership */
    308   in->name = name ? pool_intern_cstr(l->c->global, name) : 0;
    309   {
    310     Sym soname = 0;
    311     if (impl->classify_obj_input &&
    312         impl->classify_obj_input(l->c, ob, &soname)) {
    313       in->kind = LINK_INPUT_DSO_BYTES;
    314       in->soname = soname;
    315     } else {
    316       in->kind = LINK_INPUT_OBJ_BYTES;
    317     }
    318   }
    319   return id;
    320 }
    321 
    322 LinkInputId link_add_dso_bytes(Linker* l, const char* name, const u8* data,
    323                                size_t len) {
    324   ObjBuilder* ob = NULL;
    325   LinkInput* in;
    326   LinkInputId id;
    327   Sym soname = 0;
    328   KitBinFmt fmt;
    329   ObjFormatDsoReader reader;
    330   const ObjFormatImpl* target_impl;
    331   const char* reader_name;
    332   Slice label;
    333   if (!l || !data || !len) return LINK_INPUT_NONE;
    334   label = name ? slice_from_cstr(name) : SLICE_LIT("(unnamed)");
    335   link_validate_bytes_target(l, label, SLICE_NULL, data, len, 1);
    336   if (!obj_format_dso_reader_for_bytes(data, len, &fmt, &reader))
    337     compiler_panic(
    338         l->c, SRCLOC_NONE,
    339         "link_add_dso_bytes: unsupported DSO format "
    340         "(fmt=%u) for '%.*s'",
    341         (u32)fmt,
    342         SLICE_ARG(name ? slice_from_cstr(name) : SLICE_LIT("(unnamed)")));
    343   target_impl = obj_format_lookup(l->c->target.obj);
    344   if (!target_impl || reader.format != target_impl)
    345     compiler_panic(
    346         l->c, SRCLOC_NONE,
    347         "link: incompatible input '%.*s': object format mismatch; expected "
    348         "format=%s, got format=%s",
    349         SLICE_ARG(label), kit_target_obj_name(l->c->target.obj),
    350         reader.format && reader.format->name ? reader.format->name : "unknown");
    351   reader_name = reader.name;
    352   ob = reader.read(l->c, name, data, len, &soname);
    353   if (!ob)
    354     compiler_panic(
    355         l->c, SRCLOC_NONE, "link_add_dso_bytes: %.*s returned NULL for '%.*s'",
    356         SLICE_ARG(slice_from_cstr(reader_name)),
    357         SLICE_ARG(name ? slice_from_cstr(name) : SLICE_LIT("(unnamed)")));
    358   link_merge_elf_e_flags(l, ob, label);
    359   in = inputs_push(l, &id);
    360   in->kind = LINK_INPUT_DSO_BYTES;
    361   in->order = l->next_input_order++;
    362   in->obj = ob;
    363   in->name = name ? pool_intern_cstr(l->c->global, name) : 0;
    364   /* DT_SONAME wins; fall back to the file's basename if the DSO has
    365    * no SONAME (matches GNU ld's behaviour for hand-rolled libraries
    366    * that forgot to set DT_SONAME). */
    367   if (soname != 0) {
    368     in->soname = soname;
    369   } else if (name) {
    370     const char* base = name;
    371     const char* p;
    372     for (p = name; *p; ++p)
    373       if (*p == '/') base = p + 1;
    374     in->soname = pool_intern_cstr(l->c->global, base);
    375   } else {
    376     in->soname = 0;
    377   }
    378   return id;
    379 }
    380 
    381 LinkInputId link_add_archive_bytes(Linker* l, const char* name, const u8* data,
    382                                    size_t len, u8 whole_archive, u8 link_mode,
    383                                    u8 group_id) {
    384   KitSlice in_arc;
    385   KitArIter* it = NULL;
    386   KitArMember mem;
    387   LinkArchive* ar;
    388   u32 n;
    389   Sym archive_hint = 0;
    390   const ObjFormatImpl* target_impl;
    391 
    392   if (!l || !data || !len) return LINK_INPUT_NONE;
    393   target_impl = obj_format_lookup(l->c->target.obj);
    394   if (target_impl && target_impl->archive_hint)
    395     archive_hint = target_impl->archive_hint(l->c, name);
    396 
    397   in_arc.data = data;
    398   in_arc.len = len;
    399   if (kit_ar_iter_new(kit_compiler_context(l->c), &in_arc, &it) != KIT_OK ||
    400       !it)
    401     compiler_panic(
    402         l->c, SRCLOC_NONE,
    403         "link_add_archive_bytes: '%.*s' is not a valid ar archive",
    404         SLICE_ARG(name ? slice_from_cstr(name) : SLICE_LIT("(unnamed)")));
    405 
    406   /* Two-pass: count members so we allocate the member array exactly
    407    * once. The linker_release path frees by nmembers, so we need
    408    * allocation size to match. */
    409   n = 0;
    410   while (kit_ar_iter_next(it, &mem) == KIT_ITER_ITEM) ++n;
    411   kit_ar_iter_free(it);
    412   it = NULL;
    413 
    414   ar = LinkArchives_push(&l->archives, NULL);
    415   if (!ar)
    416     compiler_panic(l->c, SRCLOC_NONE, "link: out of memory growing archives");
    417   ar->name = name ? pool_intern_cstr(l->c->global, name) : 0;
    418   ar->order = l->next_input_order++;
    419   ar->whole_archive = whole_archive;
    420   ar->link_mode = link_mode;
    421   ar->group_id = group_id;
    422   ar->nmembers = n;
    423   ar->members =
    424       n ? (LinkArchiveMember*)l->heap->alloc(l->heap, sizeof(*ar->members) * n,
    425                                              _Alignof(LinkArchiveMember))
    426         : NULL;
    427   if (n && !ar->members)
    428     compiler_panic(l->c, SRCLOC_NONE, "link: oom on archive members");
    429   if (n) memset(ar->members, 0, sizeof(*ar->members) * n);
    430 
    431   /* Pass 2: parse each member as object. ar.c's iterator skips the
    432    * symbol-index ('/' and '__.SYMDEF') and long-name ('//') members
    433    * for us, so every member returned here is a real object file.
    434    * Format is detected per-member so a single archive could in
    435    * principle hold mixed formats (in practice it never does). */
    436   if (kit_ar_iter_new(kit_compiler_context(l->c), &in_arc, &it) != KIT_OK ||
    437       !it)
    438     compiler_panic(
    439         l->c, SRCLOC_NONE,
    440         "link_add_archive_bytes: ar_iter_init failed on '%.*s' "
    441         "second pass",
    442         SLICE_ARG(name ? slice_from_cstr(name) : SLICE_LIT("(unnamed)")));
    443   n = 0;
    444   while (kit_ar_iter_next(it, &mem) == KIT_ITER_ITEM && n < ar->nmembers) {
    445     ObjBuilder* ob = NULL;
    446     KitBinFmt mfmt = kit_detect_fmt(mem.data, mem.size);
    447     const ObjFormatImpl* member_impl = obj_format_lookup_bin(mfmt);
    448     link_validate_bytes_target(
    449         l, mem.name.len ? mem.name : SLICE_LIT("(unnamed)"),
    450         name ? slice_from_cstr(name) : SLICE_LIT("(unnamed)"), mem.data,
    451         mem.size, 0);
    452     if (target_impl && target_impl->archive_member) {
    453       ObjFormatArchiveMember desc;
    454       ObjFormatArchiveAction action;
    455       memset(&desc, 0, sizeof(desc));
    456       desc.archive_name = name;
    457       desc.member_name = mem.name.s;
    458       desc.data = mem.data;
    459       desc.len = mem.size;
    460       desc.bin_fmt = mfmt;
    461       desc.archive_hint = archive_hint;
    462       action = target_impl->archive_member(l->c, &desc, &ob);
    463       if (action != OBJ_FORMAT_ARCHIVE_KEEP) {
    464         ar->members[n].name =
    465             mem.name.len ? pool_intern_slice(l->c->global, mem.name) : 0;
    466         ar->members[n].obj = ob;
    467         ++n;
    468         continue;
    469       }
    470     }
    471     if (!member_impl || !member_impl->read)
    472       compiler_panic(
    473           l->c, SRCLOC_NONE,
    474           "link_add_archive_bytes: unsupported member "
    475           "format (fmt=%u) for '%.*s' in archive '%.*s'",
    476           (u32)mfmt,
    477           SLICE_ARG(mem.name.len ? mem.name : SLICE_LIT("(unnamed)")),
    478           SLICE_ARG(name ? slice_from_cstr(name) : SLICE_LIT("(unnamed)")));
    479     ob = member_impl->read(l->c, mem.name.s, mem.data, mem.size);
    480     if (!ob)
    481       compiler_panic(
    482           l->c, SRCLOC_NONE,
    483           "link_add_archive_bytes: object read failed for "
    484           "member '%.*s' of archive '%.*s'",
    485           SLICE_ARG(mem.name.len ? mem.name : SLICE_LIT("(unnamed)")),
    486           SLICE_ARG(name ? slice_from_cstr(name) : SLICE_LIT("(unnamed)")));
    487     ar->members[n].name =
    488         mem.name.len ? pool_intern_slice(l->c->global, mem.name) : 0;
    489     ar->members[n].obj = ob;
    490     ++n;
    491   }
    492   kit_ar_iter_free(it);
    493   return (LinkInputId)LinkArchives_count(
    494       &l->archives); /* opaque non-zero handle */
    495 }
    496 
    497 /* Intern a C-source-level symbol name in the format the input objects
    498  * use on the wire.  Format-specific mangling (Mach-O `_` prefix,
    499  * verbatim everywhere else) lives in obj_format_c_mangle. */
    500 Sym link_intern_c_name(Linker* l, const char* name) {
    501   if (!l || !name) return 0;
    502   return obj_format_c_mangle(l->c, name);
    503 }
    504 
    505 void link_set_entry(Linker* l, KitSlice name) {
    506   if (!l || !name.s || name.len == 0) return;
    507   /* entry names from the API/script are interned arena/pool slices and
    508    * thus NUL-terminated; the mangler scans a C string. */
    509   l->entry_name = link_intern_c_name(l, name.s);
    510 }
    511 
    512 void link_clear_entry(Linker* l) {
    513   if (!l) return;
    514   l->entry_name = 0;
    515 }
    516 
    517 void link_set_script(Linker* l, const KitLinkScript* script) {
    518   if (!l || !script) return;
    519   l->script = script;
    520   if (script->entry.s && script->entry.len)
    521     l->entry_name = link_intern_c_name(l, script->entry.s);
    522 }
    523 
    524 void link_set_extern_resolver(Linker* l, LinkExternResolver fn, void* user) {
    525   if (!l) return;
    526   l->resolver = fn;
    527   l->resolver_user = user;
    528 }
    529 
    530 void link_set_gc_sections(Linker* l, int enable) {
    531   if (!l) return;
    532   l->gc_sections = enable;
    533   /* Accepted but ignored this cut. Quiet by design — driver/ld.c may
    534    * pass 0 unconditionally and we don't want to noise that. */
    535 }
    536 
    537 void link_set_strip_debug(Linker* l, int enable) {
    538   if (!l) return;
    539   l->strip_debug = enable;
    540   /* Executable layouts already omit non-alloc debug sections. Keep the flag
    541    * recorded so driver -S/--strip-debug flows through the linker surface. */
    542 }
    543 
    544 void link_set_allow_undefined(Linker* l, int enable) {
    545   if (!l) return;
    546   l->allow_undefined = enable ? 1 : 0;
    547 }
    548 
    549 void link_set_shared(Linker* l, int enable) {
    550   if (!l) return;
    551   l->emit_shared = enable ? 1 : 0;
    552 }
    553 
    554 void link_set_emit_static_exe(Linker* l, int enable) {
    555   if (!l) return;
    556   l->emit_static_exe = enable ? 1 : 0;
    557 }
    558 
    559 void link_set_jit_mode(Linker* l, int enable) {
    560   if (!l) return;
    561   l->jit_mode = enable ? 1 : 0;
    562 }
    563 
    564 void link_set_pie(Linker* l, int enable) {
    565   if (!l) return;
    566   l->emit_pie = enable ? 1 : 0;
    567 }
    568 
    569 void link_set_text_base(Linker* l, u64 base) {
    570   if (!l) return;
    571   l->text_base_set = 1;
    572   l->text_base = base;
    573 }
    574 
    575 void link_set_pe_subsystem(Linker* l, u16 subsystem) {
    576   if (!l) return;
    577   l->pe_subsystem = subsystem;
    578 }
    579 
    580 void link_set_jit_host(Linker* l, const KitJitHost* host) {
    581   if (!l) return;
    582   l->jit_host = host;
    583 }
    584 
    585 void link_set_interp_path(Linker* l, KitSlice path) {
    586   if (!l) return;
    587   l->interp_path =
    588       (path.s && path.len) ? pool_intern_slice(l->c->global, path) : 0;
    589 }
    590 
    591 /* ---- debug-input capture ----
    592  *
    593  * Called once at the tail of link_resolve.  For each LinkInput, record
    594  * its ObjBuilder on the LinkImage so the JIT debug view (kit_jit_view)
    595  * can read .debug_* sections after the Linker is freed.  Two ownership
    596  * regimes:
    597  *
    598  *   LINK_INPUT_OBJ_BYTES: linker owns; transfer to the image and null
    599  *     the LinkInput's obj so linker_release doesn't double-free.
    600  *   LINK_INPUT_OBJ:       caller owns; borrow the pointer (do not free
    601  *     at image teardown).  Caller is responsible for keeping the
    602  *     builder alive at least as long as the JIT.
    603  *
    604  * DSO / archive-only inputs carry no source-level debug info worth
    605  * surfacing through kit_jit_view, so their slot stays NULL. */
    606 void link_capture_debug_inputs(Linker* l, LinkImage* img) {
    607   u32 n;
    608   u32 i;
    609   Heap* h;
    610   if (!l || !img) return;
    611   n = LinkInputs_count(&l->inputs);
    612   img->dbg_objs_n = n;
    613   if (n == 0) {
    614     img->dbg_objs = NULL;
    615     img->dbg_objs_owned = NULL;
    616     return;
    617   }
    618   h = img->heap;
    619   img->dbg_objs = (ObjBuilder**)h->alloc(h, sizeof(*img->dbg_objs) * n,
    620                                          _Alignof(ObjBuilder*));
    621   img->dbg_objs_owned = (u8*)h->alloc(h, sizeof(*img->dbg_objs_owned) * n, 1u);
    622   if (!img->dbg_objs || !img->dbg_objs_owned)
    623     compiler_panic(img->c, SRCLOC_NONE,
    624                    "link_capture_debug_inputs: oom on dbg arrays");
    625   memset(img->dbg_objs, 0, sizeof(*img->dbg_objs) * n);
    626   memset(img->dbg_objs_owned, 0, sizeof(*img->dbg_objs_owned) * n);
    627   for (i = 0; i < n; ++i) {
    628     LinkInput* in = LinkInputs_at(&l->inputs, i);
    629     if (!in || !in->obj) continue;
    630     switch (in->kind) {
    631       case LINK_INPUT_OBJ_BYTES:
    632         img->dbg_objs[i] = in->obj;
    633         img->dbg_objs_owned[i] = 1u;
    634         in->obj = NULL; /* transfer: linker_release must not free it */
    635         break;
    636       case LINK_INPUT_OBJ:
    637         img->dbg_objs[i] = in->obj;
    638         img->dbg_objs_owned[i] = 0u; /* borrowed; caller still owns */
    639         break;
    640       default:
    641         /* DSO / TBD: skip — no user-level debug sections we expose. */
    642         break;
    643     }
    644   }
    645 }
    646 
    647 /* ---- LinkImage accessors ---- */
    648 
    649 const LinkSymbol* link_symbol(LinkImage* img, LinkSymId id) {
    650   if (!img || id == LINK_SYM_NONE || id > LinkSyms_count(&img->syms))
    651     return NULL;
    652   return LinkSyms_at(&img->syms, id - 1);
    653 }
    654 
    655 LinkSymId link_symbol_lookup(LinkImage* img, Sym name) {
    656   if (!img) return LINK_SYM_NONE;
    657   return symhash_get(&img->globals, name);
    658 }
    659 
    660 u32 link_segment_count(LinkImage* img) { return img ? img->nsegments : 0; }
    661 
    662 const LinkSegment* link_segment_get(LinkImage* img, u32 id) {
    663   if (!img || id == LINK_SEG_NONE || id > img->nsegments) return NULL;
    664   return &img->segments[id - 1];
    665 }
    666 
    667 const u8* link_segment_bytes(LinkImage* img, LinkSegmentId id,
    668                              size_t* size_out) {
    669   if (size_out) *size_out = 0;
    670   if (!img || id == LINK_SEG_NONE || id > img->nsegments) return NULL;
    671   if (size_out) *size_out = (size_t)img->segments[id - 1].file_size;
    672   return img->segment_bytes[id - 1];
    673 }
    674 
    675 u32 link_section_count(LinkImage* img) { return img ? img->nsections : 0; }
    676 
    677 const LinkSection* link_section_get(LinkImage* img, LinkSectionId id) {
    678   if (!img || id == LINK_SEC_NONE || id > img->nsections) return NULL;
    679   return &img->sections[id - 1];
    680 }
    681 
    682 u32 link_reloc_apply_count(LinkImage* img) {
    683   return img ? LinkRelocs_count(&img->relocs) : 0;
    684 }
    685 
    686 const LinkRelocApply* link_reloc_apply_get(LinkImage* img, u32 id) {
    687   if (!img || id >= LinkRelocs_count(&img->relocs)) return NULL;
    688   return LinkRelocs_at(&img->relocs, id);
    689 }
    690 
    691 /* ---- LinkImage free / cleanup ---- */
    692 
    693 static void link_image_release(LinkImage* img) {
    694   u32 i;
    695   if (!img) return;
    696   if (img->segment_bytes) {
    697     for (i = 0; i < img->nsegments; ++i) {
    698       if (img->segment_bytes[i])
    699         img->heap->free(img->heap, img->segment_bytes[i],
    700                         img->segment_bytes_cap[i]);
    701     }
    702     img->heap->free(img->heap, img->segment_bytes,
    703                     sizeof(*img->segment_bytes) * img->nsegments);
    704     img->heap->free(img->heap, img->segment_bytes_cap,
    705                     sizeof(*img->segment_bytes_cap) * img->nsegments);
    706   }
    707   if (img->segments)
    708     img->heap->free(img->heap, img->segments,
    709                     sizeof(*img->segments) * img->nsegments);
    710   if (img->sections)
    711     img->heap->free(img->heap, img->sections,
    712                     sizeof(*img->sections) * img->nsections);
    713   LinkSyms_fini(&img->syms);
    714   LinkRelocs_fini(&img->relocs);
    715   if (img->iplt_pairs)
    716     img->heap->free(img->heap, img->iplt_pairs,
    717                     sizeof(*img->iplt_pairs) * img->niplt * 2u);
    718   if (img->input_maps) {
    719     for (i = 0; i < img->ninput_maps; ++i) {
    720       InputMap* m = &img->input_maps[i];
    721       if (m->sym) img->heap->free(img->heap, m->sym, sizeof(*m->sym) * m->nsym);
    722       if (m->section)
    723         img->heap->free(img->heap, m->section,
    724                         sizeof(*m->section) * m->nsection);
    725       if (m->atom)
    726         img->heap->free(img->heap, m->atom,
    727                         sizeof(*m->atom) * (m->natom ? m->natom : 1u));
    728       if (m->sym_atom)
    729         img->heap->free(img->heap, m->sym_atom,
    730                         sizeof(*m->sym_atom) * (m->nsym ? m->nsym : 1u));
    731       if (m->reloc_atom)
    732         img->heap->free(img->heap, m->reloc_atom,
    733                         sizeof(*m->reloc_atom) * (m->nreloc ? m->nreloc : 1u));
    734       if (m->section_has_atoms)
    735         img->heap->free(img->heap, m->section_has_atoms,
    736                         m->nsection ? m->nsection : 1u);
    737       if (m->section_atom_first)
    738         img->heap->free(
    739             img->heap, m->section_atom_first,
    740             sizeof(*m->section_atom_first) * (m->nsection ? m->nsection : 1u));
    741       if (m->section_atom_count)
    742         img->heap->free(
    743             img->heap, m->section_atom_count,
    744             sizeof(*m->section_atom_count) * (m->nsection ? m->nsection : 1u));
    745       if (m->section_atom_ids)
    746         img->heap->free(img->heap, m->section_atom_ids,
    747                         sizeof(*m->section_atom_ids) * m->nsection_atom_ids);
    748       if (m->comdat_discarded)
    749         img->heap->free(img->heap, m->comdat_discarded,
    750                         m->nsection ? m->nsection : 1u);
    751     }
    752     img->heap->free(img->heap, img->input_maps,
    753                     sizeof(*img->input_maps) * img->ninput_maps);
    754   }
    755   if (img->dbg_objs) {
    756     for (i = 0; i < img->dbg_objs_n; ++i) {
    757       if (img->dbg_objs[i] && img->dbg_objs_owned && img->dbg_objs_owned[i])
    758         obj_free(img->dbg_objs[i]);
    759     }
    760     img->heap->free(img->heap, img->dbg_objs,
    761                     sizeof(*img->dbg_objs) * img->dbg_objs_n);
    762     if (img->dbg_objs_owned)
    763       img->heap->free(img->heap, img->dbg_objs_owned,
    764                       sizeof(*img->dbg_objs_owned) * img->dbg_objs_n);
    765   }
    766   if (img->dbg_bytes) {
    767     for (i = 0; i < img->dbg_count; ++i)
    768       if (img->dbg_bytes[i])
    769         img->heap->free(img->heap, img->dbg_bytes[i], (size_t)img->dbg_size[i]);
    770     img->heap->free(img->heap, img->dbg_bytes,
    771                     sizeof(*img->dbg_bytes) * img->dbg_count);
    772   }
    773   if (img->dbg_size)
    774     img->heap->free(img->heap, img->dbg_size,
    775                     sizeof(*img->dbg_size) * img->dbg_count);
    776   symhash_fini(&img->globals);
    777   if (img->dyn) {
    778     const ObjFormatImpl* fmt = obj_format_lookup(img->c->target.obj);
    779     if (fmt && fmt->free_dyn) fmt->free_dyn(img);
    780   }
    781   img->heap->free(img->heap, img, sizeof(*img));
    782 }
    783 
    784 static void link_image_cleanup(void* arg) {
    785   link_image_release((LinkImage*)arg);
    786 }
    787 
    788 LinkImage* link_image_alloc(Compiler* c) {
    789   Heap* h = (Heap*)c->ctx->heap;
    790   LinkImage* img = (LinkImage*)h->alloc(h, sizeof(*img), _Alignof(LinkImage));
    791   if (!img)
    792     compiler_panic(c, SRCLOC_NONE, "link: out of memory allocating image");
    793   memset(img, 0, sizeof(*img));
    794   img->c = c;
    795   img->heap = h;
    796   LinkSyms_init(&img->syms, h);
    797   LinkRelocs_init(&img->relocs, h);
    798   symhash_init(&img->globals, h);
    799   img->deferred = compiler_defer(c, link_image_cleanup, img);
    800   return img;
    801 }
    802 
    803 void link_image_free(LinkImage* img) {
    804   if (!img) return;
    805   if (img->deferred) compiler_undefer(img->c, img->deferred);
    806   link_image_release(img);
    807 }
    808 
    809 /* ---- Incremental resolution (stubs) ----
    810  * Per-block JIT translation in src/emu/ wants to grow a single
    811  * LinkImage as cold blocks land (doc/EMU.md §6). The single-shot
    812  * link_resolve discipline (link.h header comment) is set up to
    813  * support this — inputs are non-destructively consumed, ObjBuilder*
    814  * mappings are stable, resolution is functional. The two entries
    815  * below are the surface; the implementation lands alongside the
    816  * emu lifter cut. */
    817 
    818 LinkImage* link_resolve_at(Linker* l, uintptr_t base_va) {
    819   (void)base_va;
    820   if (!l) return NULL;
    821   compiler_panic(l->c, SRCLOC_NONE,
    822                  "link_resolve_at: incremental resolution not yet "
    823                  "implemented");
    824   return NULL;
    825 }
    826 
    827 void link_resolve_extend(Linker* l, LinkImage* img) {
    828   (void)img;
    829   if (!l) return;
    830   compiler_panic(l->c, SRCLOC_NONE,
    831                  "link_resolve_extend: incremental resolution not "
    832                  "yet implemented");
    833 }
    834 
    835 /* ---- public emit dispatcher ---- */
    836 
    837 void link_emit_image_writer(LinkImage* img, Writer* w) {
    838   const ObjFormatImpl* fmt;
    839   if (!img || !w) return;
    840   fmt = obj_format_lookup(img->c->target.obj);
    841   if (fmt && fmt->link_emit) {
    842     fmt->link_emit(img, w);
    843     return;
    844   }
    845   compiler_panic(img->c, SRCLOC_NONE,
    846                  "link_emit_image_writer: unsupported obj format %u",
    847                  (u32)img->c->target.obj);
    848 }