kit

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

link_dyn.h (5616B)


      1 #ifndef KIT_OBJ_ELF_LINK_DYN_H
      2 #define KIT_OBJ_ELF_LINK_DYN_H
      3 
      4 /* ELF dynamic-link synthesis state.
      5  *
      6  * DynSymRec / DynRela are ELF64 wire-format records and LinkDynState is the
      7  * ELF linker's working state for .dynsym / .dynstr / .gnu.hash / .rela.* /
      8  * .plt / .got.plt / .dynamic. They live here, in an ELF-only header, so the
      9  * format-neutral link_internal.h can carry an opaque `LinkDynState* dyn` on
     10  * LinkImage without leaking ELF field names into the COFF/Mach-O linkers.
     11  * Only src/obj/elf/link.c and src/obj/elf/link_dyn.c include this. */
     12 
     13 #include "core/core.h"
     14 #include "link/link.h"
     15 
     16 /* ---- Dynamic-link synthesis state (Phase 4) ----
     17  *
     18  * Owned by LinkImage when emit_pie is set. Holds the synthesized
     19  * .interp / .dynsym / .dynstr / .gnu.hash / .rela.dyn / .rela.plt /
     20  * .plt / .got.plt / .dynamic content plus the section ids the emit
     21  * pass needs to fill PT_DYNAMIC and the .dynamic body.
     22  *
     23  * Phase 4 builds the dynsym/dynstr/gnu.hash content and the JUMP_SLOT
     24  * .rela.plt records (one per imported function, against its synthetic
     25  * .got.plt slot). The .plt body is allocated but not emitted (Phase 5).
     26  * Phase 6 populates .rela.dyn with R_AARCH64_RELATIVE records for any
     27  * internal absolute reloc seen during reloc-apply.
     28  *
     29  * Layout invariants this struct enforces:
     30  *   - dynsym entry 0 is the reserved STN_UNDEF slot (zero-filled).
     31  *   - dynsym entries 1..nimport_func+nimport_data are imports, in the
     32  *     order PLT-functions first, then GOT-data.
     33  *   - PLT slots and JUMP_SLOT entries match the import_func order 1:1.
     34  *   - .got.plt has 3 reserved leading u64 slots (per AArch64 psABI:
     35  *     slot 0 = &.dynamic, slot 1 = link_map cookie, slot 2 =
     36  *     _dl_runtime_resolve), then one slot per imported function.
     37  */
     38 
     39 typedef struct DynSymRec {
     40   u32 st_name; /* offset into .dynstr */
     41   u8 st_info;
     42   u8 st_other;
     43   u16 st_shndx;
     44   u64 st_value;
     45   u64 st_size;
     46 } DynSymRec;
     47 
     48 typedef struct DynRela {
     49   u64 r_offset; /* image-relative vaddr of the patch site */
     50   u64 r_info;   /* ELF64_R_INFO(dynsym_index, elf_reloc_type) */
     51   i64 r_addend;
     52 } DynRela;
     53 
     54 typedef struct LinkDynState {
     55   /* PT_INTERP / .interp. interp_path is interned in compiler->global. */
     56   Sym interp_path;
     57   LinkSectionId sec_interp;
     58 
     59   /* DT_SONAME / DT_RPATH / DT_RUNPATH strings, interned in compiler->global. */
     60   Sym soname;
     61   Sym* rpaths;
     62   u32 nrpaths;
     63   Sym* runpaths;
     64   u32 nrunpaths;
     65 
     66   /* .dynsym */
     67   LinkSectionId sec_dynsym;
     68   DynSymRec* dynsym;
     69   u32 ndynsym;      /* incl. slot-0 STN_UNDEF */
     70   u32 first_global; /* sh_info value: index of first non-local entry */
     71 
     72   /* .dynstr */
     73   LinkSectionId sec_dynstr;
     74   u8* dynstr;
     75   u32 dynstr_len;
     76 
     77   /* .gnu.hash */
     78   LinkSectionId sec_gnu_hash;
     79   u8* gnu_hash;
     80   u32 gnu_hash_len;
     81 
     82   /* GNU symbol versioning. Emitted only when at least one imported symbol
     83    * binds to a versioned DSO export (nverneed > 0); otherwise all three are
     84    * zero and no version sections / DT_VER* entries are produced (musl/static
     85    * links are unchanged). .gnu.version is one u16 per .dynsym entry;
     86    * .gnu.version_r holds Verneed/Vernaux requirements keyed by DT_NEEDED
     87    * soname. Both carry only .dynstr offsets + version indices (no vaddrs), so
     88    * the bytes are final at layout time and copied verbatim during emit. */
     89   LinkSectionId sec_gnu_version;
     90   u8* versym; /* ndynsym * 2 bytes */
     91   u32 versym_len;
     92   LinkSectionId sec_gnu_version_r;
     93   u8* verneed; /* nverneed Verneed records + their Vernaux */
     94   u32 verneed_len;
     95   u32 nverneed; /* DT_VERNEEDNUM */
     96 
     97   /* .rela.dyn — R_AARCH64_GLOB_DAT (imports against .got slots) and
     98    * R_AARCH64_RELATIVE (PIE internal abs64 fixups, populated during
     99    * Phase 6 emit). Pre-sized at layout time; the RELATIVE tail is
    100    * filled in during emit. */
    101   LinkSectionId sec_rela_dyn;
    102   DynRela* rela_dyn;
    103   u32 nrela_dyn;    /* number of records currently populated */
    104   u32 cap_rela_dyn; /* allocation capacity (records, not bytes) */
    105 
    106   /* .rela.plt — R_AARCH64_JUMP_SLOT, one per imported function. */
    107   LinkSectionId sec_rela_plt;
    108   DynRela* rela_plt;
    109   u32 nrela_plt;
    110 
    111   /* .plt — 32-byte PLT0 stub + 16 bytes per imported function. Body
    112    * is allocated (zero-initialized) but not emitted in Phase 4. */
    113   LinkSectionId sec_plt;
    114   u32 nplt;      /* number of imported functions */
    115   u64 plt_vaddr; /* image-relative .plt base */
    116   u64 plt_size;
    117 
    118   /* .got.plt — 24 reserved bytes + 8 per PLT slot. */
    119   LinkSectionId sec_got_plt;
    120   u64 got_plt_vaddr;
    121   u64 got_plt_size;
    122 
    123   /* .dynamic — PT_DYNAMIC body. Built at layout time; its size is
    124    * fixed once we know the DT_NEEDED count. */
    125   LinkSectionId sec_dynamic;
    126   u64 dynamic_vaddr;
    127   u64 dynamic_size;
    128   u32 ndyn_entries;
    129 
    130   /* DT_NEEDED list (interned soname Syms, in input order). */
    131   Sym* needed;
    132   u32 nneeded;
    133 
    134   /* Per-import dynsym index, indexed by LinkSymId. 0 means "not
    135    * imported / not in dynsym". Used by GLOB_DAT / JUMP_SLOT emit. */
    136   u32* sym_dynidx; /* size = sym_dynidx_size */
    137   u32 sym_dynidx_size;
    138 
    139   /* Per-import PLT entry vaddr, indexed by LinkSymId (Phase 5).  Set
    140    * for every imported function: vaddr of its 16-byte PLT stub inside
    141    * `.plt`.  0 means "no PLT stub" (symbol is data-only or not
    142    * imported).  apply_all_relocs reads this when redirecting a
    143    * CALL26/JUMP26 against an imported function — S becomes the PLT
    144    * entry vaddr instead of the symbol's (zero) vaddr.  The vaddrs
    145    * stored here track the post-shift values (shift_image_addresses
    146    * bumps them along with .plt's segment vaddr). */
    147   u64* sym_plt_vaddr; /* size = sym_dynidx_size */
    148 } LinkDynState;
    149 
    150 #endif