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