mc.c (30031B)
1 /* Generic MCEmitter implementation. 2 * 3 * MCEmitter sits between CGTarget (or asm_parse) and ObjBuilder. It owns 4 * the current section, byte position, machine label table, and forwards 5 * relocations / source-location stamps. Encoding is the caller's job — 6 * MCEmitter writes whatever bytes it's handed. 7 * 8 * One MCEmitter serves every supported arch. Label fixup encoding delegates 9 * through ArchImpl so MCEmitter owns label bookkeeping only. 10 * 11 * MCLabel handling: ids are 1-based (0 = MC_LABEL_NONE). Each label 12 * carries either a placement (sec_id, offset) or a list of pending 13 * fixups for forward references. emit_label_ref records a fixup; on 14 * label_place, all pending fixups for that label are applied. Fixup 15 * application uses RelocKind to choose how to encode the resolved 16 * displacement into the already-emitted bytes. 17 * 18 * For v1 we support these label-ref reloc kinds for intra-section 19 * fixups: 20 * R_PC32 — write 32-bit signed displacement at fixup ofs 21 * R_AARCH64_CALL26 — 26-bit imm26 << 2 in the BL instruction 22 * R_AARCH64_JUMP26 — same encoding as CALL26 (B vs BL only differs 23 * in the parent opcode the caller already emitted) 24 * 25 * Anything else for a label_ref panics; cross-section references go 26 * through emit_reloc against an ObjSymId instead. */ 27 28 #include <string.h> 29 30 #include "arch/arch.h" 31 #include "core/arena.h" 32 #include "core/buf.h" 33 #include "core/heap.h" 34 #include "core/pool.h" 35 #include "core/strbuf.h" 36 #include "debug/dwarf_defs.h" 37 #include "obj/obj.h" 38 39 typedef struct MCFixup { 40 u32 sec_id; 41 u32 offset; 42 u32 width; /* bytes the encoding occupies */ 43 RelocKind kind; 44 i64 addend; 45 struct MCFixup* next; 46 } MCFixup; 47 48 typedef struct MCDataLabelRef { 49 /* Where in the data section to write the relocation. */ 50 u32 data_sec; 51 u32 data_offset; 52 RelocKind kind; 53 u32 width; 54 i64 extra_addend; 55 struct MCDataLabelRef* next; 56 /* func_sym + func_start are read from MCEmitter at label_place time 57 * (when the label's offset becomes known). Under -O1 the queue-time 58 * call comes during opt IR recording — before any backend func_begin 59 * has set cur_func_* — so capturing them here would be wrong. The 60 * label is always placed inside its owning function's emit, so the 61 * MCEmitter's current function tracks the right symbol at that 62 * moment. */ 63 } MCDataLabelRef; 64 65 typedef struct MCLabelInfo { 66 u8 placed; 67 u8 pad[3]; 68 u32 sec_id; 69 u32 offset; 70 MCFixup* pending; 71 MCDataLabelRef* pending_data; 72 /* Lazily-minted SB_LOCAL symbol for this label, for code-location 73 * references that must survive a re-encoding assembler: switch jump-table 74 * entries (.quad <sym>) and `&&label` address-takes (a PC-relative reloc 75 * against <sym>). OBJ_SYM_NONE until first requested via mc_label_symbol; 76 * defined at the label's offset in m_label_place (forward-ref safe). */ 77 ObjSymId block_sym; 78 } MCLabelInfo; 79 80 /* ---- CFI buffering (.eh_frame producer) ---- 81 * 82 * Each cfi_startproc opens a new FDE record; the per-arch backend then 83 * calls cfi_def_cfa / cfi_offset / cfi_restore as the prologue is laid 84 * down. Each directive snapshots either the current section offset or the 85 * override set by cfi_set_next_pc_offset — which is STICKY until cfi_endproc 86 * (used by backends that emit the whole CFI batch in func_end, after the 87 * epilogue, but want every rule pinned to the post-prologue PC). The 88 * .eh_frame section is synthesised at mc_emit_eh_frame() time. */ 89 typedef enum CfiOpKind { 90 CFI_OP_DEF_CFA, 91 CFI_OP_DEF_CFA_REGISTER, 92 CFI_OP_DEF_CFA_OFFSET, 93 CFI_OP_OFFSET, 94 CFI_OP_REL_OFFSET, 95 CFI_OP_RESTORE, 96 } CfiOpKind; 97 98 typedef struct CfiDirective { 99 u32 pc_offset; /* offset within the function from func_start */ 100 u8 kind; /* CfiOpKind */ 101 u8 pad[3]; 102 u32 reg; 103 i32 imm; 104 } CfiDirective; 105 106 typedef struct CfiFde { 107 ObjSymId func_sym; 108 u32 func_section; 109 u32 func_start; 110 u32 func_end; 111 CfiDirective* directives; 112 u32 ndir; 113 u32 dir_cap; 114 } CfiFde; 115 116 typedef struct MCImpl { 117 MCEmitter base; 118 Arena* arena; 119 /* `loc` lives on MCEmitter base now (so per-arch emit hooks can read it 120 * to feed debug_emit_row). Use base.loc through impl_of(...)->base.loc 121 * or directly mc->base.loc. */ 122 MCLabelInfo* labels; /* index 0 unused (MC_LABEL_NONE) */ 123 u32 nlabels; 124 u32 cap; 125 CfiFde* fdes; 126 u32 nfdes; 127 u32 fdes_cap; 128 i32 cur_fde; 129 u8 eh_frame_emitted; 130 u8 has_pc_override; 131 u8 pad_cfi[2]; 132 u32 pc_override; 133 } MCImpl; 134 135 /* ---- helpers ---- */ 136 137 static MCImpl* impl_of(MCEmitter* m) { return (MCImpl*)m; } 138 139 static void labels_grow(MCImpl* mc, u32 want) { 140 if (want <= mc->cap) return; 141 u32 ncap = mc->cap ? mc->cap * 2 : 16; 142 while (ncap < want) ncap *= 2; 143 MCLabelInfo* nbuf = arena_array(mc->arena, MCLabelInfo, ncap); 144 if (mc->labels) memcpy(nbuf, mc->labels, sizeof(MCLabelInfo) * mc->nlabels); 145 memset(nbuf + mc->nlabels, 0, sizeof(MCLabelInfo) * (ncap - mc->nlabels)); 146 mc->labels = nbuf; 147 mc->cap = ncap; 148 } 149 150 static void emit_label_data_reloc_now(MCImpl* mc, MCLabel label, 151 const MCDataLabelRef* r) { 152 /* Reference the label's per-block local symbol (its value IS the label's 153 * offset) rather than the enclosing function symbol + a baked byte offset. 154 * That makes the entry genuinely relocatable: a third-party assembler that 155 * re-encodes the function to different instruction lengths still resolves it 156 * to the right address (a fixed fn+offset would point into the wrong 157 * instruction). */ 158 ObjSymId sym = mc_label_symbol(&mc->base, label); 159 i64 addend = r->extra_addend; 160 u8 bytes[8]; 161 u32 i; 162 int big_endian = mc->base.c->target.big_endian; 163 /* Patch the inline addend (Mach-O ARM64_RELOC_UNSIGNED reads only the inline 164 * value) and also pass it in the reloc record (ELF RELA / the JIT linker's 165 * link_reloc_apply, where the inline gets overwritten by S + A). Both paths 166 * converge on sym + addend at runtime. */ 167 memset(bytes, 0, sizeof bytes); 168 for (i = 0; i < r->width && i < sizeof bytes; ++i) { 169 u32 shift = big_endian ? (r->width - 1u - i) * 8u : i * 8u; 170 bytes[i] = (u8)((u64)addend >> shift); 171 } 172 obj_patch(mc->base.obj, r->data_sec, r->data_offset, bytes, r->width); 173 mc->base.emit_reloc_at(&mc->base, r->data_sec, r->data_offset, r->kind, sym, 174 addend, /*explicit_addend=*/1, /*pair=*/0); 175 } 176 177 static void apply_fixup(MCImpl* mc, const MCFixup* fx, u32 target_offset) { 178 /* signed displacement from end-of-instruction position to target. */ 179 ArchLabelFixup desc; 180 const ArchImpl* arch; 181 182 memset(&desc, 0, sizeof desc); 183 desc.obj = mc->base.obj; 184 desc.sec_id = fx->sec_id; 185 desc.offset = fx->offset; 186 desc.width = fx->width; 187 desc.kind = fx->kind; 188 desc.disp = (i64)target_offset - (i64)fx->offset + fx->addend; 189 desc.cur_func_sym = mc->base.cur_func_sym; 190 desc.cur_func_start = mc->base.cur_func_start; 191 192 arch = arch_for_compiler(mc->base.c); 193 if (!arch || !arch->apply_label_fixup || 194 arch->apply_label_fixup(mc->base.c, &desc) != 0) { 195 compiler_panic(mc->base.c, mc->base.loc, 196 "MCEmitter: unsupported label-ref reloc kind %d", 197 (int)fx->kind); 198 } 199 } 200 201 /* Lazily mint (and return) a per-label SB_LOCAL symbol defined at the label's 202 * placement, for code-location references an encoding-divergent assembler must 203 * be able to recompute: switch jump-table entries and `&&label` address-takes 204 * relocate against it instead of baking a fixed offset. Created undefined if 205 * the label is not yet placed (a forward reference) and defined in 206 * m_label_place; defined immediately otherwise. The name is per-object-unique 207 * (MCLabel ids are monotonic within a TU). */ 208 ObjSymId mc_label_symbol(MCEmitter* m, MCLabel id) { 209 MCImpl* mc = impl_of(m); 210 MCLabelInfo* li; 211 char buf[40]; 212 StrBuf sb; 213 Sym name; 214 if (id == MC_LABEL_NONE || id >= mc->nlabels) { 215 compiler_panic(m->c, m->loc, "MCEmitter: bad label %u for symbol", 216 (unsigned)id); 217 } 218 li = &mc->labels[id]; 219 if (li->block_sym != OBJ_SYM_NONE) return li->block_sym; 220 strbuf_init(&sb, buf, sizeof buf); 221 strbuf_put_slice(&sb, SLICE_LIT(".Lcfblk.")); 222 strbuf_put_u64(&sb, (u64)id); 223 name = pool_intern_slice(m->c->global, strbuf_slice(&sb)); 224 li->block_sym = obj_symbol(m->obj, name, SB_LOCAL, SK_NOTYPE, 225 li->placed ? li->sec_id : OBJ_SEC_NONE, 226 li->placed ? (u64)li->offset : 0u, 0); 227 return li->block_sym; 228 } 229 230 /* ---- vtable methods ---- */ 231 232 static void m_set_section(MCEmitter* m, u32 section_id) { 233 m->section_id = section_id; 234 } 235 236 static u32 m_pos(MCEmitter* m) { return obj_pos(m->obj, m->section_id); } 237 238 static MCLabel m_label_new(MCEmitter* m) { 239 MCImpl* mc = impl_of(m); 240 if (mc->nlabels == 0) { 241 labels_grow(mc, 1); 242 mc->nlabels = 1; 243 } /* skip 0 */ 244 labels_grow(mc, mc->nlabels + 1); 245 u32 id = mc->nlabels++; 246 MCLabelInfo* li = &mc->labels[id]; 247 li->placed = 0; 248 li->sec_id = 0; 249 li->offset = 0; 250 li->pending = NULL; 251 li->pending_data = NULL; 252 li->block_sym = OBJ_SYM_NONE; 253 return (MCLabel)id; 254 } 255 256 static void m_label_place(MCEmitter* m, MCLabel id) { 257 MCImpl* mc = impl_of(m); 258 if (id == MC_LABEL_NONE || id >= mc->nlabels) { 259 compiler_panic(m->c, mc->base.loc, "MCEmitter: bad label %u", (unsigned)id); 260 } 261 MCLabelInfo* li = &mc->labels[id]; 262 if (li->placed) { 263 compiler_panic(m->c, mc->base.loc, "MCEmitter: label %u placed twice", 264 (unsigned)id); 265 } 266 li->placed = 1; 267 li->sec_id = m->section_id; 268 li->offset = obj_pos(m->obj, m->section_id); 269 /* Define the lazily-minted block symbol (if any) now that the offset is 270 * known — resolves the forward-reference case for jump-table / &&label 271 * relocations emitted before the label was placed. */ 272 if (li->block_sym != OBJ_SYM_NONE) 273 obj_symbol_define(m->obj, li->block_sym, li->sec_id, (u64)li->offset, 0); 274 /* Apply pending intra-section fixups. */ 275 for (MCFixup* fx = li->pending; fx; fx = fx->next) { 276 apply_fixup(mc, fx, li->offset); 277 } 278 li->pending = NULL; 279 /* Resolve any deferred data-section relocations referencing this label. 280 * MCEmitter's cur_func_sym/cur_func_start track the function whose 281 * body is currently being emitted; the label is always placed inside 282 * its owning function's emit, so the active function context matches. */ 283 for (MCDataLabelRef* r = li->pending_data; r; r = r->next) { 284 emit_label_data_reloc_now(mc, id, r); 285 } 286 li->pending_data = NULL; 287 } 288 289 static void m_emit_bytes(MCEmitter* m, const u8* data, size_t n) { 290 obj_write(m->obj, m->section_id, data, n); 291 } 292 293 static void m_emit_fill(MCEmitter* m, size_t n, u8 byte) { 294 u8 buf[64]; 295 memset(buf, byte, sizeof buf); 296 while (n > 0) { 297 size_t k = n < sizeof buf ? n : sizeof buf; 298 obj_write(m->obj, m->section_id, buf, k); 299 n -= k; 300 } 301 } 302 303 static void m_emit_align(MCEmitter* m, u32 align, u8 fill) { 304 if (align <= 1) return; 305 u32 cur = obj_pos(m->obj, m->section_id); 306 u32 misalign = cur & (align - 1); 307 if (misalign == 0) return; 308 m_emit_fill(m, align - misalign, fill); 309 } 310 311 static void m_emit_reloc(MCEmitter* m, RelocKind k, ObjSymId sym, i64 addend) { 312 obj_reloc(m->obj, m->section_id, obj_pos(m->obj, m->section_id), k, sym, 313 addend); 314 } 315 316 static void m_emit_reloc_at(MCEmitter* m, u32 section_id, u32 offset, 317 RelocKind k, ObjSymId sym, i64 addend, 318 int explicit_addend, int pair) { 319 obj_reloc_ex(m->obj, section_id, offset, k, sym, addend, explicit_addend, 320 pair); 321 } 322 323 static void m_emit_label_ref(MCEmitter* m, MCLabel id, RelocKind kind, 324 u32 width, i64 addend) { 325 MCImpl* mc = impl_of(m); 326 if (id == MC_LABEL_NONE || id >= mc->nlabels) { 327 compiler_panic(m->c, mc->base.loc, "MCEmitter: bad label %u", (unsigned)id); 328 } 329 MCLabelInfo* li = &mc->labels[id]; 330 MCFixup* fx = arena_new(mc->arena, MCFixup); 331 fx->sec_id = m->section_id; 332 fx->offset = obj_pos(m->obj, m->section_id) - 333 width; /* fixup site is the just-emitted insn */ 334 fx->width = width; 335 fx->kind = kind; 336 fx->addend = addend; 337 fx->next = NULL; 338 if (li->placed) { 339 apply_fixup(mc, fx, li->offset); 340 } else { 341 fx->next = li->pending; 342 li->pending = fx; 343 } 344 } 345 346 static void m_emit_label_data_reloc(MCEmitter* m, u32 data_sec, u32 data_offset, 347 MCLabel id, RelocKind kind, u32 width, 348 i64 extra_addend) { 349 MCImpl* mc = impl_of(m); 350 MCLabelInfo* li; 351 if (id == MC_LABEL_NONE || id >= mc->nlabels) { 352 compiler_panic(m->c, m->loc, "MCEmitter: bad label %u", (unsigned)id); 353 } 354 li = &mc->labels[id]; 355 if (li->placed) { 356 MCDataLabelRef tmp; 357 tmp.data_sec = data_sec; 358 tmp.data_offset = data_offset; 359 tmp.kind = kind; 360 tmp.width = width; 361 tmp.extra_addend = extra_addend; 362 tmp.next = NULL; 363 emit_label_data_reloc_now(mc, id, &tmp); 364 return; 365 } 366 { 367 MCDataLabelRef* r = arena_new(mc->arena, MCDataLabelRef); 368 r->data_sec = data_sec; 369 r->data_offset = data_offset; 370 r->kind = kind; 371 r->width = width; 372 r->extra_addend = extra_addend; 373 r->next = li->pending_data; 374 li->pending_data = r; 375 } 376 } 377 378 static void m_set_loc(MCEmitter* m, SrcLoc loc) { m->loc = loc; } 379 380 /* CFI: buffered for .eh_frame emission. Backend calls cfi_startproc to 381 * open a per-function FDE record, then cfi_def_cfa / cfi_offset / ... 382 * around the prologue; mc_emit_eh_frame builds the section at TU 383 * finalize. */ 384 385 static void fde_push(MCImpl* mc, u8 kind, u32 reg, i32 imm) { 386 CfiFde* fde; 387 CfiDirective* d; 388 Heap* heap; 389 u32 pc_off; 390 if (mc->cur_fde < 0) { 391 compiler_panic(mc->base.c, mc->base.loc, 392 "MCEmitter: CFI directive outside cfi_startproc"); 393 } 394 fde = &mc->fdes[mc->cur_fde]; 395 if (mc->base.section_id != fde->func_section) { 396 compiler_panic(mc->base.c, mc->base.loc, 397 "MCEmitter: CFI directive in wrong section"); 398 } 399 heap = mc->base.c->ctx->heap; 400 if (fde->ndir == fde->dir_cap) { 401 u32 new_cap = fde->dir_cap ? fde->dir_cap * 2u : 8u; 402 CfiDirective* nbuf = (CfiDirective*)heap->alloc( 403 heap, sizeof(CfiDirective) * new_cap, _Alignof(CfiDirective)); 404 if (!nbuf) compiler_panic(mc->base.c, mc->base.loc, "MCEmitter: CFI OOM"); 405 if (fde->directives) { 406 memcpy(nbuf, fde->directives, sizeof(CfiDirective) * fde->ndir); 407 heap->free(heap, fde->directives, sizeof(CfiDirective) * fde->dir_cap); 408 } 409 fde->directives = nbuf; 410 fde->dir_cap = new_cap; 411 } 412 if (mc->has_pc_override) { 413 /* Sticky until cfi_endproc: every directive in a func_end prologue batch 414 * shares the post-prologue PC set once before cfi_def_cfa. (A one-shot 415 * override only covered the first directive, so the saved-register and 416 * return-address offset rules fell back to obj_pos() — the function END — 417 * making mid-function unwind unable to recover them.) */ 418 pc_off = mc->pc_override; 419 } else { 420 pc_off = obj_pos(mc->base.obj, mc->base.section_id) - fde->func_start; 421 } 422 d = &fde->directives[fde->ndir++]; 423 d->pc_offset = pc_off; 424 d->kind = kind; 425 d->reg = reg; 426 d->imm = imm; 427 } 428 429 static void m_cfi_startproc(MCEmitter* m) { 430 MCImpl* mc = impl_of(m); 431 Heap* heap = m->c->ctx->heap; 432 if (mc->cur_fde >= 0) { 433 compiler_panic(m->c, m->loc, "MCEmitter: nested cfi_startproc"); 434 } 435 if (m->cur_func_sym == OBJ_SYM_NONE) { 436 /* Backend must call mc_begin_function before cfi_startproc; tolerate 437 * the no-op for stand-ins. */ 438 return; 439 } 440 if (mc->nfdes == mc->fdes_cap) { 441 u32 new_cap = mc->fdes_cap ? mc->fdes_cap * 2u : 8u; 442 CfiFde* nbuf = 443 (CfiFde*)heap->alloc(heap, sizeof(CfiFde) * new_cap, _Alignof(CfiFde)); 444 if (!nbuf) compiler_panic(m->c, m->loc, "MCEmitter: CFI OOM"); 445 if (mc->fdes) { 446 memcpy(nbuf, mc->fdes, sizeof(CfiFde) * mc->nfdes); 447 heap->free(heap, mc->fdes, sizeof(CfiFde) * mc->fdes_cap); 448 } 449 mc->fdes = nbuf; 450 mc->fdes_cap = new_cap; 451 } 452 mc->cur_fde = (i32)mc->nfdes; 453 mc->has_pc_override = 0; /* no override carries across an FDE boundary */ 454 { 455 CfiFde* fde = &mc->fdes[mc->nfdes++]; 456 fde->func_sym = m->cur_func_sym; 457 fde->func_section = m->section_id; 458 fde->func_start = obj_pos(m->obj, m->section_id); 459 fde->func_end = fde->func_start; 460 fde->directives = NULL; 461 fde->ndir = 0; 462 fde->dir_cap = 0; 463 } 464 } 465 466 static void m_cfi_endproc(MCEmitter* m) { 467 MCImpl* mc = impl_of(m); 468 CfiFde* fde; 469 if (mc->cur_fde < 0) return; 470 fde = &mc->fdes[mc->cur_fde]; 471 fde->func_end = obj_pos(m->obj, m->section_id); 472 mc->cur_fde = -1; 473 mc->has_pc_override = 474 0; /* the sticky prologue-PC override ends with the FDE */ 475 } 476 477 static void m_cfi_def_cfa(MCEmitter* m, u32 r, i32 o) { 478 MCImpl* mc = impl_of(m); 479 if (mc->cur_fde < 0) return; 480 fde_push(mc, CFI_OP_DEF_CFA, r, o); 481 } 482 static void m_cfi_def_cfa_offset(MCEmitter* m, i32 o) { 483 MCImpl* mc = impl_of(m); 484 if (mc->cur_fde < 0) return; 485 fde_push(mc, CFI_OP_DEF_CFA_OFFSET, 0, o); 486 } 487 static void m_cfi_def_cfa_register(MCEmitter* m, u32 r) { 488 MCImpl* mc = impl_of(m); 489 if (mc->cur_fde < 0) return; 490 fde_push(mc, CFI_OP_DEF_CFA_REGISTER, r, 0); 491 } 492 static void m_cfi_offset(MCEmitter* m, u32 r, i32 o) { 493 MCImpl* mc = impl_of(m); 494 if (mc->cur_fde < 0) return; 495 fde_push(mc, CFI_OP_OFFSET, r, o); 496 } 497 static void m_cfi_rel_offset(MCEmitter* m, u32 r, i32 o) { 498 MCImpl* mc = impl_of(m); 499 if (mc->cur_fde < 0) return; 500 fde_push(mc, CFI_OP_REL_OFFSET, r, o); 501 } 502 static void m_cfi_restore(MCEmitter* m, u32 r) { 503 MCImpl* mc = impl_of(m); 504 if (mc->cur_fde < 0) return; 505 fde_push(mc, CFI_OP_RESTORE, r, 0); 506 } 507 static void m_cfi_set_next_pc_offset(MCEmitter* m, u32 pc_offset) { 508 MCImpl* mc = impl_of(m); 509 mc->has_pc_override = 1; 510 mc->pc_override = pc_offset; 511 } 512 513 static void m_destroy(MCEmitter* m) { (void)m; /* arena-backed */ } 514 515 /* ---- construction ---- */ 516 517 static void mc_cleanup(void* arg) { mc_free((MCEmitter*)arg); } 518 519 MCEmitter* mc_new(Compiler* c, ObjBuilder* o) { 520 MCImpl* mc = arena_new(c->tu, MCImpl); 521 memset(mc, 0, sizeof *mc); 522 523 MCEmitter* base = &mc->base; 524 base->c = c; 525 base->obj = o; 526 base->section_id = OBJ_SEC_NONE; 527 base->cur_func_sym = OBJ_SYM_NONE; 528 base->cur_func_section = 0; 529 base->cur_func_start = 0; 530 531 base->set_section = m_set_section; 532 base->pos = m_pos; 533 534 base->label_new = m_label_new; 535 base->label_place = m_label_place; 536 537 base->emit_bytes = m_emit_bytes; 538 base->emit_fill = m_emit_fill; 539 base->emit_align = m_emit_align; 540 base->emit_reloc = m_emit_reloc; 541 base->emit_reloc_at = m_emit_reloc_at; 542 base->emit_label_ref = m_emit_label_ref; 543 base->emit_label_data_reloc = m_emit_label_data_reloc; 544 base->set_loc = m_set_loc; 545 546 base->cfi_startproc = m_cfi_startproc; 547 base->cfi_endproc = m_cfi_endproc; 548 base->cfi_def_cfa = m_cfi_def_cfa; 549 base->cfi_def_cfa_offset = m_cfi_def_cfa_offset; 550 base->cfi_def_cfa_register = m_cfi_def_cfa_register; 551 base->cfi_offset = m_cfi_offset; 552 base->cfi_rel_offset = m_cfi_rel_offset; 553 base->cfi_restore = m_cfi_restore; 554 base->cfi_set_next_pc_offset = m_cfi_set_next_pc_offset; 555 556 base->destroy = m_destroy; 557 558 mc->arena = c->tu; 559 mc->labels = NULL; 560 mc->nlabels = 0; 561 mc->cap = 0; 562 mc->fdes = NULL; 563 mc->nfdes = 0; 564 mc->fdes_cap = 0; 565 mc->cur_fde = -1; 566 mc->eh_frame_emitted = 0; 567 mc->has_pc_override = 0; 568 mc->pc_override = 0; 569 570 compiler_defer(c, mc_cleanup, base); 571 return base; 572 } 573 574 void mc_free(MCEmitter* m) { 575 MCImpl* mc; 576 Heap* heap; 577 u32 i; 578 if (!m) return; 579 mc = impl_of(m); 580 /* Release any CFI directive buffers when the caller never invoked 581 * mc_emit_eh_frame (e.g. test harness or early teardown). */ 582 if (!mc->eh_frame_emitted && mc->fdes) { 583 heap = m->c->ctx->heap; 584 for (i = 0; i < mc->nfdes; ++i) { 585 if (mc->fdes[i].directives) { 586 heap->free(heap, mc->fdes[i].directives, 587 sizeof(CfiDirective) * mc->fdes[i].dir_cap); 588 } 589 } 590 heap->free(heap, mc->fdes, sizeof(CfiFde) * mc->fdes_cap); 591 mc->fdes = NULL; 592 mc->fdes_cap = 0; 593 mc->nfdes = 0; 594 } 595 } 596 597 void mc_begin_function(MCEmitter* m, ObjSymId sym, u32 section_id, 598 u32 start_offset) { 599 if (!m) return; 600 m->cur_func_sym = sym; 601 m->cur_func_section = section_id; 602 m->cur_func_start = start_offset; 603 } 604 605 void mc_end_function(MCEmitter* m) { 606 if (!m) return; 607 m->cur_func_sym = OBJ_SYM_NONE; 608 m->cur_func_section = 0; 609 m->cur_func_start = 0; 610 } 611 612 /* ============================================================ 613 * .eh_frame emitter 614 * ============================================================ */ 615 616 static void buf_uleb(Buf* b, u64 v) { 617 u8 tmp[10]; 618 u32 n = 0; 619 do { 620 u8 byte = (u8)(v & 0x7fu); 621 v >>= 7; 622 if (v) byte |= 0x80u; 623 tmp[n++] = byte; 624 } while (v); 625 buf_write(b, tmp, n); 626 } 627 628 static void buf_sleb(Buf* b, i64 v) { 629 u8 tmp[10]; 630 u32 n = 0; 631 int more = 1; 632 while (more) { 633 u8 byte = (u8)(v & 0x7fu); 634 v >>= 7; 635 if ((v == 0 && (byte & 0x40u) == 0) || (v == -1 && (byte & 0x40u) != 0)) { 636 more = 0; 637 } else { 638 byte |= 0x80u; 639 } 640 tmp[n++] = byte; 641 } 642 buf_write(b, tmp, n); 643 } 644 645 static void buf_u8(Buf* b, u8 v) { buf_write(b, &v, 1); } 646 647 static void buf_u32le(Buf* b, u32 v) { 648 u8 t[4]; 649 t[0] = (u8)v; 650 t[1] = (u8)(v >> 8); 651 t[2] = (u8)(v >> 16); 652 t[3] = (u8)(v >> 24); 653 buf_write(b, t, 4); 654 } 655 656 static void buf_pad_to(Buf* b, u32 entry_start, u32 align) { 657 u32 cur = buf_pos(b); 658 u32 rel = cur - entry_start; 659 u32 mis = rel & (align - 1u); 660 u32 pad; 661 if (mis == 0) return; 662 pad = align - mis; 663 while (pad--) buf_u8(b, 0); 664 } 665 666 static void encode_cfi_directive(Buf* prog, const CfiDirective* d, u32* cur_loc, 667 i32 code_align, i32 data_align) { 668 u32 delta = d->pc_offset - *cur_loc; 669 if (delta) { 670 u32 fac = (code_align > 0) ? (delta / (u32)code_align) : delta; 671 if (fac < 0x40u) { 672 buf_u8(prog, DW_CFA_advance_loc | (u8)fac); 673 } else if (fac < 0x100u) { 674 buf_u8(prog, DW_CFA_advance_loc1); 675 buf_u8(prog, (u8)fac); 676 } else if (fac < 0x10000u) { 677 buf_u8(prog, DW_CFA_advance_loc2); 678 buf_u8(prog, (u8)(fac & 0xff)); 679 buf_u8(prog, (u8)(fac >> 8)); 680 } else { 681 buf_u8(prog, DW_CFA_advance_loc4); 682 buf_u32le(prog, fac); 683 } 684 *cur_loc = d->pc_offset; 685 } 686 switch ((CfiOpKind)d->kind) { 687 case CFI_OP_DEF_CFA: 688 buf_u8(prog, DW_CFA_def_cfa); 689 buf_uleb(prog, d->reg); 690 buf_uleb(prog, (u64)(d->imm < 0 ? 0 : d->imm)); 691 break; 692 case CFI_OP_DEF_CFA_OFFSET: 693 buf_u8(prog, DW_CFA_def_cfa_offset); 694 buf_uleb(prog, (u64)(d->imm < 0 ? 0 : d->imm)); 695 break; 696 case CFI_OP_DEF_CFA_REGISTER: 697 buf_u8(prog, DW_CFA_def_cfa_register); 698 buf_uleb(prog, d->reg); 699 break; 700 case CFI_OP_OFFSET: { 701 i64 fac; 702 if (data_align == 0) 703 fac = d->imm; 704 else 705 fac = (i64)d->imm / (i64)data_align; 706 if (d->reg < 0x40u && fac >= 0) { 707 buf_u8(prog, DW_CFA_offset | (u8)d->reg); 708 buf_uleb(prog, (u64)fac); 709 } else { 710 buf_u8(prog, DW_CFA_offset_extended_sf); 711 buf_uleb(prog, d->reg); 712 buf_sleb(prog, fac); 713 } 714 } break; 715 case CFI_OP_REL_OFFSET: { 716 i64 fac; 717 if (data_align == 0) 718 fac = d->imm; 719 else 720 fac = (i64)d->imm / (i64)data_align; 721 buf_u8(prog, DW_CFA_offset_extended_sf); 722 buf_uleb(prog, d->reg); 723 buf_sleb(prog, fac); 724 } break; 725 case CFI_OP_RESTORE: 726 if (d->reg < 0x40u) { 727 buf_u8(prog, DW_CFA_restore | (u8)d->reg); 728 } else { 729 buf_u8(prog, DW_CFA_restore_extended); 730 buf_uleb(prog, d->reg); 731 } 732 break; 733 } 734 } 735 736 void mc_emit_eh_frame(MCEmitter* m) { 737 MCImpl* mc; 738 const ArchImpl* arch; 739 Heap* heap; 740 Buf body; 741 ObjSecId eh_sec; 742 Sym sec_name; 743 u32 cie_offset_in_buf; 744 u32 cie_len; 745 u32 entry_start; 746 u32 i; 747 u8 fde_pe; 748 if (!m) return; 749 mc = impl_of(m); 750 if (mc->eh_frame_emitted) return; 751 if (mc->nfdes == 0) { 752 mc->eh_frame_emitted = 1; 753 return; 754 } 755 arch = arch_for_compiler(m->c); 756 if (!arch || arch->cfi_return_addr_reg == 0u) { 757 mc->eh_frame_emitted = 1; 758 return; 759 } 760 /* Freestanding (bare-metal): emit no .eh_frame. kit marks .eh_frame 761 * SF_ALLOC so a hosted unwinder can consume it, but a bare-metal link 762 * (e.g. riscv32-none-elf) has no unwinder and would otherwise have to 763 * /DISCARD/ the orphaned ALLOC section. emits_eh_frame is 0 exactly for 764 * those freestanding targets and 1 for hosted output (linux/macos/windows/ 765 * freebsd/wasi), which is unaffected and byte-identical. */ 766 if (!m->c->target.emits_eh_frame) { 767 heap = m->c->ctx->heap; 768 for (i = 0; i < mc->nfdes; ++i) { 769 if (mc->fdes[i].directives) { 770 heap->free(heap, mc->fdes[i].directives, 771 sizeof(CfiDirective) * mc->fdes[i].dir_cap); 772 mc->fdes[i].directives = NULL; 773 mc->fdes[i].dir_cap = 0; 774 } 775 } 776 if (mc->fdes) { 777 heap->free(heap, mc->fdes, sizeof(CfiFde) * mc->fdes_cap); 778 mc->fdes = NULL; 779 mc->fdes_cap = 0; 780 mc->nfdes = 0; 781 } 782 mc->eh_frame_emitted = 1; 783 return; 784 } 785 heap = m->c->ctx->heap; 786 fde_pe = (u8)(DW_EH_PE_pcrel | DW_EH_PE_sdata4); 787 788 buf_init(&body, heap); 789 790 /* CIE */ 791 cie_offset_in_buf = buf_pos(&body); 792 buf_u32le(&body, 0); 793 entry_start = buf_pos(&body); 794 buf_u32le(&body, 0); /* CIE_id */ 795 buf_u8(&body, 1); /* version */ 796 buf_u8(&body, 'z'); 797 buf_u8(&body, 'R'); 798 buf_u8(&body, 0); 799 buf_uleb(&body, (u64)(u32)arch->cfi_code_align_factor); 800 buf_sleb(&body, (i64)arch->cfi_data_align_factor); 801 buf_uleb(&body, (u64)arch->cfi_return_addr_reg); 802 buf_uleb(&body, 1); 803 buf_u8(&body, fde_pe); 804 buf_u8(&body, DW_CFA_def_cfa); 805 buf_uleb(&body, (u64)arch->cfi_cfa_init_reg); 806 buf_uleb( 807 &body, 808 (u64)(arch->cfi_cfa_init_offset < 0 ? 0 : arch->cfi_cfa_init_offset)); 809 buf_pad_to(&body, entry_start, 4u); 810 cie_len = buf_pos(&body) - entry_start; 811 { 812 u8 lbytes[4]; 813 lbytes[0] = (u8)cie_len; 814 lbytes[1] = (u8)(cie_len >> 8); 815 lbytes[2] = (u8)(cie_len >> 16); 816 lbytes[3] = (u8)(cie_len >> 24); 817 buf_patch(&body, cie_offset_in_buf, lbytes, 4); 818 } 819 820 { 821 u32* pc_slot_rels = 822 (u32*)heap->alloc(heap, sizeof(u32) * mc->nfdes, _Alignof(u32)); 823 ObjSymId* fde_syms = (ObjSymId*)heap->alloc( 824 heap, sizeof(ObjSymId) * mc->nfdes, _Alignof(ObjSymId)); 825 if (!pc_slot_rels || !fde_syms) { 826 if (pc_slot_rels) heap->free(heap, pc_slot_rels, sizeof(u32) * mc->nfdes); 827 if (fde_syms) heap->free(heap, fde_syms, sizeof(ObjSymId) * mc->nfdes); 828 buf_fini(&body); 829 compiler_panic(m->c, m->loc, "MCEmitter: CFI OOM"); 830 } 831 for (i = 0; i < mc->nfdes; ++i) { 832 const CfiFde* fde = &mc->fdes[i]; 833 u32 fde_offset_in_buf = buf_pos(&body); 834 u32 fde_entry_start; 835 u32 fde_len; 836 u32 pc_slot; 837 u32 cur_loc = 0; 838 u32 j; 839 i64 cie_back_off; 840 buf_u32le(&body, 0); 841 fde_entry_start = buf_pos(&body); 842 cie_back_off = (i64)fde_entry_start - (i64)cie_offset_in_buf; 843 buf_u32le(&body, (u32)cie_back_off); 844 pc_slot = buf_pos(&body); 845 pc_slot_rels[i] = pc_slot; 846 fde_syms[i] = fde->func_sym; 847 buf_u32le(&body, 0); /* initial_location (reloc) */ 848 buf_u32le(&body, fde->func_end - fde->func_start); /* range */ 849 buf_uleb(&body, 0); /* aug_data_len = 0 */ 850 for (j = 0; j < fde->ndir; ++j) { 851 encode_cfi_directive(&body, &fde->directives[j], &cur_loc, 852 arch->cfi_code_align_factor, 853 arch->cfi_data_align_factor); 854 } 855 buf_pad_to(&body, fde_entry_start, 4u); 856 fde_len = buf_pos(&body) - fde_entry_start; 857 { 858 u8 lbytes[4]; 859 lbytes[0] = (u8)fde_len; 860 lbytes[1] = (u8)(fde_len >> 8); 861 lbytes[2] = (u8)(fde_len >> 16); 862 lbytes[3] = (u8)(fde_len >> 24); 863 buf_patch(&body, fde_offset_in_buf, lbytes, 4); 864 } 865 } 866 /* Terminator zero-length entry. */ 867 buf_u32le(&body, 0); 868 869 /* Section name: Mach-O wants "__TEXT,__eh_frame", ELF wants 870 * ".eh_frame". The Mach-O emitter splits on comma; the ELF emitter 871 * uses the literal as section name. */ 872 if (m->c->target.obj == KIT_OBJ_MACHO) { 873 sec_name = 874 pool_intern_slice(m->c->global, SLICE_LIT("__TEXT,__eh_frame")); 875 } else { 876 sec_name = pool_intern_slice(m->c->global, SLICE_LIT(".eh_frame")); 877 } 878 eh_sec = obj_section(m->obj, sec_name, SEC_OTHER, SF_ALLOC, 8); 879 { 880 u32 total = buf_pos(&body); 881 u8* bytes = (u8*)heap->alloc(heap, total, 1); 882 if (!bytes) { 883 heap->free(heap, pc_slot_rels, sizeof(u32) * mc->nfdes); 884 heap->free(heap, fde_syms, sizeof(ObjSymId) * mc->nfdes); 885 buf_fini(&body); 886 compiler_panic(m->c, m->loc, "MCEmitter: CFI OOM"); 887 } 888 buf_flatten(&body, bytes); 889 obj_write(m->obj, eh_sec, bytes, total); 890 heap->free(heap, bytes, total); 891 } 892 for (i = 0; i < mc->nfdes; ++i) { 893 /* R_PC32 against the function symbol: linker writes 894 * (S + A - P) into the 4-byte slot, yielding a pc-relative 895 * displacement that the unwinder can decode via DW_EH_PE_pcrel 896 * | DW_EH_PE_sdata4. */ 897 obj_reloc_ex(m->obj, eh_sec, pc_slot_rels[i], R_PC32, fde_syms[i], 898 /*addend=*/0, /*explicit_addend=*/1, /*pair=*/0); 899 } 900 heap->free(heap, pc_slot_rels, sizeof(u32) * mc->nfdes); 901 heap->free(heap, fde_syms, sizeof(ObjSymId) * mc->nfdes); 902 } 903 904 buf_fini(&body); 905 906 for (i = 0; i < mc->nfdes; ++i) { 907 if (mc->fdes[i].directives) { 908 heap->free(heap, mc->fdes[i].directives, 909 sizeof(CfiDirective) * mc->fdes[i].dir_cap); 910 mc->fdes[i].directives = NULL; 911 mc->fdes[i].dir_cap = 0; 912 } 913 } 914 if (mc->fdes) { 915 heap->free(heap, mc->fdes, sizeof(CfiFde) * mc->fdes_cap); 916 mc->fdes = NULL; 917 mc->fdes_cap = 0; 918 mc->nfdes = 0; 919 } 920 mc->eh_frame_emitted = 1; 921 }