kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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