commit 034c337916199487593e4e99dfddfed77e66cc6d
parent a607d9e0169a971697a9073770e075477e079853
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Tue, 16 Jun 2026 17:26:19 -0700
arm32 Phase 2: canonical branch/call placeholders (clang -4 in-field form)
kit emitted BL/B.W/Bcond.W with all-zero immediate fields (f000 d000 etc.),
which for ARM ELF REL relocations decode (via I1=NOT(J1^S)) to a bogus
+0xC00000 in-field addend that stock ARM linkers (ld.lld, gas ld) apply.
Emit the canonical clang/gas 'branch to self' placeholders (encoded -4), which
those linkers read as the correct addend. kit's own linker overwrites the
field, so this is inert for kit ld (still byte-correct). Prerequisite for ARM
REL reloc emission (external-linker compatibility).
Diffstat:
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/src/arch/arm32/isa.h b/src/arch/arm32/isa.h
@@ -225,12 +225,19 @@ static inline u16 arm_mov_hi(u32 rd, u32 rm) {
return (u16)(0x4600u | ((rd >> 3) << 7) | (rm << 3) | (rd & 7u));
}
-/* --------- branches (placeholders; immediate filled by reloc/label-fixup) --- */
-static inline u32 arm_b_w(void) { return arm_t32(0xf000u, 0x9000u); } /* B.W (T4) */
+/* --------- branches (placeholders; immediate filled by reloc/label-fixup) ---
+ * The immediate fields use the canonical clang/gas "branch to self" pattern
+ * (encoded displacement -4). For ARM ELF the branch relocs are REL, so the
+ * in-field bits ARE the addend an external linker (ld.lld, gas's ld) reads; an
+ * all-zero field decodes (via I1=NOT(J1^S)) to a bogus +0xC00000, which those
+ * linkers then apply. kit's OWN linker overwrites the field (mask 0xf800d000 /
+ * the JUMP19 imm mask), so the placeholder is inert for kit ld — these values
+ * exist purely to keep kit objects linkable by stock ARM linkers. */
+static inline u32 arm_b_w(void) { return arm_t32(0xf7ffu, 0xbffeu); } /* B.W (T4) */
static inline u32 arm_b_cond_w(u32 cond) { /* B<cond>.W (T3) */
- return arm_t32(0xf000u | (cond << 6), 0x8000u);
+ return arm_t32(0xf43fu | (cond << 6), 0xaffeu);
}
-static inline u32 arm_bl(void) { return arm_t32(0xf000u, 0xd000u); } /* BL (T1) */
+static inline u32 arm_bl(void) { return arm_t32(0xf7ffu, 0xfffeu); } /* BL (T1) */
/* --------- 16-bit instructions --------- */
static inline u16 arm_bx(u32 rm) { return (u16)(0x4700u | (rm << 3)); }