kit

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

reloc_x86_64.c (3783B)


      1 #include "core/util.h"
      2 #include "obj/macho/macho.h"
      3 
      4 u32 macho_x86_64_reloc_to(u32 kind /* RelocKind */) {
      5   switch (kind) {
      6     case R_NONE:
      7       return (u32)-1;
      8     case R_ABS64:
      9     case R_ABS32:
     10       return X86_64_RELOC_UNSIGNED;
     11     case R_PC32:
     12     case R_REL32:
     13     case R_PC64:
     14     case R_REL64:
     15     case R_X64_PC8:
     16       return X86_64_RELOC_SIGNED;
     17     case R_PLT32:
     18     case R_X64_PLT32:
     19       return X86_64_RELOC_BRANCH;
     20     case R_X64_GOTPCRELX:
     21     case R_X64_REX_GOTPCRELX:
     22       return X86_64_RELOC_GOT_LOAD;
     23     case R_X64_GOTPCREL:
     24       return X86_64_RELOC_GOT;
     25     case R_X64_TLV:
     26       return X86_64_RELOC_TLV;
     27     default:
     28       return (u32)-1;
     29   }
     30 }
     31 
     32 u32 macho_x86_64_reloc_pcrel(u32 kind /* RelocKind */) {
     33   switch (kind) {
     34     case R_PC32:
     35     case R_REL32:
     36     case R_PC64:
     37     case R_REL64:
     38     case R_X64_PC8:
     39     case R_PLT32:
     40     case R_X64_PLT32:
     41     case R_X64_GOTPCREL:
     42     case R_X64_GOTPCRELX:
     43     case R_X64_REX_GOTPCRELX:
     44     case R_X64_TLV:
     45       return 1;
     46     default:
     47       return 0;
     48   }
     49 }
     50 
     51 u32 macho_x86_64_reloc_length(u32 kind /* RelocKind */) {
     52   switch (kind) {
     53     case R_ABS64:
     54     case R_PC64:
     55     case R_REL64:
     56       return 3;
     57     case R_X64_PC8:
     58       return 0;
     59     default:
     60       return 2;
     61   }
     62 }
     63 
     64 /* Mark a PC-relative x86_64 reloc: its addend has no out-of-band carrier — the
     65  * patched field holds symrel = (kit addend) + width, so the reader recovers the
     66  * addend by sign-extending the field and subtracting the width. */
     67 static void x86_64_pcrel_inplace(const MachoRelocEntry* in,
     68                                  MachoRelocDecoded* out, i64 extra_bias) {
     69   out->inplace_addend = 1;
     70   out->inplace_signed = 1;
     71   out->inplace_bias = -(i64)(1u << in->r_length) + extra_bias;
     72 }
     73 
     74 int macho_x86_64_reloc_decode(const MachoRelocEntry* in,
     75                               MachoRelocDecoded* out) {
     76   out->kind = R_NONE;
     77   out->role = MACHO_RELOC_NORMAL;
     78   out->addend = 0;
     79   out->inplace_bias = 0;
     80   out->inplace_addend = 0;
     81   out->inplace_signed = 0;
     82   switch (in->r_type) {
     83     case X86_64_RELOC_UNSIGNED:
     84       /* Absolute datum; the shared reader rewrites it to R_ADD* when it
     85        * completes a pending subtractor. Its addend rides verbatim in the
     86        * patched field (no PC bias). */
     87       out->role = MACHO_RELOC_ABSOLUTE;
     88       out->inplace_addend = 1;
     89       out->kind = (in->r_length == 3) ? R_ABS64 : R_ABS32;
     90       return 1;
     91     /* SIGNED_{1,2,4} bias the addend by an extra 1/2/4 bytes (the distance from
     92      * the field's end to the instruction's end). */
     93     case X86_64_RELOC_SIGNED:
     94       out->kind = R_PC32;
     95       x86_64_pcrel_inplace(in, out, 0);
     96       return 1;
     97     case X86_64_RELOC_SIGNED_1:
     98       out->kind = R_PC32;
     99       x86_64_pcrel_inplace(in, out, -1);
    100       return 1;
    101     case X86_64_RELOC_SIGNED_2:
    102       out->kind = R_PC32;
    103       x86_64_pcrel_inplace(in, out, -2);
    104       return 1;
    105     case X86_64_RELOC_SIGNED_4:
    106       out->kind = R_PC32;
    107       x86_64_pcrel_inplace(in, out, -4);
    108       return 1;
    109     case X86_64_RELOC_BRANCH:
    110       out->kind = R_X64_PLT32;
    111       x86_64_pcrel_inplace(in, out, 0);
    112       return 1;
    113     case X86_64_RELOC_GOT_LOAD:
    114       out->kind = R_X64_REX_GOTPCRELX;
    115       x86_64_pcrel_inplace(in, out, 0);
    116       return 1;
    117     case X86_64_RELOC_GOT:
    118       out->kind = R_X64_GOTPCREL;
    119       x86_64_pcrel_inplace(in, out, 0);
    120       return 1;
    121     case X86_64_RELOC_SUBTRACTOR:
    122       out->role = MACHO_RELOC_SUBTRACTOR;
    123       out->kind = (in->r_length == 3)   ? R_SUB64
    124                   : (in->r_length == 2) ? R_SUB32
    125                   : (in->r_length == 1) ? R_SUB16
    126                                         : R_SUB8;
    127       return 1;
    128     case X86_64_RELOC_TLV:
    129       out->kind = R_X64_TLV;
    130       x86_64_pcrel_inplace(in, out, 0);
    131       return 1;
    132     default:
    133       return 0;
    134   }
    135 }