kit

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

link.h (13213B)


      1 #ifndef KIT_INTERNAL_LINK_H
      2 #define KIT_INTERNAL_LINK_H
      3 
      4 #include <kit/core.h>
      5 #include <kit/jit.h>
      6 #include <kit/link.h>
      7 
      8 #include "obj/obj.h"
      9 
     10 typedef struct Linker Linker;
     11 typedef struct LinkImage LinkImage;
     12 
     13 struct KitLinkSession {
     14   Compiler* c;
     15   Linker* linker;
     16   KitLinkSessionOptions opts;
     17   LinkImage* image;
     18   KitObjBuilder** publish_objs;
     19   u32 npublish_objs;
     20   u32 publish_objs_cap;
     21   u32 non_obj_inputs;
     22   u8 resolved;
     23   u8 linker_transferred;
     24   u8 pad[2];
     25 };
     26 
     27 typedef enum LinkInputKind {
     28   LINK_INPUT_OBJ,
     29   LINK_INPUT_OBJ_BYTES,
     30   LINK_INPUT_ARCHIVE_BYTES,
     31   /* Shared-object input (ET_DYN). Parsed via read_elf_dso into an
     32    * ObjBuilder containing only the DSO's exported (dynsym) symbols.
     33    * Contributes nothing to layout — its symbols are searched by
     34    * resolve_undefs to satisfy imported references. */
     35   LINK_INPUT_DSO_BYTES,
     36 } LinkInputKind;
     37 
     38 typedef u32 LinkInputId;
     39 #define LINK_INPUT_NONE 0u
     40 
     41 typedef u32 LinkSymId;
     42 #define LINK_SYM_NONE 0u
     43 
     44 typedef u32 LinkSegmentId;
     45 #define LINK_SEG_NONE 0u
     46 
     47 typedef u32 LinkSectionId;
     48 #define LINK_SEC_NONE 0u
     49 
     50 typedef struct LinkInput {
     51   LinkInputId id;
     52   u8 kind; /* LinkInputKind */
     53   u8 pad[3];
     54   u32 order;
     55   ObjBuilder* obj; /* for LINK_INPUT_OBJ, otherwise NULL until read */
     56   Sym name;        /* diagnostic name for bytes inputs */
     57   /* DSO-only: SONAME extracted from PT_DYNAMIC.DT_SONAME. 0 if absent.
     58    * Used as the DT_NEEDED entry for the consuming exe / shared lib —
     59    * the runtime loader looks up the dependency by SONAME, not by the
     60    * filesystem path passed at link time. */
     61   Sym soname;
     62   /* COFF short-import only: the name the loader must resolve in the DLL when
     63    * it differs from the symbol's link name (Microsoft short-import NameType
     64    * NOPREFIX/UNDECORATE/EXPORTAS — e.g. local __msvcrt_assert -> export
     65    * _assert). 0 when the import name equals the symbol name. Consumed by the
     66    * COFF import-table synthesis for the PE hint/name-table entry. */
     67   Sym coff_import_name;
     68 } LinkInput;
     69 
     70 typedef struct LinkSymbol {
     71   LinkSymId id;
     72   Sym name;
     73   LinkInputId input_id;
     74   ObjSymId obj_sym;
     75   ObjSecId section_id;
     76   ObjAtomId atom_id;
     77   u64 value;
     78   u64 vaddr; /* final linked address, 0 for unresolved undef */
     79   u64 size;
     80   u32 common_align; /* alignment for SK_COMMON symbols */
     81   u8 bind;          /* SymBind */
     82   u8 kind;          /* SymKind */
     83   u8 defined;
     84   /* Dynamic-link bookkeeping. `imported` is set when an undef was
     85    * matched against a DSO input's exports — the symbol stays
     86    * structurally undefined (the static linker has no value for it)
     87    * but resolve_undefs no longer panics on it. `dso_input_id` is the
     88    * id of the providing DSO LinkInput; the DSO's SONAME ends up in
     89    * the produced image's DT_NEEDED list. The needs_* flags are set
     90    * during reloc-rewrite (Phase 5) — declared here so the model is
     91    * stable across the dyn-link work. */
     92   u8 imported;
     93   LinkInputId dso_input_id;
     94   /* ELF-only: explicit version required by a name@VERSION undefined reference.
     95    * Dynamic symbol emission still writes the base name; this field drives the
     96    * matching .gnu.version_r entry. 0 means use the providing DSO's default
     97    * version, if any. */
     98   Sym elf_version;
     99   u8 needs_plt;
    100   u8 needs_got;
    101   u8 needs_copy;
    102   u8 vis;
    103   u8 pad[4];
    104 } LinkSymbol;
    105 
    106 typedef struct LinkSegment {
    107   LinkSegmentId id;
    108   u32 flags; /* SecFlag-like permissions after layout */
    109   u64 file_offset;
    110   u64 vaddr;
    111   u64 paddr;
    112   u64 mem_size;
    113   u64 file_size;
    114   u32 align;
    115   u32 phdr_type;
    116   u32 phdr_flags;
    117   u32 nsections;
    118   u8 phdr_flags_set;
    119   u8 phdr_filehdr;
    120   u8 phdr_phdrs;
    121   u8 pad[5];
    122 } LinkSegment;
    123 
    124 typedef struct LinkSection {
    125   LinkSectionId id;
    126   LinkInputId input_id;
    127   ObjSecId obj_section_id;
    128   ObjAtomId obj_atom_id;
    129   LinkSegmentId segment_id;
    130   u64 obj_offset;
    131   u64 input_offset;
    132   u64 file_offset;
    133   u64 vaddr;
    134   u64 size;
    135   u32 flags;
    136   u32 align;
    137   Sym name; /* section name (interned); 0 if anon */
    138   u16 sem;  /* SecSem of the source obj section */
    139   /* Non-segment, file-resident section (a .debug_* contribution). It
    140    * lives in img->sections so its SK_SECTION symbol resolves and the
    141    * reloc engine applies, but it has segment_id == LINK_SEG_NONE and
    142    * carries its bytes in the LinkImage debug registry, not a segment
    143    * buffer. See link_layout_debug / link_fileonly_bytes. */
    144   u8 file_only;
    145   u8 pad;
    146 } LinkSection;
    147 
    148 typedef struct LinkRelocApply {
    149   LinkInputId input_id;
    150   ObjSecId section_id;
    151   LinkSectionId link_section_id;
    152   u32 offset;
    153   u32 width;
    154   u64 write_vaddr;
    155   u64 write_file_offset;
    156   RelocKind kind;
    157   LinkSymId target;
    158   i64 addend;
    159 } LinkRelocApply;
    160 
    161 /* Internal resolver type matches the public KitExternResolver: name is a
    162  * C string at the linker boundary. The Linker interns it on entry. */
    163 typedef KitExternResolver LinkExternResolver;
    164 
    165 Linker* link_new(Compiler*);
    166 void link_free(Linker*);
    167 
    168 /* Inputs are byte-buffer-shaped. Path-based adapters live in the driver
    169  * (see driver/driver.h) and use Compiler.env->file_io to read bytes before
    170  * calling these. All bytes inputs must remain alive until link_resolve
    171  * returns; ObjBuilder inputs must remain alive until link_image_free.
    172  *
    173  * `name` is an unowned diagnostic string; the linker interns it on entry
    174  * (callers do not need to pre-intern). */
    175 LinkInputId link_add_obj(Linker*, ObjBuilder*);
    176 LinkInputId link_add_obj_bytes(Linker*, const char* name, const u8* data,
    177                                size_t len);
    178 /* Shared-object input. The bytes are parsed as ET_DYN ELF; only the
    179  * DSO's dynsym (exported symbols) is materialized. The DSO contributes
    180  * no sections to the output image — its presence influences resolution
    181  * (an undef matched by name against this DSO's exports becomes an
    182  * imported symbol) and DT_NEEDED bookkeeping (the DSO's SONAME, or its
    183  * filename if no SONAME, is recorded as a runtime dependency). */
    184 LinkInputId link_add_dso_bytes(Linker*, const char* name, const u8* data,
    185                                size_t len);
    186 /* `whole_archive` (nonzero == --whole-archive) and `link_mode`
    187  * (KitLinkMode: -Bstatic / -Bdynamic / --as-needed positional state) are
    188  * orthogonal per-archive flags. `group_id == 0` means linear single-pass;
    189  * archives sharing a nonzero `group_id` are scanned cyclically (equivalent
    190  * to GNU ld --start-group ... --end-group). */
    191 LinkInputId link_add_archive_bytes(Linker*, const char* name, const u8* data,
    192                                    size_t len, u8 whole_archive, u8 link_mode,
    193                                    u8 group_id);
    194 
    195 void link_set_entry(Linker*, KitSlice name);
    196 void link_clear_entry(Linker*);
    197 /* Borrowed reference; the script and every sub-object must outlive
    198  * link_resolve. The linker accepts only the structured form — there is no
    199  * text-shaped setter. Hosts that have GNU-ld text use
    200  * kit_link_script_parse first. */
    201 void link_set_script(Linker*, const KitLinkScript*);
    202 void link_set_extern_resolver(Linker*, LinkExternResolver, void* user);
    203 /* Enable --gc-sections on this link. Roots are: entry symbol, exported
    204  * symbols (shared link), and any section flagged KEEP by the linker
    205  * script. Unreferenced sections are dropped from the output. */
    206 void link_set_gc_sections(Linker*, int enable);
    207 void link_set_strip_debug(Linker*, int enable);
    208 void link_set_allow_undefined(Linker*, int enable);
    209 void link_set_shared(Linker*, int enable);
    210 
    211 /* Mark this link as targeting a static ET_EXEC ELF binary (vs. the
    212  * in-process JIT).  Setter is called by kit_link_exe; the JIT path
    213  * leaves it disabled.  Currently controls the IFUNC startup-init
    214  * synthesis in layout_iplt: with this flag set, layout appends a
    215  * .init_array entry that calls __kit_ifunc_init at exe startup so
    216  * .igot.plt slots get filled before user code runs.  The JIT pre-
    217  * resolves slots in-process and doesn't need the ctor. */
    218 void link_set_emit_static_exe(Linker*, int enable);
    219 /* Mark this link as the in-process JIT lane (set by kit_link_jit).
    220  * Lets link_resolve tolerate platform undefs the JIT image patches
    221  * post-link (currently: Mach-O `__tlv_bootstrap`).  Leaves AOT lanes
    222  * untouched. */
    223 void link_set_jit_mode(Linker*, int enable);
    224 
    225 /* Mark this link as producing a position-independent ET_DYN exe (-pie).
    226  * Triggers Phase 4 layout_dyn pass (synthetic .interp/.dynsym/.dynstr/
    227  * .gnu.hash/.plt/.got.plt/.rela.dyn/.rela.plt/.dynamic) and Phase 6 ELF
    228  * emit (e_type=ET_DYN, IMAGE_BASE=0, PT_PHDR/PT_INTERP/PT_DYNAMIC,
    229  * R_AARCH64_RELATIVE on internal absolute relocs). Orthogonal to
    230  * emit_static_exe; both may be set in the same link (the IFUNC ctor
    231  * still wants to run on the exe path regardless of PIE). */
    232 void link_set_pie(Linker*, int enable);
    233 /* Override the static ET_EXEC image (text) base, from `kit ld -Ttext ADDR`. No
    234  * effect on PIE/shared (base 0) or scripted layout (script pins vaddrs). */
    235 void link_set_text_base(Linker*, u64 base);
    236 void link_set_pe_subsystem(Linker*, u16 subsystem);
    237 
    238 /* Runtime loader path written into PT_INTERP / .interp. NULL leaves the
    239  * default ("/lib/ld-musl-aarch64.so.1" for aarch64-linux). Only
    240  * consulted when -pie is enabled (or any DSO input is present). */
    241 void link_set_interp_path(Linker*, KitSlice path);
    242 
    243 /* Borrowed JIT host. The layout passes read execmem->page_size; the JIT
    244  * mapper reads the full host (execmem reserve/protect, tls). NULL on
    245  * AOT exe/shared lanes. The host and its sub-tables must outlive the
    246  * link / the produced KitJit. */
    247 void link_set_jit_host(Linker*, const KitJitHost*);
    248 
    249 /* Symbol resolution and layout are explicit so file linking and JIT share the
    250  * same resolved image. Fatal diagnostics use Compiler.panic.
    251  *
    252  * link_resolve registers the returned LinkImage with compiler_defer so a
    253  * panic between resolve and consumer (emit_writer / jit_from_image) reaps
    254  * it. Successful consumers either call link_image_free (which undefers and
    255  * frees) or transfer ownership via kit_jit_from_image (which undefers and
    256  * keeps the image alive for the JIT's lifetime).
    257  *
    258  * ---- Incremental-linking invariant (forward compat) ----
    259  * The single-shot link_resolve implementation must not destroy or consume
    260  * input-side state that a future incremental re-resolve would need.
    261  * Specifically:
    262  *   - LinkRelocApply records stay as data: do not burn them into segment
    263  *     bytes destructively without preserving the originals.
    264  *   - LinkInputId -> ObjBuilder* mappings stay stable for the lifetime of
    265  *     the Linker — adding an input never invalidates an existing handle.
    266  *   - Resolution is structured as a function from inputs to a fresh
    267  *     LinkImage, not as in-place mutation of the Linker.
    268  * Incremental linking is the single most likely future addition; this
    269  * comment locks in the implementation discipline that keeps the existing
    270  * surface amenable, with no speculative API. */
    271 LinkImage* link_resolve(Linker*);
    272 
    273 /* Incremental resolution (per doc/EMU.md §6). link_resolve_at reserves
    274  * the image's layout starting at the caller-specified base VA — used
    275  * by the emu so the JIT image's host addresses are stable for the
    276  * session (chaining patches live host code with section addresses).
    277  * link_resolve_extend appends new inputs to an existing image: places
    278  * new sections at the next free offset within the reserved region,
    279  * resolves new symbols against the existing image's globals plus the
    280  * registered LinkExternResolver, and applies new relocations. It
    281  * MUST NOT change host addresses of previously placed sections —
    282  * chaining and the code cache depend on it. The image must have been
    283  * produced by a prior link_resolve_at call on the same Linker. */
    284 LinkImage* link_resolve_at(Linker*, uintptr_t base_va);
    285 void link_resolve_extend(Linker*, LinkImage*);
    286 
    287 void link_image_free(LinkImage*);
    288 const LinkSymbol* link_symbol(LinkImage*, LinkSymId);
    289 LinkSymId link_symbol_lookup(LinkImage*, Sym name);
    290 u32 link_segment_count(LinkImage*);
    291 const LinkSegment* link_segment_get(LinkImage*, u32 id);
    292 const u8* link_segment_bytes(LinkImage*, LinkSegmentId, size_t* size_out);
    293 u32 link_section_count(LinkImage*);
    294 const LinkSection* link_section_get(LinkImage*, LinkSectionId id);
    295 u32 link_reloc_apply_count(LinkImage*);
    296 const LinkRelocApply* link_reloc_apply_get(LinkImage*, u32 id);
    297 
    298 /* Writes an executable in the format implied by Compiler.target into the
    299  * caller-provided Writer. Path-based emit lives in the driver. */
    300 void link_emit_image_writer(LinkImage*, Writer*);
    301 
    302 /* Writes an ET_REL / MH_OBJECT relocatable partial-link output. This consumes
    303  * the Linker's object/archive inputs and emits a fresh ObjBuilder through the
    304  * active object-format writer; it does not perform executable layout, section
    305  * GC, entry resolution, GOT/IPLT synthesis, or DSO binding. */
    306 void link_emit_relocatable_writer(Linker*, Writer*);
    307 
    308 /* JIT: maps the image into executable memory and returns an owning handle.
    309  * The returned KitJit takes ownership of the LinkImage (undefers it from
    310  * the cleanup stack registered by link_resolve); on kit_jit_free both the
    311  * JIT mapping and the LinkImage are released. Lookup is by name; the public
    312  * `kit_jit_lookup` and `kit_jit_free` declarations live in
    313  * <kit/jit.h>. */
    314 KitJit* kit_jit_from_image(LinkImage*);
    315 
    316 #endif