Files
Odin/core/rexcode/isa/arm32/reloc.odin
Brendan Punsky 95df04fbe1 rexcode: re-house ISA packages under core:rexcode/isa/<arch>
Move all ten ISA packages (x86, arm32, arm64, mips, riscv, ppc, ppc_vle,
rsp, mos6502, mos65816) from core/rexcode/<arch> to core/rexcode/isa/<arch>,
so the import pattern is now `import "core:rexcode/isa/x86"`. The shared
core stays at core:rexcode/isa.

Mechanical: relative `import "../isa"` / "../../isa" -> absolute
"core:rexcode/isa" (the only path that survives the move; the "../" and
"../.." self/generated imports move with their packages). build.lua now
builds paths as <root>/isa/<name>; stale `cd <arch>` hints in the verify
tools and the doc.odin paths updated.

WASM stays at core/rexcode/wasm for now -- it is an IR, not an ISA, and
will move under the forthcoming core:rexcode/ir once that layer lands.

All 10 arches gen/builders/check/test green; import core:rexcode/isa/x86
verified working; wasm still compiles.
2026-06-18 19:03:27 -04:00

70 lines
2.5 KiB
Odin

// rexcode · Brendan Punsky (dotbmp@github), original author
package rexcode_arm32
// =============================================================================
// AArch32 RELOCATIONS
// =============================================================================
//
// AArch32 has many PC-relative forms because both A32 and T32 modes encode
// branches with varying displacement widths:
//
// * A32 B/BL: 24-bit signed << 2 (-32MB..+32MB)
// * A32 BLX imm: 24-bit signed << 2 + H bit (half-word align for arm->thumb)
// * T32 unconditional B: 25-bit signed (S/J1/J2/imm10/imm11 scattered, ±16MB)
// * T32 conditional B: 21-bit signed (cond + S/J1/J2/imm6/imm11 scattered, ±1MB)
// * T16 unconditional B: 12-bit signed << 1 (±2KB)
// * T16 conditional B: 9-bit signed << 1 (±256B)
// * T16 CBZ/CBNZ: 7-bit unsigned << 1 (forward only)
// * ADR/LDR-literal: PC-relative literal pool access
//
// PC for arm32 is always (current_inst_addr + 8) in A32 / (+4) in T32.
// The relocation resolver bakes this in.
Relocation_Type :: enum u8 {
NONE = 0,
// A32 branches
BRANCH_A32_24, // B / BL, 24-bit signed << 2
BLX_A32, // BLX imm, 24-bit signed << 2 + H bit at bit 24
// T32 branches
BRANCH_T32_25, // T32 B unconditional (J1/J2 + imm10 + imm11)
BRANCH_T32_21, // T32 B<cond> (S + cond + imm6 + J1/J2 + imm11)
// T16 branches
BRANCH_T16_11, // T16 B unconditional (signed 11-bit << 1)
BRANCH_T16_8, // T16 B<cond> (signed 8-bit << 1)
BRANCH_T16_CBZ, // T16 CBZ/CBNZ (i + imm5 + Rn)
// T32 low-overhead loops (ARMv8.1-M)
BRANCH_T32_WLS, // WLS / WLSTP imm11
BRANCH_T32_LE, // LE / LETP imm11
// T32 Branch Future (ARMv8.1-M)
BF_BOFF_T32, // bf-point: imm4 at hw0[10:7] = (label - (PC+4))/2
BF_BLOC_T32, // branch target: J at hw1[11] + imm10 at hw1[10:1]
// Literal load (ADR / LDR PC-rel)
LDR_LITERAL_A32, // signed 12-bit (U bit + imm12)
LDR_LITERAL_T32, // signed 12-bit (U bit + imm12) Thumb-2
LDR_LITERAL_T16, // unsigned 8-bit << 2 (Thumb-1 PC-rel)
ADR_A32, // ADR encoded as ADD/SUB to PC
ADR_T32,
ADR_T16, // Thumb-1 ADR (imm8 << 2)
// Absolute forms via MOVW + MOVT pair
MOVW_ABS, // imm16 low half
MOVT_ABS, // imm16 high half
}
Relocation :: struct #packed {
offset: u32,
label_id: u32,
addend: i32,
type: Relocation_Type,
size: u8, // 2 (T16) or 4 (A32/T32)
inst_idx: u16,
}
#assert(size_of(Relocation) == 16)