kit

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

link.c (3829B)


      1 /* x86_64 link-time arch descriptor.
      2  *
      3  * Implements the LinkArchDesc contract from link/link_arch.h for
      4  * EM_X86_64.  The PLT/IPLT byte sequences here mirror the inline
      5  * encodings previously living in link_dyn.c (PLT0 + per-import entry)
      6  * and link_layout.c (IPLT stub) — kept identical byte-for-byte so the
      7  * descriptor switchover is a pure refactor.  All raw byte values come
      8  * from named constants / inline writers in arch/x64/isa.h. */
      9 
     10 #include "arch/x64/isa.h"
     11 #include "core/bytes.h"
     12 #include "core/core.h"
     13 #include "link/link_arch.h"
     14 
     15 /* PLT0 layout under DF_1_NOW: never executed (loader pre-binds every
     16  * slot via .rela.plt before user code runs), so we just emit 32 bytes
     17  * of single-byte NOPs.  Self-documenting and trivially well-formed for
     18  * disassemblers and unwinders that walk the section. */
     19 static void x64_emit_plt0(u8* dst, u64 plt0_vaddr, u64 gotplt_vaddr) {
     20   (void)plt0_vaddr;
     21   (void)gotplt_vaddr;
     22   x64_write_nop_pad(dst, 32u);
     23 }
     24 
     25 /* Per-import PLT entry (16 B):
     26  *
     27  *   ff 25 disp32           ; jmpq *[rip + disp_to_slot]   (6 B)
     28  *   90 90 90 90 90 90 90 90 90 90  ; pad to 16 with single-byte NOPs
     29  *
     30  * disp32 is measured from the END of the JMP (entry_vaddr + 6) to the
     31  * .got.plt slot.  The 10-byte tail matches link_dyn.c's prior
     32  * memset(0x90)+patch behavior exactly. */
     33 static void x64_emit_plt_entry(u8* dst, u64 entry_vaddr, u64 slot_vaddr) {
     34   i64 disp = (i64)slot_vaddr - (i64)(entry_vaddr + X64_JMP_RIPREL_SIZE);
     35   i32 disp32 = (i32)(u32)((u64)disp & 0xffffffffu);
     36   x64_write_jmp_riprel(dst, disp32);
     37   x64_write_nop_pad(dst + X64_JMP_RIPREL_SIZE, 16u - X64_JMP_RIPREL_SIZE);
     38 }
     39 
     40 /* IPLT (ifunc) trampoline stub (12 B):
     41  *
     42  *   ff 25 disp32           ; jmpq *[rip + disp_to_slot]   (6 B)
     43  *   66 0f 1f 44 00 00      ; 6-byte multibyte NOP         (6 B)
     44  *
     45  * Like the PLT entry, disp32 is from the END of the JMP to the
     46  * .igot.plt slot.  The displacement is invariant under image-base
     47  * shift (both ends move together), so it's encoded inline and we
     48  * report zero apply-time relocations. */
     49 static u32 x64_emit_iplt_stub(u8* dst, u64 stub_vaddr, u64 slot_vaddr,
     50                               LinkArchIPltReloc out[2]) {
     51   (void)out;
     52   i64 disp = (i64)slot_vaddr - (i64)(stub_vaddr + X64_JMP_RIPREL_SIZE);
     53   i32 disp32 = (i32)(u32)((u64)disp & 0xffffffffu);
     54   x64_write_jmp_riprel(dst, disp32);
     55   x64_write_nop6(dst + X64_JMP_RIPREL_SIZE);
     56   return 0;
     57 }
     58 
     59 /* Width + classification rows + instruction-immediate byte encoders for
     60  * x86-64's relocation kinds; defined in src/arch/x64/reloc.c and consulted
     61  * through the .reloc_desc / .reloc_apply_insn hooks. */
     62 const RelocDesc* x64_reloc_desc(RelocKind);
     63 int x64_reloc_apply_insn(Compiler*, RelocKind, u8*, u64, i64, u64);
     64 void x64_jit_tls_le_relax(Compiler*, RelocKind, u8*, u64, u64);
     65 
     66 /* PE/COFF IAT stub for x86_64 (6 B):
     67  *
     68  *   ff 25 disp32      ; jmpq *[rip + disp_to_iat_slot]
     69  *
     70  * disp32 is signed offset from the END of the JMP (stub_vaddr + 6)
     71  * to the IAT slot in .idata. Identical layout to the ELF PLT entry
     72  * head, minus the trailing NOP pad — Win64 calls don't need a stub
     73  * aligned to a fixed entry stride because there's no PLT0 to share
     74  * the address space with. */
     75 void x64_emit_coff_iat_stub(u8* dst, u64 stub_vaddr, u64 iat_slot_vaddr) {
     76   i64 disp = (i64)iat_slot_vaddr - (i64)(stub_vaddr + X64_JMP_RIPREL_SIZE);
     77   i32 disp32 = (i32)(u32)((u64)disp & 0xffffffffu);
     78   x64_write_jmp_riprel(dst, disp32);
     79 }
     80 
     81 const LinkArchDesc link_arch_x64 = {
     82     .plt0_size = 32u,
     83     .plt_entry_size = 16u,
     84     .iplt_stub_size = 12u,
     85 
     86     .emit_plt0 = x64_emit_plt0,
     87     .emit_plt_entry = x64_emit_plt_entry,
     88     .emit_iplt_stub = x64_emit_iplt_stub,
     89 
     90     .reloc_desc = x64_reloc_desc,
     91     .reloc_apply_insn = x64_reloc_apply_insn,
     92     .jit_tls_le_relax = x64_jit_tls_le_relax,
     93 
     94     .tls_variant_ii = 1,
     95 };