commit 4f9d8c341c11e0ed72c7621b6517c47a9159d25f
parent beb0ad1e2b1f44d0c85a4de95c4481e7feb7e552
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Wed, 17 Jun 2026 00:54:38 -0700
arm32: leave __ARM_FP undefined on soft-float; add UDF
Two prerequisites for the kit-self-built runtime (§3):
- __ARM_FP was predefined to 0, so the coroutine register-save asm's
`#ifdef __ARM_FP` selected the VFP (d8..d15 vstr/vldr) path on a soft-float
build. clang/gcc leave __ARM_FP UNDEFINED when there is no hardware FP; match
that so the integer path is taken.
- UDF #imm8 (T1) — the coro trampoline traps a returned entry fn with `udf #0`.
Add the encoder + descriptor row (BKPT-shaped imm8) + assembler case.
Diffstat:
4 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/src/arch/arm32/arch.c b/src/arch/arm32/arch.c
@@ -129,7 +129,10 @@ static const KitPredefinedMacro arm32_predefined_macros[] = {
{KIT_SLICE_LIT("__ARM_EABI__"), KIT_SLICE_LIT("1")},
{KIT_SLICE_LIT("__ARM_PCS"), KIT_SLICE_LIT("1")},
{KIT_SLICE_LIT("__SOFTFP__"), KIT_SLICE_LIT("1")},
- {KIT_SLICE_LIT("__ARM_FP"), KIT_SLICE_LIT("0")},
+ /* __ARM_FP is a bitmask of hardware FP precisions; on soft-float it is left
+ * UNDEFINED (not 0), matching clang/gcc — `#ifdef __ARM_FP` then correctly
+ * selects the integer code path (e.g. the coroutine register-save asm skips
+ * the d8..d15 VFP saves). A hard-float variant will define it. */
{KIT_SLICE_LIT("__ARM_FEATURE_CLZ"), KIT_SLICE_LIT("1")},
{KIT_SLICE_LIT("__ARM_FEATURE_IDIV"), KIT_SLICE_LIT("1")},
{KIT_SLICE_LIT("__ARM_FEATURE_UNALIGNED"), KIT_SLICE_LIT("1")},
diff --git a/src/arch/arm32/asm.c b/src/arch/arm32/asm.c
@@ -660,7 +660,7 @@ static void assemble_one(AsmDriver* d, const Arm32InsnDesc* desc, u32 cond) {
}
case ARM_FMT_BKPT: {
u32 imm8 = (u32)parse_imm(d) & 0xffu;
- emit_t16(d, arm_bkpt(imm8));
+ emit_t16(d, slice_eq_cstr(mn, "udf") ? arm_udf(imm8) : arm_bkpt(imm8));
return;
}
case ARM_FMT_EXT16: {
diff --git a/src/arch/arm32/isa.c b/src/arch/arm32/isa.c
@@ -250,6 +250,9 @@ const Arm32InsnDesc arm32_insn_table[] = {
* mask==0 hint; pin mask nonzero is implicit by ordering after the hints. */
{MN("it"), 0x0000bf00u, 0x0000ff00u, ARM_FMT_IT, ARM_FMT_W16, {0}},
{MN("bkpt"), 0x0000be00u, 0x0000ff00u, ARM_FMT_BKPT, ARM_FMT_W16, {0}},
+ /* UDF #imm8 (T1, 0xDExx): same imm8 shape as BKPT, decoded after the 0xB0xx
+ * hint/branch block so it does not shadow a tighter match. */
+ {MN("udf"), 0x0000de00u, 0x0000ff00u, ARM_FMT_BKPT, ARM_FMT_W16, {0}},
/* CBZ/CBNZ: 0xB1xx (op=0)/0xB9xx (op=1); mask the i/imm5/rn fields. */
{MN("cbz"), 0x0000b100u, 0x0000fd00u, ARM_FMT_CBZ, ARM_FMT_W16, {0}},
{MN("cbnz"), 0x0000b900u, 0x0000fd00u, ARM_FMT_CBZ, ARM_FMT_W16, {0}},
diff --git a/src/arch/arm32/isa.h b/src/arch/arm32/isa.h
@@ -281,6 +281,9 @@ static inline u32 arm_bl(void) { return arm_t32(0xf7ffu, 0xfffeu); } /* B
static inline u16 arm_bx(u32 rm) { return (u16)(0x4700u | (rm << 3)); }
static inline u16 arm_blx_reg(u32 rm) { return (u16)(0x4780u | (rm << 3)); }
static inline u16 arm_bkpt(u32 imm8) { return (u16)(0xbe00u | (imm8 & 0xffu)); }
+/* UDF #imm8 (T1, permanently undefined) — the coroutine trampoline's trap on a
+ * returned entry fn. Same 16-bit imm8 shape as BKPT, different opcode. */
+static inline u16 arm_udf(u32 imm8) { return (u16)(0xde00u | (imm8 & 0xffu)); }
static inline u16 arm_nop16(void) { return (u16)0xbf00u; }
/* NOP.W (32-bit) — pads a multi-slot prologue placeholder region. */
static inline u32 arm_nop32(void) { return arm_t32(0xf3afu, 0x8000u); }