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