link_jit.c (64244B)
1 /* JIT mapper. Takes a resolved LinkImage, reserves a fresh writable 2 * region (via env->execmem), copies segments, applies relocations 3 * against the runtime base, flips to final permissions, and returns 4 * an owning KitJit handle. 5 * 6 * Lookup is by interned Sym name (object-local handles never escape). 7 * Inspector entries (kit_jit_view, _addr_to_sym, _sym_iter_*) are 8 * stubbed for now — the linker can land without dragging the inspector 9 * surface up. */ 10 11 #include <kit/core.h> 12 #include <kit/jit.h> 13 #include <kit/object.h> 14 #include <string.h> 15 16 #include "core/buf.h" 17 #include "core/bytes.h" 18 #include "core/heap.h" 19 #include "core/metrics.h" 20 #include "core/pool.h" 21 #include "core/slice.h" 22 #include "core/util.h" 23 #include "link/link.h" 24 #include "link/link_arch.h" 25 #include "link/link_internal.h" 26 #include "link/link_reloc_desc.h" 27 #include "obj/obj.h" 28 29 /* Defined in src/api/objfile.c — exposes the underlying ObjBuilder of a 30 * KitObjFile and the internal-only helpers for allocating an empty 31 * KitObjFile (used by the JIT debug-view builder). */ 32 ObjBuilder* kit_objfile_builder(const KitObjFile*); 33 KitObjFile* kit_objfile_internal_new(const KitContext* ctx, 34 KitTargetSpec target, KitObjFmt fmt); 35 void kit_objfile_internal_free(KitObjFile*); 36 #define jit_view_objfile_free(f) kit_objfile_internal_free(f) 37 38 static const KitJitHost* jit_host_from_linker(Linker* l, Compiler* c) { 39 const KitJitHost* host = l ? l->jit_host : NULL; 40 if (!host) 41 compiler_panic(c, SRCLOC_NONE, 42 "kit_jit: link jit host is required for JIT"); 43 return host; 44 } 45 46 static const KitExecMem* require_execmem_h(const KitJitHost* host, 47 Compiler* c) { 48 const KitExecMem* m = host ? host->execmem : NULL; 49 if (!m || !m->reserve || !m->protect || !m->release) { 50 compiler_panic(c, SRCLOC_NONE, 51 "kit_jit: jit host execmem is required for JIT"); 52 } 53 return m; 54 } 55 56 static u64 jit_page_size_h(const KitJitHost* host, Compiler* c) { 57 const KitExecMem* m = require_execmem_h(host, c); 58 return m->page_size ? (u64)m->page_size : 0x4000u; 59 } 60 61 /* Per-segment runtime placement. Each segment gets its own host 62 * reservation. Code segments come back as a dual mapping (write alias / 63 * runtime alias backing the same physical pages); data and rodata are 64 * single-aliased. We populate via the write alias, encode runtime 65 * addresses against the runtime alias, then protect the runtime alias to 66 * its final perms. No virtual page is ever simultaneously writable and 67 * executable. */ 68 struct KitJit { 69 Compiler* c; 70 LinkImage* image; 71 /* Single contiguous reservation covering every segment. All segments 72 * are sub-ranges of this region — runtime/write aliases are derived 73 * by offsetting against (image-vaddr - image_base). Keeping them 74 * inside one mapping guarantees inter-segment displacements stay in 75 * range for ADRP (±4 GiB) and CALL26 (±128 MiB), which would 76 * otherwise depend on the OS placing independent mmap'd segments 77 * close together. */ 78 KitExecMemRegion master; 79 u64 image_base; /* page-aligned image vaddr that maps to master.* */ 80 KitExecMemRegion* segs; /* one per image->nsegments; views into master */ 81 u32 nsegs; 82 /* DWARF view, lazily constructed on first kit_jit_view call. Built 83 * over a private Compiler so its string pools and the new ObjBuilder 84 * are owned end-to-end by the view; freed in kit_jit_free. NULL 85 * means "not yet built"; view_built distinguishes "tried and gave up" 86 * (multi-input v1, etc.) from "untried". */ 87 KitObjFile* view; 88 Linker* linker; /* kept alive for append-time resolver/input context */ 89 u64 append_cursor[SEG_NBUCKETS]; 90 u64 append_limit[SEG_NBUCKETS]; 91 u64 generation; 92 /* Borrowed JIT host: execmem vtable. Mirrors the Linker's 93 * jit_host so the JIT's lifetime accessors don't need to walk back to 94 * the Linker (which is still live behind jit->linker but may be 95 * decoupled in incremental flows). */ 96 const KitJitHost* jit_host; 97 u8 view_built; 98 u8 pad[7]; 99 }; 100 101 #define JIT_APPEND_RX_SLACK (64ull * 1024ull * 1024ull) 102 #define JIT_APPEND_R_SLACK (16ull * 1024ull * 1024ull) 103 #define JIT_APPEND_RW_SLACK (16ull * 1024ull * 1024ull) 104 #define JIT_APPEND_TLS_SLACK (4ull * 1024ull * 1024ull) 105 106 /* RISC-V PCREL_LO12_I/S target a local "anchor" symbol whose vaddr is 107 * the address of the paired AUIPC's PCREL_HI20 (or GOT_HI20) site. 108 * Defined below vaddr_to_runtime. */ 109 static i64 jit_rv_pcrel_lo12_disp(LinkImage* img, KitExecMemRegion* segs, 110 u64 auipc_image_vaddr); 111 112 static int perms_for(u32 secflags) { 113 int p = KIT_PROT_READ; 114 if (secflags & SF_EXEC) p |= KIT_PROT_EXEC; 115 if (secflags & SF_WRITE) p |= KIT_PROT_WRITE; 116 /* JIT TLS storage is the single live instance (the JIT is single-threaded), 117 * accessed and mutated in place, so the TLS segment must be writable — even 118 * though the AOT image treats .tdata/.tbss as a read-only init template that 119 * each thread copies. */ 120 if (secflags & SF_TLS) p |= KIT_PROT_WRITE; 121 return p; 122 } 123 124 /* A reference the single-threaded JIT drops because the format's TLS access 125 * idiom that materializes its target is relaxed in-image. On Windows/COFF the 126 * idiom reads TEB.ThreadLocalStoragePointer, indexes it by the module's 127 * `_tls_index`, then `+ SECREL(var)` — there is no loaded PE for the OS to 128 * assign a `_tls_index`, so jit_tls_le_relax rewrites that load away and the 129 * `_tls_index` ADRP/PC32 relocs must not be applied. The format authority 130 * (obj_format_jit_drops_symbol_ref) owns which symbol that is. */ 131 static int jit_tls_is_index_ref(Compiler* c, const LinkSymbol* tgt) { 132 return tgt && obj_format_jit_drops_symbol_ref(c, tgt->name); 133 } 134 135 /* TLS Local-Exec classifier for the JIT reloc passes, entirely flag-driven: 136 * the per-arch tp-relative idiom and the aa64 COFF SECREL12A pair carry 137 * RELOC_IS_TLS_LE; x86-64's generic COFF SECREL (RELOC_IS_SECREL) is a TLS 138 * access exactly when its target is a TLS symbol. */ 139 static int jit_reloc_is_tls_le(Compiler* c, RelocKind k, u8 tgt_kind) { 140 return reloc_kind_is_tls_le(c, k) || 141 (reloc_kind_is_secrel(c, k) && tgt_kind == SK_TLS); 142 } 143 144 /* Find the segment that contains image-relative `vaddr` and return its 145 * runtime address (the runtime alias, not the write alias). Up to 3 146 * segments after layout, so a linear scan is fine. 147 * 148 * The two-pass shape lets a vaddr that lands exactly on a segment's 149 * one-past-end boundary (e.g. `__fini_array_end` when .fini_array is 150 * the last section in its segment) still resolve, while preferring an 151 * exact start-of-next-segment match when segments happen to abut. */ 152 static uintptr_t vaddr_to_runtime(const LinkImage* img, 153 const KitExecMemRegion* segs, u64 vaddr) { 154 u32 i; 155 for (i = 0; i < img->nsegments; ++i) { 156 const LinkSegment* s = &img->segments[i]; 157 u64 lo = s->vaddr; 158 u64 hi = lo + s->mem_size; 159 if (vaddr >= lo && vaddr < hi) 160 return (uintptr_t)segs[i].runtime + (uintptr_t)(vaddr - lo); 161 } 162 for (i = 0; i < img->nsegments; ++i) { 163 const LinkSegment* s = &img->segments[i]; 164 u64 hi = s->vaddr + s->mem_size; 165 if (vaddr == hi) return (uintptr_t)segs[i].runtime + (uintptr_t)s->mem_size; 166 } 167 return 0; 168 } 169 170 /* Same as above but returns the WRITE-alias address — used to determine 171 * the byte position at which to apply a relocation. The PC-relative 172 * arithmetic in link_reloc_apply uses the runtime address; the bytes 173 * themselves get patched at the matching offset of the write alias. */ 174 static uintptr_t vaddr_to_write(const LinkImage* img, 175 const KitExecMemRegion* segs, u64 vaddr) { 176 u32 i; 177 for (i = 0; i < img->nsegments; ++i) { 178 const LinkSegment* s = &img->segments[i]; 179 u64 lo = s->vaddr; 180 u64 hi = lo + s->mem_size; 181 if (vaddr >= lo && vaddr < hi) 182 return (uintptr_t)segs[i].write + (uintptr_t)(vaddr - lo); 183 } 184 for (i = 0; i < img->nsegments; ++i) { 185 const LinkSegment* s = &img->segments[i]; 186 u64 hi = s->vaddr + s->mem_size; 187 if (vaddr == hi) return (uintptr_t)segs[i].write + (uintptr_t)s->mem_size; 188 } 189 return 0; 190 } 191 192 /* See forward decl above. Find the paired AUIPC PCREL_HI20/GOT_HI20 193 * reloc whose write_vaddr matches the anchor target, recompute the 194 * displacement using runtime addresses, and return it so the 195 * link_reloc_apply LO12_I/S encoder produces matching low-12 bits. 196 * 197 * Linear scan; reloc counts are small even for full JIT images. */ 198 static i64 jit_rv_pcrel_lo12_disp(LinkImage* img, KitExecMemRegion* segs, 199 u64 auipc_image_vaddr) { 200 u32 n = LinkRelocs_count(&img->relocs); 201 u32 i; 202 for (i = 0; i < n; ++i) { 203 const LinkRelocApply* hi = LinkRelocs_at(&img->relocs, i); 204 const LinkSymbol* hi_tgt; 205 u64 hi_S, hi_P; 206 if (!reloc_kind_is_pcrel_anchor(img->c, hi->kind)) continue; 207 if (hi->write_vaddr != auipc_image_vaddr) continue; 208 hi_tgt = LinkSyms_at(&img->syms, hi->target - 1); 209 if (!hi_tgt) continue; 210 if (hi_tgt->kind == SK_ABS) 211 hi_S = hi_tgt->vaddr; 212 else 213 hi_S = (u64)vaddr_to_runtime(img, segs, hi_tgt->vaddr); 214 hi_P = (u64)vaddr_to_runtime(img, segs, hi->write_vaddr); 215 return (i64)hi_S + hi->addend - (i64)hi_P; 216 } 217 compiler_panic(img->c, SRCLOC_NONE, 218 "kit_jit: RV PCREL_LO12 at 0x%llx has no paired PCREL_HI20", 219 (unsigned long long)auipc_image_vaddr); 220 return 0; 221 } 222 223 static void jit_copy_input_section_bytes(LinkImage* img, 224 const KitExecMemRegion* segs) { 225 Compiler* c = img->c; 226 Linker* l = img->linker; 227 u32 i; 228 for (i = 0; i < img->nsections; ++i) { 229 const LinkSection* ls = &img->sections[i]; 230 const LinkSegment* seg; 231 ObjBuilder* ob; 232 const Section* s; 233 u32 input_idx; 234 u8* dst; 235 if (ls->input_id == LINK_INPUT_NONE) continue; 236 input_idx = ls->input_id - 1u; 237 if (ls->segment_id == LINK_SEG_NONE || ls->segment_id > img->nsegments) 238 compiler_panic(c, SRCLOC_NONE, 239 "kit_jit_from_image: section has invalid segment"); 240 seg = &img->segments[ls->segment_id - 1u]; 241 ob = (input_idx < img->dbg_objs_n) ? img->dbg_objs[input_idx] : NULL; 242 if (!ob && l && input_idx < LinkInputs_count(&l->inputs)) 243 ob = LinkInputs_at(&l->inputs, input_idx)->obj; 244 if (!ob) 245 compiler_panic(c, SRCLOC_NONE, 246 "kit_jit_from_image: input section bytes unavailable"); 247 s = obj_section_get(ob, ls->obj_section_id); 248 if (!s || s->sem == SSEM_NOBITS || s->kind == SEC_BSS) continue; 249 if (ls->size == 0) continue; 250 dst = (u8*)segs[seg->id - 1u].write + (size_t)(ls->vaddr - seg->vaddr); 251 metrics_count(c, "jit.input_section_bytes", ls->size); 252 buf_read(&s->bytes, (u32)ls->obj_offset, dst, (size_t)ls->size); 253 } 254 } 255 256 /* Opaque user data for the JitRelaxCtx.resolve_pair callback: the arch hook 257 * (RISC-V PCREL_LO12) gets the paired AUIPC's runtime displacement without 258 * reaching into LinkImage itself. */ 259 typedef struct { 260 LinkImage* img; 261 KitExecMemRegion* segs; 262 } JitPairResolve; 263 264 static i64 jit_resolve_pcrel_pair(void* user, u64 anchor_vaddr) { 265 JitPairResolve* p = (JitPairResolve*)user; 266 return jit_rv_pcrel_lo12_disp(p->img, p->segs, anchor_vaddr); 267 } 268 269 /* Apply one relocation against the JIT runtime base. Shared by the bulk 270 * from-image pass and the incremental-append pass so their reloc handling can 271 * never drift. Patch-site bytes go through the write alias; PC-relative 272 * arithmetic uses the runtime alias. 273 * 274 * Order mirrors the resolution chain: drop Windows `_tls_index` refs, relax 275 * Local-Exec TLS via the arch idiom hook, then resolve S and offer the reloc 276 * to the arch's JIT-relaxation hook (TLV / GOT / weak-undef / RISC-V pcrel 277 * pairing) before the ordinary apply. `got_relaxed` is 1 on the append path 278 * (no real GOT was built) and 0 for the full link (where .got slots exist). */ 279 static void jit_apply_reloc(Compiler* c, LinkImage* img, KitExecMemRegion* segs, 280 const LinkRelocApply* r, int got_relaxed) { 281 const LinkSymbol* tgt = LinkSyms_at(&img->syms, r->target - 1); 282 const LinkArchDesc* d; 283 JitPairResolve pair; 284 JitRelaxCtx ctx; 285 u64 S, P; 286 u8* P_bytes; 287 288 /* Windows TLS idiom `_tls_index` references are dropped: the access is 289 * relaxed to in-image addressing, so the index load is rewritten away. */ 290 if (jit_tls_is_index_ref(c, tgt)) return; 291 292 /* Local-Exec TLS -> in-image addressing (single-threaded JIT). The per-arch 293 * idiom rewrite lives behind LinkArchDesc.jit_tls_le_relax; this stays 294 * arch-neutral, classifying ELF via RELOC_IS_TLS_LE and the COFF Windows 295 * idiom via its terminal SECREL reloc(s). */ 296 if (jit_reloc_is_tls_le(c, r->kind, tgt->kind)) { 297 u64 storage = (tgt->kind == SK_ABS) 298 ? tgt->vaddr + (u64)r->addend 299 : (u64)vaddr_to_runtime(img, segs, tgt->vaddr) + 300 (u64)r->addend; 301 u8* bytes = (u8*)vaddr_to_write(img, segs, r->write_vaddr); 302 u64 site_pc = (u64)vaddr_to_runtime(img, segs, r->write_vaddr); 303 d = link_arch_desc_for(c); 304 if (!d || !d->jit_tls_le_relax || !bytes) 305 compiler_panic(c, SRCLOC_NONE, 306 "kit_jit: target has no TLS Local-Exec relaxation"); 307 d->jit_tls_le_relax(c, r->kind, bytes, storage, site_pc); 308 return; 309 } 310 311 /* extern resolver result OR true absolute symbol — vaddr already holds the 312 * runtime address; otherwise map the image vaddr to its runtime alias. */ 313 S = (tgt->kind == SK_ABS) ? tgt->vaddr 314 : (u64)vaddr_to_runtime(img, segs, tgt->vaddr); 315 P = (u64)vaddr_to_runtime(img, segs, r->write_vaddr); 316 P_bytes = (u8*)vaddr_to_write(img, segs, r->write_vaddr); 317 if (!P_bytes) 318 compiler_panic(c, SRCLOC_NONE, "kit_jit: relocation site is unmapped"); 319 320 /* Arch JIT relaxation: collapse the runtime indirection (Mach-O TLV 321 * descriptor call, GOT load on the append path, weak-undef zeroing, RISC-V 322 * PCREL_LO12 anchor recompute) to direct in-image addressing. Returns 1 if 323 * it owned the kind; otherwise fall through to the ordinary apply. */ 324 pair.img = img; 325 pair.segs = segs; 326 ctx.site = P_bytes; 327 ctx.S = S; 328 ctx.addend = r->addend; 329 ctx.site_pc = P; 330 ctx.weak_undef_zero = 331 (tgt->bind == SB_WEAK && tgt->kind == SK_ABS && tgt->vaddr == 0); 332 ctx.got_relaxed = got_relaxed; 333 ctx.resolve_pair = jit_resolve_pcrel_pair; 334 ctx.resolve_user = &pair; 335 ctx.anchor_vaddr = tgt->vaddr; 336 d = link_arch_desc_for(c); 337 if (d && d->jit_reloc_relax && d->jit_reloc_relax(c, r->kind, &ctx)) return; 338 339 link_reloc_apply(c, r->kind, P_bytes, S, r->addend, P); 340 } 341 342 KitJit* kit_jit_from_image(LinkImage* img) { 343 Compiler* c; 344 Heap* heap; 345 const KitExecMem* mem; 346 const KitJitHost* host; 347 KitJit* jit; 348 KitExecMemRegion* segs; 349 KitExecMemRegion master; 350 u64 page; 351 u64 image_base = (u64)-1; 352 u64 image_end = 0; 353 u64 append_start; 354 u64 append_total; 355 u64 master_size; 356 int needs_exec = 0; 357 int needs_input_materialize = 0; 358 u32 i; 359 360 if (!img) return NULL; 361 c = img->c; 362 heap = img->heap; 363 host = jit_host_from_linker(img->linker, c); 364 mem = require_execmem_h(host, c); 365 page = jit_page_size_h(host, c); 366 367 /* Compute the span all segments must fit inside. Layout guarantees 368 * each segment's vaddr is page-aligned (layout_segments / layout_got 369 * align via ALIGN_UP at the page size), so the offset within the 370 * master mapping is (vaddr - image_base). An empty JIT image has no 371 * initial segments, but still owns append slack so the debugger can 372 * start from an empty translation unit and append code later. */ 373 if (img->nsegments == 0) { 374 image_base = page; 375 image_end = page; 376 needs_exec = 1; 377 } else { 378 for (i = 0; i < img->nsegments; ++i) { 379 const LinkSegment* seg = &img->segments[i]; 380 u64 hi = ALIGN_UP(seg->vaddr + seg->mem_size, page); 381 if (seg->vaddr < image_base) image_base = seg->vaddr; 382 if (hi > image_end) image_end = hi; 383 if (seg->flags & SF_EXEC) needs_exec = 1; 384 } 385 } 386 if (image_base & (page - 1u)) 387 compiler_panic(c, SRCLOC_NONE, 388 "kit_jit_from_image: segment vaddr not page-aligned"); 389 append_start = image_end; 390 append_total = JIT_APPEND_RX_SLACK + JIT_APPEND_R_SLACK + 391 JIT_APPEND_RW_SLACK + JIT_APPEND_TLS_SLACK; 392 master_size = (image_end - image_base) + append_total; 393 metrics_count(c, "jit.master_size", master_size); 394 metrics_count(c, "jit.nsegments", img->nsegments); 395 396 /* One reservation for the whole image. Requesting EXEC if any segment 397 * is exec triggers the dual-mapping path on Apple silicon; non-exec 398 * regions just leave the alternate alias unused. Per-segment final 399 * perms are applied via mem->protect on sub-ranges below. */ 400 { 401 int master_prot = KIT_PROT_READ | KIT_PROT_WRITE; 402 if (needs_exec) master_prot |= KIT_PROT_EXEC; 403 metrics_scope_begin(c, "jit.reserve"); 404 if (mem->reserve(mem->user, (size_t)master_size, master_prot, &master) != 405 0) { 406 compiler_panic(c, SRCLOC_NONE, 407 "kit_jit_from_image: execmem.reserve failed"); 408 } 409 metrics_scope_end(c, "jit.reserve"); 410 } 411 412 segs = NULL; 413 if (img->nsegments) { 414 segs = (KitExecMemRegion*)heap->alloc(heap, sizeof(*segs) * img->nsegments, 415 _Alignof(KitExecMemRegion)); 416 if (!segs) { 417 mem->release(mem->user, &master); 418 compiler_panic(c, SRCLOC_NONE, 419 "kit_jit_from_image: oom on segment table"); 420 } 421 memset(segs, 0, sizeof(*segs) * img->nsegments); 422 } 423 424 /* Subdivide the master mapping. segs[i].token stays NULL — the 425 * master reservation owns the underlying mapping and is released in 426 * kit_jit_free. */ 427 for (i = 0; i < img->nsegments; ++i) { 428 const LinkSegment* seg = &img->segments[i]; 429 u64 off = seg->vaddr - image_base; 430 size_t mlen = (size_t)ALIGN_UP(seg->mem_size, page); 431 segs[i].write = (u8*)master.write + off; 432 segs[i].runtime = (u8*)master.runtime + off; 433 segs[i].size = mlen; 434 segs[i].token = NULL; 435 } 436 /* Master reservation is zeroed; BSS is naturally zero. */ 437 438 /* Copy synthetic segment buffers to their write aliases. In JIT mode, 439 * ordinary input-section segments intentionally have NULL payload buffers 440 * and are materialized directly from input Buf chunks below. */ 441 metrics_scope_begin(c, "jit.copy_segments"); 442 for (i = 0; i < img->nsegments; ++i) { 443 const LinkSegment* seg = &img->segments[i]; 444 if (seg->file_size == 0) continue; 445 if (!img->segment_bytes[i]) { 446 needs_input_materialize = 1; 447 continue; 448 } 449 metrics_count(c, "jit.segment_bytes", seg->file_size); 450 memcpy(segs[i].write, img->segment_bytes[i], (size_t)seg->file_size); 451 } 452 if (needs_input_materialize) { 453 if (!img->linker || !img->linker->jit_mode) 454 compiler_panic(c, SRCLOC_NONE, 455 "kit_jit_from_image: segment bytes are not materialized"); 456 jit_copy_input_section_bytes(img, segs); 457 } 458 metrics_scope_end(c, "jit.copy_segments"); 459 460 /* Apply relocations. The patch site bytes go through the write 461 * alias; PC-relative arithmetic uses the runtime alias address. */ 462 metrics_scope_begin(c, "jit.apply_relocs"); 463 for (i = 0; i < LinkRelocs_count(&img->relocs); ++i) { 464 /* got_relaxed=0: the full from-image link ran GOT layout, so .got slots 465 * exist and GOT loads apply normally (S points at the slot). */ 466 jit_apply_reloc(c, img, segs, LinkRelocs_at(&img->relocs, i), 0); 467 } 468 metrics_scope_end(c, "jit.apply_relocs"); 469 470 /* Flip the runtime alias of each segment to its final perms. The 471 * write alias is unaffected (still RW for any segment we'd want to 472 * write to from JITed code; for EXEC segments the write alias is 473 * orphaned after this point — JITed code is not expected to write 474 * to its own code). Each segs[i] is a sub-range of master; protect 475 * accepts arbitrary [addr,size) inside the reservation. */ 476 metrics_scope_begin(c, "jit.protect"); 477 for (i = 0; i < img->nsegments; ++i) { 478 const LinkSegment* seg = &img->segments[i]; 479 if (mem->protect(mem->user, segs[i].runtime, segs[i].size, 480 perms_for(seg->flags)) != 0) { 481 mem->release(mem->user, &master); 482 if (segs) heap->free(heap, segs, sizeof(*segs) * img->nsegments); 483 compiler_panic(c, SRCLOC_NONE, 484 "kit_jit_from_image: execmem.protect failed"); 485 } 486 } 487 if (append_total) { 488 void* slack_rt = 489 (u8*)master.runtime + (uintptr_t)(append_start - image_base); 490 (void)mem->protect(mem->user, slack_rt, (size_t)append_total, 491 KIT_PROT_NONE); 492 } 493 metrics_scope_end(c, "jit.protect"); 494 495 /* Flush only the segments that will be executed, against the 496 * runtime alias (the address from which the CPU will fetch). */ 497 if (mem->flush_icache) { 498 metrics_scope_begin(c, "jit.flush_icache"); 499 for (i = 0; i < img->nsegments; ++i) { 500 const LinkSegment* seg = &img->segments[i]; 501 if (seg->flags & SF_EXEC) 502 mem->flush_icache(mem->user, segs[i].runtime, segs[i].size); 503 } 504 metrics_scope_end(c, "jit.flush_icache"); 505 } 506 507 /* IFUNC pre-resolution: now that code is executable and slots are 508 * writable, walk every (resolver_vaddr, slot_vaddr) pair, call the 509 * resolver in-process, and store its return value into the slot's 510 * runtime address. The iplt stub then loads the slot and tail- 511 * calls the chosen implementation on every invocation. */ 512 if (img->niplt) { 513 typedef void* (*ResolverFn)(void); 514 for (i = 0; i < img->niplt; ++i) { 515 u64 resolver_vaddr = img->iplt_pairs[2u * i + 0]; 516 u64 slot_vaddr = img->iplt_pairs[2u * i + 1]; 517 uintptr_t resolver_rt = vaddr_to_runtime(img, segs, resolver_vaddr); 518 uintptr_t slot_rt = vaddr_to_runtime(img, segs, slot_vaddr); 519 void* impl; 520 if (!resolver_rt || !slot_rt) 521 compiler_panic(c, SRCLOC_NONE, 522 "kit_jit: iplt vaddr does not map to runtime"); 523 impl = ((ResolverFn)resolver_rt)(); 524 *(void**)(uintptr_t)slot_rt = impl; 525 } 526 } 527 528 jit = (KitJit*)heap->alloc(heap, sizeof(*jit), _Alignof(KitJit)); 529 if (!jit) { 530 mem->release(mem->user, &master); 531 if (segs) heap->free(heap, segs, sizeof(*segs) * img->nsegments); 532 compiler_panic(c, SRCLOC_NONE, "kit_jit_from_image: oom on jit handle"); 533 } 534 jit->c = c; 535 jit->image = img; 536 jit->master = master; 537 jit->image_base = image_base; 538 jit->segs = segs; 539 jit->nsegs = img->nsegments; 540 jit->view = NULL; 541 jit->linker = img->linker; 542 jit->append_cursor[SEG_RX] = append_start; 543 jit->append_limit[SEG_RX] = jit->append_cursor[SEG_RX] + JIT_APPEND_RX_SLACK; 544 jit->append_cursor[SEG_R] = jit->append_limit[SEG_RX]; 545 jit->append_limit[SEG_R] = jit->append_cursor[SEG_R] + JIT_APPEND_R_SLACK; 546 jit->append_cursor[SEG_RW] = jit->append_limit[SEG_R]; 547 jit->append_limit[SEG_RW] = jit->append_cursor[SEG_RW] + JIT_APPEND_RW_SLACK; 548 jit->append_cursor[SEG_TLS] = jit->append_limit[SEG_RW]; 549 jit->append_limit[SEG_TLS] = 550 jit->append_cursor[SEG_TLS] + JIT_APPEND_TLS_SLACK; 551 jit->generation = 0; 552 jit->view_built = 0u; 553 jit->jit_host = host; 554 555 /* Take ownership of the image: undefer it from the compiler so a 556 * future panic doesn't reap something we still hold. */ 557 if (img->deferred) { 558 compiler_undefer(c, img->deferred); 559 img->deferred = NULL; 560 } 561 if (jit->linker && jit->linker->deferred) { 562 compiler_undefer(c, jit->linker->deferred); 563 jit->linker->deferred = NULL; 564 } 565 566 /* Run .init_array constructors in forward order. */ 567 { 568 typedef void (*VoidFn)(void); 569 void* p_start = kit_jit_lookup(jit, KIT_SLICE_LIT("__init_array_start")); 570 void* p_end = kit_jit_lookup(jit, KIT_SLICE_LIT("__init_array_end")); 571 if (p_start && p_end) { 572 VoidFn* fn = (VoidFn*)p_start; 573 VoidFn* end = (VoidFn*)p_end; 574 metrics_scope_begin(c, "jit.ctors"); 575 for (; fn != end; ++fn) 576 if (*fn) (*fn)(); 577 metrics_scope_end(c, "jit.ctors"); 578 } 579 } 580 581 return jit; 582 } 583 584 const KitExecMem* kit_jit_image_execmem(KitJit* jit) { 585 if (!jit || !jit->jit_host) return NULL; 586 return jit->jit_host->execmem; 587 } 588 589 void kit_jit_free(KitJit* jit) { 590 Heap* heap; 591 const KitExecMem* mem; 592 if (!jit) return; 593 heap = (Heap*)jit->c->ctx->heap; 594 mem = jit->jit_host ? jit->jit_host->execmem : NULL; 595 /* The debug view (if built) is closed first — it owns a private 596 * Compiler whose pools must be released before the image's 597 * referenced builders are freed in link_image_free. */ 598 if (jit->view) { 599 jit_view_objfile_free(jit->view); 600 jit->view = NULL; 601 } 602 /* segs[] are views into master — release master only. */ 603 if (mem && mem->release && jit->master.size) { 604 mem->release(mem->user, &jit->master); 605 } 606 if (jit->segs) { 607 heap->free(heap, jit->segs, sizeof(*jit->segs) * jit->nsegs); 608 } 609 if (jit->image) { 610 /* link_image_free unfederes (no-op now) and releases storage. */ 611 link_image_free(jit->image); 612 } 613 if (jit->linker) { 614 link_free(jit->linker); 615 jit->linker = NULL; 616 } 617 heap->free(heap, jit, sizeof(*jit)); 618 } 619 620 void* kit_jit_lookup(KitJit* jit, KitSlice name) { 621 Sym sym; 622 LinkSymId id; 623 const LinkSymbol* s; 624 if (!jit || !name.s) return NULL; 625 /* C-symbol mangling lives in obj_format_c_mangle so JIT lookups by 626 * source-level name find the symbol regardless of target format. 627 * name.s is NUL-terminated (KIT_SLICE_LIT / kit_slice_cstr / interned). 628 */ 629 sym = obj_format_c_mangle(jit->c, name.s); 630 id = symhash_get(&jit->image->globals, sym); 631 if (id == LINK_SYM_NONE) return NULL; 632 s = LinkSyms_at(&jit->image->syms, id - 1); 633 if (!s) return NULL; 634 if (!s->defined) return NULL; 635 if (s->kind == SK_ABS) return (void*)(uintptr_t)s->vaddr; 636 return (void*)vaddr_to_runtime(jit->image, jit->segs, s->vaddr); 637 } 638 639 void* kit_jit_tls_addr(KitJit* jit, void* sym_addr) { 640 /* Resolve a thread-local's in-image storage from the address its SYMBOL 641 * resolves to (single-threaded JIT: the in-image .tdata/.tbss is the single 642 * instance — see the TLVP relaxation in kit_jit_from_image). 643 * 644 * - Mach-O: the symbol resolves to a 24-byte TLV descriptor; its +16 slot 645 * holds the variable's in-image storage address (the normal R_ABS64 646 * against the storage symbol, applied during the reloc pass). 647 * - ELF/COFF: the symbol already resolves to the in-image storage. 648 * 649 * Returns NULL for anything outside this image's reservation — e.g. a 650 * foreign/extern thread-local resolved through the host (dlsym) — which we 651 * must not dereference. The interpreter relies on this NULL to diagnose 652 * cleanly rather than treat a foreign pointer as our storage. */ 653 u8* p = (u8*)sym_addr; 654 u8* lo = (u8*)jit->master.runtime; 655 u8* hi = lo + jit->master.size; 656 if (!jit || !p) return NULL; 657 if (!jit->master.runtime || p < lo || p >= hi) return NULL; 658 if (obj_format_tls_via_descriptor(jit->c)) { 659 void* storage; 660 if (p + 24u > hi) return NULL; 661 memcpy(&storage, p + 16u, sizeof storage); 662 return storage; 663 } 664 return p; 665 } 666 667 uint64_t kit_jit_generation(KitJit* jit) { return jit ? jit->generation : 0; } 668 669 typedef struct JitAppendSec { 670 ObjSecId obj_sec; 671 ObjAtomId obj_atom; 672 LinkSectionId link_sec; 673 LinkSegmentId link_seg; 674 SegBucket bucket; 675 u64 obj_offset; 676 u64 vaddr; 677 u64 size; 678 u64 file_size; 679 u32 align; 680 u16 flags; 681 u16 sem; 682 Sym name; 683 } JitAppendSec; 684 685 SEGVEC_DEFINE(JitAppendSecs, JitAppendSec, 4); 686 687 static InputMap jit_input_map_alloc(KitJit* jit, ObjBuilder* ob) { 688 InputMap m; 689 ObjSymIter* it; 690 ObjSymEntry e; 691 u32 nsyms = 0; 692 it = obj_symiter_new(ob); 693 while (obj_symiter_next(it, &e)) ++nsyms; 694 obj_symiter_free(it); 695 link_input_map_alloc(jit->image, &m, ob, nsyms + 1u); 696 return m; 697 } 698 699 static void jit_invalidate_view(KitJit* jit) { 700 if (jit->view) { 701 jit_view_objfile_free(jit->view); 702 jit->view = NULL; 703 } 704 jit->view_built = 0u; 705 } 706 707 /* Incremental-append reloc apply. Delegates to the shared jit_apply_reloc 708 * with got_relaxed=1: the append path does not re-run GOT layout, so GOT loads 709 * in the appended object are relaxed to direct in-image addressing. */ 710 static void jit_apply_one_reloc(KitJit* jit, const LinkRelocApply* r) { 711 jit_apply_reloc(jit->c, jit->image, jit->segs, r, 1); 712 } 713 714 static void jit_append_obj_inner(KitJit* jit, ObjBuilder* ob) { 715 LinkImage* img = jit->image; 716 Heap* h = img->heap; 717 const KitExecMem* mem = require_execmem_h(jit->jit_host, jit->c); 718 u64 page = jit_page_size_h(jit->jit_host, jit->c); 719 u32 old_nsections = img->nsections; 720 u32 old_nsegments = img->nsegments; 721 u32 old_nsegs = jit->nsegs; 722 u32 old_nmaps = img->ninput_maps; 723 u32 old_dbg_n = img->dbg_objs_n; 724 u32 old_nrelocs = LinkRelocs_count(&img->relocs); 725 u64 old_cursor[SEG_NBUCKETS]; 726 InputMap m; 727 JitAppendSecs secs; 728 u32 nsecs = 0; 729 u32 obj_sec_count; 730 u64 cursor[SEG_NBUCKETS]; 731 LinkInputId new_input_id; 732 u32 new_input_idx; 733 ObjSymIter* it; 734 ObjSymEntry e; 735 u32 i; 736 737 JitAppendSecs_init(&secs, h); 738 for (i = 0; i < SEG_NBUCKETS; ++i) old_cursor[i] = jit->append_cursor[i]; 739 740 if (!jit || !ob || !jit->linker || obj_compiler(ob) != jit->c) 741 compiler_panic(jit ? jit->c : NULL, SRCLOC_NONE, 742 "kit_jit_append_obj: object is not appendable"); 743 744 /* Preflight duplicate strong definitions and unresolved references before 745 * mutating image-visible state. */ 746 it = obj_symiter_new(ob); 747 while (obj_symiter_next(it, &e)) { 748 const ObjSym* s = e.sym; 749 if (link_sym_is_spurious_undef(s)) continue; 750 if (link_sym_is_def(s) && s->name != 0 && 751 (s->bind == SB_GLOBAL || s->bind == SB_WEAK)) { 752 LinkSymId existing = symhash_get(&img->globals, s->name); 753 if (existing != LINK_SYM_NONE) { 754 LinkSymbol* prev = LinkSyms_at(&img->syms, existing - 1); 755 if (prev && prev->defined && 756 link_bind_strength((u8)s->bind) == link_bind_strength(SB_GLOBAL) && 757 link_bind_strength(prev->bind) == link_bind_strength(SB_GLOBAL)) { 758 Slice nm_s = pool_slice(jit->c->global, s->name); 759 const char* nm = nm_s.s; 760 size_t namelen = nm_s.len; 761 obj_format_demangle_c(jit->c, &nm, &namelen); 762 obj_symiter_free(it); 763 compiler_panic(jit->c, SRCLOC_NONE, 764 "kit_jit_append_obj: duplicate global '%.*s'", 765 (int)namelen, nm); 766 } 767 } 768 } else if (!link_sym_is_def(s) && s->name != 0) { 769 LinkSymId hit = symhash_get(&img->globals, s->name); 770 int ok = 0; 771 if (hit != LINK_SYM_NONE) { 772 LinkSymbol* def = LinkSyms_at(&img->syms, hit - 1); 773 if (def && def->defined) ok = 1; 774 } 775 if (!ok) { 776 ObjSymIter* it2 = obj_symiter_new(ob); 777 ObjSymEntry e2; 778 while (obj_symiter_next(it2, &e2)) { 779 const ObjSym* d = e2.sym; 780 if (d && d->name == s->name && link_sym_is_def(d) && 781 (d->bind == SB_GLOBAL || d->bind == SB_WEAK)) { 782 ok = 1; 783 break; 784 } 785 } 786 obj_symiter_free(it2); 787 } 788 if (!ok && jit->linker->resolver) { 789 Slice nm_s = pool_slice(jit->c->global, s->name); 790 if (jit->linker->resolver(jit->linker->resolver_user, nm_s)) ok = 1; 791 } 792 if (!ok && s->bind == SB_WEAK) ok = 1; 793 if (!ok) { 794 Slice nm_s = pool_slice(jit->c->global, s->name); 795 const char* nm = nm_s.s; 796 size_t nlen = nm_s.len; 797 if (nm && nlen == 15u && memcmp(nm, "__tlv_bootstrap", 15u) == 0) 798 ok = 1; 799 /* Windows COFF TLS module-index symbol: the JIT relaxes every TLS 800 * access to in-image addressing, so `_tls_index` is never read. */ 801 if (nm && nlen == 10u && memcmp(nm, "_tls_index", 10u) == 0) 802 ok = 1; 803 if (!ok) { 804 obj_format_demangle_c(jit->c, &nm, &nlen); 805 obj_symiter_free(it); 806 compiler_panic(jit->c, SRCLOC_NONE, 807 "kit_jit_append_obj: undefined reference to '%.*s'", 808 (int)nlen, nm); 809 } 810 } 811 } 812 } 813 obj_symiter_free(it); 814 815 m = jit_input_map_alloc(jit, ob); 816 obj_sec_count = obj_section_count(ob); 817 for (i = 0; i < SEG_NBUCKETS; ++i) cursor[i] = jit->append_cursor[i]; 818 819 for (i = 1; i < obj_sec_count; ++i) { 820 const Section* s = obj_section_get(ob, (ObjSecId)i); 821 u32 first = 0, count = 1, ai; 822 int has_atoms; 823 if (!s || !link_section_kept(s)) continue; 824 has_atoms = link_input_section_has_atoms(&m, (ObjSecId)i); 825 if (has_atoms) link_input_section_atoms(&m, (ObjSecId)i, &first, &count); 826 for (ai = 0; ai < count; ++ai) { 827 ObjAtomId aid = 828 has_atoms ? m.section_atom_ids[first + ai] : OBJ_ATOM_NONE; 829 const ObjAtom* atom = has_atoms ? obj_atom_get(ob, aid) : NULL; 830 SegBucket b; 831 u64 obj_offset; 832 u64 size; 833 u64 vaddr; 834 JitAppendSec* ps; 835 u32 sec_idx; 836 if (has_atoms) { 837 if (!atom || atom->removed) continue; 838 obj_offset = atom->offset; 839 size = atom->size; 840 } else { 841 obj_offset = 0u; 842 size = link_section_size_for_link(s); 843 } 844 if (size == 0) continue; 845 b = link_bucket_for(s->flags); 846 vaddr = ALIGN_UP(cursor[b], (u64)(s->align ? s->align : 1u)); 847 if (vaddr + size > jit->append_limit[b]) 848 compiler_panic(jit->c, SRCLOC_NONE, 849 "kit_jit_append_obj: append slack exhausted"); 850 ps = JitAppendSecs_push(&secs, &sec_idx); 851 if (!ps) 852 compiler_panic(jit->c, SRCLOC_NONE, 853 "kit_jit_append_obj: oom on section plan"); 854 ps->obj_sec = (ObjSecId)i; 855 ps->obj_atom = has_atoms ? aid : OBJ_ATOM_NONE; 856 ps->link_sec = (LinkSectionId)(old_nsections + sec_idx + 1u); 857 ps->link_seg = (LinkSegmentId)(old_nsegments + sec_idx + 1u); 858 ps->bucket = b; 859 ps->obj_offset = obj_offset; 860 ps->vaddr = vaddr; 861 ps->size = size; 862 ps->file_size = (s->sem == SSEM_NOBITS || s->kind == SEC_BSS) ? 0 : size; 863 ps->align = s->align ? s->align : 1u; 864 ps->flags = s->flags; 865 ps->sem = (s->kind == SEC_BSS) ? SSEM_NOBITS : s->sem; 866 ps->name = s->name; 867 if (has_atoms) { 868 m.atom[aid] = ps->link_sec; 869 if (m.section[i] == LINK_SEC_NONE) m.section[i] = ps->link_sec; 870 } else { 871 m.section[i] = ps->link_sec; 872 } 873 cursor[b] = vaddr + size; 874 } 875 } 876 nsecs = JitAppendSecs_count(&secs); 877 for (i = 0; i < SEG_NBUCKETS; ++i) jit->append_cursor[i] = cursor[i]; 878 879 it = obj_symiter_new(ob); 880 while (obj_symiter_next(it, &e)) { 881 const ObjSym* s = e.sym; 882 int is_def; 883 if (e.id >= m.nsym || link_sym_is_spurious_undef(s)) continue; 884 is_def = link_sym_is_def(s); 885 if (is_def && (s->bind == SB_GLOBAL || s->bind == SB_WEAK) && 886 s->name != 0) { 887 LinkSymId existing = symhash_get(&img->globals, s->name); 888 if (existing != LINK_SYM_NONE) { 889 LinkSymbol* prev = LinkSyms_at(&img->syms, existing - 1); 890 if (prev && prev->defined && 891 link_bind_strength((u8)s->bind) == link_bind_strength(SB_GLOBAL) && 892 link_bind_strength(prev->bind) == link_bind_strength(SB_GLOBAL)) { 893 Slice nm_s = pool_slice(jit->c->global, s->name); 894 const char* nm = nm_s.s; 895 size_t namelen = nm_s.len; 896 obj_format_demangle_c(jit->c, &nm, &namelen); 897 obj_symiter_free(it); 898 compiler_panic(jit->c, SRCLOC_NONE, 899 "kit_jit_append_obj: duplicate global '%.*s'", 900 (int)namelen, nm); 901 } 902 if (prev && prev->defined) { 903 m.sym[e.id] = existing; 904 continue; 905 } 906 } 907 } 908 m.sym[e.id] = (LinkSymId)(LinkSyms_count(&img->syms) + 1u); 909 { 910 LinkSymbol rec; 911 memset(&rec, 0, sizeof(rec)); 912 rec.name = s->name; 913 rec.input_id = (LinkInputId)(LinkInputs_count(&jit->linker->inputs) + 1u); 914 rec.obj_sym = e.id; 915 rec.section_id = LINK_SEC_NONE; 916 rec.atom_id = is_def ? link_input_sym_atom(&m, e.id) : OBJ_ATOM_NONE; 917 rec.value = s->value; 918 rec.size = s->size; 919 rec.common_align = (s->kind == SK_COMMON) ? (u32)s->common_align : 0u; 920 rec.bind = (u8)s->bind; 921 rec.kind = (u8)s->kind; 922 rec.defined = (u8)is_def; 923 if (is_def && s->section_id != OBJ_SEC_NONE && 924 s->section_id < m.nsection) { 925 rec.section_id = link_input_symbol_section(&m, s, e.id); 926 if (rec.section_id != LINK_SEC_NONE) { 927 u32 sj; 928 for (sj = 0; sj < nsecs; ++sj) { 929 JitAppendSec* ps = JitAppendSecs_at(&secs, sj); 930 if (ps && ps->link_sec == rec.section_id) { 931 rec.vaddr = ps->vaddr + (s->value - ps->obj_offset); 932 break; 933 } 934 } 935 } 936 } else if (s->kind == SK_ABS) { 937 rec.vaddr = s->value; 938 } 939 m.sym[e.id] = link_append_symbol(img, &rec); 940 if (is_def && (s->bind == SB_GLOBAL || s->bind == SB_WEAK) && 941 s->name != 0) { 942 LinkSymId existing; 943 if (symhash_insert(&img->globals, s->name, m.sym[e.id], &existing)) { 944 } else { 945 m.sym[e.id] = existing; 946 } 947 } 948 } 949 } 950 obj_symiter_free(it); 951 952 /* Resolve newly appended undefs before any bytes become executable. */ 953 for (i = 0; i < LinkSyms_count(&img->syms); ++i) { 954 LinkSymbol* s = LinkSyms_at(&img->syms, i); 955 if (s->input_id != 956 (LinkInputId)(LinkInputs_count(&jit->linker->inputs) + 1u)) 957 continue; 958 if (s->defined) continue; 959 if (s->name != 0) { 960 LinkSymId hit = symhash_get(&img->globals, s->name); 961 if (hit != LINK_SYM_NONE && hit != s->id) { 962 LinkSymbol* def = LinkSyms_at(&img->syms, hit - 1); 963 if (def->defined) { 964 s->section_id = def->section_id; 965 s->atom_id = def->atom_id; 966 s->value = def->value; 967 s->vaddr = def->vaddr; 968 s->kind = def->kind; 969 s->bind = def->bind; 970 s->defined = 1; 971 continue; 972 } 973 } 974 } 975 if (jit->linker->resolver && s->name != 0) { 976 Slice nm_s = pool_slice(jit->c->global, s->name); 977 void* p = jit->linker->resolver(jit->linker->resolver_user, nm_s); 978 if (p) { 979 s->kind = SK_ABS; 980 s->vaddr = (u64)(uintptr_t)p; 981 s->defined = 1; 982 continue; 983 } 984 } 985 if (s->bind == SB_WEAK) { 986 s->kind = SK_ABS; 987 s->vaddr = 0; 988 s->defined = 1; 989 continue; 990 } 991 if (s->name != 0) { 992 Slice nm_s = pool_slice(jit->c->global, s->name); 993 const char* nm = nm_s.s; 994 size_t nlen = nm_s.len; 995 if (nm && nlen == 15u && memcmp(nm, "__tlv_bootstrap", 15u) == 0) { 996 s->kind = SK_ABS; 997 s->vaddr = 0; 998 s->defined = 1; 999 continue; 1000 } 1001 obj_format_demangle_c(jit->c, &nm, &nlen); 1002 compiler_panic(jit->c, SRCLOC_NONE, 1003 "kit_jit_append_obj: undefined reference to '%.*s'", 1004 (int)nlen, nm); 1005 } 1006 compiler_panic(jit->c, SRCLOC_NONE, 1007 "kit_jit_append_obj: undefined anonymous symbol"); 1008 } 1009 1010 new_input_id = link_add_obj(jit->linker, ob); 1011 new_input_idx = new_input_id - 1u; 1012 1013 { 1014 InputMap* maps = (InputMap*)h->realloc( 1015 h, img->input_maps, sizeof(*img->input_maps) * img->ninput_maps, 1016 sizeof(*img->input_maps) * (new_input_idx + 1u), _Alignof(InputMap)); 1017 if (!maps) 1018 compiler_panic(jit->c, SRCLOC_NONE, 1019 "kit_jit_append_obj: oom growing input maps"); 1020 img->input_maps = maps; 1021 while (img->ninput_maps < new_input_idx) { 1022 memset(&img->input_maps[img->ninput_maps], 0, sizeof(InputMap)); 1023 img->ninput_maps++; 1024 } 1025 img->input_maps[new_input_idx] = m; 1026 img->ninput_maps = new_input_idx + 1u; 1027 } 1028 1029 if (nsecs) { 1030 LinkSection* nsections = (LinkSection*)h->realloc( 1031 h, img->sections, sizeof(*img->sections) * old_nsections, 1032 sizeof(*img->sections) * (old_nsections + nsecs), 1033 _Alignof(LinkSection)); 1034 LinkSegment* nsegments = (LinkSegment*)h->realloc( 1035 h, img->segments, sizeof(*img->segments) * old_nsegments, 1036 sizeof(*img->segments) * (old_nsegments + nsecs), 1037 _Alignof(LinkSegment)); 1038 u8** nsegbytes = (u8**)h->realloc( 1039 h, img->segment_bytes, sizeof(*img->segment_bytes) * old_nsegments, 1040 sizeof(*img->segment_bytes) * (old_nsegments + nsecs), _Alignof(u8*)); 1041 size_t* nsegcaps = (size_t*)h->realloc( 1042 h, img->segment_bytes_cap, 1043 sizeof(*img->segment_bytes_cap) * old_nsegments, 1044 sizeof(*img->segment_bytes_cap) * (old_nsegments + nsecs), 1045 _Alignof(size_t)); 1046 KitExecMemRegion* njsegs = (KitExecMemRegion*)h->realloc( 1047 h, jit->segs, sizeof(*jit->segs) * old_nsegs, 1048 sizeof(*jit->segs) * (old_nsegs + nsecs), _Alignof(KitExecMemRegion)); 1049 if (!nsections || !nsegments || !nsegbytes || !nsegcaps || !njsegs) 1050 compiler_panic(jit->c, SRCLOC_NONE, 1051 "kit_jit_append_obj: oom growing image tables"); 1052 img->sections = nsections; 1053 img->segments = nsegments; 1054 img->segment_bytes = nsegbytes; 1055 img->segment_bytes_cap = nsegcaps; 1056 jit->segs = njsegs; 1057 } 1058 1059 for (i = 0; i < nsecs; ++i) { 1060 JitAppendSec* ps = JitAppendSecs_at(&secs, i); 1061 LinkSection* ls = &img->sections[old_nsections + i]; 1062 LinkSegment* seg = &img->segments[old_nsegments + i]; 1063 KitExecMemRegion* js = &jit->segs[old_nsegs + i]; 1064 const Section* os = obj_section_get(ob, ps->obj_sec); 1065 memset(ls, 0, sizeof(*ls)); 1066 ls->id = ps->link_sec; 1067 ls->input_id = new_input_id; 1068 ls->obj_section_id = ps->obj_sec; 1069 ls->obj_atom_id = ps->obj_atom; 1070 ls->segment_id = ps->link_seg; 1071 ls->obj_offset = ps->obj_offset; 1072 ls->input_offset = 0; 1073 ls->file_offset = ps->vaddr; 1074 ls->vaddr = ps->vaddr; 1075 ls->size = ps->size; 1076 ls->flags = ps->flags; 1077 ls->align = ps->align; 1078 ls->name = ps->name; 1079 ls->sem = ps->sem; 1080 1081 memset(seg, 0, sizeof(*seg)); 1082 seg->id = ps->link_seg; 1083 seg->flags = SF_ALLOC; 1084 if (ps->bucket == SEG_RX) seg->flags |= SF_EXEC; 1085 if (ps->bucket == SEG_RW) seg->flags |= SF_WRITE; 1086 if (ps->bucket == SEG_TLS) seg->flags |= SF_TLS; 1087 seg->file_offset = ps->vaddr; 1088 seg->vaddr = ps->vaddr; 1089 seg->mem_size = ps->size; 1090 seg->file_size = ps->file_size; 1091 seg->align = (u32)page; 1092 seg->nsections = 1; 1093 img->segment_bytes[old_nsegments + i] = NULL; 1094 img->segment_bytes_cap[old_nsegments + i] = 0; 1095 1096 memset(js, 0, sizeof(*js)); 1097 js->write = 1098 (u8*)jit->master.write + (uintptr_t)(ps->vaddr - jit->image_base); 1099 js->runtime = 1100 (u8*)jit->master.runtime + (uintptr_t)(ps->vaddr - jit->image_base); 1101 js->size = (size_t)ps->size; 1102 js->token = NULL; 1103 1104 if (os && os->sem != SSEM_NOBITS && os->kind != SEC_BSS && 1105 os->bytes.total && ps->size) 1106 buf_read(&os->bytes, (u32)ps->obj_offset, (u8*)js->write, 1107 (size_t)ps->size); 1108 img->nsections++; 1109 img->nsegments++; 1110 jit->nsegs++; 1111 } 1112 1113 { 1114 u32 total = obj_reloc_total(ob); 1115 for (i = 0; i < total; ++i) { 1116 const Reloc* r = obj_reloc_at(ob, i); 1117 LinkRelocApply rec; 1118 LinkSectionId ls_id; 1119 const LinkSection* ls; 1120 if (!r || r->section_id == OBJ_SEC_NONE || r->section_id >= m.nsection) 1121 continue; 1122 ls_id = link_input_reloc_section(&m, r, i); 1123 if (ls_id == LINK_SEC_NONE) continue; 1124 if (r->sym == OBJ_SYM_NONE || r->sym >= m.nsym || 1125 m.sym[r->sym] == LINK_SYM_NONE) 1126 continue; 1127 ls = &img->sections[ls_id - 1]; 1128 memset(&rec, 0, sizeof(rec)); 1129 rec.input_id = new_input_id; 1130 rec.section_id = r->section_id; 1131 rec.link_section_id = ls_id; 1132 rec.offset = r->offset - (u32)ls->obj_offset; 1133 rec.width = reloc_kind_width(jit->c, (RelocKind)r->kind); 1134 rec.write_vaddr = ls->vaddr + rec.offset; 1135 rec.write_file_offset = rec.write_vaddr; 1136 rec.kind = (RelocKind)r->kind; 1137 rec.target = m.sym[r->sym]; 1138 rec.addend = r->addend; 1139 *link_append_reloc_slot(img) = rec; 1140 } 1141 } 1142 1143 for (i = old_nrelocs; i < LinkRelocs_count(&img->relocs); ++i) { 1144 const LinkRelocApply* r = LinkRelocs_at(&img->relocs, i); 1145 jit_apply_one_reloc(jit, r); 1146 } 1147 1148 for (i = old_nsegs; i < jit->nsegs; ++i) { 1149 const LinkSegment* seg = &img->segments[i]; 1150 u64 page_lo = seg->vaddr & ~(page - 1u); 1151 u64 page_hi = ALIGN_UP(seg->vaddr + seg->mem_size, page); 1152 void* rt = 1153 (u8*)jit->master.runtime + (uintptr_t)(page_lo - jit->image_base); 1154 if (mem->protect(mem->user, rt, (size_t)(page_hi - page_lo), 1155 perms_for(seg->flags)) != 0) { 1156 compiler_panic(jit->c, SRCLOC_NONE, 1157 "kit_jit_append_obj: execmem.protect failed"); 1158 } 1159 } 1160 if (mem->flush_icache) { 1161 for (i = old_nsegs; i < jit->nsegs; ++i) { 1162 const LinkSegment* seg = &img->segments[i]; 1163 if (seg->flags & SF_EXEC) 1164 mem->flush_icache(mem->user, jit->segs[i].runtime, jit->segs[i].size); 1165 } 1166 } 1167 1168 { 1169 ObjBuilder** nd = (ObjBuilder**)h->realloc( 1170 h, img->dbg_objs, sizeof(*img->dbg_objs) * old_dbg_n, 1171 sizeof(*img->dbg_objs) * (new_input_idx + 1u), _Alignof(ObjBuilder*)); 1172 u8* no = (u8*)h->realloc( 1173 h, img->dbg_objs_owned, sizeof(*img->dbg_objs_owned) * old_dbg_n, 1174 sizeof(*img->dbg_objs_owned) * (new_input_idx + 1u), 1u); 1175 if (!nd || !no) 1176 compiler_panic(jit->c, SRCLOC_NONE, 1177 "kit_jit_append_obj: oom growing debug inputs"); 1178 img->dbg_objs = nd; 1179 img->dbg_objs_owned = no; 1180 while (img->dbg_objs_n < new_input_idx) { 1181 img->dbg_objs[img->dbg_objs_n] = NULL; 1182 img->dbg_objs_owned[img->dbg_objs_n] = 0u; 1183 img->dbg_objs_n++; 1184 } 1185 img->dbg_objs[new_input_idx] = ob; 1186 img->dbg_objs_owned[new_input_idx] = 0u; 1187 img->dbg_objs_n = new_input_idx + 1u; 1188 } 1189 1190 jit_invalidate_view(jit); 1191 jit->generation++; 1192 JitAppendSecs_fini(&secs); 1193 (void)old_cursor; 1194 (void)old_nmaps; 1195 } 1196 1197 KitStatus kit_jit_publish(KitJit* jit, const KitJitPublishOptions* opts, 1198 KitJitPublishResult* result) { 1199 PanicFrame panic; 1200 Compiler* c; 1201 KitLinkSession* link; 1202 u32 i; 1203 1204 if (result) memset(result, 0, sizeof(*result)); 1205 if (!jit || !opts || !opts->link) return KIT_INVALID; 1206 if ((KitJitPublishKind)opts->kind != KIT_JIT_PUBLISH_APPEND_OBJECTS) 1207 return KIT_UNSUPPORTED; 1208 link = opts->link; 1209 if (link->non_obj_inputs) return KIT_UNSUPPORTED; 1210 c = jit->c; 1211 compiler_panic_push(c, &panic); 1212 if (setjmp(panic.env)) { 1213 /* A failed append (e.g. duplicate global) panics from 1214 * jit_append_obj_inner. compiler_run_cleanups fires the borrowed link 1215 * session's deferred linker_cleanup, which frees its Linker; null the 1216 * session's references so the caller's kit_link_session_free does not 1217 * double-free. Mirrors link_session_guard's recovery. */ 1218 compiler_run_cleanups(c); 1219 link->linker = NULL; 1220 link->image = NULL; 1221 compiler_panic_pop(c, &panic); 1222 return KIT_ERR; 1223 } 1224 for (i = 0; i < link->npublish_objs; ++i) 1225 jit_append_obj_inner(jit, link->publish_objs[i]); 1226 compiler_panic_pop(c, &panic); 1227 if (result) result->generation = jit->generation; 1228 return KIT_OK; 1229 } 1230 1231 /* ---- inspector entries ---- */ 1232 1233 /* True if `name` (NUL-terminated) is a debug section the DWARF consumer 1234 * (src/debug/dwarf_open.c) might read. Everything else is skipped. */ 1235 static int jit_view_is_debug_name(const char* name) { 1236 if (!name) return 0; 1237 if (name[0] == '.' && name[1] == 'd' && name[2] == 'e' && name[3] == 'b' && 1238 name[4] == 'u' && name[5] == 'g' && name[6] == '_') 1239 return 1; /* .debug_* */ 1240 /* .eh_frame is consulted by kit_dwarf for CFI unwinding when 1241 * available; kit itself doesn't currently emit it, but inputs read 1242 * from external .o files may carry it. */ 1243 if (name[0] == '.' && name[1] == 'e' && name[2] == 'h' && name[3] == '_' && 1244 name[4] == 'f' && name[5] == 'r' && name[6] == 'a' && name[7] == 'm' && 1245 name[8] == 'e' && name[9] == '\0') 1246 return 1; 1247 return 0; 1248 } 1249 1250 /* True if input `ii` carries any debug section that's worth surfacing. 1251 * Cheap walk over the input's section table. Sym values are pool-local, 1252 * so name strings must be dereferenced through the input's *own* 1253 * compiler pool — not the jit's pool. */ 1254 static int jit_view_input_has_debug(KitJit* jit, u32 ii) { 1255 ObjBuilder* ob; 1256 Pool* in_pool; 1257 u32 nsec, k; 1258 if (ii >= jit->image->dbg_objs_n) return 0; 1259 ob = jit->image->dbg_objs[ii]; 1260 if (!ob) return 0; 1261 in_pool = obj_compiler(ob)->global; 1262 nsec = obj_section_count(ob); 1263 for (k = 0; k < nsec; ++k) { 1264 const Section* s = obj_section_get(ob, (ObjSecId)(k + 1)); 1265 const char* nm; 1266 if (!s || !s->name) continue; 1267 nm = pool_slice(in_pool, s->name).s; 1268 if (jit_view_is_debug_name(nm)) return 1; 1269 } 1270 return 0; 1271 } 1272 1273 /* Resolve an input-local ObjSymId to the final image vaddr of the 1274 * defining LinkSymbol, going through the per-input InputMap and the 1275 * image's LinkSyms table. Returns 0 if the symbol is undefined or the 1276 * mapping is missing — debug relocations against unresolved symbols 1277 * collapse to zero, which is the DWARF "absent" convention. */ 1278 static u64 jit_view_sym_vaddr(KitJit* jit, u32 ii, ObjSymId obj_sym) { 1279 const InputMap* m; 1280 LinkSymId lid; 1281 const LinkSymbol* s; 1282 if (obj_sym == OBJ_SYM_NONE) return 0; 1283 if (ii >= jit->image->ninput_maps) return 0; 1284 m = &jit->image->input_maps[ii]; 1285 if (!m->sym || obj_sym >= m->nsym) return 0; 1286 lid = m->sym[obj_sym]; 1287 if (lid == LINK_SYM_NONE || lid > LinkSyms_count(&jit->image->syms)) return 0; 1288 s = LinkSyms_at(&jit->image->syms, lid - 1); 1289 if (!s || !s->defined) return 0; 1290 return s->vaddr; /* image-relative — what DWARF was emitted in */ 1291 } 1292 1293 /* Per-output-section state used while concatenating multi-input debug 1294 * bytes. Keyed by interned name in the view compiler's pool. */ 1295 typedef struct ViewSec { 1296 Sym view_name; /* interned in view_ob's compiler pool */ 1297 ObjSecId view_id; 1298 u32 cur_size; /* bytes currently in the view section */ 1299 /* Snapshot of cur_size taken at the start of processing the current 1300 * input. Reloc apply for SK_SECTION targets must use this value so 1301 * that intra-input references resolve to *this* input's contribution, 1302 * not bytes appended later from the same input. */ 1303 u32 snap; 1304 } ViewSec; 1305 1306 /* Find-or-create a ViewSec entry by debug-section name. */ 1307 static ViewSec* view_sec_for(KitJit* jit, ViewSec* tab, u32* ntab, 1308 u32* cap_inout, const char* name, u16 flags, 1309 u32 align, u32 entsize, ObjBuilder* view_ob, 1310 ViewSec** tab_out) { 1311 Heap* h = (Heap*)jit->c->ctx->heap; 1312 Pool* view_pool = obj_compiler(view_ob)->global; 1313 Sym vn = pool_intern_slice(view_pool, slice_from_cstr(name)); 1314 u32 i; 1315 for (i = 0; i < *ntab; ++i) { 1316 if (tab[i].view_name == vn) { 1317 if (tab_out) *tab_out = tab; 1318 return &tab[i]; 1319 } 1320 } 1321 if (*ntab == *cap_inout) { 1322 u32 ncap = *cap_inout ? *cap_inout * 2u : 4u; 1323 ViewSec* na = (ViewSec*)h->realloc(h, tab, *cap_inout * sizeof(*tab), 1324 ncap * sizeof(*tab), _Alignof(ViewSec)); 1325 if (!na) return NULL; 1326 tab = na; 1327 *cap_inout = ncap; 1328 if (tab_out) *tab_out = tab; 1329 } else if (tab_out) { 1330 *tab_out = tab; 1331 } 1332 { 1333 ViewSec* slot = &tab[(*ntab)++]; 1334 slot->view_name = vn; 1335 slot->view_id = obj_section_ex(view_ob, vn, SEC_DEBUG, SSEM_PROGBITS, flags, 1336 align ? align : 1u, entsize, 0, 0); 1337 slot->cur_size = 0; 1338 slot->snap = 0; 1339 return slot; 1340 } 1341 } 1342 1343 /* Find a ViewSec by view-pool name (no creation). Returns NULL on miss. */ 1344 static ViewSec* view_sec_find(ViewSec* tab, u32 ntab, Sym view_name) { 1345 u32 i; 1346 for (i = 0; i < ntab; ++i) 1347 if (tab[i].view_name == view_name) return &tab[i]; 1348 return NULL; 1349 } 1350 1351 /* Copy one debug section from input `ii` into the view, applying its 1352 * relocations against either the view-relative section prefix (for 1353 * SK_SECTION targets pointing at a debug section) or the final image 1354 * vaddr (for code/data symbol targets like DW_AT_low_pc). 1355 * 1356 * `tab` is the find-or-create table of view sections, keyed by name; 1357 * snapshots taken at the start of this input are read from it via 1358 * view_sec_find. */ 1359 static void jit_view_copy_debug_section(KitJit* jit, u32 ii, ObjSecId in_sec_id, 1360 ObjBuilder* view_ob, ViewSec* tab, 1361 u32 ntab, ViewSec* out_vs) { 1362 ObjBuilder* in_ob = jit->image->dbg_objs[ii]; 1363 const Section* in_sec = obj_section_get(in_ob, in_sec_id); 1364 Pool* in_pool; 1365 Pool* view_pool = obj_compiler(view_ob)->global; 1366 Heap* h; 1367 u32 nbytes, k, total_relocs; 1368 u8* bytes; 1369 if (!in_sec) return; 1370 nbytes = in_sec->bytes.total; 1371 if (nbytes == 0) return; 1372 in_pool = obj_compiler(in_ob)->global; 1373 h = (Heap*)jit->c->ctx->heap; 1374 (void)in_pool; 1375 1376 bytes = (u8*)h->alloc(h, nbytes, 1); 1377 if (!bytes) return; 1378 buf_flatten(&in_sec->bytes, bytes); 1379 1380 /* Apply this section's relocations in place. obj_reloc_at returns 1381 * all relocations across the input; filter by section_id. */ 1382 total_relocs = obj_reloc_total(in_ob); 1383 for (k = 0; k < total_relocs; ++k) { 1384 const Reloc* r = obj_reloc_at(in_ob, k); 1385 u64 S = 0; 1386 int handled = 0; 1387 if (!r || r->section_id != in_sec_id) continue; 1388 if (r->offset >= nbytes) continue; /* malformed; skip */ 1389 /* SK_SECTION target → resolve against the per-input snapshot of the 1390 * matching view section's prefix size. This is what makes the 1391 * concatenated multi-input view's cross-section offsets land in 1392 * the right slot. */ 1393 if (r->sym != OBJ_SYM_NONE) { 1394 const ObjSym* ts = obj_symbol_get(in_ob, r->sym); 1395 if (ts && ts->kind == SK_SECTION && ts->section_id != OBJ_SEC_NONE) { 1396 const Section* tsec = obj_section_get(in_ob, ts->section_id); 1397 if (tsec && tsec->kind == SEC_DEBUG && tsec->name) { 1398 Slice tnm_s = pool_slice(obj_compiler(in_ob)->global, tsec->name); 1399 const char* tnm = tnm_s.s; 1400 size_t tnlen = tnm_s.len; 1401 if (tnm) { 1402 Sym v_tn = 1403 pool_intern_slice(view_pool, (Slice){.s = tnm, .len = tnlen}); 1404 ViewSec* tgt = view_sec_find(tab, ntab, v_tn); 1405 if (tgt) { 1406 S = (u64)tgt->snap; 1407 handled = 1; 1408 } 1409 } 1410 } 1411 } 1412 } 1413 if (!handled) S = jit_view_sym_vaddr(jit, ii, r->sym); 1414 /* P is unused by ABS kinds; PC-relative debug-section relocs are 1415 * not produced by kit's debug emitter, but if some external .o 1416 * carried one against a debug section, P=0 would give a 1417 * non-meaningful offset — acceptable for a viewer that only reads 1418 * absolute address fields. */ 1419 link_reloc_apply(jit->c, (RelocKind)r->kind, bytes + r->offset, S, 1420 r->addend, 0); 1421 } 1422 1423 obj_write(view_ob, out_vs->view_id, bytes, nbytes); 1424 out_vs->cur_size += nbytes; 1425 h->free(h, bytes, nbytes); 1426 } 1427 1428 /* Build the view on first call. Walks every input that carries a debug 1429 * section and concatenates per-section bytes into the view's matching 1430 * sections. SK_SECTION relocations are resolved against the view-side 1431 * prefix length snapshotted at the start of each input, so the merged 1432 * CU2/CU3/... cross-section offsets land in the right slot. */ 1433 static KitObjFile* jit_view_build(KitJit* jit) { 1434 KitObjFile* view; 1435 ObjBuilder* view_ob; 1436 ViewSec* tab = NULL; 1437 u32 ntab = 0, cap = 0; 1438 Heap* h; 1439 u32 ii, k; 1440 int any = 0; 1441 1442 if (!jit->image || jit->image->dbg_objs_n == 0) return NULL; 1443 for (ii = 0; ii < jit->image->dbg_objs_n; ++ii) { 1444 if (jit_view_input_has_debug(jit, ii)) { 1445 any = 1; 1446 break; 1447 } 1448 } 1449 if (!any) return NULL; 1450 1451 view = 1452 kit_objfile_internal_new(jit->c->ctx, jit->c->target, jit->c->target.obj); 1453 if (!view) return NULL; 1454 view_ob = kit_objfile_builder(view); 1455 if (!view_ob) { 1456 kit_objfile_internal_free(view); 1457 return NULL; 1458 } 1459 h = (Heap*)jit->c->ctx->heap; 1460 1461 for (ii = 0; ii < jit->image->dbg_objs_n; ++ii) { 1462 ObjBuilder* in_ob; 1463 u32 nsec; 1464 if (!jit_view_input_has_debug(jit, ii)) continue; 1465 in_ob = jit->image->dbg_objs[ii]; 1466 1467 /* Phase A: find-or-create every debug section this input contributes 1468 * to, and snapshot cur_size as the per-input prefix. */ 1469 nsec = obj_section_count(in_ob); 1470 for (k = 0; k < nsec; ++k) { 1471 const Section* s = obj_section_get(in_ob, (ObjSecId)(k + 1)); 1472 const char* nm; 1473 ViewSec* vs; 1474 if (!s || !s->name) continue; 1475 nm = pool_slice(obj_compiler(in_ob)->global, s->name).s; 1476 if (!nm || !jit_view_is_debug_name(nm)) continue; 1477 vs = view_sec_for(jit, tab, &ntab, &cap, nm, s->flags, 1478 s->align ? s->align : 1u, s->entsize, view_ob, &tab); 1479 if (!vs) continue; 1480 } 1481 for (k = 0; k < ntab; ++k) tab[k].snap = tab[k].cur_size; 1482 1483 /* Phase B: copy each debug section + apply relocs. cur_size grows 1484 * as bytes get appended; SK_SECTION resolution always reads `snap` 1485 * (the start-of-input snapshot), so intra-input references inside 1486 * any debug section still land in this input's slice. */ 1487 for (k = 0; k < nsec; ++k) { 1488 const Section* s = obj_section_get(in_ob, (ObjSecId)(k + 1)); 1489 const char* nm; 1490 size_t nlen = 0; 1491 Sym v_nm; 1492 ViewSec* vs; 1493 if (!s || !s->name) continue; 1494 { 1495 Slice nm_s = pool_slice(obj_compiler(in_ob)->global, s->name); 1496 nm = nm_s.s; 1497 nlen = nm_s.len; 1498 } 1499 if (!nm || !jit_view_is_debug_name(nm)) continue; 1500 v_nm = pool_intern_slice(obj_compiler(view_ob)->global, 1501 (Slice){.s = nm, .len = nlen}); 1502 vs = view_sec_find(tab, ntab, v_nm); 1503 if (!vs) continue; 1504 jit_view_copy_debug_section(jit, ii, (ObjSecId)(k + 1), view_ob, tab, 1505 ntab, vs); 1506 } 1507 } 1508 1509 if (tab) h->free(h, tab, sizeof(*tab) * cap); 1510 obj_finalize(view_ob); 1511 return view; 1512 } 1513 1514 const KitObjFile* kit_jit_view(KitJit* jit) { 1515 if (!jit) return NULL; 1516 if (jit->view_built) return jit->view; 1517 jit->view = jit_view_build(jit); 1518 jit->view_built = 1u; 1519 return jit->view; 1520 } 1521 1522 /* True for symbol kinds the user-facing JIT inspector surfaces. Mapping 1523 * symbols (SK_NOTYPE — aarch64 $x/$d), section/file/undef symbols are 1524 * skipped. */ 1525 static int jit_sym_kind_visible(u8 k) { 1526 return k == SK_FUNC || k == SK_OBJ || k == SK_COMMON || k == SK_TLS || 1527 k == SK_IFUNC || k == SK_ABS; 1528 } 1529 1530 /* Resolve a LinkSymbol's interned name to a stable C string, stripping 1531 * the target format's C-mangling prefix (Mach-O's leading `_`) so the 1532 * user sees the source-level name. */ 1533 static Slice jit_sym_name_slice(KitJit* jit, const LinkSymbol* s) { 1534 Slice nm_s = pool_slice(jit->c->global, s->name); 1535 const char* nm = nm_s.s; 1536 size_t len = nm_s.len; 1537 if (!nm) return KIT_SLICE_NULL; 1538 obj_format_demangle_c(jit->c, &nm, &len); 1539 nm_s.s = nm; 1540 nm_s.len = len; 1541 return nm_s; 1542 } 1543 1544 static uint64_t jit_sym_runtime_addr(KitJit* jit, const LinkSymbol* s) { 1545 if (s->kind == SK_ABS) return s->vaddr; 1546 return (uint64_t)vaddr_to_runtime(jit->image, jit->segs, s->vaddr); 1547 } 1548 1549 KitStatus kit_jit_addr_to_sym(KitJit* jit, uint64_t addr, KitSlice* name_out, 1550 uint64_t* off_out) { 1551 u32 n; 1552 u32 i; 1553 const LinkSymbol* best = NULL; 1554 uint64_t best_base = 0; 1555 uint64_t best_off = (uint64_t)-1; 1556 if (name_out) *name_out = KIT_SLICE_NULL; 1557 if (off_out) *off_out = 0; 1558 if (!jit) return KIT_INVALID; 1559 n = LinkSyms_count(&jit->image->syms); 1560 for (i = 0; i < n; ++i) { 1561 LinkSymbol* s = LinkSyms_at(&jit->image->syms, i); 1562 uint64_t base; 1563 if (!s || !s->defined) continue; 1564 if (!jit_sym_kind_visible(s->kind)) continue; 1565 base = jit_sym_runtime_addr(jit, s); 1566 if (!base) continue; 1567 if (addr >= base && (s->size == 0 || addr < base + s->size)) { 1568 uint64_t off = addr - base; 1569 if (off < best_off || 1570 (off == best_off && best && best->size == 0 && s->size != 0)) { 1571 best = s; 1572 best_base = base; 1573 best_off = off; 1574 } 1575 } 1576 } 1577 if (best) { 1578 if (name_out) *name_out = jit_sym_name_slice(jit, best); 1579 if (off_out) *off_out = addr - best_base; 1580 return KIT_OK; 1581 } 1582 return KIT_NOT_FOUND; 1583 } 1584 1585 struct KitJitSymIter { 1586 KitJit* jit; 1587 u32 next; 1588 }; 1589 1590 KitStatus kit_jit_sym_iter_new(KitJit* jit, KitJitSymIter** out) { 1591 Heap* h; 1592 KitJitSymIter* it; 1593 if (!out) return KIT_INVALID; 1594 *out = NULL; 1595 if (!jit) return KIT_INVALID; 1596 h = (Heap*)jit->c->ctx->heap; 1597 it = (KitJitSymIter*)h->alloc(h, sizeof(*it), _Alignof(KitJitSymIter)); 1598 if (!it) return KIT_NOMEM; 1599 it->jit = jit; 1600 it->next = 0; 1601 *out = it; 1602 return KIT_OK; 1603 } 1604 1605 KitIterResult kit_jit_sym_iter_next(KitJitSymIter* it, KitJitSym* out) { 1606 u32 n; 1607 if (!it || !out) return KIT_ITER_ERROR; 1608 n = LinkSyms_count(&it->jit->image->syms); 1609 while (it->next < n) { 1610 LinkSymbol* s = LinkSyms_at(&it->jit->image->syms, it->next++); 1611 if (!s || !s->defined) continue; 1612 if (!jit_sym_kind_visible(s->kind)) continue; 1613 out->name = jit_sym_name_slice(it->jit, s); 1614 out->addr = jit_sym_runtime_addr(it->jit, s); 1615 out->size = s->size; 1616 out->kind = (KitSymKind)s->kind; 1617 return KIT_ITER_ITEM; 1618 } 1619 return KIT_ITER_END; 1620 } 1621 1622 void kit_jit_sym_iter_free(KitJitSymIter* it) { 1623 Heap* h; 1624 if (!it) return; 1625 h = (Heap*)it->jit->c->ctx->heap; 1626 h->free(h, it, sizeof(*it)); 1627 } 1628 1629 /* ---- accessors for src/dbg/ ---- 1630 * 1631 * The KitJit struct is private to this TU. The debugger session needs a 1632 * way to validate that an address lies inside the JIT image (so it can 1633 * reject breakpoint and read/write requests pointing outside the code 1634 * region) and a way to read the image's target arch. These accessors give 1635 * it just that, without exporting the segment table or the LinkImage. */ 1636 int kit_jit_image_contains(KitJit* jit, uint64_t runtime_addr) { 1637 u32 i; 1638 uintptr_t a; 1639 if (!jit || !jit->segs) return 0; 1640 a = (uintptr_t)runtime_addr; 1641 for (i = 0; i < jit->nsegs; ++i) { 1642 uintptr_t lo = (uintptr_t)jit->segs[i].runtime; 1643 uintptr_t hi = lo + (uintptr_t)jit->segs[i].size; 1644 if (a >= lo && a < hi) return 1; 1645 } 1646 return 0; 1647 } 1648 1649 /* runtime <-> image vaddr translation. The pair is symmetric with 1650 * vaddr_to_runtime above; exposed here so dwarf consumers and the 1651 * driver can cross the boundary at every DWARF call. Walks the 1652 * segment table (at most a handful of entries) so callers can do this 1653 * per stop without measurable cost. */ 1654 uint64_t kit_jit_runtime_to_image(KitJit* jit, uint64_t runtime_pc) { 1655 u32 i; 1656 uintptr_t a; 1657 if (!jit || !jit->segs) return 0; 1658 a = (uintptr_t)runtime_pc; 1659 for (i = 0; i < jit->nsegs; ++i) { 1660 uintptr_t lo = (uintptr_t)jit->segs[i].runtime; 1661 uintptr_t hi = lo + (uintptr_t)jit->segs[i].size; 1662 if (a >= lo && a < hi) { 1663 const LinkSegment* s = &jit->image->segments[i]; 1664 return s->vaddr + (uint64_t)(a - lo); 1665 } 1666 } 1667 /* One-past-end: lets a return-address that sits exactly at a 1668 * segment's end-boundary still round-trip. */ 1669 for (i = 0; i < jit->nsegs; ++i) { 1670 uintptr_t hi = 1671 (uintptr_t)jit->segs[i].runtime + (uintptr_t)jit->segs[i].size; 1672 if (a == hi) { 1673 const LinkSegment* s = &jit->image->segments[i]; 1674 return s->vaddr + s->mem_size; 1675 } 1676 } 1677 return 0; 1678 } 1679 1680 uint64_t kit_jit_image_to_runtime(KitJit* jit, uint64_t image_vaddr) { 1681 uintptr_t rt; 1682 if (!jit || !jit->segs) return 0; 1683 rt = vaddr_to_runtime(jit->image, jit->segs, image_vaddr); 1684 return (uint64_t)rt; 1685 } 1686 1687 KitArchKind kit_jit_image_arch(KitJit* jit) { return jit->c->target.arch; } 1688 1689 Compiler* kit_jit_compiler(KitJit* jit) { return jit->c; } 1690 1691 void kit_jit_run_dtors(KitJit* jit) { 1692 typedef void (*VoidFn)(void); 1693 void* p_start; 1694 void* p_end; 1695 if (!jit) return; 1696 p_start = kit_jit_lookup(jit, KIT_SLICE_LIT("__fini_array_start")); 1697 p_end = kit_jit_lookup(jit, KIT_SLICE_LIT("__fini_array_end")); 1698 if (p_start && p_end) { 1699 VoidFn* begin = (VoidFn*)p_start; 1700 VoidFn* fn = (VoidFn*)p_end; 1701 while (fn != begin) { 1702 --fn; 1703 if (*fn) (*fn)(); 1704 } 1705 } 1706 }