commit 5098244ac67063d5fd9879937551d40974fa6137
parent 2ea9a8b5413b8c1995264ec8c2e9b5aaaf36dfda
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Fri, 12 Jun 2026 10:23:01 -0700
refactor(macho): decode relocations per-arch (fix x86_64 read-back link)
The Mach-O relocation reader was entirely ARM64-shaped and applied
ARM64_RELOC_* reinterpretation ungated by CPU type. Mach-O's 4-bit
r_type field overlaps across architectures (X86_64_RELOC_BRANCH == 2 ==
ARM64_RELOC_BRANCH26), so a self-emitted x86_64 BRANCH (a call) was read
back as R_AARCH64_CALL26 and the link died with 'unsupported reloc kind
16'. It bit any x86_64 read-back link of a call; the toy corpus hid it by
linking in-memory or via ld64, never round-tripping a kit x86_64 .o
through kit's own reader (as a self-host cross build does).
Replace the bare reloc_from wire-type map with a per-arch reloc_decode
hook on ObjMachoArchOps. macho_{aarch64,x86_64}_reloc_decode own the kind
plus the entry's structural role (addend carrier / subtractor / absolute)
and its in-place-addend policy; the shared read.c loop is now arch-neutral.
x86_64 bakes a PC-relative reloc's addend in-place as symrel = addend +
width (arm64 uses an out-of-band ADDEND pseudo-reloc), so the reader
sign-extends the field and subtracts the width to recover the kit addend.
Without it a RIP-relative 'mov g(%rip)' (ELF addend -4) linked off by 4.
test-macho/link/elf/ar green; arm64 read-back unregressed.
Diffstat:
6 files changed, 248 insertions(+), 116 deletions(-)
diff --git a/src/obj/format.h b/src/obj/format.h
@@ -79,6 +79,51 @@ typedef struct ObjElfArchOps {
KitFloatAbi (*float_abi_from_e_flags)(u32 e_flags);
} ObjElfArchOps;
+/* Structural role of a Mach-O relocation entry. Mach-O's r_type is a 4-bit
+ * field whose values OVERLAP across architectures (e.g. value 2 is both
+ * X86_64_RELOC_BRANCH and ARM64_RELOC_BRANCH26), so the entry's meaning can
+ * only be resolved per-arch. The shared reader threads the cross-entry state
+ * (addend carriers, subtractor pairs) the per-arch decoder reports via this
+ * role; everything arch-specific (the kind, the lo12 instruction inspection,
+ * the addend carrier) lives in the decoder. */
+typedef enum MachoRelocRole {
+ MACHO_RELOC_NORMAL = 0, /* `kind` is final; stands alone */
+ MACHO_RELOC_ADDEND, /* addend-carrier pseudo-reloc (arm64): emits */
+ /* nothing; `addend` seeds the next entry */
+ MACHO_RELOC_SUBTRACTOR, /* minuend marker: `kind` = R_SUB*; arms the pair */
+ MACHO_RELOC_ABSOLUTE, /* unsigned datum: carries its addend in-place */
+ /* and becomes R_ADD* when it completes a */
+ /* pending subtractor, else stands as `kind` */
+} MachoRelocRole;
+
+/* One decoded Mach-O relocation entry (the raw on-disk bitfields). */
+typedef struct MachoRelocEntry {
+ u32 r_type; /* 4-bit ARM64_RELOC_* / X86_64_RELOC_* code */
+ u32 r_pcrel;
+ u32 r_length; /* 0=byte 1=hword 2=word 3=quad */
+ u32 r_extern;
+ u32 r_symbolnum;
+ u32 r_address;
+ const u8* insn; /* patch-site bytes (>=4 readable iff insn_len>=4), for the */
+ u32 insn_len; /* arm64 PAGEOFF12 load/store-width inspection; else NULL */
+} MachoRelocEntry;
+
+typedef struct MachoRelocDecoded {
+ u32 kind; /* RelocKind */
+ u32 role; /* MachoRelocRole */
+ i64 addend; /* MACHO_RELOC_ADDEND: the carried value */
+ i64 inplace_bias; /* added to the in-place field value when recovering the */
+ /* addend. x86_64 bakes a PC-relative reloc's addend as */
+ /* symrel = addend + width, so the reader subtracts the */
+ /* width (bias = -(1<<r_length)); 0 for absolute data. */
+ u8 inplace_addend; /* extern entries recover their addend from the patch */
+ /* field: the ABSOLUTE family (both arches) and every */
+ /* x86_64 reloc, which has no out-of-band addend. */
+ u8 inplace_signed; /* sign-extend the (sub-64-bit) field read — a PC-relative */
+ /* displacement is signed; an absolute datum is not. */
+ u8 pad[6];
+} MachoRelocDecoded;
+
typedef struct ObjMachoArchOps {
KitArchKind arch;
u32 cputype;
@@ -88,7 +133,12 @@ typedef struct ObjMachoArchOps {
u32 (*reloc_to)(u32 kind);
u32 (*reloc_pcrel)(u32 kind);
u32 (*reloc_length)(u32 kind);
- u32 (*reloc_from)(u32 wire_type);
+ /* Decode one relocation entry to a kit RelocKind + structural role. Returns
+ * 1 on success, 0 if r_type is not a relocation this arch emits. This is the
+ * reader's inverse of (reloc_to, reloc_pcrel, reloc_length): unlike a bare
+ * wire-type map it sees r_pcrel/r_length and the patch-site bytes, which the
+ * overlapping 4-bit r_type field requires to resolve a kind unambiguously. */
+ int (*reloc_decode)(const MachoRelocEntry* in, MachoRelocDecoded* out);
} ObjMachoArchOps;
typedef struct ObjCoffArchOps {
diff --git a/src/obj/macho/macho.h b/src/obj/macho/macho.h
@@ -15,6 +15,7 @@
#define KIT_OBJ_MACHO_H
#include "core/core.h"
+#include "obj/format.h"
#include "obj/obj.h"
/* ---- magic ---- */
@@ -271,10 +272,10 @@ typedef struct MachRelocInfo {
u32 macho_aarch64_reloc_to(u32 kind /* RelocKind */);
u32 macho_aarch64_reloc_pcrel(u32 kind /* RelocKind */);
u32 macho_aarch64_reloc_length(u32 kind /* RelocKind */);
-u32 macho_aarch64_reloc_from(u32 macho_type);
+int macho_aarch64_reloc_decode(const MachoRelocEntry*, MachoRelocDecoded*);
u32 macho_x86_64_reloc_to(u32 kind /* RelocKind */);
u32 macho_x86_64_reloc_pcrel(u32 kind /* RelocKind */);
u32 macho_x86_64_reloc_length(u32 kind /* RelocKind */);
-u32 macho_x86_64_reloc_from(u32 macho_type);
+int macho_x86_64_reloc_decode(const MachoRelocEntry*, MachoRelocDecoded*);
#endif
diff --git a/src/obj/macho/read.c b/src/obj/macho/read.c
@@ -427,7 +427,7 @@ ObjBuilder* read_macho(Compiler* c, const char* name, const u8* data,
u32 sizeofcmds = rd_u32_le(data + 20);
u32 mh_flags = rd_u32_le(data + 24);
- if (!macho || !macho->reloc_from)
+ if (!macho || !macho->reloc_decode)
compiler_panic(c, SRCLOC_NONE, "read_macho: unsupported cputype 0x%x",
cputype);
/* MH_OBJECT parses to the section/symbol/reloc view only. MH_EXECUTE /
@@ -706,80 +706,46 @@ ObjBuilder* read_macho(Compiler* c, const char* name, const u8* data,
u32 r_extern = (packed >> 27) & 1u;
u32 r_type = (packed >> 28) & 0xfu;
- if (r_type == ARM64_RELOC_ADDEND) {
- /* Sign-extend 24-bit addend. */
- i32 ad = (i32)(r_symbolnum & 0x00ffffffu);
- if (ad & 0x00800000) ad |= ~0x00ffffff;
- pending_addend = (i64)ad;
- have_pending = 1;
- continue;
- }
-
- u32 kind;
- if (r_type == ARM64_RELOC_SUBTRACTOR) {
- kind = (r_length == 3) ? R_SUB64
- : (r_length == 2) ? R_SUB32
- : (r_length == 1) ? R_SUB16
- : R_SUB8;
+ /* Decode the entry per-arch: r_type's 4 bits are not arch-unique (e.g.
+ * value 2 is both X86_64_RELOC_BRANCH and ARM64_RELOC_BRANCH26), so the
+ * arch hook resolves the kind from (r_type, r_pcrel, r_length) and the
+ * patched instruction, and classifies the entry's structural role. */
+ MachoRelocEntry rin;
+ MachoRelocDecoded rdc;
+ rin.r_type = r_type;
+ rin.r_pcrel = r_pcrel;
+ rin.r_length = r_length;
+ rin.r_extern = r_extern;
+ rin.r_symbolnum = r_symbolnum;
+ rin.r_address = r_address;
+ if ((u64)m->fileoff + r_address + 4u <= len) {
+ rin.insn = data + m->fileoff + r_address;
+ rin.insn_len = 4u;
} else {
- kind = macho->reloc_from(r_type);
+ rin.insn = NULL;
+ rin.insn_len = 0u;
}
- if (kind == (u32)-1)
+ if (!macho->reloc_decode(&rin, &rdc))
compiler_panic(c, SRCLOC_NONE, "read_macho: unsupported reloc type %u",
r_type);
- /* Refine kind by (r_pcrel, r_length) when the type field alone
- * is ambiguous. ARM64_RELOC_UNSIGNED collapses R_ABS64/R_ABS32
- * and PC-relative variants. */
- if (r_type == ARM64_RELOC_UNSIGNED) {
- if (pending_subtractor && pending_subtractor_offset == r_address &&
- pending_subtractor_length == r_length) {
- kind = (r_length == 3) ? R_ADD64
- : (r_length == 2) ? R_ADD32
- : (r_length == 1) ? R_ADD16
- : R_ADD8;
- pending_subtractor = 0;
- } else if (r_pcrel) {
- kind = (r_length == 3) ? R_PC64 : R_PC32;
- } else {
- kind = (r_length == 3) ? R_ABS64 : R_ABS32;
- }
- } else if (r_type == ARM64_RELOC_BRANCH26) {
- kind = R_AARCH64_CALL26;
- } else if (r_type == ARM64_RELOC_PAGEOFF12) {
- /* PAGEOFF12 is access-size-agnostic in Mach-O; the linker
- * applier needs to scale the immediate by the load/store size
- * (or apply it raw for ADD). Inspect the patched instruction
- * at r_address to pick the right RelocKind so the applier in
- * link_reloc.c shifts the lo12 correctly. */
- if (m->fileoff + r_address + 4u > len)
- compiler_panic(c, SRCLOC_NONE,
- "read_macho: PAGEOFF12 r_address %u out of range",
- r_address);
- u32 ins = rd_u32_le(data + m->fileoff + r_address);
- /* ADD (immediate): bits 30:24 = 0010001 (W=10001 / X=10010001).
- * Mask 0x7f800000 isolates sf=0/1 + the 0010001 pattern; values
- * 0x11000000 (32-bit) and 0x91000000 (64-bit) — match the latter
- * via the same 0x7f mask leaving bit 31 free. */
- if ((ins & 0x7f800000u) == 0x11000000u) {
- kind = R_AARCH64_ADD_ABS_LO12_NC;
- } else if ((ins & 0x3b000000u) == 0x39000000u) {
- /* LDR/STR (immediate unsigned offset). Bits 29:27=111, bit 26=V
- * (0=integer, 1=SIMD/FP), bits 25:24=01. size in [31:30] plus
- * opc bit 23 for the SIMD 128-bit case (size=00, opc=11). */
- u32 sz = (ins >> 30) & 3u;
- u32 v_bit = (ins >> 26) & 1u;
- u32 opc1 = (ins >> 23) & 1u;
- if (v_bit && sz == 0 && opc1) {
- kind = R_AARCH64_LDST128_ABS_LO12_NC;
- } else {
- kind = (sz == 0) ? R_AARCH64_LDST8_ABS_LO12_NC
- : (sz == 1) ? R_AARCH64_LDST16_ABS_LO12_NC
- : (sz == 2) ? R_AARCH64_LDST32_ABS_LO12_NC
- : R_AARCH64_LDST64_ABS_LO12_NC;
- }
- }
- /* else: leave as the default R_AARCH64_ADD_ABS_LO12_NC. */
+ if (rdc.role == MACHO_RELOC_ADDEND) {
+ pending_addend = rdc.addend;
+ have_pending = 1;
+ continue;
+ }
+
+ u32 kind = rdc.kind;
+ /* An absolute datum at the same offset/width as a just-seen SUBTRACTOR
+ * is the addend half of a symbol-difference pair: SUB* + ADD*. */
+ if (rdc.role == MACHO_RELOC_ABSOLUTE && pending_subtractor &&
+ pending_subtractor_offset == r_address &&
+ pending_subtractor_length == r_length) {
+ kind = (r_length == 3) ? R_ADD64
+ : (r_length == 2) ? R_ADD32
+ : (r_length == 1) ? R_ADD16
+ : R_ADD8;
+ pending_subtractor = 0;
}
ObjSymId target = OBJ_SYM_NONE;
@@ -787,23 +753,27 @@ ObjBuilder* read_macho(Compiler* c, const char* name, const u8* data,
int use_inplace_addend = 0;
if (r_extern) {
if (r_symbolnum < nsyms) target = sym_macho_to_obj[r_symbolnum];
- if (!have_pending && r_type == ARM64_RELOC_UNSIGNED) {
+ if (!have_pending && rdc.inplace_addend) {
u32 rsz = 1u << r_length;
if ((u64)m->fileoff + r_address + rsz > len)
compiler_panic(c, SRCLOC_NONE,
- "read_macho: extern unsigned reloc r_address out "
- "of range");
+ "read_macho: extern reloc r_address out of range");
const u8* pv = data + m->fileoff + r_address;
- u64 inplace;
+ i64 inplace;
+ /* A PC-relative displacement is signed (rdc.inplace_signed); an
+ * absolute datum reads as written. The arch decoder's bias undoes any
+ * PC adjustment baked into the field (x86_64: +width). */
if (r_length == 3)
- inplace = rd_u64_le(pv);
+ inplace = (i64)rd_u64_le(pv);
else if (r_length == 2)
- inplace = (u64)rd_u32_le(pv);
+ inplace = rdc.inplace_signed ? (i64)(i32)rd_u32_le(pv)
+ : (i64)(u64)rd_u32_le(pv);
else if (r_length == 1)
- inplace = (u64)rd_u16_le(pv);
+ inplace = rdc.inplace_signed ? (i64)(i16)rd_u16_le(pv)
+ : (i64)(u64)rd_u16_le(pv);
else
- inplace = (u64)pv[0];
- inplace_addend_override = (i64)inplace;
+ inplace = rdc.inplace_signed ? (i64)(i8)pv[0] : (i64)(u64)pv[0];
+ inplace_addend_override = inplace + rdc.inplace_bias;
use_inplace_addend = 1;
}
} else {
@@ -871,7 +841,7 @@ ObjBuilder* read_macho(Compiler* c, const char* name, const u8* data,
obj_reloc_ex(ob, m->obj_sec, r_address, (RelocKind)kind, target, addend,
has_explicit, 0);
- if (r_type == ARM64_RELOC_SUBTRACTOR) {
+ if (rdc.role == MACHO_RELOC_SUBTRACTOR) {
pending_subtractor = 1;
pending_subtractor_offset = r_address;
pending_subtractor_length = r_length;
diff --git a/src/obj/macho/reloc_aarch64.c b/src/obj/macho/reloc_aarch64.c
@@ -1,13 +1,15 @@
/* RelocKind <-> arm64 Mach-O reloc-type mapping. Mirror of
* elf_reloc_aarch64.c for Mach-O.
*
- * Mach-O relocations carry three independent fields that the kit
+ * Mach-O relocations carry several independent fields that the kit
* RelocKind enum collapses into a single value: r_type (the 4-bit
- * ARM64_RELOC_* code), r_pcrel, and r_length. The translator therefore
- * exposes three accessors — the writer (macho_emit.c) consults all of
- * them per Reloc, and the reader (macho_read.c) inverts via
- * macho_aarch64_reloc_from which keys on (r_type, r_pcrel, r_length). */
+ * ARM64_RELOC_* code), r_pcrel, and r_length. The writer (macho_emit.c)
+ * consults the reloc_to / reloc_pcrel / reloc_length accessors per Reloc;
+ * the reader (macho_read.c) inverts them in macho_aarch64_reloc_decode,
+ * which also classifies the entry's structural role (addend carrier,
+ * subtractor) and inspects the patched instruction for the lo12 width. */
+#include "core/bytes.h"
#include "core/util.h"
#include "obj/macho/macho.h"
@@ -83,31 +85,89 @@ u32 macho_aarch64_reloc_length(u32 kind /* RelocKind */) {
}
}
-u32 macho_aarch64_reloc_from(u32 macho_type) {
- /* The (r_type, r_pcrel, r_length) tuple disambiguates several kinds
- * collapsed by macho_aarch64_reloc_to. The reader inspects pcrel and
- * length itself when it matters; this function only maps the type
- * field, returning the most common AArch64 instance for each. Reader
- * callers refine via the pcrel/length companion if they need to
- * distinguish R_ABS64 vs R_PC64 (both UNSIGNED). */
- switch (macho_type) {
+/* ARM64_RELOC_PAGEOFF12 is access-size-agnostic on the wire; the linker
+ * applier needs the load/store width (or ADD) to scale the lo12 immediate, so
+ * inspect the patched instruction to pick the precise RelocKind. Defaults to
+ * the ADD form when the patch bytes are unavailable. */
+static u32 macho_aarch64_pageoff12_kind(const u8* insn, u32 insn_len) {
+ if (insn_len < 4) return R_AARCH64_ADD_ABS_LO12_NC;
+ u32 ins = rd_u32_le(insn);
+ /* ADD (immediate): bits 30:24 = 0010001 (W=0x11000000 / X=0x91000000);
+ * the 0x7f800000 mask isolates the pattern leaving sf free. */
+ if ((ins & 0x7f800000u) == 0x11000000u) return R_AARCH64_ADD_ABS_LO12_NC;
+ /* LDR/STR (immediate, unsigned offset): bits 29:27=111, 25:24=01. size in
+ * [31:30]; V=bit26 (SIMD/FP); opc bit23 distinguishes the 128-bit case. */
+ if ((ins & 0x3b000000u) == 0x39000000u) {
+ u32 sz = (ins >> 30) & 3u;
+ u32 v_bit = (ins >> 26) & 1u;
+ u32 opc1 = (ins >> 23) & 1u;
+ if (v_bit && sz == 0 && opc1) return R_AARCH64_LDST128_ABS_LO12_NC;
+ return (sz == 0) ? R_AARCH64_LDST8_ABS_LO12_NC
+ : (sz == 1) ? R_AARCH64_LDST16_ABS_LO12_NC
+ : (sz == 2) ? R_AARCH64_LDST32_ABS_LO12_NC
+ : R_AARCH64_LDST64_ABS_LO12_NC;
+ }
+ return R_AARCH64_ADD_ABS_LO12_NC;
+}
+
+int macho_aarch64_reloc_decode(const MachoRelocEntry* in,
+ MachoRelocDecoded* out) {
+ out->kind = R_NONE;
+ out->role = MACHO_RELOC_NORMAL;
+ out->addend = 0;
+ out->inplace_bias = 0;
+ out->inplace_addend = 0;
+ out->inplace_signed = 0;
+ switch (in->r_type) {
+ case ARM64_RELOC_ADDEND: {
+ /* Addend carrier: a signed 24-bit immediate in r_symbolnum (not a
+ * symbol-table reference). Seeds the following reloc's addend. */
+ i32 ad = (i32)(in->r_symbolnum & 0x00ffffffu);
+ if (ad & 0x00800000) ad |= ~0x00ffffff;
+ out->role = MACHO_RELOC_ADDEND;
+ out->addend = (i64)ad;
+ return 1;
+ }
+ case ARM64_RELOC_SUBTRACTOR:
+ out->role = MACHO_RELOC_SUBTRACTOR;
+ out->kind = (in->r_length == 3) ? R_SUB64
+ : (in->r_length == 2) ? R_SUB32
+ : (in->r_length == 1) ? R_SUB16
+ : R_SUB8;
+ return 1;
case ARM64_RELOC_UNSIGNED:
- return R_ABS64;
+ /* The unsigned datum: pcrel + length pick the kit kind; the shared
+ * reader rewrites it to R_ADD* when it completes a pending subtractor.
+ * Its addend rides in the patched field. */
+ out->role = MACHO_RELOC_ABSOLUTE;
+ out->inplace_addend = 1;
+ if (in->r_pcrel)
+ out->kind = (in->r_length == 3) ? R_PC64 : R_PC32;
+ else
+ out->kind = (in->r_length == 3) ? R_ABS64 : R_ABS32;
+ return 1;
case ARM64_RELOC_BRANCH26:
- return R_AARCH64_CALL26;
+ out->kind = R_AARCH64_CALL26;
+ return 1;
case ARM64_RELOC_PAGE21:
- return R_AARCH64_ADR_PREL_PG_HI21;
+ out->kind = R_AARCH64_ADR_PREL_PG_HI21;
+ return 1;
case ARM64_RELOC_PAGEOFF12:
- return R_AARCH64_ADD_ABS_LO12_NC;
+ out->kind = macho_aarch64_pageoff12_kind(in->insn, in->insn_len);
+ return 1;
case ARM64_RELOC_GOT_LOAD_PAGE21:
- return R_AARCH64_ADR_GOT_PAGE;
+ out->kind = R_AARCH64_ADR_GOT_PAGE;
+ return 1;
case ARM64_RELOC_GOT_LOAD_PAGEOFF12:
- return R_AARCH64_LD64_GOT_LO12_NC;
+ out->kind = R_AARCH64_LD64_GOT_LO12_NC;
+ return 1;
case ARM64_RELOC_TLVP_LOAD_PAGE21:
- return R_AARCH64_TLVP_LOAD_PAGE21;
+ out->kind = R_AARCH64_TLVP_LOAD_PAGE21;
+ return 1;
case ARM64_RELOC_TLVP_LOAD_PAGEOFF12:
- return R_AARCH64_TLVP_LOAD_PAGEOFF12;
+ out->kind = R_AARCH64_TLVP_LOAD_PAGEOFF12;
+ return 1;
default:
- return (u32)-1;
+ return 0;
}
}
diff --git a/src/obj/macho/reloc_x86_64.c b/src/obj/macho/reloc_x86_64.c
@@ -61,24 +61,75 @@ u32 macho_x86_64_reloc_length(u32 kind /* RelocKind */) {
}
}
-u32 macho_x86_64_reloc_from(u32 macho_type) {
- switch (macho_type) {
+/* Mark a PC-relative x86_64 reloc: its addend has no out-of-band carrier — the
+ * patched field holds symrel = (kit addend) + width, so the reader recovers the
+ * addend by sign-extending the field and subtracting the width. */
+static void x86_64_pcrel_inplace(const MachoRelocEntry* in,
+ MachoRelocDecoded* out, i64 extra_bias) {
+ out->inplace_addend = 1;
+ out->inplace_signed = 1;
+ out->inplace_bias = -(i64)(1u << in->r_length) + extra_bias;
+}
+
+int macho_x86_64_reloc_decode(const MachoRelocEntry* in,
+ MachoRelocDecoded* out) {
+ out->kind = R_NONE;
+ out->role = MACHO_RELOC_NORMAL;
+ out->addend = 0;
+ out->inplace_bias = 0;
+ out->inplace_addend = 0;
+ out->inplace_signed = 0;
+ switch (in->r_type) {
case X86_64_RELOC_UNSIGNED:
- return R_ABS64;
+ /* Absolute datum; the shared reader rewrites it to R_ADD* when it
+ * completes a pending subtractor. Its addend rides verbatim in the
+ * patched field (no PC bias). */
+ out->role = MACHO_RELOC_ABSOLUTE;
+ out->inplace_addend = 1;
+ out->kind = (in->r_length == 3) ? R_ABS64 : R_ABS32;
+ return 1;
+ /* SIGNED_{1,2,4} bias the addend by an extra 1/2/4 bytes (the distance from
+ * the field's end to the instruction's end). */
case X86_64_RELOC_SIGNED:
+ out->kind = R_PC32;
+ x86_64_pcrel_inplace(in, out, 0);
+ return 1;
case X86_64_RELOC_SIGNED_1:
+ out->kind = R_PC32;
+ x86_64_pcrel_inplace(in, out, -1);
+ return 1;
case X86_64_RELOC_SIGNED_2:
+ out->kind = R_PC32;
+ x86_64_pcrel_inplace(in, out, -2);
+ return 1;
case X86_64_RELOC_SIGNED_4:
- return R_PC32;
+ out->kind = R_PC32;
+ x86_64_pcrel_inplace(in, out, -4);
+ return 1;
case X86_64_RELOC_BRANCH:
- return R_X64_PLT32;
+ out->kind = R_X64_PLT32;
+ x86_64_pcrel_inplace(in, out, 0);
+ return 1;
case X86_64_RELOC_GOT_LOAD:
- return R_X64_REX_GOTPCRELX;
+ out->kind = R_X64_REX_GOTPCRELX;
+ x86_64_pcrel_inplace(in, out, 0);
+ return 1;
case X86_64_RELOC_GOT:
- return R_X64_GOTPCREL;
+ out->kind = R_X64_GOTPCREL;
+ x86_64_pcrel_inplace(in, out, 0);
+ return 1;
+ case X86_64_RELOC_SUBTRACTOR:
+ out->role = MACHO_RELOC_SUBTRACTOR;
+ out->kind = (in->r_length == 3) ? R_SUB64
+ : (in->r_length == 2) ? R_SUB32
+ : (in->r_length == 1) ? R_SUB16
+ : R_SUB8;
+ return 1;
case X86_64_RELOC_TLV:
- return R_X64_TLV;
+ out->kind = R_X64_TLV;
+ x86_64_pcrel_inplace(in, out, 0);
+ return 1;
default:
- return (u32)-1;
+ return 0;
}
}
diff --git a/src/obj/registry.c b/src/obj/registry.c
@@ -218,7 +218,7 @@ static const ObjMachoArchOps obj_macho_arch_ops[] = {
.reloc_to = macho_aarch64_reloc_to,
.reloc_pcrel = macho_aarch64_reloc_pcrel,
.reloc_length = macho_aarch64_reloc_length,
- .reloc_from = macho_aarch64_reloc_from,
+ .reloc_decode = macho_aarch64_reloc_decode,
},
#endif
#if KIT_ARCH_X64_ENABLED
@@ -231,7 +231,7 @@ static const ObjMachoArchOps obj_macho_arch_ops[] = {
.reloc_to = macho_x86_64_reloc_to,
.reloc_pcrel = macho_x86_64_reloc_pcrel,
.reloc_length = macho_x86_64_reloc_length,
- .reloc_from = macho_x86_64_reloc_from,
+ .reloc_decode = macho_x86_64_reloc_decode,
},
#endif
#if !KIT_ARCH_AA64_ENABLED && !KIT_ARCH_X64_ENABLED