mc.h (7597B)
1 #ifndef KIT_INTERNAL_ARCH_MC_H 2 #define KIT_INTERNAL_ARCH_MC_H 3 4 #include <kit/compile.h> 5 6 #include "cg/cgtarget.h" 7 #include "core/core.h" 8 #include "obj/obj.h" 9 10 /* Machine-code / object emission interface. One generic implementation in 11 * src/arch/mc.c serves every machine-code arch; arch-specific behavior enters 12 * only via ArchImpl.apply_label_fixup (label reloc encoding) and the 13 * ArchImpl.cfi_* constants (eh_frame CIE defaults). Pulled out of arch.h so 14 * the many emission-only consumers (per-arch emit/ops/alloc TUs, the 15 * assembler, the Debug producer) don't transitively depend on the 16 * decode/disasm/emu/dbg surfaces. */ 17 18 /* Forward-declared so CgTarget can carry an optional Debug* without 19 * pulling debug/debug.h into every translation unit that includes this 20 * header. Per doc/DWARF.md §3.2 the backend gets exactly one new dependency 21 * on Debug: this forward decl plus debug_emit_row (declared by the few 22 * backend TUs that actually emit line rows). */ 23 typedef struct Debug Debug; 24 25 /* Native-only register id. The semantic CgTarget surface uses CGLocal; this 26 * remains here for MC/native helpers and disabled native backends. */ 27 typedef u32 Reg; 28 #define REG_NONE 0xffffffffu 29 30 typedef u32 MCLabel; 31 #define MC_LABEL_NONE 0u 32 33 typedef struct ArchLabelFixup { 34 ObjBuilder* obj; 35 u32 sec_id; 36 u32 offset; 37 u32 width; 38 RelocKind kind; 39 i64 disp; 40 ObjSymId cur_func_sym; 41 u32 cur_func_start; 42 } ArchLabelFixup; 43 44 typedef struct MCEmitter MCEmitter; 45 struct MCEmitter { 46 /* Machine/object emission context. Subclasses extend. */ 47 Compiler* c; 48 ObjBuilder* obj; 49 u32 section_id; 50 51 /* Pending source location, updated by set_loc. Promoted to the base so 52 * arch backends' emit-bytes choke point can read it without reaching 53 * into the per-arch impl (used to feed debug_emit_row). */ 54 SrcLoc loc; 55 56 /* Optional Debug producer. NULL means -g is off and the per-instruction 57 * line-row fanout is skipped. Set after construction by cg_new (or by 58 * the cg_test harness, which is the parser stand-in). Per doc/DWARF.md 59 * §3.2 this is the backend's only new dependency on Debug. */ 60 Debug* debug; 61 62 /* Currently active function. Backends manage these via the 63 * mc_begin_function / mc_end_function helpers from their func_begin / 64 * func_end once they've computed the post-alignment function start 65 * position. emit_label_data_reloc reads them to compute reloc 66 * addends that resolve to the runtime address of an intra-function 67 * label. */ 68 ObjSymId cur_func_sym; 69 u32 cur_func_section; 70 u32 cur_func_start; 71 72 void (*set_section)(MCEmitter*, u32 section_id); 73 u32 (*pos)(MCEmitter*); 74 75 MCLabel (*label_new)(MCEmitter*); 76 void (*label_place)(MCEmitter*, MCLabel); 77 78 void (*emit_bytes)(MCEmitter*, const u8*, size_t); 79 void (*emit_fill)(MCEmitter*, size_t n, u8 byte); 80 void (*emit_align)(MCEmitter*, u32 align, u8 fill); 81 void (*emit_reloc)(MCEmitter*, RelocKind, ObjSymId, i64 addend); 82 void (*emit_reloc_at)(MCEmitter*, u32 section_id, u32 offset, RelocKind, 83 ObjSymId, i64 addend, int explicit_addend, int pair); 84 void (*emit_label_ref)(MCEmitter*, MCLabel, RelocKind, u32 width, i64 addend); 85 86 /* Emit a relocation at (data_sec, data_offset) that resolves at link 87 * time to the runtime address of `label` (an intra-function code label). 88 * 89 * The relocation is generated against the currently active function 90 * symbol (cur_func_sym) with addend = (label_offset_in_section - 91 * cur_func_start) + extra_addend. If `label` is already placed, the 92 * reloc is emitted immediately; otherwise it is queued and emitted at 93 * label_place time. Callers must have an active function (set by 94 * backend func_begin); panics otherwise. */ 95 void (*emit_label_data_reloc)(MCEmitter*, u32 data_sec, u32 data_offset, 96 MCLabel label, RelocKind kind, u32 width, 97 i64 extra_addend); 98 void (*set_loc)(MCEmitter*, SrcLoc); 99 100 /* ---- CFI / unwind ---- 101 * Buffered per-function and emitted into .debug_frame / .eh_frame by Debug 102 * at TU finalize. CFI directives are byte-position-bound — they describe 103 * the register-save state starting at the current pos() in the current 104 * section — so they live on MCEmitter (the only common point that already 105 * tracks (section_id, offset)). If the CG was constructed with Debug=NULL, 106 * records are discarded. Register numbering is the per-arch DWARF reg 107 * number; offsets are byte deltas from the CFA. */ 108 void (*cfi_startproc)(MCEmitter*); 109 void (*cfi_endproc)(MCEmitter*); 110 void (*cfi_def_cfa)(MCEmitter*, u32 reg, i32 ofs); 111 void (*cfi_def_cfa_offset)(MCEmitter*, i32 ofs); 112 void (*cfi_def_cfa_register)(MCEmitter*, u32 reg); 113 void (*cfi_offset)(MCEmitter*, u32 reg, i32 ofs); 114 void (*cfi_rel_offset)(MCEmitter*, u32 reg, i32 ofs); 115 void (*cfi_restore)(MCEmitter*, u32 reg); 116 /* Override the PC offset used by the *next* cfi_* directive (one-shot). 117 * Backends that patch the prologue in func_end (so the live pc has 118 * moved past the prologue) call this with the post-prologue offset 119 * (relative to cfi_startproc's recorded func_start) before emitting 120 * the frame-state directives. */ 121 void (*cfi_set_next_pc_offset)(MCEmitter*, u32 pc_offset); 122 123 void (*destroy)(MCEmitter*); 124 }; 125 126 /* Construct the right target/emitter pair for c->target. */ 127 MCEmitter* mc_new(Compiler*, ObjBuilder*); 128 void mc_free(MCEmitter*); 129 130 /* Lazily mint (and return) a per-label SB_LOCAL symbol defined at `label`'s 131 * placement. Backends use this to reference a code location relocatably — 132 * `&&label` address-takes emit a PC-relative reloc against it instead of baking 133 * a fixed displacement, so a re-encoding assembler (clang) recomputes the right 134 * address. Forward-ref safe: if `label` is not yet placed the symbol is created 135 * undefined and defined in label_place. */ 136 ObjSymId mc_label_symbol(MCEmitter*, MCLabel label); 137 138 /* Per-function context helpers. Backends call mc_begin_function from 139 * their CgTarget func_begin (after computing the post-alignment function 140 * start) and mc_end_function from func_end. The pair sets / clears 141 * MCEmitter.cur_func_* — the metadata that emit_label_data_reloc reads 142 * to resolve deferred intra-function label fixups in data sections. */ 143 void mc_begin_function(MCEmitter*, ObjSymId sym, u32 section_id, 144 u32 start_offset); 145 void mc_end_function(MCEmitter*); 146 147 /* Flush buffered CFI state into a .eh_frame section in the ObjBuilder. 148 * No-op when no functions called cfi_startproc. Idempotent. */ 149 void mc_emit_eh_frame(MCEmitter*); 150 151 /* Construct the MCEmitter + (optionally) Debug pair that a machine-code 152 * CGBackend's `make` typically needs. On success, sets *out_mc to a fresh 153 * MCEmitter; sets *out_debug to a Debug producer (and wires mc->debug) when 154 * opts->debug_info is true, else NULL. On allocation failure returns 155 * KIT_NOMEM with both outputs left NULL and any partial state cleaned up. 156 * c_target's backend ignores this and does not create either. */ 157 KitStatus cg_mc_debug_new(Compiler*, ObjBuilder*, const KitCodeOptions*, 158 MCEmitter** out_mc, Debug** out_debug); 159 160 /* Helper for backends without a native indexed addressing mode. If addr has 161 * an index (addr.v.ind.index != REG_NONE), materializes 162 * base + (index << log2_scale) into `scratch` and returns a plain 163 * OPK_INDIRECT(scratch, ofs). Otherwise returns `addr` unchanged. The caller 164 * supplies the scratch register from its scratch pool. */ 165 Operand arch_lower_indexed(CgTarget*, Operand addr, Reg scratch); 166 167 #endif