kit

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

format.h (16899B)


      1 #ifndef KIT_OBJ_FORMAT_H
      2 #define KIT_OBJ_FORMAT_H
      3 
      4 #include <kit/object.h>
      5 #include <stddef.h>
      6 
      7 #include "core/core.h"
      8 
      9 typedef struct LinkImage LinkImage;
     10 typedef struct Linker Linker;
     11 typedef struct EmuLoadOptions EmuLoadOptions;
     12 typedef struct EmuLoadedImage EmuLoadedImage;
     13 typedef struct EmuProcess EmuProcess;
     14 typedef struct EmuLoadedObject EmuLoadedObject;
     15 typedef struct EmuDynNeededIter EmuDynNeededIter;
     16 typedef struct EmuDynSymbol EmuDynSymbol;
     17 typedef struct EmuDynRelocIter EmuDynRelocIter;
     18 typedef struct EmuDynReloc EmuDynReloc;
     19 typedef u32 EmuDynRelocClass;
     20 typedef u32 EmuDynRelocTableKind;
     21 
     22 typedef ObjBuilder* (*ObjFormatReadFn)(Compiler*, const char* name,
     23                                        const u8* data, size_t len);
     24 typedef ObjBuilder* (*ObjFormatReadDsoFn)(Compiler*, const char* name,
     25                                           const u8* data, size_t len,
     26                                           Sym* soname_out);
     27 typedef void (*ObjFormatEmitFn)(Compiler*, ObjBuilder*, Writer*);
     28 typedef void (*ObjFormatLinkEmitFn)(LinkImage*, Writer*);
     29 typedef void (*ObjFormatLayoutDynFn)(Linker*, LinkImage*);
     30 typedef void (*ObjFormatFreeDynFn)(LinkImage*);
     31 typedef void (*ObjFormatMachoStubFn)(u8* dst, u64 stub_vaddr,
     32                                      u64 got_slot_vaddr);
     33 typedef void (*ObjFormatCoffStubFn)(u8* dst, u64 stub_vaddr,
     34                                     u64 iat_slot_vaddr);
     35 
     36 /* Resolve a build target (arch/OS/obj/endian/float-ABI) from this format's
     37  * on-disk header bytes. Invoked by kit_detect_target once kit_detect_fmt has
     38  * classified the leading bytes to this format. The detector lives in the
     39  * format vtable so a format compiled out of the build drops its detection
     40  * logic with it — no format-identity #if in the API layer. The COFF detector
     41  * additionally handles PE images (the dispatcher routes KIT_BIN_PE to COFF). */
     42 typedef KitStatus (*ObjFormatDetectTargetFn)(const u8* data, size_t len,
     43                                              KitTargetSpec* out);
     44 typedef KitStatus (*ObjFormatRewriteLinkedFn)(
     45     const KitContext*, KitSlice name, const KitSlice* input,
     46     const KitLinkedRewriteOptions*, KitWriter* out,
     47     KitLinkedRewriteReport* report_out);
     48 
     49 /* Synthetic-input hook: invoked before symbol resolution to inject a
     50  * synthetic input object (e.g. the COFF __CTOR_LIST__/__DTOR_LIST__
     51  * boundary blob). The hook receives the Linker so it can append a
     52  * LinkInput; returns the freshly built ObjBuilder, or NULL when nothing
     53  * needs synthesizing for the current target. Formats with no synthetic
     54  * inputs leave this NULL. */
     55 typedef void (*ObjFormatSynthInputsFn)(Linker*);
     56 
     57 typedef struct ObjElfArchOps {
     58   KitArchKind arch;
     59   u32 e_machine;
     60   u32 e_flags;
     61   const char* default_musl_interp;
     62   u32 r_relative;
     63   u32 r_glob_dat;
     64   u32 r_jump_slot;
     65   u32 r_irelative; /* R_*_IRELATIVE static-IFUNC resolver reloc (__rela_iplt).
     66                     */
     67   /* Variant-I TP bias: distance from the TLS image start to where `tp`
     68    * points for a freestanding (kit start.c) layout. AArch64/RISC-V place
     69    * a 16-byte TCB ahead of the image, so this is 16 for those arches; 0
     70    * for variant-II arches (x86_64) and any arch with no TLS support. The
     71    * hosted-vs-freestanding split for RISC-V is still applied by the
     72    * caller in src/obj/elf/link.c; this field is the per-arch maximum. */
     73   u32 tls_tp_bias;
     74   /* SHT_REL (vs SHT_RELA): 1 for arches whose ELF ABI carries relocation
     75    * addends in the relocated field rather than an explicit r_addend slot.
     76    * The 32-bit ARM EABI (AAELF32) mandates REL; clang/gas/GNU ld all emit
     77    * and expect `.rel.<name>` with 8-byte Elf32_Rel entries. Every other
     78    * arch kit targets uses RELA (0). emit.c folds the addend into the field
     79    * and writes Elf32_Rel when this is set. */
     80   u8 uses_rel;
     81   u32 (*reloc_to)(u32 kind);
     82   u32 (*reloc_from)(u32 wire_type);
     83   /* Diagnostic spelling of a per-arch ELF reloc wire type (e.g.
     84    * "R_AARCH64_CALL26"). NULL means "no per-arch name table"; callers
     85    * fall back to the format-neutral reloc_kind_name(). */
     86   const char* (*reloc_name)(u32 wire_type);
     87   /* Decode the float ABI from this arch's ELF e_flags. RISC-V reads
     88    * EF_RISCV_FLOAT_ABI_*; other arches have no float-ABI e_flags and
     89    * leave this NULL (callers treat NULL as KIT_FLOAT_ABI_DEFAULT). */
     90   KitFloatAbi (*float_abi_from_e_flags)(u32 e_flags);
     91   /* REL-only: reconstruct the implicit addend a relocation carries in its
     92    * relocated field (Elf32_Rel has no r_addend slot). `field` points at the
     93    * `width`-byte relocated location in the target section. Only set for
     94    * `uses_rel` arches (ARM); the reader calls it per REL reloc so kit's own
     95    * linker reads the same addend a field-reading linker (ld.lld) would.
     96    * NULL or a NOBITS target -> addend 0. */
     97   i64 (*reloc_field_addend)(u32 kind, const u8* field, u32 width);
     98   /* Build this arch's ELF vendor build-attributes section payload (e.g. ARM's
     99    * `.ARM.attributes`, SHT_*_ATTRIBUTES). Returns a freshly allocated buffer
    100    * (in `c->scratch`) of `*size_out` bytes; the emitter synthesizes the
    101    * section only when this is non-NULL. NULL for arches that emit no vendor
    102    * attributes (aarch64, x86-64, RISC-V, …) — replaces the former
    103    * `e_machine == EM_ARM` identity gate in the ELF emitter. */
    104   const u8* (*build_attributes)(Compiler* c, u32* size_out);
    105 } ObjElfArchOps;
    106 
    107 /* Structural role of a Mach-O relocation entry. Mach-O's r_type is a 4-bit
    108  * field whose values OVERLAP across architectures (e.g. value 2 is both
    109  * X86_64_RELOC_BRANCH and ARM64_RELOC_BRANCH26), so the entry's meaning can
    110  * only be resolved per-arch. The shared reader threads the cross-entry state
    111  * (addend carriers, subtractor pairs) the per-arch decoder reports via this
    112  * role; everything arch-specific (the kind, the lo12 instruction inspection,
    113  * the addend carrier) lives in the decoder. */
    114 typedef enum MachoRelocRole {
    115   MACHO_RELOC_NORMAL = 0,   /* `kind` is final; stands alone                  */
    116   MACHO_RELOC_ADDEND,       /* addend-carrier pseudo-reloc (arm64): emits     */
    117                             /*   nothing; `addend` seeds the next entry       */
    118   MACHO_RELOC_SUBTRACTOR,   /* minuend marker: `kind` = R_SUB*; arms the pair */
    119   MACHO_RELOC_ABSOLUTE,     /* unsigned datum: carries its addend in-place    */
    120                             /*   and becomes R_ADD* when it completes a       */
    121                             /*   pending subtractor, else stands as `kind`    */
    122 } MachoRelocRole;
    123 
    124 /* One decoded Mach-O relocation entry (the raw on-disk bitfields). */
    125 typedef struct MachoRelocEntry {
    126   u32 r_type;      /* 4-bit ARM64_RELOC_* / X86_64_RELOC_* code */
    127   u32 r_pcrel;
    128   u32 r_length;    /* 0=byte 1=hword 2=word 3=quad */
    129   u32 r_extern;
    130   u32 r_symbolnum;
    131   u32 r_address;
    132   const u8* insn;  /* patch-site bytes (>=4 readable iff insn_len>=4), for the */
    133   u32 insn_len;    /*   arm64 PAGEOFF12 load/store-width inspection; else NULL */
    134 } MachoRelocEntry;
    135 
    136 typedef struct MachoRelocDecoded {
    137   u32 kind;            /* RelocKind */
    138   u32 role;            /* MachoRelocRole */
    139   i64 addend;          /* MACHO_RELOC_ADDEND: the carried value */
    140   i64 inplace_bias;    /* added to the in-place field value when recovering the */
    141                        /*   addend. x86_64 bakes a PC-relative reloc's addend as */
    142                        /*   symrel = addend + width, so the reader subtracts the */
    143                        /*   width (bias = -(1<<r_length)); 0 for absolute data.  */
    144   u8 inplace_addend;   /* extern entries recover their addend from the patch    */
    145                        /*   field: the ABSOLUTE family (both arches) and every   */
    146                        /*   x86_64 reloc, which has no out-of-band addend.       */
    147   u8 inplace_signed;   /* sign-extend the (sub-64-bit) field read — a PC-relative */
    148                        /*   displacement is signed; an absolute datum is not.    */
    149   u8 pad[6];
    150 } MachoRelocDecoded;
    151 
    152 typedef struct ObjMachoArchOps {
    153   KitArchKind arch;
    154   u32 cputype;
    155   u32 cpusubtype;
    156   u32 stub_size;
    157   ObjFormatMachoStubFn emit_stub;
    158   u32 (*reloc_to)(u32 kind);
    159   u32 (*reloc_pcrel)(u32 kind);
    160   u32 (*reloc_length)(u32 kind);
    161   /* Decode one relocation entry to a kit RelocKind + structural role. Returns
    162    * 1 on success, 0 if r_type is not a relocation this arch emits. This is the
    163    * reader's inverse of (reloc_to, reloc_pcrel, reloc_length): unlike a bare
    164    * wire-type map it sees r_pcrel/r_length and the patch-site bytes, which the
    165    * overlapping 4-bit r_type field requires to resolve a kind unambiguously. */
    166   int (*reloc_decode)(const MachoRelocEntry* in, MachoRelocDecoded* out);
    167 } ObjMachoArchOps;
    168 
    169 typedef struct ObjCoffArchOps {
    170   KitArchKind arch;
    171   u16 machine;
    172   u32 stub_size;
    173   ObjFormatCoffStubFn emit_iat_stub;
    174   u32 (*reloc_to)(u32 kind);
    175   u32 (*reloc_from)(u32 wire_type);
    176 } ObjCoffArchOps;
    177 
    178 typedef enum ObjFormatArchiveAction {
    179   OBJ_FORMAT_ARCHIVE_KEEP = 0,
    180   OBJ_FORMAT_ARCHIVE_REPLACE = 1,
    181   OBJ_FORMAT_ARCHIVE_SKIP = 2,
    182 } ObjFormatArchiveAction;
    183 
    184 /* ObjTlsModel (TLS access model) is defined in obj.h, the obj-layer
    185  * public header that carries the obj_format_tls_model wrapper. */
    186 
    187 typedef struct ObjFormatArchiveMember {
    188   const char* archive_name;
    189   const char* member_name;
    190   const u8* data;
    191   size_t len;
    192   KitBinFmt bin_fmt;
    193   Sym archive_hint;
    194 } ObjFormatArchiveMember;
    195 
    196 typedef struct ObjFormatDsoReader {
    197   const struct ObjFormatImpl* format;
    198   ObjFormatReadDsoFn read;
    199   const char* name;
    200 } ObjFormatDsoReader;
    201 
    202 typedef struct ObjFormatEmuOps {
    203   KitStatus (*detect_executable)(Compiler*, KitSlice bytes,
    204                                  KitTargetSpec* target_out);
    205   KitStatus (*load_executable)(Compiler*, const EmuLoadOptions*,
    206                                EmuLoadedImage* out);
    207   KitStatus (*map_object)(Compiler*, EmuProcess*, EmuLoadedImage*,
    208                           KitSlice name, KitSlice bytes, int is_main,
    209                           u32* out_index);
    210   void (*dyn_needed_iter)(const EmuLoadedObject*, EmuDynNeededIter* out);
    211   int (*dyn_needed_next)(EmuProcess*, EmuDynNeededIter*, KitSlice* out);
    212   KitStatus (*dyn_symbol_lookup)(EmuProcess*, const EmuLoadedObject*,
    213                                  KitSlice symbol, EmuDynSymbol* out);
    214   KitStatus (*dyn_symbol_by_index)(EmuProcess*, const EmuLoadedObject*,
    215                                    u64 symbol_index, EmuDynSymbol* out);
    216   void (*reloc_iter)(const EmuLoadedObject*, EmuDynRelocTableKind table,
    217                      EmuDynRelocIter* out);
    218   int (*reloc_next)(EmuProcess*, EmuDynRelocIter*, EmuDynReloc* out);
    219   KitStatus (*reloc_classify)(EmuProcess*, const EmuLoadedObject*,
    220                               const EmuDynReloc*, EmuDynRelocClass* cls,
    221                               u32* kind_out);
    222   u32 (*reloc_from)(KitArchKind arch, u32 wire_type);
    223 } ObjFormatEmuOps;
    224 
    225 typedef struct ObjFormatImpl {
    226   ObjFmt kind;
    227   const char* name;
    228   const char* read_name;
    229   const char* read_dso_name;
    230 
    231   ObjFormatEmitFn emit;
    232   ObjFormatReadFn read;
    233   ObjFormatReadDsoFn read_dso;
    234   ObjFormatLinkEmitFn link_emit;
    235   ObjFormatLayoutDynFn layout_dyn;
    236   ObjFormatFreeDynFn free_dyn;
    237   const ObjFormatEmuOps* emu;
    238   u8 split_sections_as_atoms;
    239 
    240   /* C source-level symbol prefix the format prepends on disk: "_" for
    241    * Mach-O, "" (or NULL, treated as "") for ELF / COFF / Wasm. Read by
    242    * obj_format_c_mangle / obj_format_demangle_c. */
    243   const char* c_label_prefix;
    244   /* Default entry symbol name for a freshly created Linker on this
    245    * format: "_main" for Mach-O (LC_MAIN), "mainCRTStartup" for COFF,
    246    * "_start" for ELF / Wasm. NULL means "_start". */
    247   const char* default_entry_name;
    248   /* Carries DWARF debug sections file-only (not mapped into a loadable
    249    * segment): ELF=1, Mach-O=1, COFF=0. */
    250   u8 carries_file_only_debug;
    251   /* Builds its own static GOT / non-lazy pointer table at link time even
    252    * for a static image: Mach-O=1, else 0. */
    253   u8 builds_own_static_got;
    254   /* COFF pulls an archive member to satisfy a *weak* undef reference
    255    * (binutils/PE COMDAT semantics); ELF/Mach-O only pull for strong
    256    * undefs. COFF=1, else 0. */
    257   u8 weak_undef_pulls_archive_member;
    258   /* Archive libraries are searched as a global fixed point instead of a
    259    * strictly positional POSIX scan.  COFF linkers use library-set semantics
    260    * close to this; ELF/Mach-O keep command-line archive order. */
    261   u8 global_archive_fixpoint;
    262   /* Can represent the ELF/Mach-O TLS-access symbol features the CG layer
    263    * mints (local-exec/initial-exec/local-dynamic/general-dynamic): ELF=1,
    264    * Mach-O=1; COFF (Windows TEB model) and Wasm have no such representation,
    265    * =0. Read by obj_format_supports_symbol_feature. */
    266   u8 tls_symbol_features;
    267   /* Resolves weak-external / undefined references via the mingw single-
    268    * underscore alias convention (e.g. `__set_app_type` <-> `_set_app_type`)
    269    * during link symbol resolution: COFF=1, else 0. Read by
    270    * obj_format_weak_extern_underscore_alias. */
    271   u8 weak_extern_underscore_alias;
    272 
    273   /* ---- Synthetic linker-section spellings ----
    274    *
    275    * Canonical names the linker assigns to the synthetic sections it builds
    276    * (ctor/dtor arrays + TLS) at synthesis time, before any writer sees them.
    277    * The kit-internal section model is otherwise format-neutral (ELF-spelled
    278    * end to end). A NULL entry means the format cannot represent that section,
    279    * and the matching obj_secname_* wrapper panics. Read only via those
    280    * wrappers in obj_secnames.c. */
    281   const char* secname_init_array;    /* ctor table */
    282   const char* secname_fini_array;    /* dtor table */
    283   const char* secname_preinit_array; /* pre-init ctors */
    284   const char* secname_tdata;         /* TLS initialized data */
    285   const char* secname_tbss;          /* TLS zero-fill */
    286 
    287   /* ---- C-source backend (c_target) emission spellings ----
    288    *
    289    * The portable C backend re-emits symbols as C source; a few constructs
    290    * spell differently per object format. These fields let c_target read the
    291    * spelling from the format vtable instead of branching on format identity.
    292    *
    293    * alias_via_thunk: how an aliased symbol is re-emitted. 0 = the format
    294    * accepts `__attribute__((alias("target")))` directly (ELF / PE-COFF /
    295    * Wasm). 1 = the format has no working alias attribute, so the backend
    296    * emits a forwarding thunk function instead (Mach-O). */
    297   u8 alias_via_thunk;
    298   /* weak_undef_attr: the GCC/Clang attribute spelling that declares an
    299    * *undefined* weak reference. "weak" works for ELF / PE-COFF / Wasm; on
    300    * Mach-O the `weak` attribute requires a definition, so an undefined weak
    301    * ref must use "weak_import". NULL is treated as "weak". */
    302   const char* weak_undef_attr;
    303 
    304   /* Inject a synthetic input object before symbol resolution. NULL when
    305    * the format synthesizes nothing. */
    306   ObjFormatSynthInputsFn synth_inputs;
    307 
    308   const ObjElfArchOps* (*elf_arch)(KitArchKind);
    309   const ObjElfArchOps* (*elf_machine)(u32 e_machine);
    310   const ObjMachoArchOps* (*macho_arch)(KitArchKind);
    311   const ObjMachoArchOps* (*macho_cputype)(u32 cputype);
    312   const ObjCoffArchOps* (*coff_arch)(KitArchKind);
    313   const ObjCoffArchOps* (*coff_machine)(u16 machine);
    314 
    315   /* Header-bytes -> KitTargetSpec detector (see ObjFormatDetectTargetFn). */
    316   ObjFormatDetectTargetFn detect_target;
    317 
    318   /* Raw linked-image metadata rewrite. This deliberately consumes the
    319    * original bytes instead of an ObjBuilder so loader state is preserved. */
    320   ObjFormatRewriteLinkedFn rewrite_linked;
    321 
    322   /* Optional format-specific linker ingestion policy. */
    323   int (*classify_obj_input)(Compiler*, ObjBuilder*, Sym* soname_out);
    324   Sym (*archive_hint)(Compiler*, const char* archive_name);
    325   ObjFormatArchiveAction (*archive_member)(Compiler*,
    326                                            const ObjFormatArchiveMember*,
    327                                            ObjBuilder** out);
    328 } ObjFormatImpl;
    329 
    330 const ObjFormatImpl* obj_format_lookup(ObjFmt fmt);
    331 const ObjFormatImpl* obj_format_lookup_bin(KitBinFmt fmt);
    332 int obj_format_dso_reader_for_bytes(const u8* data, size_t len,
    333                                     KitBinFmt* bin_out,
    334                                     ObjFormatDsoReader* out);
    335 
    336 /* Internal name<->KitObjFmt mapping, backed by the ObjFormatImpl name
    337  * list. The thin public KIT_API wrappers (kit_obj_fmt_from_name /
    338  * kit_obj_fmt_name, declared in include/kit/object.h) are added in
    339  * src/api by a later wave; these are the internal data helpers.
    340  *
    341  * obj_format_fmt_from_name returns 1 and writes *out on a match (case
    342  * sensitive, matching the canonical ObjFormatImpl.name spelling and any
    343  * registered alias); returns 0 on an unknown name. obj_format_fmt_name
    344  * returns the canonical NUL-terminated literal name, or NULL for an
    345  * out-of-range KitObjFmt. */
    346 int obj_format_fmt_from_name(const char* name, KitObjFmt* out);
    347 const char* obj_format_fmt_name(KitObjFmt fmt);
    348 
    349 #endif