kit

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

link_internal.h (28288B)


      1 #ifndef KIT_LINK_INTERNAL_H
      2 #define KIT_LINK_INTERNAL_H
      3 
      4 /* Shared private definitions for the linker (link.c, link_layout.c,
      5  * link_reloc.c, link_elf.c, link_jit.c). Not part of any public surface;
      6  * not included by anything outside src/link/. */
      7 
      8 #include "core/core.h"
      9 #include "core/hashmap.h"
     10 #include "core/segvec.h"
     11 #include "link/link.h"
     12 #include "obj/obj.h"
     13 #include "obj/symresolve.h"
     14 
     15 /* Per-input mapping built during link_resolve. ObjSymId / ObjSecId are
     16  * scoped to a single ObjBuilder, so the linker maintains an explicit
     17  * lookup from each input's id space into the global LinkSymId /
     18  * LinkSectionId space. Indices are dense (0..count-1 within the input);
     19  * the array is sized to the input's nsymbols / nsections at allocation
     20  * time. Index 0 of each id space is the "none" sentinel and maps to the
     21  * matching LINK_*_NONE. */
     22 typedef struct InputMap {
     23   LinkSymId* sym; /* size = ObjBuilder.nsymbols */
     24   u32 nsym;
     25   LinkSectionId* section; /* size = ObjBuilder.nsections */
     26   u32 nsection;
     27   LinkSectionId* atom; /* size = ObjBuilder.natoms */
     28   u32 natom;
     29   ObjAtomId* sym_atom;   /* size = nsym; ObjSymId -> ObjAtomId */
     30   ObjAtomId* reloc_atom; /* size = obj_reloc_total(input) */
     31   u32 nreloc;
     32   u8* section_has_atoms;   /* size = nsection */
     33   u32* section_atom_first; /* size = nsection; index into section_atom_ids */
     34   u32* section_atom_count; /* size = nsection */
     35   ObjAtomId* section_atom_ids; /* active atoms grouped by section */
     36   u32 nsection_atom_ids;
     37   /* COMDAT discard mask, size = nsection. Set by link_resolve_symbols
     38    * for COFF/PE SELECTANY: when an input's COMDAT section conflicts
     39    * with an earlier definition, the duplicate section is marked here
     40    * so link_gc_compute and link_layout_sections skip it. */
     41   u8* comdat_discarded;
     42 } InputMap;
     43 
     44 void link_input_map_alloc(LinkImage*, InputMap*, ObjBuilder*, u32 nsym_slots);
     45 
     46 static inline ObjAtomId link_input_sym_atom(const InputMap* m, ObjSymId sym) {
     47   return (m && m->sym_atom && sym < m->nsym) ? m->sym_atom[sym] : OBJ_ATOM_NONE;
     48 }
     49 
     50 static inline ObjAtomId link_input_reloc_atom(const InputMap* m,
     51                                               u32 reloc_index) {
     52   return (m && m->reloc_atom && reloc_index < m->nreloc)
     53              ? m->reloc_atom[reloc_index]
     54              : OBJ_ATOM_NONE;
     55 }
     56 
     57 static inline int link_input_section_has_atoms(const InputMap* m,
     58                                                ObjSecId sid) {
     59   return m && m->section_has_atoms && sid < m->nsection &&
     60          m->section_has_atoms[sid];
     61 }
     62 
     63 static inline void link_input_section_atoms(const InputMap* m, ObjSecId sid,
     64                                             u32* first, u32* count) {
     65   if (m && sid < m->nsection && m->section_atom_first &&
     66       m->section_atom_count) {
     67     *first = m->section_atom_first[sid];
     68     *count = m->section_atom_count[sid];
     69   } else {
     70     *first = 0;
     71     *count = 0;
     72   }
     73 }
     74 
     75 static inline LinkSectionId link_input_reloc_section(const InputMap* m,
     76                                                      const Reloc* r,
     77                                                      u32 reloc_index) {
     78   if (!m || !r || r->section_id == OBJ_SEC_NONE || r->section_id >= m->nsection)
     79     return LINK_SEC_NONE;
     80   if (link_input_section_has_atoms(m, r->section_id)) {
     81     ObjAtomId aid = link_input_reloc_atom(m, reloc_index);
     82     if (aid == OBJ_ATOM_NONE || aid >= m->natom) return LINK_SEC_NONE;
     83     return m->atom[aid];
     84   }
     85   return m->section[r->section_id];
     86 }
     87 
     88 static inline LinkSectionId link_input_symbol_section(const InputMap* m,
     89                                                       const ObjSym* s,
     90                                                       ObjSymId sym) {
     91   if (!m || !s || s->section_id == OBJ_SEC_NONE || s->section_id >= m->nsection)
     92     return LINK_SEC_NONE;
     93   if (link_input_section_has_atoms(m, s->section_id)) {
     94     ObjAtomId aid = link_input_sym_atom(m, sym);
     95     if (aid == OBJ_ATOM_NONE || aid >= m->natom) return LINK_SEC_NONE;
     96     return m->atom[aid];
     97   }
     98   return m->section[s->section_id];
     99 }
    100 
    101 /* ---- ObjSym classification (single source of truth) ---------------------
    102  *
    103  * The linker's three lanes (AOT exe/shared in link_resolve.c, `-r`
    104  * relocatable in link_relocatable.c, in-process JIT in link_jit.c) all
    105  * classify input symbols the same way. These predicates are the one
    106  * authority; every lane routes through them. */
    107 
    108 /* Resolution policy now lives in obj/symresolve.h so the LTO staging merge can
    109  * reuse it. These keep the historical link_* spellings (every lane routes
    110  * through them) as thin wrappers over the shared definitions. */
    111 static inline int link_bind_strength(u16 bind) {
    112   return symresolve_bind_strength(bind);
    113 }
    114 static inline int link_sym_is_def(const ObjSym* s) {
    115   return symresolve_sym_is_def(s);
    116 }
    117 static inline int link_sym_is_spurious_undef(const ObjSym* s) {
    118   return symresolve_sym_is_spurious_undef(s);
    119 }
    120 
    121 /* In-section byte count for an input section: BSS/NOBITS report their
    122  * zero-fill size, everything else its emitted byte total
    123  * (link_layout.c / link_jit.c). */
    124 static inline u32 link_section_size_for_link(const Section* s) {
    125   return (s->sem == SSEM_NOBITS || s->kind == SEC_BSS) ? s->bss_size
    126                                                        : s->bytes.total;
    127 }
    128 
    129 /* Open-addressed name -> LinkSymId hash for global / weak definitions
    130  * and lookups (kit_jit_lookup, entry-symbol resolution). Locals never
    131  * land in this table. Sym 0 is the empty-slot sentinel (it's also the
    132  * "none" id per core.h:42 and never appears as a real name). */
    133 
    134 static inline u32 link_sym_hash_(Sym s) { return hash_u32((u32)s); }
    135 HASHMAP_DEFINE(SymHash, Sym, LinkSymId, link_sym_hash_);
    136 
    137 /* Convenience wrappers: the existing call sites pass LinkSymId by value
    138  * (LINK_SYM_NONE on miss) and use insert-if-absent semantics. */
    139 static inline void symhash_init(SymHash* h, Heap* heap) {
    140   SymHash_init(h, heap);
    141 }
    142 static inline void symhash_fini(SymHash* h) { SymHash_fini(h); }
    143 static inline LinkSymId symhash_get(const SymHash* h, Sym name) {
    144   LinkSymId* hit = SymHash_get(h, name);
    145   return hit ? *hit : LINK_SYM_NONE;
    146 }
    147 static inline void symhash_set(SymHash* h, Sym name, LinkSymId id) {
    148   (void)SymHash_set(h, name, id);
    149 }
    150 static inline int symhash_insert(SymHash* h, Sym name, LinkSymId id,
    151                                  LinkSymId* existing_out) {
    152   return SymHash_try_insert(h, name, id, existing_out);
    153 }
    154 
    155 struct KitJit; /* forward; see link_jit.c */
    156 
    157 /* Archive ingestion state. Members are eagerly parsed into ObjBuilders
    158  * at link_add_archive_bytes time; the demand/whole-archive decision is
    159  * deferred to link_resolve, where matching members are transferred into
    160  * Linker.inputs. ObjBuilder ownership: while `included` is 0 the archive
    161  * owns the builder (freed in linker_release); on inclusion the pointer
    162  * moves into a LinkInput slot and `obj` is nulled to avoid double-free. */
    163 typedef struct LinkArchiveMember {
    164   Sym name; /* interned member name; 0 if anonymous */
    165   ObjBuilder* obj;
    166   u8 included;
    167   u8 pad[7];
    168 } LinkArchiveMember;
    169 
    170 typedef struct LinkArchive {
    171   Sym name;
    172   LinkArchiveMember* members;
    173   u32 nmembers;
    174   u32 order;
    175   u8 whole_archive;
    176   u8 link_mode;
    177   u8 group_id;
    178   u8 pad;
    179 } LinkArchive;
    180 
    181 SEGVEC_DEFINE(LinkInputs, LinkInput, 4); /* 16 entries per segment */
    182 SEGVEC_DEFINE(LinkArchives, LinkArchive, 4);
    183 
    184 struct Linker {
    185   Compiler* c;
    186   Heap* heap;
    187   LinkInputs inputs; /* LinkInputId = slot index + 1 */
    188   LinkArchives archives;
    189   u32 next_input_order;
    190   Sym entry_name;
    191   /* Set by link_set_script. NULL: layout takes the existing default
    192    * bucket-based path. Non-NULL: layout_sections_scripted walks the
    193    * script's output sections in declaration order. Borrowed; the
    194    * script and every sub-object must outlive link_resolve. */
    195   const KitLinkScript* script;
    196   /* -Ttext override of the static ET_EXEC image base. text_base_set==0 leaves
    197    * the default IMAGE_BASE_STATIC; ignored on PIE/shared/scripted layouts. */
    198   int text_base_set;
    199   u64 text_base;
    200   int gc_sections;
    201   int strip_debug;
    202   /* Set by kit_link_exe before link_resolve.  When 1, layout_iplt
    203    * synthesizes a .init_array entry pointing at __kit_ifunc_init so
    204    * the emitted ET_EXEC binary fills its IFUNC slots at startup.  The
    205    * JIT path leaves this 0 — slots are pre-resolved in-process by
    206    * link_jit.c, no ctor needed. */
    207   int emit_static_exe;
    208   /* In-process JIT lane (set by kit_link_jit).  Currently used to
    209    * tolerate undef `__tlv_bootstrap` on Mach-O inputs — the JIT image
    210    * has no dyld, descriptor[+0] is rewritten to kit's thunk during
    211    * kit_jit_from_image, so the symbol's resolved value doesn't
    212    * matter.  Without this, clang-produced .o files (which emit
    213    * `__tlv_bootstrap` as a plain non-weak undef) would panic at
    214    * link_resolve_undefs. */
    215   int jit_mode;
    216   /* PIE / ET_DYN output. Set by kit_link_exe when opts->pie or any
    217    * DSO input is present. Triggers layout_dyn (Phase 4) and the
    218    * dynamic ELF emit path (Phase 6). */
    219   int emit_pie;
    220   u16 pe_subsystem;
    221   /* Caller-supplied PT_INTERP. layout_dyn falls back to a target-
    222    * derived default when this is 0. */
    223   Sym interp_path;
    224   LinkExternResolver resolver;
    225   void* resolver_user;
    226   /* Borrowed JIT host. Set by kit_link_jit before link_resolve so the
    227    * layout/reloc passes can read execmem->page_size and the JIT mapper
    228    * can reach the host's reserve/protect/tls hooks without rummaging
    229    * through Compiler.ctx (which no longer carries those). NULL on the
    230    * AOT exe/shared lanes. */
    231   const KitJitHost* jit_host;
    232   CompilerCleanup* deferred; /* registered by link_new */
    233 };
    234 
    235 /* ---- GC liveness (link_resolve.c) ---------------------------------------- */
    236 
    237 typedef struct GcLive {
    238   u8**
    239       marks; /* marks[input_idx][obj_sec_id] for implicit whole-section units */
    240   u8** atom_marks; /* atom_marks[input_idx][obj_atom_id] for explicit atoms */
    241   u32* nsec;       /* obj_section_count per input */
    242   u32* natom;      /* obj_atom_count per input */
    243   u32 ninputs;
    244 } GcLive;
    245 
    246 typedef struct GcQueue {
    247   u64* items; /* hi32=input_idx, low31=id, bit31=set for atom */
    248   u32 n;
    249   u32 cap;
    250 } GcQueue;
    251 
    252 /* ---- Cross-file helpers (link_layout.c → link_reloc_layout.c) ------------ */
    253 
    254 /* Four-bucket segment partitioning by permission (defined in link_layout.c). */
    255 typedef enum SegBucket {
    256   SEG_RX = 0,  /* SF_ALLOC | SF_EXEC                  */
    257   SEG_R = 1,   /* SF_ALLOC, no EXEC, no WRITE          */
    258   SEG_RW = 2,  /* SF_ALLOC | SF_WRITE (incl. BSS)      */
    259   SEG_TLS = 3, /* SF_ALLOC | SF_TLS (.tdata + .tbss)   */
    260   SEG_NBUCKETS = 4,
    261 } SegBucket;
    262 
    263 /* section_kept: 1 for allocatable progbits/nobits sections (link_layout.c). */
    264 int link_section_kept(const Section* s);
    265 /* section_kept_fileonly: 1 for non-allocatable .debug_* sections that the
    266  * AOT ELF path carries through as file-only sections (link_layout.c). */
    267 int link_section_kept_fileonly(const Section* s);
    268 /* bucket_for: map section flags to SegBucket (link_layout.c). */
    269 SegBucket link_bucket_for(u16 flags);
    270 /* layout_page_size: page size for segment alignment (link_layout.c). */
    271 u64 link_layout_page_size(Linker* l);
    272 
    273 /* Append a fresh symbol slot and return its id (link_layout.c). */
    274 LinkSymId link_append_symbol(LinkImage* img, const LinkSymbol* tmpl);
    275 /* Append a fresh reloc slot and return it (link_layout.c). */
    276 LinkRelocApply* link_append_reloc_slot(LinkImage* img);
    277 
    278 /* Emit or upsert a synthetic global boundary symbol (link_layout.c). */
    279 void link_emit_boundary_sym(Linker* l, LinkImage* img, const char* name,
    280                             u64 vaddr);
    281 void link_emit_section_boundary_sym(Linker* l, LinkImage* img,
    282                                     const char* name, LinkSectionId section_id,
    283                                     u64 value);
    284 
    285 /* Detect __start_<X> / __stop_<X> with <X> a valid C identifier.
    286  * Defined in link_resolve.c; used by link_reloc_layout.c. */
    287 int link_gc_split_start_stop(const char* s, size_t n, size_t* out_off,
    288                              size_t* out_len, int* out_is_start);
    289 
    290 /* GC liveness helpers (link_resolve.c). */
    291 int link_gc_live_get(const GcLive* g, u32 ii, ObjSecId j);
    292 int link_gc_atom_live_get(const GcLive* g, u32 ii, ObjAtomId j);
    293 
    294 /* Segment/section growth helpers for iplt (link_reloc_layout.c). */
    295 u32 link_iplt_alloc_segments(LinkImage* img, u32 nseg);
    296 u32 link_iplt_alloc_sections(LinkImage* img, u32 nsec);
    297 
    298 /* Append one fixed-size synthetic region to the image: a fresh
    299  * page-aligned PT_LOAD segment plus its single covering section, sized
    300  * `size` with permissions `perms` (SF_* flags) and section semantics
    301  * `sem`. The region is placed at page-align(max segment end) so it never
    302  * overlaps existing content. A zero-filled byte buffer of `size` bytes is
    303  * allocated for the segment; *out_vaddr receives the image-relative base
    304  * and *out_bytes the buffer. `sec_align` sets the section's alignment
    305  * (the segment always aligns to the page). Returns the new section's id.
    306  * Backs the GOT / JIT-call-stub / IPLT layout passes
    307  * (link_reloc_layout.c). */
    308 LinkSectionId link_synth_region(LinkImage* img, Linker* l, Sym name, u16 perms,
    309                                 u16 sem, u64 size, u32 sec_align, u64* out_vaddr,
    310                                 u8** out_bytes);
    311 
    312 /* Append one fixed 8-byte ABS64 reloc-apply record targeting `target` at
    313  * `offset` within synthetic section `lsid` (write_vaddr == its file
    314  * offset, as every synthetic region is identity-mapped at layout time).
    315  * Backs the GOT / IPLT / JIT-slot fills (link_reloc_layout.c). */
    316 void link_emit_internal_abs64(LinkImage* img, LinkSectionId lsid, u32 offset,
    317                               u64 write_vaddr, LinkSymId target);
    318 
    319 /* ---- Public entries (link_resolve.c) --------------------------------------
    320  */
    321 void link_ingest_archives(struct Linker*);
    322 /* PE/COFF only: synthesize a tiny ObjBuilder providing the mingw CRT
    323  * `__CTOR_LIST__` / `__CTOR_END__` / `__DTOR_LIST__` / `__DTOR_END__`
    324  * boundary symbols.  See link_resolve.c for the contract. */
    325 void link_synth_coff_ctor_dtor_list(struct Linker*);
    326 void link_resolve_symbols(struct Linker*, LinkImage*);
    327 void link_resolve_undefs(struct Linker*, LinkImage*);
    328 void link_gc_compute(struct Linker*, LinkImage*, GcLive*);
    329 void link_gc_live_alloc(GcLive* g, struct Linker* l, Heap* h);
    330 void link_gc_live_free(GcLive* g, Heap* h);
    331 void link_gc_drop_dead_globals(struct Linker*, LinkImage*, const GcLive*);
    332 
    333 /* ---- Public entries (link_layout.c) ---------------------------------------
    334  */
    335 void link_layout_sections(struct Linker*, LinkImage*, const GcLive*);
    336 void link_layout_commons(struct Linker*, LinkImage*);
    337 void link_emit_segment_bytes(struct Linker*, LinkImage*);
    338 /* Carry .debug_* sections through as file-only sections + populate the
    339  * debug registry (link_layout.c). AOT ELF path only; gated by the
    340  * caller on !strip_debug / !jit_mode / ELF target. */
    341 void link_layout_debug(struct Linker*, LinkImage*);
    342 /* Byte buffer for a file-only debug LinkSection, or NULL if `id` is not
    343  * a registered file-only section (link_layout.c). */
    344 u8* link_fileonly_bytes(LinkImage*, LinkSectionId);
    345 
    346 /* ---- Public entries (link_reloc_layout.c) ---------------------------------
    347  */
    348 void link_assign_symbol_vaddrs(struct Linker*, LinkImage*);
    349 void link_emit_array_boundaries(struct Linker*, LinkImage*);
    350 void link_emit_tls_boundaries(struct Linker*, LinkImage*);
    351 void link_emit_encoding_section_boundaries(struct Linker*, LinkImage*);
    352 void link_layout_jit_stubs(struct Linker*, LinkImage*, u32 map_size,
    353                            LinkSymId** stub_map_out);
    354 void link_layout_got(struct Linker*, LinkImage*, u32 map_size,
    355                      LinkSymId** got_map_out);
    356 void link_layout_iplt(struct Linker*, LinkImage*);
    357 void link_emit_relocations(struct Linker*, LinkImage*, const LinkSymId* got_map,
    358                            const LinkSymId* stub_map);
    359 void link_resolve_entry(struct Linker*, LinkImage*);
    360 
    361 /* Defined in link.c. Walks the Linker's inputs and records each input's
    362  * ObjBuilder on the LinkImage so the JIT debug view can reach its
    363  * .debug_* sections after link_free runs.  LINK_INPUT_OBJ_BYTES
    364  * builders are moved (the LinkInput's obj pointer is nulled so
    365  * linker_release skips them); LINK_INPUT_OBJ builders are borrowed
    366  * (the caller still owns).  DSO / TBD inputs are skipped. */
    367 void link_capture_debug_inputs(struct Linker*, LinkImage*);
    368 
    369 /* Default PE/COFF ImageBase for executables.  Mirrored in link_coff.c
    370  * (the emitter writes this into the optional header).  Exposed here so
    371  * link_layout can synthesize the `__ImageBase` symbol at the same
    372  * vaddr, before resolve_undefs runs. */
    373 #define LINK_PE_IMAGE_BASE 0x140000000ULL
    374 
    375 /* Define / upsert a synthetic global symbol resolved to `vaddr`.
    376  * Satisfies any prior undef ref (e.g. _DYNAMIC from Scrt1.o,
    377  * __dso_handle from libc_nonshared.a) and fans out across per-input
    378  * duplicate name slots so emit_reloc_records sees the resolved
    379  * vaddr.  Implemented in link_layout.c. */
    380 void link_define_boundary(struct Linker*, LinkImage*, const char* name,
    381                           u64 vaddr);
    382 
    383 /* SegVec instances for image-owned tables. Pointers returned by *_at /
    384  * *_push remain valid for the LinkImage's lifetime. */
    385 SEGVEC_DEFINE(LinkSyms, LinkSymbol, 6);       /*  64 entries per segment */
    386 SEGVEC_DEFINE(LinkRelocs, LinkRelocApply, 7); /* 128 entries per segment */
    387 
    388 /* ---- Dynamic-link synthesis state (Phase 4) ----
    389  *
    390  * Owned by LinkImage when emit_pie is set. Holds the synthesized
    391  * .interp / .dynsym / .dynstr / .gnu.hash / .rela.dyn / .rela.plt /
    392  * .plt / .got.plt / .dynamic content plus the section ids the emit
    393  * pass needs to fill PT_DYNAMIC and the .dynamic body.
    394  *
    395  * Phase 4 builds the dynsym/dynstr/gnu.hash content and the JUMP_SLOT
    396  * .rela.plt records (one per imported function, against its synthetic
    397  * .got.plt slot). The .plt body is allocated but not emitted (Phase 5).
    398  * Phase 6 populates .rela.dyn with R_AARCH64_RELATIVE records for any
    399  * internal absolute reloc seen during reloc-apply.
    400  *
    401  * Layout invariants this struct enforces:
    402  *   - dynsym entry 0 is the reserved STN_UNDEF slot (zero-filled).
    403  *   - dynsym entries 1..nimport_func+nimport_data are imports, in the
    404  *     order PLT-functions first, then GOT-data.
    405  *   - PLT slots and JUMP_SLOT entries match the import_func order 1:1.
    406  *   - .got.plt has 3 reserved leading u64 slots (per AArch64 psABI:
    407  *     slot 0 = &.dynamic, slot 1 = link_map cookie, slot 2 =
    408  *     _dl_runtime_resolve), then one slot per imported function.
    409  */
    410 
    411 typedef struct DynSymRec {
    412   u32 st_name; /* offset into .dynstr */
    413   u8 st_info;
    414   u8 st_other;
    415   u16 st_shndx;
    416   u64 st_value;
    417   u64 st_size;
    418 } DynSymRec;
    419 
    420 typedef struct DynRela {
    421   u64 r_offset; /* image-relative vaddr of the patch site */
    422   u64 r_info;   /* ELF64_R_INFO(dynsym_index, elf_reloc_type) */
    423   i64 r_addend;
    424 } DynRela;
    425 
    426 typedef struct LinkDynState {
    427   /* PT_INTERP / .interp. interp_path is interned in compiler->global. */
    428   Sym interp_path;
    429   LinkSectionId sec_interp;
    430 
    431   /* .dynsym */
    432   LinkSectionId sec_dynsym;
    433   DynSymRec* dynsym;
    434   u32 ndynsym;      /* incl. slot-0 STN_UNDEF */
    435   u32 first_global; /* sh_info value: index of first non-local entry */
    436 
    437   /* .dynstr */
    438   LinkSectionId sec_dynstr;
    439   u8* dynstr;
    440   u32 dynstr_len;
    441 
    442   /* .gnu.hash */
    443   LinkSectionId sec_gnu_hash;
    444   u8* gnu_hash;
    445   u32 gnu_hash_len;
    446 
    447   /* GNU symbol versioning. Emitted only when at least one imported symbol
    448    * binds to a versioned DSO export (nverneed > 0); otherwise all three are
    449    * zero and no version sections / DT_VER* entries are produced (musl/static
    450    * links are unchanged). .gnu.version is one u16 per .dynsym entry;
    451    * .gnu.version_r holds Verneed/Vernaux requirements keyed by DT_NEEDED
    452    * soname. Both carry only .dynstr offsets + version indices (no vaddrs), so
    453    * the bytes are final at layout time and copied verbatim during emit. */
    454   LinkSectionId sec_gnu_version;
    455   u8* versym; /* ndynsym * 2 bytes */
    456   u32 versym_len;
    457   LinkSectionId sec_gnu_version_r;
    458   u8* verneed; /* nverneed Verneed records + their Vernaux */
    459   u32 verneed_len;
    460   u32 nverneed; /* DT_VERNEEDNUM */
    461 
    462   /* .rela.dyn — R_AARCH64_GLOB_DAT (imports against .got slots) and
    463    * R_AARCH64_RELATIVE (PIE internal abs64 fixups, populated during
    464    * Phase 6 emit). Pre-sized at layout time; the RELATIVE tail is
    465    * filled in during emit. */
    466   LinkSectionId sec_rela_dyn;
    467   DynRela* rela_dyn;
    468   u32 nrela_dyn;    /* number of records currently populated */
    469   u32 cap_rela_dyn; /* allocation capacity (records, not bytes) */
    470 
    471   /* .rela.plt — R_AARCH64_JUMP_SLOT, one per imported function. */
    472   LinkSectionId sec_rela_plt;
    473   DynRela* rela_plt;
    474   u32 nrela_plt;
    475 
    476   /* .plt — 32-byte PLT0 stub + 16 bytes per imported function. Body
    477    * is allocated (zero-initialized) but not emitted in Phase 4. */
    478   LinkSectionId sec_plt;
    479   u32 nplt;      /* number of imported functions */
    480   u64 plt_vaddr; /* image-relative .plt base */
    481   u64 plt_size;
    482 
    483   /* .got.plt — 24 reserved bytes + 8 per PLT slot. */
    484   LinkSectionId sec_got_plt;
    485   u64 got_plt_vaddr;
    486   u64 got_plt_size;
    487 
    488   /* .dynamic — PT_DYNAMIC body. Built at layout time; its size is
    489    * fixed once we know the DT_NEEDED count. */
    490   LinkSectionId sec_dynamic;
    491   u64 dynamic_vaddr;
    492   u64 dynamic_size;
    493   u32 ndyn_entries;
    494 
    495   /* DT_NEEDED list (interned soname Syms, in input order). */
    496   Sym* needed;
    497   u32 nneeded;
    498 
    499   /* Per-import dynsym index, indexed by LinkSymId. 0 means "not
    500    * imported / not in dynsym". Used by GLOB_DAT / JUMP_SLOT emit. */
    501   u32* sym_dynidx; /* size = sym_dynidx_size */
    502   u32 sym_dynidx_size;
    503 
    504   /* Per-import PLT entry vaddr, indexed by LinkSymId (Phase 5).  Set
    505    * for every imported function: vaddr of its 16-byte PLT stub inside
    506    * `.plt`.  0 means "no PLT stub" (symbol is data-only or not
    507    * imported).  apply_all_relocs reads this when redirecting a
    508    * CALL26/JUMP26 against an imported function — S becomes the PLT
    509    * entry vaddr instead of the symbol's (zero) vaddr.  The vaddrs
    510    * stored here track the post-shift values (shift_image_addresses
    511    * bumps them along with .plt's segment vaddr). */
    512   u64* sym_plt_vaddr; /* size = sym_dynidx_size */
    513 } LinkDynState;
    514 
    515 struct LinkImage {
    516   Compiler* c;
    517   Heap* heap;
    518   CompilerCleanup* deferred; /* registered by link_resolve */
    519   /* Borrowed back-pointer set by link_resolve.  The Linker is not
    520    * mutated through this handle; it's used by the format-specific emit
    521    * passes that need to walk LinkInputs (e.g. resolving an imported
    522    * symbol's dso_input_id back to the providing dylib's install-name). */
    523   struct Linker* linker;
    524 
    525   LinkSyms syms;   /* LinkSymId = slot index + 1 */
    526   SymHash globals; /* name -> LinkSymId for global/weak */
    527 
    528   LinkSection* sections; /* id = index + 1 */
    529   u32 nsections;
    530 
    531   LinkSegment* segments; /* id = index + 1 */
    532   u32 nsegments;
    533   u8** segment_bytes;        /* one per segment; size = file_size */
    534   size_t* segment_bytes_cap; /* allocation size for free */
    535 
    536   LinkRelocs relocs;
    537 
    538   /* IFUNC trampoline table (image-relative vaddrs).  One entry per
    539    * defined STT_GNU_IFUNC symbol: (resolver_vaddr, slot_vaddr).  The
    540    * JIT path walks this after applying relocations, calls each
    541    * resolver in-process, and stores the result into the slot's write
    542    * alias.  The ELF emit path uses it to seed a startup init routine
    543    * (or panics when the routine is not yet wired in). */
    544   u64* iplt_pairs; /* 2 * niplt entries */
    545   u32 niplt;
    546 
    547   LinkSymId entry_sym;
    548 
    549   /* TLS image span (image-relative).  Set when any input contributes
    550    * an SF_TLS section.  filesz covers the .tdata bytes that initialize
    551    * the per-thread block; memsz adds .tbss zero-fill.  tls_align is
    552    * the natural alignment of the TLS image (max of contributing
    553    * sections), distinct from the containing PT_LOAD's page align.
    554    * AArch64 ELF ABI: TP-relative offset of a TLS symbol with image
    555    * offset `o` is `o + 16` (16-byte TCB ahead of the TLS data). */
    556   u64 tls_vaddr;
    557   u64 tls_filesz;
    558   u64 tls_memsz;
    559   u32 tls_align;
    560 
    561   InputMap* input_maps; /* one per input; indexed by input_id-1 */
    562   u32 ninput_maps;
    563 
    564   /* Debug-capture state for the JIT path.  Populated by
    565    * link_capture_debug_inputs at the tail of link_resolve so the input
    566    * ObjBuilders (which carry .debug_* sections + their per-section
    567    * relocations — neither consumed nor mutated by layout) survive the
    568    * Linker's teardown and become reachable from kit_jit_view.
    569    *
    570    * Parallel to input_maps: dbg_objs[i] is the ObjBuilder for input
    571    * (i+1), or NULL when no debug info is present / the input kind isn't
    572    * relevant (DSO/TBD).  dbg_objs_owned[i] is 1 when the image must
    573    * obj_free the builder at link_image_free (transferred from
    574    * LINK_INPUT_OBJ_BYTES), 0 when borrowed (LINK_INPUT_OBJ — caller
    575    * still owns). */
    576   ObjBuilder** dbg_objs;
    577   u8* dbg_objs_owned;
    578   u32 dbg_objs_n;
    579 
    580   /* File-only debug-section registry (AOT ELF path).  link_layout_debug
    581    * appends one file-only LinkSection per surviving .debug_* contribution
    582    * as a contiguous id range [dbg_first_lsid, dbg_first_lsid+dbg_count).
    583    * dbg_bytes[i] / dbg_size[i] hold that contribution's own byte buffer
    584    * (relocs applied in place at reloc-offset), indexed by lsid -
    585    * dbg_first_lsid.  Empty on the JIT / Mach-O / COFF lanes. */
    586   LinkSectionId dbg_first_lsid;
    587   u32 dbg_count;
    588   u8** dbg_bytes;
    589   u64* dbg_size;
    590 
    591   /* Dynamic-link state (Phase 4). NULL when emit_pie was not set on
    592    * the Linker — i.e., the static-exe / JIT path. Owned by the image. */
    593   LinkDynState* dyn;
    594   /* Mirror of Linker.emit_pie at link_resolve time; consulted by emit. */
    595   int pie;
    596   /* Set when layout was driven by Linker.script. The emitter then keeps
    597    * segment vaddrs at their script-assigned absolute values, drops the
    598    * self-describing headers PT_LOAD / build-id PT_NOTE, and only shifts
    599    * file offsets to make room for ehdr+phdrs. */
    600   u8 scripted;
    601   /* -Ttext: when text_base_set, the static-exe image base override, mirrored
    602    * from Linker at link_resolve time. Ignored if pie/scripted. */
    603   int text_base_set;
    604   u64 text_base;
    605 };
    606 
    607 /* Page granularity used for ELF segment alignment and the file-offset /
    608  * vaddr congruence the runtime loader requires. 16 KiB matches AArch64
    609  * Apple Silicon and the common Linux/AArch64 kernel config; 4 KiB pages
    610  * are also valid at runtime since 16K is a multiple. */
    611 #define PAGE_SIZE 0x4000u
    612 
    613 /* Apply one relocation in place. P_bytes points at the first byte of the
    614  * relocation site within the final memory; S is the resolved final
    615  * address of the target symbol; A the addend; P the final address of
    616  * the relocation site. Panics on unsupported kinds. */
    617 void link_reloc_apply(Compiler*, RelocKind, u8* P_bytes, u64 S, i64 A, u64 P);
    618 
    619 /* kit emits local-exec TLS only: a thread-local's offset within THIS image's
    620  * TLS block is fixed at link time, so a local-exec access (or the TP-relative
    621  * fill of a TLS initial-exec GOT slot) is valid only against a thread-local
    622  * *defined in the image being linked*.  Panic with a clear diagnostic if `tgt`
    623  * is imported from a shared object (its TLS block belongs to another module,
    624  * sized and placed by the dynamic loader) or resolved to a non-thread-local
    625  * definition.  There is no initial-exec/global-dynamic fallback to relax to,
    626  * so the only alternative is a silently bogus tp-relative offset -- hence the
    627  * hard error.  A no-op when `tgt` is a thread-local defined here. */
    628 void link_require_local_tls(Compiler*, const LinkSymbol* tgt);
    629 
    630 /* Public link_emit_image_writer dispatches by Compiler.target.obj. The
    631  * ELF and Mach-O writers get architecture identity from LinkArchDesc;
    632  * reloc application remains keyed by RelocKind. COFF arrives later. */
    633 void link_emit_elf(LinkImage*, Writer*);
    634 void link_emit_macho(LinkImage*, Writer*);
    635 void link_emit_coff(LinkImage*, Writer*);
    636 
    637 /* Format-agnostic 16-byte image identity, derived from per-segment
    638  * post-shift bytes + vaddrs/sizes.  ELF wraps it in a
    639  * .note.gnu.build-id; Mach-O will wrap it in LC_UUID; COFF/PE in a
    640  * debug directory entry.  One source of truth so the bytes match
    641  * across formats. */
    642 #define LINK_IMAGE_ID_BYTES 16u
    643 void link_image_id_compute(const LinkImage*, u8 out[LINK_IMAGE_ID_BYTES]);
    644 
    645 #endif