kit

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

link.c (18037B)


      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 <setjmp.h>
     20 #include <string.h>
     21 
     22 #include "cg/internal.h"
     23 #include "cg/ir_recorder.h"
     24 #include "core/core.h"
     25 #include "link/link_internal.h"
     26 
     27 KitJit* kit_jit_from_image(LinkImage*);
     28 
     29 static KitStatus link_session_guard(KitLinkSession* s,
     30                                     void (*fn)(KitLinkSession*, void*),
     31                                     void* arg) {
     32   PanicFrame panic;
     33   if (!s || !s->c || !s->linker || !fn) return KIT_INVALID;
     34   compiler_panic_push(s->c, &panic);
     35   if (setjmp(panic.env)) {
     36     compiler_run_cleanups(s->c);
     37     s->linker = NULL;
     38     s->image = NULL;
     39     compiler_panic_pop(s->c, &panic);
     40     return KIT_ERR;
     41   }
     42   fn(s, arg);
     43   compiler_panic_pop(s->c, &panic);
     44   return KIT_OK;
     45 }
     46 
     47 static KitStatus link_session_remember_publish_obj(KitLinkSession* s,
     48                                                    KitObjBuilder* ob) {
     49   Heap* h;
     50   KitObjBuilder** nb;
     51   u32 new_cap;
     52   if (!s || !ob) return KIT_INVALID;
     53   if (s->npublish_objs < s->publish_objs_cap) {
     54     s->publish_objs[s->npublish_objs++] = ob;
     55     return KIT_OK;
     56   }
     57   h = s->c->ctx->heap;
     58   new_cap = s->publish_objs_cap ? s->publish_objs_cap * 2u : 8u;
     59   nb = (KitObjBuilder**)h->realloc(
     60       h, s->publish_objs, sizeof(*s->publish_objs) * s->publish_objs_cap,
     61       sizeof(*s->publish_objs) * new_cap, _Alignof(KitObjBuilder*));
     62   if (!nb) return KIT_NOMEM;
     63   s->publish_objs = nb;
     64   s->publish_objs_cap = new_cap;
     65   s->publish_objs[s->npublish_objs++] = ob;
     66   return KIT_OK;
     67 }
     68 
     69 KitStatus kit_link_session_new(KitCompiler* c,
     70                                const KitLinkSessionOptions* opts,
     71                                KitLinkSession** out) {
     72   Heap* h;
     73   KitLinkSession* s;
     74   Linker* l;
     75   if (!out) return KIT_INVALID;
     76   *out = NULL;
     77   if (!c || !opts) return KIT_INVALID;
     78   h = c->ctx->heap;
     79   l = link_new(c);
     80   if (!l) return KIT_NOMEM;
     81   s = (KitLinkSession*)h->alloc(h, sizeof(*s), _Alignof(KitLinkSession));
     82   if (!s) {
     83     link_free(l);
     84     return KIT_NOMEM;
     85   }
     86   memset(s, 0, sizeof(*s));
     87   s->c = (Compiler*)c;
     88   s->linker = l;
     89   s->opts = *opts;
     90   if (opts->output_kind > KIT_LINK_OUTPUT_JIT) {
     91     h->free(h, s, sizeof(*s));
     92     link_free(l);
     93     return KIT_INVALID;
     94   }
     95   if (opts->pe_subsystem != KIT_PE_SUBSYSTEM_DEFAULT &&
     96       opts->pe_subsystem != KIT_PE_SUBSYSTEM_WINDOWS_GUI &&
     97       opts->pe_subsystem != KIT_PE_SUBSYSTEM_WINDOWS_CUI) {
     98     h->free(h, s, sizeof(*s));
     99     link_free(l);
    100     return KIT_INVALID;
    101   }
    102   link_set_pe_subsystem(l, opts->pe_subsystem);
    103 
    104   switch ((KitLinkOutputKind)opts->output_kind) {
    105     case KIT_LINK_OUTPUT_EXE:
    106       link_set_emit_static_exe(l, 1);
    107       link_set_gc_sections(l, opts->gc_sections);
    108       link_set_strip_debug(l, opts->strip_debug);
    109       link_set_pie(l, opts->pie);
    110       link_set_interp_path(l, opts->interp_path);
    111       break;
    112     case KIT_LINK_OUTPUT_SHARED:
    113       link_set_gc_sections(l, opts->gc_sections);
    114       link_set_strip_debug(l, opts->strip_debug);
    115       link_set_pie(l, 1);
    116       (void)opts->soname;
    117       (void)opts->rpaths;
    118       (void)opts->nrpaths;
    119       (void)opts->runpaths;
    120       (void)opts->nrunpaths;
    121       (void)opts->exports;
    122       (void)opts->nexports;
    123       (void)opts->allow_undefined;
    124       break;
    125     case KIT_LINK_OUTPUT_RELOCATABLE:
    126       break;
    127     case KIT_LINK_OUTPUT_JIT:
    128       if (!opts->jit_host) {
    129         h->free(h, s, sizeof(*s));
    130         link_free(l);
    131         return KIT_INVALID;
    132       }
    133       link_set_jit_host(l, opts->jit_host);
    134       link_set_jit_mode(l, 1);
    135       link_set_gc_sections(l, opts->gc_sections);
    136       if (!opts->entry.s || opts->entry.len == 0) link_clear_entry(l);
    137       if (opts->extern_resolver) {
    138         link_set_extern_resolver(l, opts->extern_resolver,
    139                                  opts->extern_resolver_user);
    140       }
    141       break;
    142   }
    143   if (opts->linker_script) link_set_script(l, opts->linker_script);
    144   if (opts->text_base_set) link_set_text_base(l, opts->text_base);
    145   if (opts->entry.s && opts->entry.len) {
    146     link_set_entry(l, opts->entry);
    147   } else if (opts->pe_subsystem == KIT_PE_SUBSYSTEM_WINDOWS_GUI &&
    148              !(opts->linker_script && opts->linker_script->entry.s &&
    149                opts->linker_script->entry.len)) {
    150     link_set_entry(l, KIT_SLICE_LIT("WinMainCRTStartup"));
    151   }
    152   (void)opts->build_id_mode;
    153   (void)opts->build_id_bytes;
    154   (void)opts->build_id_len;
    155   *out = s;
    156   return KIT_OK;
    157 }
    158 
    159 typedef struct LinkAddObjArg {
    160   KitObjBuilder* ob;
    161 } LinkAddObjArg;
    162 
    163 static void link_session_add_obj_inner(KitLinkSession* s, void* arg) {
    164   LinkAddObjArg* a = (LinkAddObjArg*)arg;
    165   link_add_obj(s->linker, (ObjBuilder*)a->ob);
    166 }
    167 
    168 KitStatus kit_link_session_add_obj(KitLinkSession* s, KitObjBuilder* ob) {
    169   LinkAddObjArg arg;
    170   KitStatus st;
    171   if (!s || !ob || s->resolved) return KIT_INVALID;
    172   arg.ob = ob;
    173   st = link_session_guard(s, link_session_add_obj_inner, &arg);
    174   if (st != KIT_OK) return st;
    175   return link_session_remember_publish_obj(s, ob);
    176 }
    177 
    178 typedef struct LinkAddBytesArg {
    179   KitSlice name;
    180   const KitSlice* bytes;
    181   const KitLinkArchiveInput* archive;
    182 } LinkAddBytesArg;
    183 
    184 static void link_session_add_obj_bytes_inner(KitLinkSession* s, void* arg) {
    185   LinkAddBytesArg* a = (LinkAddBytesArg*)arg;
    186   link_add_obj_bytes(s->linker, a->name.s, a->bytes->data, a->bytes->len);
    187 }
    188 
    189 KitStatus kit_link_session_add_obj_bytes(KitLinkSession* s, KitSlice name,
    190                                          const KitSlice* bytes) {
    191   LinkAddBytesArg arg;
    192   if (!s || !bytes || s->resolved) return KIT_INVALID;
    193   arg.name = name;
    194   arg.bytes = bytes;
    195   arg.archive = NULL;
    196   s->non_obj_inputs++;
    197   return link_session_guard(s, link_session_add_obj_bytes_inner, &arg);
    198 }
    199 
    200 static void link_session_add_archive_bytes_inner(KitLinkSession* s, void* arg) {
    201   const KitLinkArchiveInput* a = ((LinkAddBytesArg*)arg)->archive;
    202   link_add_archive_bytes(s->linker, a->name.s, a->bytes.data, a->bytes.len,
    203                          a->whole_archive, a->link_mode, a->group_id);
    204 }
    205 
    206 KitStatus kit_link_session_add_archive_bytes(
    207     KitLinkSession* s, const KitLinkArchiveInput* archive) {
    208   LinkAddBytesArg arg;
    209   if (!s || !archive || s->resolved) return KIT_INVALID;
    210   arg.bytes = NULL;
    211   arg.archive = archive;
    212   s->non_obj_inputs++;
    213   return link_session_guard(s, link_session_add_archive_bytes_inner, &arg);
    214 }
    215 
    216 static void link_session_add_dso_bytes_inner(KitLinkSession* s, void* arg) {
    217   LinkAddBytesArg* a = (LinkAddBytesArg*)arg;
    218   link_add_dso_bytes(s->linker, a->name.s, a->bytes->data, a->bytes->len);
    219 }
    220 
    221 KitStatus kit_link_session_add_dso_bytes(KitLinkSession* s, KitSlice name,
    222                                          const KitSlice* bytes) {
    223   LinkAddBytesArg arg;
    224   if (!s || !bytes || s->resolved) return KIT_INVALID;
    225   arg.name = name;
    226   arg.bytes = bytes;
    227   arg.archive = NULL;
    228   s->non_obj_inputs++;
    229   return link_session_guard(s, link_session_add_dso_bytes_inner, &arg);
    230 }
    231 
    232 typedef struct LinkLtoPreserveArg {
    233   KitObjBuilder* lto_obj;
    234   KitCg* lto_cg;
    235   KitLinkLtoPreservedCallback cb;
    236   void* user;
    237 } LinkLtoPreserveArg;
    238 
    239 typedef struct LinkLtoRefMark {
    240   ObjSymId sym;
    241   u8 referenced;
    242   u8 pad[3];
    243 } LinkLtoRefMark;
    244 
    245 typedef struct LinkLtoRefMarks {
    246   Compiler* c;
    247   ObjBuilder* ob;
    248   LinkLtoRefMark* marks;
    249   u32 nmarks;
    250   u32 cap;
    251 } LinkLtoRefMarks;
    252 
    253 static int link_lto_sym_is_logical_undef(const ObjSym* s) {
    254   return s && s->section_id == OBJ_SEC_NONE && s->kind != SK_ABS &&
    255          s->kind != SK_COMMON;
    256 }
    257 
    258 static int link_lto_sym_is_preservable_def(const ObjSym* s) {
    259   return s && !s->removed && s->name != 0 && s->bind != SB_LOCAL &&
    260          link_sym_is_def(s);
    261 }
    262 
    263 static void link_lto_preserve_name(LinkLtoPreserveArg* a, Sym name) {
    264   ObjSymIter* it;
    265   ObjSymEntry e;
    266   if (!a || !name) return;
    267   it = obj_symiter_new((ObjBuilder*)a->lto_obj);
    268   while (it && obj_symiter_next(it, &e)) {
    269     const ObjSym* s = e.sym;
    270     if (!s || s->name != name) continue;
    271     if (link_lto_sym_is_preservable_def(s)) a->cb(a->user, (KitCgSym)e.id);
    272   }
    273   if (it) obj_symiter_free(it);
    274 }
    275 
    276 static int link_lto_sym_in_preserved_section(ObjBuilder* ob, ObjSymId sym,
    277                                              const ObjSym* s) {
    278   const Section* sec;
    279   const ObjAtom* atom;
    280   ObjAtomId aid;
    281   if (!ob || !s) return 0;
    282   if (s->section_id == OBJ_SEC_NONE) return 0;
    283   sec = obj_section_get(ob, s->section_id);
    284   if (sec && ((sec->flags & SF_RETAIN) || sec->sem == SSEM_INIT_ARRAY ||
    285               sec->sem == SSEM_FINI_ARRAY || sec->sem == SSEM_PREINIT_ARRAY))
    286     return 1;
    287   aid = obj_atom_find_symbol(ob, sym);
    288   atom = obj_atom_get(ob, aid);
    289   return atom && (atom->flags & OBJ_ATOM_RETAIN);
    290 }
    291 
    292 static void link_lto_refmarks_add(LinkLtoRefMarks* marks, ObjSymId sym,
    293                                   const ObjSym* s) {
    294   Heap* h;
    295   LinkLtoRefMark* nm;
    296   u32 ncap;
    297   if (!marks || sym == OBJ_SYM_NONE || !s) return;
    298   for (u32 i = 0; i < marks->nmarks; ++i)
    299     if (marks->marks[i].sym == sym) return;
    300   if (marks->nmarks == marks->cap) {
    301     h = marks->c->ctx->heap;
    302     ncap = marks->cap ? marks->cap * 2u : 32u;
    303     nm = (LinkLtoRefMark*)h->realloc(h, marks->marks,
    304                                      sizeof(*marks->marks) * marks->cap,
    305                                      sizeof(*marks->marks) * ncap,
    306                                      _Alignof(LinkLtoRefMark));
    307     if (!nm)
    308       compiler_panic(marks->c, SRCLOC_NONE,
    309                      "link: oom on LTO semantic-ref marks");
    310     marks->marks = nm;
    311     marks->cap = ncap;
    312   }
    313   marks->marks[marks->nmarks].sym = sym;
    314   marks->marks[marks->nmarks].referenced = s->referenced ? 1u : 0u;
    315   marks->nmarks++;
    316 }
    317 
    318 static void link_lto_mark_refset(ObjBuilder* ob, const ObjSymSet* refs,
    319                                  LinkLtoRefMarks* marks) {
    320   if (!ob || !refs || !refs->cap) return;
    321   for (u32 i = 0; i < refs->cap; ++i) {
    322     ObjSymId sym = refs->slots[i].k;
    323     const ObjSym* s;
    324     if (sym == OBJ_SYM_NONE) continue;
    325     s = obj_symbol_get(ob, sym);
    326     if (link_lto_sym_is_logical_undef(s)) {
    327       link_lto_refmarks_add(marks, sym, s);
    328       obj_sym_mark_referenced(ob, sym);
    329     }
    330   }
    331 }
    332 
    333 static int link_lto_module_has_asm(const CgIrModule* module) {
    334   if (!module) return 0;
    335   if (module->nfile_scope_asms) return 1;
    336   for (u32 i = 0; i < module->nfuncs; ++i) {
    337     const CgIrFunc* f = module->funcs[i];
    338     if (!f || f->removed) continue;
    339     for (u32 k = 0; k < f->ninsts; ++k)
    340       if (f->insts[k].op == CG_IR_ASM_BLOCK) return 1;
    341   }
    342   return 0;
    343 }
    344 
    345 static void link_lto_mark_semantic_refs(LinkLtoPreserveArg* a,
    346                                         LinkLtoRefMarks* marks) {
    347   ObjBuilder* ob = (ObjBuilder*)a->lto_obj;
    348   const CgIrModule* module;
    349   if (!a->lto_cg || !a->lto_cg->target) return;
    350   module = cg_ir_recorder_module(a->lto_cg->target);
    351   if (!module) return;
    352   for (u32 i = 0; i < module->nfuncs; ++i) {
    353     const CgIrFunc* f = module->funcs[i];
    354     if (!f || f->removed) continue;
    355     link_lto_mark_refset(ob, &f->call_refs, marks);
    356     link_lto_mark_refset(ob, &f->global_refs, marks);
    357   }
    358 }
    359 
    360 static void link_lto_refmarks_restore(LinkLtoRefMarks* marks) {
    361   if (!marks || !marks->ob) return;
    362   for (u32 i = 0; i < marks->nmarks; ++i) {
    363     obj_sym_set_referenced(marks->ob, marks->marks[i].sym,
    364                            marks->marks[i].referenced);
    365   }
    366 }
    367 
    368 static void link_lto_refmarks_fini(LinkLtoRefMarks* marks) {
    369   Heap* h;
    370   if (!marks || !marks->marks) return;
    371   h = marks->c->ctx->heap;
    372   h->free(h, marks->marks, sizeof(*marks->marks) * marks->cap);
    373   memset(marks, 0, sizeof(*marks));
    374 }
    375 
    376 static void link_lto_preserve_intrinsic_roots(KitLinkSession* s,
    377                                               LinkLtoPreserveArg* a) {
    378   ObjBuilder* ob = (ObjBuilder*)a->lto_obj;
    379   const CgIrModule* module = NULL;
    380   int preserve_all_nonlocal = 0;
    381   ObjSymIter* it;
    382   ObjSymEntry e;
    383 
    384   if (a->lto_cg && a->lto_cg->target)
    385     module = cg_ir_recorder_module(a->lto_cg->target);
    386 
    387   preserve_all_nonlocal = s->opts.output_kind != KIT_LINK_OUTPUT_EXE ||
    388                           link_lto_module_has_asm(module);
    389   if (s->opts.output_kind == KIT_LINK_OUTPUT_SHARED) preserve_all_nonlocal = 1;
    390 
    391   it = obj_symiter_new(ob);
    392   while (it && obj_symiter_next(it, &e)) {
    393     const ObjSym* os = e.sym;
    394     if (!link_lto_sym_is_preservable_def(os)) continue;
    395     if (preserve_all_nonlocal || os->bind == SB_WEAK || os->kind == SK_IFUNC ||
    396         (os->flags & KIT_CG_SYM_USED) ||
    397         link_lto_sym_in_preserved_section(ob, e.id, os)) {
    398       a->cb(a->user, (KitCgSym)e.id);
    399     }
    400   }
    401   if (it) obj_symiter_free(it);
    402 
    403   if (s->linker->entry_name) link_lto_preserve_name(a, s->linker->entry_name);
    404   for (u32 i = 0; i < s->opts.nexports; ++i) {
    405     const KitSlice* ex = &s->opts.exports[i];
    406     if (ex->s && ex->len)
    407       link_lto_preserve_name(
    408           a,
    409           pool_intern_slice(s->c->global, (Slice){.s = ex->s, .len = ex->len}));
    410   }
    411 }
    412 
    413 static void link_lto_preserve_opaque_undef_refs(KitLinkSession* s,
    414                                                 LinkLtoPreserveArg* a) {
    415   u32 ninputs = LinkInputs_count(&s->linker->inputs);
    416   for (u32 ii = 0; ii < ninputs; ++ii) {
    417     LinkInput* in = LinkInputs_at(&s->linker->inputs, ii);
    418     ObjSymIter* it;
    419     ObjSymEntry e;
    420     if (!in || !in->obj || in->obj == (ObjBuilder*)a->lto_obj) continue;
    421     it = obj_symiter_new(in->obj);
    422     while (it && obj_symiter_next(it, &e)) {
    423       const ObjSym* os = e.sym;
    424       if (!os || os->name == 0 || os->bind == SB_LOCAL) continue;
    425       if (link_sym_is_spurious_undef(os)) continue;
    426       if (!link_lto_sym_is_logical_undef(os)) continue;
    427       link_lto_preserve_name(a, os->name);
    428     }
    429     if (it) obj_symiter_free(it);
    430   }
    431 }
    432 
    433 static void link_session_visit_lto_preserved_inner(KitLinkSession* s,
    434                                                    void* arg) {
    435   LinkLtoPreserveArg* a = (LinkLtoPreserveArg*)arg;
    436   LinkLtoRefMarks marks;
    437   memset(&marks, 0, sizeof marks);
    438   marks.c = s->c;
    439   marks.ob = (ObjBuilder*)a->lto_obj;
    440   if (s->opts.output_kind != KIT_LINK_OUTPUT_RELOCATABLE) {
    441     /* Archive selection needs pre-finish semantic refs, but those refs may
    442      * disappear after LTO internalization/DCE. Borrow ObjSym::referenced only
    443      * for archive ingestion, then restore it before CG finish. */
    444     link_lto_mark_semantic_refs(a, &marks);
    445     link_ingest_archives(s->linker);
    446     link_lto_refmarks_restore(&marks);
    447     link_lto_refmarks_fini(&marks);
    448   }
    449   link_lto_preserve_intrinsic_roots(s, a);
    450   link_lto_preserve_opaque_undef_refs(s, a);
    451 }
    452 
    453 KitStatus kit_link_session_visit_lto_preserved(KitLinkSession* s,
    454                                                KitObjBuilder* lto_obj,
    455                                                KitCg* lto_cg,
    456                                                KitLinkLtoPreservedCallback cb,
    457                                                void* user) {
    458   LinkLtoPreserveArg arg;
    459   if (!s || !lto_obj || !lto_cg || !cb || s->resolved) return KIT_INVALID;
    460   memset(&arg, 0, sizeof arg);
    461   arg.lto_obj = lto_obj;
    462   arg.lto_cg = lto_cg;
    463   arg.cb = cb;
    464   arg.user = user;
    465   return link_session_guard(s, link_session_visit_lto_preserved_inner, &arg);
    466 }
    467 
    468 static void link_session_resolve_inner(KitLinkSession* s, void* arg) {
    469   (void)arg;
    470   if ((KitLinkOutputKind)s->opts.output_kind == KIT_LINK_OUTPUT_RELOCATABLE) {
    471     s->resolved = 1;
    472     return;
    473   }
    474   s->image = link_resolve(s->linker);
    475   s->resolved = 1;
    476 }
    477 
    478 KitStatus kit_link_session_resolve(KitLinkSession* s) {
    479   if (!s || s->resolved) return KIT_INVALID;
    480   return link_session_guard(s, link_session_resolve_inner, NULL);
    481 }
    482 
    483 typedef struct LinkEmitArg {
    484   KitWriter* out;
    485 } LinkEmitArg;
    486 
    487 static void link_session_emit_inner(KitLinkSession* s, void* arg) {
    488   KitWriter* out = ((LinkEmitArg*)arg)->out;
    489   if ((KitLinkOutputKind)s->opts.output_kind == KIT_LINK_OUTPUT_RELOCATABLE) {
    490     link_emit_relocatable_writer(s->linker, out);
    491   } else {
    492     link_emit_image_writer(s->image, out);
    493   }
    494 }
    495 
    496 KitStatus kit_link_session_emit(KitLinkSession* s, KitWriter* out) {
    497   LinkEmitArg arg;
    498   KitStatus st;
    499   if (!s || !out) return KIT_INVALID;
    500   if (!s->resolved) {
    501     st = kit_link_session_resolve(s);
    502     if (st != KIT_OK) return st;
    503   }
    504   if ((KitLinkOutputKind)s->opts.output_kind == KIT_LINK_OUTPUT_JIT)
    505     return KIT_INVALID;
    506   arg.out = out;
    507   return link_session_guard(s, link_session_emit_inner, &arg);
    508 }
    509 
    510 typedef struct LinkJitArg {
    511   KitJit* jit;
    512 } LinkJitArg;
    513 
    514 static void link_session_jit_inner(KitLinkSession* s, void* arg) {
    515   LinkJitArg* a = (LinkJitArg*)arg;
    516   a->jit = kit_jit_from_image(s->image);
    517   if (a->jit) {
    518     s->image = NULL;
    519     s->linker_transferred = 1;
    520     s->linker = NULL;
    521   }
    522 }
    523 
    524 KitStatus kit_link_session_jit(KitLinkSession* s, KitJit** out_jit) {
    525   LinkJitArg arg;
    526   KitStatus st;
    527   if (!out_jit) return KIT_INVALID;
    528   *out_jit = NULL;
    529   if (!s || (KitLinkOutputKind)s->opts.output_kind != KIT_LINK_OUTPUT_JIT)
    530     return KIT_INVALID;
    531   if (!s->resolved) {
    532     st = kit_link_session_resolve(s);
    533     if (st != KIT_OK) return st;
    534   }
    535   arg.jit = NULL;
    536   st = link_session_guard(s, link_session_jit_inner, &arg);
    537   if (st != KIT_OK) return st;
    538   if (!arg.jit) return KIT_ERR;
    539   *out_jit = arg.jit;
    540   return KIT_OK;
    541 }
    542 
    543 void kit_link_session_free(KitLinkSession* s) {
    544   Heap* h;
    545   if (!s) return;
    546   h = s->c->ctx->heap;
    547   if (s->image) link_image_free(s->image);
    548   if (s->linker) link_free(s->linker);
    549   if (s->publish_objs) {
    550     h->free(h, s->publish_objs, sizeof(*s->publish_objs) * s->publish_objs_cap);
    551   }
    552   h->free(h, s, sizeof(*s));
    553 }