arch.h (18194B)
1 #ifndef KIT_INTERNAL_ARCH_H 2 #define KIT_INTERNAL_ARCH_H 3 4 #include <kit/arch.h> 5 #include <kit/compile.h> 6 #include <kit/disasm.h> 7 8 #include "abi/abi.h" 9 #include "arch/mc.h" 10 #include "cg/cgtarget.h" 11 #include "core/core.h" 12 #include "obj/obj.h" 13 14 typedef struct AsmDriver AsmDriver; 15 16 typedef struct ArchAsm ArchAsm; 17 struct ArchAsm { 18 void (*insn)(ArchAsm*, AsmDriver*, Sym mnemonic); 19 void (*destroy)(ArchAsm*); 20 }; 21 22 /* ---- Disassembler hook ---- 23 * Bytes -> records, not frontend-driven lowering, so this is a separate 24 * hook from CgTarget/MCEmitter. The internal implementation may share 25 * encoding tables with the per-arch backend (sequencing concern, not an 26 * interface concern). Constructed for c->target. 27 * 28 * arch_disasm_decode returns the number of bytes consumed, or 0 if input 29 * is too short or undecodable (in which case the public iterator advances 30 * by the arch's minimum unit). ArchDisasm owns the mnemonic / operands / 31 * annotation string buffers placed into *out; they are valid until the 32 * next decode or arch_disasm_free, whichever comes first. */ 33 typedef struct ArchDisasm ArchDisasm; 34 struct ArchDisasm { 35 u32 (*decode)(ArchDisasm*, const u8* bytes, size_t len, u64 vaddr, 36 KitInsn* out); 37 void (*destroy)(ArchDisasm*); 38 }; 39 40 #define KIT_DECODE_MAX_OPERANDS 6u 41 42 typedef enum KitDecodeFlag { 43 KIT_DECODE_TERMINATOR = 1u << 0, 44 KIT_DECODE_BRANCH = 1u << 1, 45 KIT_DECODE_CALL = 1u << 2, 46 KIT_DECODE_RET = 1u << 3, 47 KIT_DECODE_MEMORY = 1u << 4, 48 KIT_DECODE_TRAP = 1u << 5, 49 } KitDecodeFlag; 50 51 typedef enum KitDecodedOperandKind { 52 KIT_DECOP_NONE, 53 KIT_DECOP_REG, 54 KIT_DECOP_IMM, 55 KIT_DECOP_MEM, 56 KIT_DECOP_PCREL, 57 KIT_DECOP_SYSREG, 58 } KitDecodedOperandKind; 59 60 typedef struct KitDecodedOperand { 61 u8 kind; 62 u8 width_bits; 63 u16 flags; 64 u32 reg; 65 u32 index_reg; 66 i64 imm; 67 u8 scale; 68 u8 pad[7]; 69 } KitDecodedOperand; 70 71 typedef struct KitDecodedInsn { 72 u64 pc; 73 const u8* bytes; 74 u8 nbytes; 75 u8 noperands; 76 u16 flags; 77 u32 opcode; /* Arch-owned stable opcode id. */ 78 u32 encoding_id; /* Optional row/table id for formatting. */ 79 KitDecodedOperand operands[KIT_DECODE_MAX_OPERANDS]; 80 u64 arch[2]; /* Small arch-private payload. */ 81 } KitDecodedInsn; 82 83 typedef struct ArchInsnFormatter ArchInsnFormatter; 84 typedef struct KitCg KitCg; 85 typedef struct EmuCPUState EmuCPUState; 86 typedef struct EmuLiftCtx EmuLiftCtx; 87 typedef struct EmuProcess EmuProcess; 88 typedef struct EmuThread EmuThread; 89 struct ArchInsnFormatter { 90 KitStatus (*format)(ArchInsnFormatter*, const KitDecodedInsn*, KitInsn* out); 91 void (*destroy)(ArchInsnFormatter*); 92 }; 93 94 typedef struct ArchDecodeOps { 95 u8 min_insn_len; 96 u8 max_insn_len; 97 98 KitStatus (*decode_one)(Compiler*, const u8* bytes, size_t len, u64 pc, 99 KitDecodedInsn* out); 100 KitStatus (*decode_block)(Compiler*, const u8* bytes, size_t len, u64 pc, 101 KitDecodedInsn* out, u32 cap, u32* n_out); 102 103 ArchInsnFormatter* (*formatter_new)(Compiler*); 104 KitStatus (*format)(ArchInsnFormatter*, const KitDecodedInsn*, KitInsn* out); 105 void (*formatter_free)(ArchInsnFormatter*); 106 } ArchDecodeOps; 107 108 typedef struct ArchEmuOps { 109 EmuCPUState* (*cpu_new)(Compiler*, u64 initial_pc, u64 initial_sp); 110 KitCgTypeId (*block_fn_type)(Compiler*); 111 KitStatus (*lift_block)(Compiler*, KitCg*, const KitDecodedInsn*, u32 n, 112 const EmuLiftCtx*); 113 u64 (*get_gpr)(EmuThread*, u32 reg); 114 void (*set_gpr)(EmuThread*, u32 reg, u64 value); 115 u64 (*get_syscall_no)(EmuThread*); 116 u64 (*get_syscall_arg)(EmuThread*, u32 index); 117 void (*set_syscall_result)(EmuThread*, u64 value); 118 u64 (*get_sp)(EmuThread*); 119 void (*set_sp)(EmuThread*, u64 value); 120 u64 (*get_tp)(EmuThread*); 121 void (*set_tp)(EmuThread*, u64 value); 122 u64 (*signal_context_size)(EmuProcess*, EmuThread*); 123 KitStatus (*save_signal_context)(EmuProcess*, EmuThread*, u8* dst, u64 size); 124 KitStatus (*restore_signal_context)(EmuProcess*, EmuThread*, const u8* src, 125 u64 size); 126 KitStatus (*set_signal_handler_args)(EmuProcess*, EmuThread*, int signo, 127 u64 siginfo, u64 ucontext); 128 u64 (*signal_stack_align)(EmuProcess*, EmuThread*); 129 u32 import_thunk_size; 130 KitStatus (*emit_import_thunk)(EmuProcess*, u64 thunk_vaddr); 131 void* (*resolve_runtime_helper)(void* emu, KitSlice name); 132 } ArchEmuOps; 133 134 typedef struct LinkArchDesc LinkArchDesc; 135 136 typedef struct ArchDwarfOps { 137 /* DWARF .debug_line minimum instruction length and maximum operations per 138 * instruction. Fixed-width ISAs normally use their instruction width; x86_64 139 * uses 1 because line-program PC advances are byte granular. */ 140 u8 min_inst_len; 141 u8 max_ops_per_inst; 142 u8 pad[2]; 143 } ArchDwarfOps; 144 145 typedef struct ArchTargetFeature { 146 const char* name; 147 } ArchTargetFeature; 148 149 #define ARCH_DBG_MAX_TRAP_BYTES 8u 150 #define ARCH_DBG_MAX_INSN_BYTES 15u 151 152 typedef struct ArchDbgInsn { 153 u64 pc; 154 u8 bytes[ARCH_DBG_MAX_INSN_BYTES]; 155 u32 len; 156 } ArchDbgInsn; 157 158 typedef struct ArchDbgOps { 159 u32 min_insn_len; 160 u32 max_insn_len; 161 162 KitStatus (*breakpoint_patch)(u8* out, u32 cap, u32* len_out); 163 u64 (*breakpoint_addr_from_fault_pc)(u64 fault_pc); 164 165 KitStatus (*decode_insn)(const u8* bytes, u32 len, u64 pc, ArchDbgInsn* out); 166 KitStatus (*build_displaced_shim)(const ArchDbgInsn* insn, 167 void* scratch_write, u64 scratch_runtime, 168 u32 scratch_cap, u32* sentinel_off, 169 u64* fallthrough_pc); 170 int (*is_call)(const ArchDbgInsn* insn); 171 KitStatus (*direct_call_target)(const ArchDbgInsn* insn, u64* target_out); 172 KitStatus (*direct_jump_target)(const ArchDbgInsn* insn, u64* target_out); 173 KitStatus (*link_register_return_address)(const KitUnwindFrame* frame, 174 u64* target_out); 175 } ArchDbgOps; 176 177 /* ---- textual-assembly operand syntax (printer <-> parser) ---------------- 178 * 179 * How a relocated operand is spelled in `cc -S` output. The shape selects 180 * which part of the disassembled operand text the symbolizer rewrites; the 181 * prefix/suffix are the relocation-modifier spelling for the target object 182 * format (e.g. aarch64 ELF `:lo12:sym` is a prefix; Mach-O `sym@PAGEOFF` is a 183 * suffix). At most one of prefix/suffix is non-empty for a given (kind, fmt). 184 * This is the inverse of the arch assembler's operand reloc-modifier parser. */ 185 typedef enum ArchRelocSurg { 186 ARCH_RELOC_SURG_NONE = 0, /* not symbolizable here; keep numeric operand */ 187 ARCH_RELOC_SURG_TAIL, /* replace last comma component (or whole operand) */ 188 ARCH_RELOC_SURG_MEM, /* rewrite the offset inside [...] (aarch64 ldst) */ 189 ARCH_RELOC_SURG_RIP, /* insert sym before disp(%rip) (x86-64 RIP-rel) */ 190 /* RISC-V `%pcrel_lo`/`%lo` low-half operand. A single reloc kind covers two 191 * disassembled shapes: a register-immediate ADDI (printed as `mv rd, rs` 192 * when the immediate is 0) where the modifier becomes a new trailing 193 * operand (`mv rd, rs, %pcrel_lo(L)`, which the assembler folds back into 194 * ADDI), and a `disp(base)` load/store where the modifier replaces the 195 * displacement (`%pcrel_lo(L)(base)`). The shape is picked from the operand 196 * text: a trailing `(...)` group selects the memory form. */ 197 ARCH_RELOC_SURG_RV_LO12, 198 } ArchRelocSurg; 199 200 typedef struct ArchRelocOperand { 201 ArchRelocSurg surg; 202 const char* prefix; /* e.g. ":lo12:" (ELF); "" if none */ 203 const char* suffix; /* e.g. "@PAGEOFF" / "@GOTPCREL"; "" if none */ 204 /* Added to the relocation's stored addend before spelling `sym[+/-N]`. Undoes 205 * an instruction-encoding bias so the printed offset is the *symbol* offset: 206 * 0 for aarch64; +4 for x86-64 rel32 (PC32/PLT32/GOTPCREL store addend-4). */ 207 int addend_bias; 208 /* hi/lo anchor pairing (RISC-V `%pcrel_hi`/`%pcrel_lo`). A high-half reloc 209 * (AUIPC `%pcrel_hi(sym)`) sets `emit_anchor` so the symbolizer defines a 210 * unique local label at this instruction. The paired low-half reloc 211 * (`%pcrel_lo`) sets `ref_anchor`: its operand references that synthesized 212 * anchor label (the nearest preceding anchor) instead of the reloc's own 213 * symbol — matching the RISC-V ABI, where `%pcrel_lo` names the AUIPC's 214 * label, not the target symbol. Other arches leave both 0. */ 215 u8 emit_anchor; 216 u8 ref_anchor; 217 } ArchRelocOperand; 218 219 typedef struct ArchAsmOps { 220 /* Map (reloc kind, target object format) to the operand syntax the cc -S 221 * symbolizer must emit (and that this arch's .s parser accepts back). 222 * Returns 1 and fills *out when the kind is symbolizable for fmt; 0 223 * otherwise (printer keeps the numeric operand). The symbolizer picks the 224 * surgery site from the operand text (an `(%rip)` operand always uses RIP 225 * surgery regardless of `out->surg`), so a single reloc kind can serve both 226 * a branch target and a RIP-relative memory operand (x86-64 R_PC32). */ 227 int (*reloc_operand)(u16 reloc_kind, KitObjFmt fmt, ArchRelocOperand* out); 228 /* 1 if `mnemonic` is an intra-section local branch whose un-relocated 229 * numeric target the symbolizer should replace with a synthesized label 230 * (aarch64 b/b.cc/cbz/...; x86-64 jmp/jcc). Calls are excluded — they carry 231 * relocations. NULL hook = no local-branch symbolization for the arch. */ 232 int (*is_local_branch)(KitSlice mnemonic); 233 /* Fuse a relocation that the disassembler renders as a 2-instruction pair 234 * back into a single relocated pseudo-instruction line. RISC-V R_RV_CALL 235 * sits on an AUIPC whose JALR partner carries no reloc; the canonical `.s` 236 * spelling is a single `call`/`tail sym`. When `kind` names such a reloc, 237 * the hook returns 1 and sets *mnemonic_out to the fused mnemonic — the 238 * symbolizer then emits "<mnemonic>\t<sym[+addend]>" in place of BOTH 239 * instructions (skipping the partner). `pair_mnemonic`/`pair_ops` are the 240 * SECOND instruction's disassembled text (the JALR), used to disambiguate 241 * (e.g. call vs tail by its link register). Returns 0 to leave the pair 242 * un-fused (per-instruction operand symbolization applies). NULL hook = no 243 * pair fusion for the arch. */ 244 int (*reloc_call_pair)(u16 reloc_kind, KitSlice pair_mnemonic, 245 KitSlice pair_ops, const char** mnemonic_out); 246 } ArchAsmOps; 247 248 typedef struct ArchImpl { 249 /* First field, so `(const CGBackend*)&arch_impl_x` is the arch's backend 250 * view. Every machine-code arch is a CGBackend by composition; c_target 251 * is a standalone CGBackend with no ArchImpl. */ 252 CGBackend backend; 253 254 KitArchKind kind; 255 const char* name; 256 257 /* Low-level CgTarget constructor: caller supplies the MCEmitter. Tests use 258 * this directly via the cgtarget_new() wrapper; the arch's `backend.make` 259 * also calls it after creating an MCEmitter internally. */ 260 CgTarget* (*cgtarget_new)(Compiler*, ObjBuilder*, MCEmitter*); 261 ArchAsm* (*asm_new)(Compiler*); 262 ArchDisasm* (*disasm_new)(Compiler*); 263 int (*apply_label_fixup)(Compiler*, const ArchLabelFixup*); 264 265 const ArchDecodeOps* decode; 266 const ArchEmuOps* emu; 267 const LinkArchDesc* link; 268 const ArchDwarfOps* dwarf; 269 const ArchDbgOps* dbg; 270 const ArchAsmOps* 271 asm_ops; /* textual-asm operand syntax; NULL = keep numeric */ 272 273 const KitPredefinedMacro* predefined_macros; 274 u32 npredefined_macros; 275 const ArchTargetFeature* target_features; 276 u32 ntarget_features; 277 void (*target_feature_defaults)(const Target*, u64* words, u32 nwords); 278 KitStatus (*target_feature_apply_isa)(const Target*, KitSlice isa, u64* words, 279 u32 nwords); 280 281 const char* (*register_name)(uint32_t dwarf_idx); 282 int (*register_index)(const char* name, uint32_t* idx_out); 283 uint32_t (*register_count)(void); 284 int (*register_at)(uint32_t idx, KitArchReg* out); 285 286 /* DWARF CFI defaults per psABI, used by the CIE the .eh_frame 287 * producer emits. cfi_cfa_init_{reg,offset} describe the at-entry 288 * CFA state — before any cfi_def_cfa override — so an unwinder can 289 * recover the caller's stack pointer at the very first instruction. */ 290 u32 cfi_return_addr_reg; 291 i32 cfi_code_align_factor; 292 i32 cfi_data_align_factor; 293 u32 cfi_cfa_init_reg; 294 i32 cfi_cfa_init_offset; 295 296 /* === Generic-layer capability queries ===================================== 297 * Let generic (non-backend) code in src/cg and src/link decide by capability 298 * instead of by arch identity (target.arch == KIT_ARCH_*). Each backend 299 * declares its answer here once. */ 300 301 /* Backend codegen capability bitmask (KitCgBackendFeatureFlag). Per-arch 302 * constant: the x86 family sets UNALIGNED_MEMORY|RED_ZONE|SIMD, every other 303 * arch sets STRICT_ALIGNMENT. Read via kit_cg_target_backend_features. */ 304 u64 backend_features; 305 306 /* Largest power-of-two byte width this arch lowers as a lock-free native 307 * atomic: 8 for aa64/x64/rv64/wasm, 4 for rv32 (no lr.d/sc.d/amo*.d). The 308 * single source of truth for kit_cg_atomic_is_lock_free and the C front-end's 309 * __atomic_always_lock_free. */ 310 u32 atomic_lock_free_max; 311 312 /* 1 if call convention `cc` is selectable for this compiler's (arch, os). 313 * KIT_CG_CC_TARGET_C is handled generically (always 1); INTERRUPT is 0. May 314 * read c->target.os (a property, not arch identity). Read via 315 * kit_cg_target_supports_call_conv. */ 316 int (*supports_call_conv)(const Compiler* c, KitCgCallConv cc); 317 318 /* 1 if this arch has a legal lowering for `intrin`. Kept in sync with the 319 * backend's IntrinKind lowering switch (x64_intrinsic / aa_intrinsic / 320 * rv_intrinsic / wasm_intrinsic). Read via kit_cg_target_supports_intrinsic. 321 */ 322 int (*supports_intrinsic)(const Compiler* c, KitCgIntrinsic intrin); 323 324 /* Resolve & validate the float ABI for the target being constructed, given 325 * the explicit -mabi string (`abi`, empty for none) and the already-resolved 326 * -march feature bits (`feature_words`/`nfeature_words`). On success returns 327 * KIT_OK with `spec->float_abi` set to the chosen KitFloatAbi. On a bad/ 328 * mismatched ABI returns KIT_INVALID and writes a NUL-terminated message into 329 * `err` (capacity `errcap`) for the caller to surface as a diagnostic. NULL 330 * hook means the arch has no float-ABI axis: leave spec->float_abi at 331 * KIT_FLOAT_ABI_DEFAULT (the arch_resolve_float_abi wrapper no-ops). Set for 332 * RISC-V (handles rv32 + rv64); read via arch_resolve_float_abi. */ 333 KitStatus (*resolve_float_abi)(const struct ArchImpl* impl, 334 KitTargetSpec* spec, const u64* feature_words, 335 u32 nfeature_words, KitSlice abi, char* err, 336 size_t errcap); 337 } ArchImpl; 338 339 const ArchImpl* arch_lookup(KitArchKind); 340 const ArchImpl* arch_for_compiler(const Compiler*); 341 int arch_target_feature_index(const ArchImpl*, KitSlice name, u32* idx_out); 342 void arch_target_feature_defaults(const ArchImpl*, const Target*, u64* words, 343 u32 nwords); 344 KitStatus arch_target_feature_apply_isa(const ArchImpl*, const Target*, 345 KitSlice isa, u64* words, u32 nwords); 346 347 /* Resolve & validate `spec->float_abi` from the explicit -mabi string and the 348 * resolved -march feature bits, dispatching to `impl->resolve_float_abi`. When 349 * `impl` is NULL or the arch sets no hook this is a no-op returning KIT_OK and 350 * leaving spec->float_abi untouched (KIT_FLOAT_ABI_DEFAULT) — exactly the old 351 * "non-RISC-V arches leave the float ABI at default" behavior. On a bad ABI the 352 * hook returns KIT_INVALID and fills `err` (NUL-terminated, capacity `errcap`). 353 * Header-only thin dispatch: the matching `arch_reloc_*` wrappers live in 354 * src/arch/registry.c, but float-ABI resolution runs during target 355 * construction (no Compiler yet), so this wrapper takes the ArchImpl directly. 356 */ 357 static inline KitStatus arch_resolve_float_abi(const ArchImpl* impl, 358 KitTargetSpec* spec, 359 const u64* feature_words, 360 u32 nfeature_words, KitSlice abi, 361 char* err, size_t errcap) { 362 if (!impl || !impl->resolve_float_abi) return KIT_OK; 363 return impl->resolve_float_abi(impl, spec, feature_words, nfeature_words, abi, 364 err, errcap); 365 } 366 367 /* Spelling for a relocated operand in `cc -S` text, for the compiler's target 368 * arch+format. Returns 1 and fills *out when symbolizable, 0 to keep numeric 369 * (also when the arch provides no asm_ops). Thin dispatch over ArchAsmOps. */ 370 int arch_reloc_operand(const Compiler* c, u16 reloc_kind, 371 ArchRelocOperand* out); 372 373 /* 1 if `mnemonic` is an intra-section local branch for the compiler's target 374 * arch (so cc -S synthesizes a label at its un-relocated target). 0 when the 375 * arch has no asm_ops/is_local_branch hook. */ 376 int arch_is_local_branch(const Compiler* c, KitSlice mnemonic); 377 378 /* 1 if `reloc_kind` names a 2-instruction call pair the symbolizer should fuse 379 * into a single pseudo line (RISC-V R_RV_CALL -> `call`/`tail`), with 380 * *mnemonic_out set to the fused mnemonic. `pair_*` are the partner (second) 381 * instruction's disassembled text. 0 when not fused / no hook. Thin dispatch 382 * over ArchAsmOps.reloc_call_pair. */ 383 int arch_reloc_call_pair(const Compiler* c, u16 reloc_kind, 384 KitSlice pair_mnemonic, KitSlice pair_ops, 385 const char** mnemonic_out); 386 387 ArchDisasm* arch_disasm_new(Compiler*); 388 u32 arch_disasm_decode(ArchDisasm*, const u8* bytes, size_t len, u64 vaddr, 389 KitInsn* out); 390 void arch_disasm_free(ArchDisasm*); 391 KitStatus arch_decode_one(Compiler*, const u8* bytes, size_t len, u64 pc, 392 KitDecodedInsn* out); 393 KitStatus arch_decode_block(Compiler*, const u8* bytes, size_t len, u64 pc, 394 KitDecodedInsn* out, u32 cap, u32* n_out); 395 ArchInsnFormatter* arch_insn_formatter_new(Compiler*); 396 KitStatus arch_format_insn(ArchInsnFormatter*, const KitDecodedInsn*, 397 KitInsn* out); 398 void arch_insn_formatter_free(ArchInsnFormatter*); 399 400 #endif