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 }