kit

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

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:
Msrc/obj/format.h | 52+++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/obj/macho/macho.h | 5+++--
Msrc/obj/macho/read.c | 130+++++++++++++++++++++++++++++++-------------------------------------------------
Msrc/obj/macho/reloc_aarch64.c | 104++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Msrc/obj/macho/reloc_x86_64.c | 69++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Msrc/obj/registry.c | 4++--
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