kit

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

link.c (23085B)


      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 <string.h>
     19 
     20 #include "core/heap.h"
     21 #include "core/pool.h"
     22 #include "core/slice.h"
     23 #include "core/vec.h"
     24 #include "link/link_internal.h"
     25 #include "obj/format.h"
     26 
     27 /* ---- SrcLoc helper ---- */
     28 
     29 /* SymHash is a HASHMAP_DEFINE instance — see link_internal.h. The thin
     30  * symhash_* wrappers there preserve the historic insert-if-absent / by-
     31  * value get API. */
     32 
     33 /* ---- Linker lifecycle ---- */
     34 
     35 static void linker_release(Linker* l) {
     36   u32 i, j;
     37   if (!l) return;
     38   /* Free the ObjBuilders we own (the ones we read from bytes inputs).
     39    * link_add_obj inputs are caller-owned and stay alive. */
     40   for (i = 0; i < LinkInputs_count(&l->inputs); ++i) {
     41     LinkInput* in = LinkInputs_at(&l->inputs, i);
     42     if ((in->kind == LINK_INPUT_OBJ_BYTES ||
     43          in->kind == LINK_INPUT_DSO_BYTES) &&
     44         in->obj)
     45       obj_free(in->obj);
     46   }
     47   /* Free archive member ObjBuilders that were never pulled into inputs.
     48    * Pulled members had their `obj` pointer transferred and nulled, so
     49    * obj_free(NULL) is safe regardless. */
     50   for (i = 0; i < LinkArchives_count(&l->archives); ++i) {
     51     LinkArchive* ar = LinkArchives_at(&l->archives, i);
     52     for (j = 0; j < ar->nmembers; ++j) {
     53       if (ar->members[j].obj) obj_free(ar->members[j].obj);
     54     }
     55     if (ar->members)
     56       l->heap->free(l->heap, ar->members, sizeof(*ar->members) * ar->nmembers);
     57   }
     58   LinkArchives_fini(&l->archives);
     59   LinkInputs_fini(&l->inputs);
     60   l->heap->free(l->heap, l, sizeof(*l));
     61 }
     62 
     63 static void linker_cleanup(void* arg) { linker_release((Linker*)arg); }
     64 
     65 Linker* link_new(Compiler* c) {
     66   Heap* h = (Heap*)c->ctx->heap;
     67   Linker* l = (Linker*)h->alloc(h, sizeof(*l), _Alignof(Linker));
     68   if (!l) return NULL;
     69   memset(l, 0, sizeof(*l));
     70   l->c = c;
     71   l->heap = h;
     72   LinkInputs_init(&l->inputs, h);
     73   LinkArchives_init(&l->archives, h);
     74   /* Default entry: ELF/static convention uses `_start`.  Mach-O's
     75    * LC_MAIN names main directly (dyld owns the C runtime startup),
     76    * so the on-disk symbol is `_main` (the mangled form of `main`).
     77    * Format choice lives in obj_format_default_entry_name. */
     78   l->entry_name = pool_intern_slice(
     79       c->global, slice_from_cstr(obj_format_default_entry_name(c)));
     80   /* Match the rest of libkit's lifetime story: the new'd Linker is
     81    * registered for cleanup in case a panic fires before link_free. */
     82   l->deferred = compiler_defer(c, linker_cleanup, l);
     83   return l;
     84 }
     85 
     86 void link_free(Linker* l) {
     87   Compiler* c;
     88   CompilerCleanup* d;
     89   if (!l) return;
     90   c = l->c;
     91   d = l->deferred;
     92   linker_release(l);
     93   if (d) compiler_undefer(c, d);
     94 }
     95 
     96 /* ---- input registration ---- */
     97 
     98 static LinkInput* inputs_push(Linker* l, LinkInputId* id_out) {
     99   u32 idx;
    100   LinkInput* in = LinkInputs_push(&l->inputs, &idx);
    101   if (!in) compiler_panic(l->c, SRCLOC_NONE, "link: out of memory growing inputs");
    102   *id_out = (LinkInputId)(idx + 1u);
    103   in->id = *id_out;
    104   return in;
    105 }
    106 
    107 LinkInputId link_add_obj(Linker* l, ObjBuilder* ob) {
    108   LinkInputId id;
    109   LinkInput* in;
    110   if (!l || !ob) return LINK_INPUT_NONE;
    111   in = inputs_push(l, &id);
    112   in->kind = LINK_INPUT_OBJ;
    113   in->order = l->next_input_order++;
    114   in->obj = ob;
    115   return id;
    116 }
    117 
    118 LinkInputId link_add_obj_bytes(Linker* l, const char* name, const u8* data,
    119                                size_t len) {
    120   ObjBuilder* ob;
    121   LinkInput* in;
    122   LinkInputId id;
    123   KitBinFmt fmt;
    124   const ObjFormatImpl* impl;
    125   const char* reader_name;
    126   if (!l || !data || !len) return LINK_INPUT_NONE;
    127   fmt = kit_detect_fmt(data, len);
    128   impl = obj_format_lookup_bin(fmt);
    129   if (!impl || !impl->read)
    130     compiler_panic(
    131         l->c, SRCLOC_NONE,
    132         "link_add_obj_bytes: unsupported object format "
    133         "(fmt=%u) for '%.*s'",
    134         (u32)fmt,
    135         SLICE_ARG(name ? slice_from_cstr(name) : SLICE_LIT("(unnamed)")));
    136   reader_name = impl->read_name;
    137   ob = impl->read(l->c, name, data, len);
    138   if (!ob)
    139     compiler_panic(
    140         l->c, SRCLOC_NONE, "link_add_obj_bytes: %.*s returned NULL for '%.*s'",
    141         SLICE_ARG(slice_from_cstr(reader_name)),
    142         SLICE_ARG(name ? slice_from_cstr(name) : SLICE_LIT("(unnamed)")));
    143   in = inputs_push(l, &id);
    144   in->order = l->next_input_order++;
    145   in->obj = ob; /* re-uses the ObjBuilder slot for ownership */
    146   in->name = name ? pool_intern_slice(l->c->global, slice_from_cstr(name)) : 0;
    147   {
    148     Sym soname = 0;
    149     if (impl->classify_obj_input &&
    150         impl->classify_obj_input(l->c, ob, &soname)) {
    151       in->kind = LINK_INPUT_DSO_BYTES;
    152       in->soname = soname;
    153     } else {
    154       in->kind = LINK_INPUT_OBJ_BYTES;
    155     }
    156   }
    157   return id;
    158 }
    159 
    160 LinkInputId link_add_dso_bytes(Linker* l, const char* name, const u8* data,
    161                                size_t len) {
    162   ObjBuilder* ob = NULL;
    163   LinkInput* in;
    164   LinkInputId id;
    165   Sym soname = 0;
    166   KitBinFmt fmt;
    167   ObjFormatDsoReader reader;
    168   const char* reader_name;
    169   if (!l || !data || !len) return LINK_INPUT_NONE;
    170   if (!obj_format_dso_reader_for_bytes(data, len, &fmt, &reader))
    171     compiler_panic(
    172         l->c, SRCLOC_NONE,
    173         "link_add_dso_bytes: unsupported DSO format "
    174         "(fmt=%u) for '%.*s'",
    175         (u32)fmt,
    176         SLICE_ARG(name ? slice_from_cstr(name) : SLICE_LIT("(unnamed)")));
    177   reader_name = reader.name;
    178   ob = reader.read(l->c, name, data, len, &soname);
    179   if (!ob)
    180     compiler_panic(
    181         l->c, SRCLOC_NONE, "link_add_dso_bytes: %.*s returned NULL for '%.*s'",
    182         SLICE_ARG(slice_from_cstr(reader_name)),
    183         SLICE_ARG(name ? slice_from_cstr(name) : SLICE_LIT("(unnamed)")));
    184   in = inputs_push(l, &id);
    185   in->kind = LINK_INPUT_DSO_BYTES;
    186   in->order = l->next_input_order++;
    187   in->obj = ob;
    188   in->name = name ? pool_intern_slice(l->c->global, slice_from_cstr(name)) : 0;
    189   /* DT_SONAME wins; fall back to the file's basename if the DSO has
    190    * no SONAME (matches GNU ld's behaviour for hand-rolled libraries
    191    * that forgot to set DT_SONAME). */
    192   if (soname != 0) {
    193     in->soname = soname;
    194   } else if (name) {
    195     const char* base = name;
    196     const char* p;
    197     for (p = name; *p; ++p)
    198       if (*p == '/') base = p + 1;
    199     in->soname = pool_intern_slice(l->c->global, slice_from_cstr(base));
    200   } else {
    201     in->soname = 0;
    202   }
    203   return id;
    204 }
    205 
    206 LinkInputId link_add_archive_bytes(Linker* l, const char* name, const u8* data,
    207                                    size_t len, u8 whole_archive, u8 link_mode,
    208                                    u8 group_id) {
    209   KitSlice in_arc;
    210   KitArIter* it = NULL;
    211   KitArMember mem;
    212   LinkArchive* ar;
    213   u32 n;
    214   Sym archive_hint = 0;
    215   const ObjFormatImpl* target_impl;
    216 
    217   if (!l || !data || !len) return LINK_INPUT_NONE;
    218   target_impl = obj_format_lookup(l->c->target.obj);
    219   if (target_impl && target_impl->archive_hint)
    220     archive_hint = target_impl->archive_hint(l->c, name);
    221 
    222   in_arc.data = data;
    223   in_arc.len = len;
    224   if (kit_ar_iter_new(kit_compiler_context(l->c), &in_arc, &it) != KIT_OK ||
    225       !it)
    226     compiler_panic(
    227         l->c, SRCLOC_NONE,
    228         "link_add_archive_bytes: '%.*s' is not a valid ar archive",
    229         SLICE_ARG(name ? slice_from_cstr(name) : SLICE_LIT("(unnamed)")));
    230 
    231   /* Two-pass: count members so we allocate the member array exactly
    232    * once. The linker_release path frees by nmembers, so we need
    233    * allocation size to match. */
    234   n = 0;
    235   while (kit_ar_iter_next(it, &mem) == KIT_ITER_ITEM) ++n;
    236   kit_ar_iter_free(it);
    237   it = NULL;
    238 
    239   ar = LinkArchives_push(&l->archives, NULL);
    240   if (!ar)
    241     compiler_panic(l->c, SRCLOC_NONE, "link: out of memory growing archives");
    242   ar->name = name ? pool_intern_slice(l->c->global, slice_from_cstr(name)) : 0;
    243   ar->order = l->next_input_order++;
    244   ar->whole_archive = whole_archive;
    245   ar->link_mode = link_mode;
    246   ar->group_id = group_id;
    247   ar->nmembers = n;
    248   ar->members =
    249       n ? (LinkArchiveMember*)l->heap->alloc(l->heap, sizeof(*ar->members) * n,
    250                                              _Alignof(LinkArchiveMember))
    251         : NULL;
    252   if (n && !ar->members)
    253     compiler_panic(l->c, SRCLOC_NONE, "link: oom on archive members");
    254   if (n) memset(ar->members, 0, sizeof(*ar->members) * n);
    255 
    256   /* Pass 2: parse each member as object. ar.c's iterator skips the
    257    * symbol-index ('/' and '__.SYMDEF') and long-name ('//') members
    258    * for us, so every member returned here is a real object file.
    259    * Format is detected per-member so a single archive could in
    260    * principle hold mixed formats (in practice it never does). */
    261   if (kit_ar_iter_new(kit_compiler_context(l->c), &in_arc, &it) != KIT_OK ||
    262       !it)
    263     compiler_panic(
    264         l->c, SRCLOC_NONE,
    265         "link_add_archive_bytes: ar_iter_init failed on '%.*s' "
    266         "second pass",
    267         SLICE_ARG(name ? slice_from_cstr(name) : SLICE_LIT("(unnamed)")));
    268   n = 0;
    269   while (kit_ar_iter_next(it, &mem) == KIT_ITER_ITEM && n < ar->nmembers) {
    270     ObjBuilder* ob = NULL;
    271     KitBinFmt mfmt = kit_detect_fmt(mem.data, mem.size);
    272     const ObjFormatImpl* member_impl = obj_format_lookup_bin(mfmt);
    273     if (target_impl && target_impl->archive_member) {
    274       ObjFormatArchiveMember desc;
    275       ObjFormatArchiveAction action;
    276       memset(&desc, 0, sizeof(desc));
    277       desc.archive_name = name;
    278       desc.member_name = mem.name.s;
    279       desc.data = mem.data;
    280       desc.len = mem.size;
    281       desc.bin_fmt = mfmt;
    282       desc.archive_hint = archive_hint;
    283       action = target_impl->archive_member(l->c, &desc, &ob);
    284       if (action != OBJ_FORMAT_ARCHIVE_KEEP) {
    285         ar->members[n].name =
    286             mem.name.len ? pool_intern_slice(l->c->global, mem.name) : 0;
    287         ar->members[n].obj = ob;
    288         ++n;
    289         continue;
    290       }
    291     }
    292     if (!member_impl || !member_impl->read)
    293       compiler_panic(
    294           l->c, SRCLOC_NONE,
    295           "link_add_archive_bytes: unsupported member "
    296           "format (fmt=%u) for '%.*s' in archive '%.*s'",
    297           (u32)mfmt,
    298           SLICE_ARG(mem.name.len ? mem.name : SLICE_LIT("(unnamed)")),
    299           SLICE_ARG(name ? slice_from_cstr(name) : SLICE_LIT("(unnamed)")));
    300     ob = member_impl->read(l->c, mem.name.s, mem.data, mem.size);
    301     if (!ob)
    302       compiler_panic(
    303           l->c, SRCLOC_NONE,
    304           "link_add_archive_bytes: object read failed for "
    305           "member '%.*s' of archive '%.*s'",
    306           SLICE_ARG(mem.name.len ? mem.name : SLICE_LIT("(unnamed)")),
    307           SLICE_ARG(name ? slice_from_cstr(name) : SLICE_LIT("(unnamed)")));
    308     ar->members[n].name =
    309         mem.name.len ? pool_intern_slice(l->c->global, mem.name) : 0;
    310     ar->members[n].obj = ob;
    311     ++n;
    312   }
    313   kit_ar_iter_free(it);
    314   return (LinkInputId)LinkArchives_count(
    315       &l->archives); /* opaque non-zero handle */
    316 }
    317 
    318 /* Intern a C-source-level symbol name in the format the input objects
    319  * use on the wire.  Format-specific mangling (Mach-O `_` prefix,
    320  * verbatim everywhere else) lives in obj_format_c_mangle. */
    321 Sym link_intern_c_name(Linker* l, const char* name) {
    322   if (!l || !name) return 0;
    323   return obj_format_c_mangle(l->c, name);
    324 }
    325 
    326 void link_set_entry(Linker* l, KitSlice name) {
    327   if (!l || !name.s || name.len == 0) return;
    328   /* entry names from the API/script are interned arena/pool slices and
    329    * thus NUL-terminated; the mangler scans a C string. */
    330   l->entry_name = link_intern_c_name(l, name.s);
    331 }
    332 
    333 void link_clear_entry(Linker* l) {
    334   if (!l) return;
    335   l->entry_name = 0;
    336 }
    337 
    338 void link_set_script(Linker* l, const KitLinkScript* script) {
    339   if (!l || !script) return;
    340   l->script = script;
    341   if (script->entry.s && script->entry.len)
    342     l->entry_name = link_intern_c_name(l, script->entry.s);
    343 }
    344 
    345 void link_set_extern_resolver(Linker* l, LinkExternResolver fn, void* user) {
    346   if (!l) return;
    347   l->resolver = fn;
    348   l->resolver_user = user;
    349 }
    350 
    351 void link_set_gc_sections(Linker* l, int enable) {
    352   if (!l) return;
    353   l->gc_sections = enable;
    354   /* Accepted but ignored this cut. Quiet by design — driver/ld.c may
    355    * pass 0 unconditionally and we don't want to noise that. */
    356 }
    357 
    358 void link_set_strip_debug(Linker* l, int enable) {
    359   if (!l) return;
    360   l->strip_debug = enable;
    361   /* Executable layouts already omit non-alloc debug sections. Keep the flag
    362    * recorded so driver -S/--strip-debug flows through the linker surface. */
    363 }
    364 
    365 void link_set_emit_static_exe(Linker* l, int enable) {
    366   if (!l) return;
    367   l->emit_static_exe = enable ? 1 : 0;
    368 }
    369 
    370 void link_set_jit_mode(Linker* l, int enable) {
    371   if (!l) return;
    372   l->jit_mode = enable ? 1 : 0;
    373 }
    374 
    375 void link_set_pie(Linker* l, int enable) {
    376   if (!l) return;
    377   l->emit_pie = enable ? 1 : 0;
    378 }
    379 
    380 void link_set_text_base(Linker* l, u64 base) {
    381   if (!l) return;
    382   l->text_base_set = 1;
    383   l->text_base = base;
    384 }
    385 
    386 void link_set_pe_subsystem(Linker* l, u16 subsystem) {
    387   if (!l) return;
    388   l->pe_subsystem = subsystem;
    389 }
    390 
    391 void link_set_jit_host(Linker* l, const KitJitHost* host) {
    392   if (!l) return;
    393   l->jit_host = host;
    394 }
    395 
    396 void link_set_interp_path(Linker* l, KitSlice path) {
    397   if (!l) return;
    398   l->interp_path =
    399       (path.s && path.len) ? pool_intern_slice(l->c->global, path) : 0;
    400 }
    401 
    402 /* ---- debug-input capture ----
    403  *
    404  * Called once at the tail of link_resolve.  For each LinkInput, record
    405  * its ObjBuilder on the LinkImage so the JIT debug view (kit_jit_view)
    406  * can read .debug_* sections after the Linker is freed.  Two ownership
    407  * regimes:
    408  *
    409  *   LINK_INPUT_OBJ_BYTES: linker owns; transfer to the image and null
    410  *     the LinkInput's obj so linker_release doesn't double-free.
    411  *   LINK_INPUT_OBJ:       caller owns; borrow the pointer (do not free
    412  *     at image teardown).  Caller is responsible for keeping the
    413  *     builder alive at least as long as the JIT.
    414  *
    415  * DSO / archive-only inputs carry no source-level debug info worth
    416  * surfacing through kit_jit_view, so their slot stays NULL. */
    417 void link_capture_debug_inputs(Linker* l, LinkImage* img) {
    418   u32 n;
    419   u32 i;
    420   Heap* h;
    421   if (!l || !img) return;
    422   n = LinkInputs_count(&l->inputs);
    423   img->dbg_objs_n = n;
    424   if (n == 0) {
    425     img->dbg_objs = NULL;
    426     img->dbg_objs_owned = NULL;
    427     return;
    428   }
    429   h = img->heap;
    430   img->dbg_objs = (ObjBuilder**)h->alloc(h, sizeof(*img->dbg_objs) * n,
    431                                          _Alignof(ObjBuilder*));
    432   img->dbg_objs_owned = (u8*)h->alloc(h, sizeof(*img->dbg_objs_owned) * n, 1u);
    433   if (!img->dbg_objs || !img->dbg_objs_owned)
    434     compiler_panic(img->c, SRCLOC_NONE,
    435                    "link_capture_debug_inputs: oom on dbg arrays");
    436   memset(img->dbg_objs, 0, sizeof(*img->dbg_objs) * n);
    437   memset(img->dbg_objs_owned, 0, sizeof(*img->dbg_objs_owned) * n);
    438   for (i = 0; i < n; ++i) {
    439     LinkInput* in = LinkInputs_at(&l->inputs, i);
    440     if (!in || !in->obj) continue;
    441     switch (in->kind) {
    442       case LINK_INPUT_OBJ_BYTES:
    443         img->dbg_objs[i] = in->obj;
    444         img->dbg_objs_owned[i] = 1u;
    445         in->obj = NULL; /* transfer: linker_release must not free it */
    446         break;
    447       case LINK_INPUT_OBJ:
    448         img->dbg_objs[i] = in->obj;
    449         img->dbg_objs_owned[i] = 0u; /* borrowed; caller still owns */
    450         break;
    451       default:
    452         /* DSO / TBD: skip — no user-level debug sections we expose. */
    453         break;
    454     }
    455   }
    456 }
    457 
    458 /* ---- LinkImage accessors ---- */
    459 
    460 const LinkSymbol* link_symbol(LinkImage* img, LinkSymId id) {
    461   if (!img || id == LINK_SYM_NONE || id > LinkSyms_count(&img->syms))
    462     return NULL;
    463   return LinkSyms_at(&img->syms, id - 1);
    464 }
    465 
    466 LinkSymId link_symbol_lookup(LinkImage* img, Sym name) {
    467   if (!img) return LINK_SYM_NONE;
    468   return symhash_get(&img->globals, name);
    469 }
    470 
    471 u32 link_segment_count(LinkImage* img) { return img ? img->nsegments : 0; }
    472 
    473 const LinkSegment* link_segment_get(LinkImage* img, u32 id) {
    474   if (!img || id == LINK_SEG_NONE || id > img->nsegments) return NULL;
    475   return &img->segments[id - 1];
    476 }
    477 
    478 const u8* link_segment_bytes(LinkImage* img, LinkSegmentId id,
    479                              size_t* size_out) {
    480   if (size_out) *size_out = 0;
    481   if (!img || id == LINK_SEG_NONE || id > img->nsegments) return NULL;
    482   if (size_out) *size_out = (size_t)img->segments[id - 1].file_size;
    483   return img->segment_bytes[id - 1];
    484 }
    485 
    486 u32 link_section_count(LinkImage* img) { return img ? img->nsections : 0; }
    487 
    488 const LinkSection* link_section_get(LinkImage* img, LinkSectionId id) {
    489   if (!img || id == LINK_SEC_NONE || id > img->nsections) return NULL;
    490   return &img->sections[id - 1];
    491 }
    492 
    493 u32 link_reloc_apply_count(LinkImage* img) {
    494   return img ? LinkRelocs_count(&img->relocs) : 0;
    495 }
    496 
    497 const LinkRelocApply* link_reloc_apply_get(LinkImage* img, u32 id) {
    498   if (!img || id >= LinkRelocs_count(&img->relocs)) return NULL;
    499   return LinkRelocs_at(&img->relocs, id);
    500 }
    501 
    502 /* ---- LinkImage free / cleanup ---- */
    503 
    504 static void link_image_release(LinkImage* img) {
    505   u32 i;
    506   if (!img) return;
    507   if (img->segment_bytes) {
    508     for (i = 0; i < img->nsegments; ++i) {
    509       if (img->segment_bytes[i])
    510         img->heap->free(img->heap, img->segment_bytes[i],
    511                         img->segment_bytes_cap[i]);
    512     }
    513     img->heap->free(img->heap, img->segment_bytes,
    514                     sizeof(*img->segment_bytes) * img->nsegments);
    515     img->heap->free(img->heap, img->segment_bytes_cap,
    516                     sizeof(*img->segment_bytes_cap) * img->nsegments);
    517   }
    518   if (img->segments)
    519     img->heap->free(img->heap, img->segments,
    520                     sizeof(*img->segments) * img->nsegments);
    521   if (img->sections)
    522     img->heap->free(img->heap, img->sections,
    523                     sizeof(*img->sections) * img->nsections);
    524   LinkSyms_fini(&img->syms);
    525   LinkRelocs_fini(&img->relocs);
    526   if (img->iplt_pairs)
    527     img->heap->free(img->heap, img->iplt_pairs,
    528                     sizeof(*img->iplt_pairs) * img->niplt * 2u);
    529   if (img->input_maps) {
    530     for (i = 0; i < img->ninput_maps; ++i) {
    531       InputMap* m = &img->input_maps[i];
    532       if (m->sym) img->heap->free(img->heap, m->sym, sizeof(*m->sym) * m->nsym);
    533       if (m->section)
    534         img->heap->free(img->heap, m->section,
    535                         sizeof(*m->section) * m->nsection);
    536       if (m->atom)
    537         img->heap->free(img->heap, m->atom,
    538                         sizeof(*m->atom) * (m->natom ? m->natom : 1u));
    539       if (m->sym_atom)
    540         img->heap->free(img->heap, m->sym_atom,
    541                         sizeof(*m->sym_atom) * (m->nsym ? m->nsym : 1u));
    542       if (m->reloc_atom)
    543         img->heap->free(img->heap, m->reloc_atom,
    544                         sizeof(*m->reloc_atom) * (m->nreloc ? m->nreloc : 1u));
    545       if (m->section_has_atoms)
    546         img->heap->free(img->heap, m->section_has_atoms,
    547                         m->nsection ? m->nsection : 1u);
    548       if (m->section_atom_first)
    549         img->heap->free(
    550             img->heap, m->section_atom_first,
    551             sizeof(*m->section_atom_first) * (m->nsection ? m->nsection : 1u));
    552       if (m->section_atom_count)
    553         img->heap->free(
    554             img->heap, m->section_atom_count,
    555             sizeof(*m->section_atom_count) * (m->nsection ? m->nsection : 1u));
    556       if (m->section_atom_ids)
    557         img->heap->free(img->heap, m->section_atom_ids,
    558                         sizeof(*m->section_atom_ids) * m->nsection_atom_ids);
    559       if (m->comdat_discarded)
    560         img->heap->free(img->heap, m->comdat_discarded,
    561                         m->nsection ? m->nsection : 1u);
    562     }
    563     img->heap->free(img->heap, img->input_maps,
    564                     sizeof(*img->input_maps) * img->ninput_maps);
    565   }
    566   if (img->dbg_objs) {
    567     for (i = 0; i < img->dbg_objs_n; ++i) {
    568       if (img->dbg_objs[i] && img->dbg_objs_owned && img->dbg_objs_owned[i])
    569         obj_free(img->dbg_objs[i]);
    570     }
    571     img->heap->free(img->heap, img->dbg_objs,
    572                     sizeof(*img->dbg_objs) * img->dbg_objs_n);
    573     if (img->dbg_objs_owned)
    574       img->heap->free(img->heap, img->dbg_objs_owned,
    575                       sizeof(*img->dbg_objs_owned) * img->dbg_objs_n);
    576   }
    577   if (img->dbg_bytes) {
    578     for (i = 0; i < img->dbg_count; ++i)
    579       if (img->dbg_bytes[i])
    580         img->heap->free(img->heap, img->dbg_bytes[i], (size_t)img->dbg_size[i]);
    581     img->heap->free(img->heap, img->dbg_bytes,
    582                     sizeof(*img->dbg_bytes) * img->dbg_count);
    583   }
    584   if (img->dbg_size)
    585     img->heap->free(img->heap, img->dbg_size,
    586                     sizeof(*img->dbg_size) * img->dbg_count);
    587   symhash_fini(&img->globals);
    588   if (img->dyn) {
    589     const ObjFormatImpl* fmt = obj_format_lookup(img->c->target.obj);
    590     if (fmt && fmt->free_dyn) fmt->free_dyn(img);
    591   }
    592   img->heap->free(img->heap, img, sizeof(*img));
    593 }
    594 
    595 static void link_image_cleanup(void* arg) {
    596   link_image_release((LinkImage*)arg);
    597 }
    598 
    599 LinkImage* link_image_alloc(Compiler* c) {
    600   Heap* h = (Heap*)c->ctx->heap;
    601   LinkImage* img = (LinkImage*)h->alloc(h, sizeof(*img), _Alignof(LinkImage));
    602   if (!img) compiler_panic(c, SRCLOC_NONE, "link: out of memory allocating image");
    603   memset(img, 0, sizeof(*img));
    604   img->c = c;
    605   img->heap = h;
    606   LinkSyms_init(&img->syms, h);
    607   LinkRelocs_init(&img->relocs, h);
    608   symhash_init(&img->globals, h);
    609   img->deferred = compiler_defer(c, link_image_cleanup, img);
    610   return img;
    611 }
    612 
    613 void link_image_free(LinkImage* img) {
    614   if (!img) return;
    615   if (img->deferred) compiler_undefer(img->c, img->deferred);
    616   link_image_release(img);
    617 }
    618 
    619 /* ---- Incremental resolution (stubs) ----
    620  * Per-block JIT translation in src/emu/ wants to grow a single
    621  * LinkImage as cold blocks land (doc/EMU.md §6). The single-shot
    622  * link_resolve discipline (link.h header comment) is set up to
    623  * support this — inputs are non-destructively consumed, ObjBuilder*
    624  * mappings are stable, resolution is functional. The two entries
    625  * below are the surface; the implementation lands alongside the
    626  * emu lifter cut. */
    627 
    628 LinkImage* link_resolve_at(Linker* l, uintptr_t base_va) {
    629   (void)base_va;
    630   if (!l) return NULL;
    631   compiler_panic(l->c, SRCLOC_NONE,
    632                  "link_resolve_at: incremental resolution not yet "
    633                  "implemented");
    634   return NULL;
    635 }
    636 
    637 void link_resolve_extend(Linker* l, LinkImage* img) {
    638   (void)img;
    639   if (!l) return;
    640   compiler_panic(l->c, SRCLOC_NONE,
    641                  "link_resolve_extend: incremental resolution not "
    642                  "yet implemented");
    643 }
    644 
    645 /* ---- public emit dispatcher ---- */
    646 
    647 void link_emit_image_writer(LinkImage* img, Writer* w) {
    648   const ObjFormatImpl* fmt;
    649   if (!img || !w) return;
    650   fmt = obj_format_lookup(img->c->target.obj);
    651   if (fmt && fmt->link_emit) {
    652     fmt->link_emit(img, w);
    653     return;
    654   }
    655   compiler_panic(img->c, SRCLOC_NONE,
    656                  "link_emit_image_writer: unsupported obj format %u",
    657                  (u32)img->c->target.obj);
    658 }