obj.c (54992B)
1 /* In-memory ObjBuilder. Section, symbol, group, and reloc storage all 2 * use segmented arrays (core/segvec.h) so the T* pointers obj_*_get 3 * returns stay valid as the table grows. Section bytes use the chunked 4 * Buf type. Index 0 of each id space is reserved as "none". 5 * 6 * obj_finalize is the read-side gate: post-finalize, write-side calls 7 * are still legal (the reader paths use them too) but consumers can 8 * count on the index spaces being stable. */ 9 10 #include "obj/obj.h" 11 12 #include <string.h> 13 14 #include "core/hashmap.h" 15 #include "core/heap.h" 16 #include "core/pool.h" 17 #include "core/segvec.h" 18 #include "core/vec.h" 19 20 SEGVEC_DEFINE(Sections, Section, 5); /* 32 entries per segment */ 21 SEGVEC_DEFINE(Symbols, ObjSym, 6); /* 64 entries per segment */ 22 23 /* name (interned Sym) -> first defining ObjSymId. The authoritative index for 24 * obj_symbol_find: the whole-program LTO builder holds every TU's symbols in 25 * one builder, so the historical linear scan is O(n^2) at decl time. The index 26 * stores the first id seen for a name (matching the scan's "first match" 27 * semantics), and obj_symbol_find is a pure O(1) hash lookup with no fallback. 28 * obj_symbol_rename keeps the index exact (re-homing or dropping a renamed 29 * symbol's entry), so the lookup never sees a stale hit. */ 30 HASHMAP_DEFINE(SymNameIndex, Sym, ObjSymId, hash_u32); 31 32 /* (name, kind) -> first PROGBITS ObjSecId. obj_section is a find-or-create that 33 * collapses repeated requests for the same logical section (e.g. one .rodata 34 * per literal) onto a single Section; without this index that find is a linear 35 * scan of every section, which is O(n^2) once a build emits many distinct 36 * sections (e.g. -ffunction-sections). The key packs (name, kind) and is always 37 * odd so it never collides with the hashmap's 0 empty-slot sentinel. */ 38 HASHMAP_DEFINE(SecKeyIndex, u64, ObjSecId, hash_u64); 39 SEGVEC_DEFINE(Relocs, Reloc, 6); /* 64 entries per segment */ 40 SEGVEC_DEFINE(Groups, ObjGroup, 3); /* 8 entries per segment */ 41 SEGVEC_DEFINE(Atoms, ObjAtom, 5); /* 32 entries per segment */ 42 43 /* COFF WEAK_EXTERNAL alias declaration: symbol `sym` is an alias for the 44 * symbol named `target`. Rare (only import-archive members and the like 45 * carry these), so a side-vector keyed by ObjSymId keeps ObjSym lean 46 * instead of growing every symbol. See obj_set_weak_alias. */ 47 typedef struct ObjWeakAlias { 48 ObjSymId sym; 49 Sym target; 50 } ObjWeakAlias; 51 SEGVEC_DEFINE(WeakAliases, ObjWeakAlias, 3); /* 8 entries per segment */ 52 53 #define OBJ_EXT_SLOT_COUNT 6 /* OBJ_EXT_NONE..OBJ_EXT_WASM_IMPORTS */ 54 55 typedef struct ObjExtSlot { 56 void* payload; 57 ObjExtFreeFn free_fn; 58 } ObjExtSlot; 59 60 struct KitObjBuilder { 61 Compiler* c; 62 Heap* heap; 63 Sections sections; /* index 0 reserved as "none" */ 64 Symbols symbols; /* index 0 reserved as "none" */ 65 Relocs relocs; /* flat across all sections; filtered on read */ 66 Groups groups; /* index 0 reserved as "none" */ 67 Atoms atoms; /* index 0 reserved as "none" */ 68 SymNameIndex sym_by_name; /* name -> first ObjSymId; accelerates find */ 69 SecKeyIndex sec_by_key; /* (name,kind) -> first PROGBITS ObjSecId */ 70 /* Format-specific ELF e_flags. Set by read_elf to the input's 71 * e_flags (e.g. on RISC-V, EF_RISCV_RVC | EF_RISCV_FLOAT_ABI_DOUBLE); 72 * consumed by emit_elf to round-trip. Zero when not set — emit_elf 73 * derives a sensible default by arch. */ 74 u32 elf_e_flags; 75 u8 elf_e_flags_set; 76 /* COFF short-import annotation. Carries the providing DLL name when 77 * the builder was synthesized by read_coff from a Microsoft short 78 * import record; zero / unset otherwise. See obj_set_coff_import_dll. */ 79 Sym coff_import_dll; 80 u8 coff_import_dll_set; 81 /* COFF short-import IMPORT NAME override. The Microsoft short-import 82 * NameType field can make the name the loader resolves in the DLL differ 83 * from the local symbol name (NOPREFIX/UNDECORATE strip decoration; 84 * EXPORTAS stores an explicit export name). Carries that resolved import 85 * name when it differs from the symbol name; zero / unset otherwise. The 86 * local symbol keeps its own name so references still resolve; only the PE 87 * hint/name-table entry uses this. See obj_set_coff_import_name. */ 88 Sym coff_import_name; 89 u8 coff_import_name_set; 90 /* COFF WEAK_EXTERNAL alias declarations read from the input (symbol -> 91 * fallback/default symbol name). Empty on builders that carry none. See 92 * obj_set_weak_alias / obj_get_weak_alias. */ 93 WeakAliases weak_aliases; 94 /* Cached undef extern `__tlv_bootstrap` (Mach-O on-disk name) used by 95 * obj_define_tls when emitting `_Thread_local` storage on Mach-O. 96 * Lazily materialized on the first TLV emission; OBJ_SYM_NONE otherwise. */ 97 ObjSymId tlv_bootstrap_sym; 98 /* Format-specific extension payloads keyed by ObjExtKind. */ 99 ObjExtSlot ext[OBJ_EXT_SLOT_COUNT]; 100 /* Linked-image view (segments + dynamic info). NULL on relocatable 101 * inputs; lazily created by obj_image_ensure. See obj.h. */ 102 ObjImage* image; 103 /* Per-section reloc index (lazy cache). Without it, every native emitter 104 * rescans the whole flat reloc table once per section — O(n_sections * 105 * n_relocs), a latent superlinear axis that grows with -ffunction-sections 106 * and literal fan-out. `reloc_index` holds the global indices of live 107 * relocs grouped by section in ascending global order; `reloc_index_off` 108 * is the prefix-offset array (len reloc_index_nsec+1) so section `s`'s run 109 * is reloc_index[off[s] .. off[s+1]). Rebuilt by obj_reloc_index_ensure 110 * when `reloc_index_dirty` (set on reloc add and on obj_sweep_dead). */ 111 u32* reloc_index; 112 u32* reloc_index_off; 113 u32 reloc_index_nsec; /* #sections reloc_index_off was sized for */ 114 u32 reloc_index_len; /* #live relocs in reloc_index */ 115 u8 reloc_index_dirty; 116 }; 117 118 struct ObjSymIter { 119 const ObjBuilder* ob; 120 u32 idx; /* next index to return */ 121 }; 122 123 static void obj_image_free_(ObjBuilder*); 124 125 /* ---- lifecycle ---- */ 126 127 ObjBuilder* obj_new(Compiler* c) { 128 Heap* h = (Heap*)c->ctx->heap; 129 ObjBuilder* ob = (ObjBuilder*)h->alloc(h, sizeof(*ob), _Alignof(ObjBuilder)); 130 if (!ob) return NULL; 131 memset(ob, 0, sizeof(*ob)); 132 ob->c = c; 133 ob->heap = h; 134 Sections_init(&ob->sections, h); 135 Symbols_init(&ob->symbols, h); 136 Relocs_init(&ob->relocs, h); 137 Groups_init(&ob->groups, h); 138 Atoms_init(&ob->atoms, h); 139 /* Pre-size the symbol-name index: a typical TU has hundreds of symbols, and 140 * the default 16-slot map would otherwise resize/rehash ~4 times (16->256) 141 * while declarations stream in. 256 (a power of two, holds 192 at the 3/4 142 * load factor) skips that early cascade. Order-preserving — resize reinserts 143 * and the first-wins set at obj_symbol_make is unchanged. */ 144 SymNameIndex_init_cap(&ob->sym_by_name, h, 256u); 145 SecKeyIndex_init(&ob->sec_by_key, h); 146 WeakAliases_init(&ob->weak_aliases, h); 147 148 /* Reserve index 0 in each id space as the "none" sentinel. SegVec 149 * pushes are zeroed, so the sentinel slots have all-zero fields. */ 150 if (!Sections_push(&ob->sections, NULL) || 151 !Symbols_push(&ob->symbols, NULL) || !Groups_push(&ob->groups, NULL) || 152 !Atoms_push(&ob->atoms, NULL)) { 153 obj_free(ob); 154 return NULL; 155 } 156 return ob; 157 } 158 159 Compiler* obj_compiler(const ObjBuilder* ob) { return ob ? ob->c : NULL; } 160 161 /* Pre-size the symbol-name index for `n` incoming symbols. Object readers know 162 * the symbol count up front (the symtab header), so calling this before 163 * streaming symbols in skips the resize cascade off obj_new's 256-slot default 164 * on a symbol-heavy object (e.g. a large .o the linker ingests). No-op once the 165 * index is already large enough; order-preserving (resize reinserts). */ 166 void obj_reserve_symbols(ObjBuilder* ob, u32 n) { 167 if (ob) SymNameIndex_reserve(&ob->sym_by_name, n); 168 } 169 170 /* Private accessors for the `_tlv_bootstrap` cache used by obj_define_tls. 171 * Lives in obj.c so the ObjBuilder field doesn't leak through obj.h. */ 172 ObjSymId obj_tlv_bootstrap_get(const ObjBuilder* ob) { 173 return ob ? ob->tlv_bootstrap_sym : OBJ_SYM_NONE; 174 } 175 void obj_tlv_bootstrap_set(ObjBuilder* ob, ObjSymId id) { 176 if (ob) ob->tlv_bootstrap_sym = id; 177 } 178 179 void obj_free(ObjBuilder* ob) { 180 u32 i, n; 181 if (!ob) return; 182 for (i = 0; i < OBJ_EXT_SLOT_COUNT; ++i) { 183 if (ob->ext[i].payload && ob->ext[i].free_fn) { 184 ob->ext[i].free_fn(ob->c, ob->ext[i].payload); 185 } 186 ob->ext[i].payload = NULL; 187 ob->ext[i].free_fn = NULL; 188 } 189 n = Sections_count(&ob->sections); 190 for (i = 1; i < n; ++i) { 191 Section* s = Sections_at(&ob->sections, i); 192 if (s) buf_fini(&s->bytes); 193 } 194 n = Groups_count(&ob->groups); 195 for (i = 1; i < n; ++i) { 196 ObjGroup* g = Groups_at(&ob->groups, i); 197 if (g && g->sections) { 198 ob->heap->free(ob->heap, g->sections, sizeof(ObjSecId) * g->nsections); 199 } 200 } 201 Sections_fini(&ob->sections); 202 Symbols_fini(&ob->symbols); 203 Relocs_fini(&ob->relocs); 204 Groups_fini(&ob->groups); 205 Atoms_fini(&ob->atoms); 206 SymNameIndex_fini(&ob->sym_by_name); 207 SecKeyIndex_fini(&ob->sec_by_key); 208 WeakAliases_fini(&ob->weak_aliases); 209 obj_image_free_(ob); 210 if (ob->reloc_index) 211 ob->heap->free(ob->heap, ob->reloc_index, 212 sizeof(u32) * ob->reloc_index_len); 213 if (ob->reloc_index_off) 214 ob->heap->free(ob->heap, ob->reloc_index_off, 215 sizeof(u32) * (ob->reloc_index_nsec + 1u)); 216 ob->heap->free(ob->heap, ob, sizeof(*ob)); 217 } 218 219 void obj_set_elf_e_flags(ObjBuilder* ob, u32 e_flags) { 220 if (!ob) return; 221 ob->elf_e_flags = e_flags; 222 ob->elf_e_flags_set = 1; 223 } 224 225 int obj_get_elf_e_flags(const ObjBuilder* ob, u32* out) { 226 if (!ob || !ob->elf_e_flags_set) return 0; 227 if (out) *out = ob->elf_e_flags; 228 return 1; 229 } 230 231 void obj_set_coff_import_dll(ObjBuilder* ob, Sym dll_name) { 232 if (!ob) return; 233 ob->coff_import_dll = dll_name; 234 ob->coff_import_dll_set = 1; 235 } 236 237 int obj_get_coff_import_dll(const ObjBuilder* ob, Sym* out) { 238 if (!ob || !ob->coff_import_dll_set) return 0; 239 if (out) *out = ob->coff_import_dll; 240 return 1; 241 } 242 243 void obj_set_coff_import_name(ObjBuilder* ob, Sym import_name) { 244 if (!ob) return; 245 ob->coff_import_name = import_name; 246 ob->coff_import_name_set = 1; 247 } 248 249 int obj_get_coff_import_name(const ObjBuilder* ob, Sym* out) { 250 if (!ob || !ob->coff_import_name_set) return 0; 251 if (out) *out = ob->coff_import_name; 252 return 1; 253 } 254 255 void obj_set_weak_alias(ObjBuilder* ob, ObjSymId sym, Sym target) { 256 if (!ob || sym == OBJ_SYM_NONE || target == 0) return; 257 /* Overwrite an existing entry for this sym rather than duplicating. */ 258 u32 n = WeakAliases_count(&ob->weak_aliases); 259 for (u32 i = 0; i < n; ++i) { 260 ObjWeakAlias* a = WeakAliases_at(&ob->weak_aliases, i); 261 if (a->sym == sym) { 262 a->target = target; 263 return; 264 } 265 } 266 ObjWeakAlias* slot = WeakAliases_push(&ob->weak_aliases, NULL); 267 if (!slot) return; /* OOM: alias recovery falls back to the name heuristic */ 268 slot->sym = sym; 269 slot->target = target; 270 } 271 272 Sym obj_get_weak_alias(const ObjBuilder* ob, ObjSymId sym) { 273 if (!ob || sym == OBJ_SYM_NONE) return 0; 274 u32 n = WeakAliases_count(&ob->weak_aliases); 275 for (u32 i = 0; i < n; ++i) { 276 const ObjWeakAlias* a = WeakAliases_at(&ob->weak_aliases, i); 277 if (a->sym == sym) return a->target; 278 } 279 return 0; 280 } 281 282 u32 obj_weak_alias_count(const ObjBuilder* ob) { 283 return ob ? WeakAliases_count(&ob->weak_aliases) : 0; 284 } 285 286 int obj_weak_alias_at(const ObjBuilder* ob, u32 i, ObjSymId* sym_out, 287 Sym* target_out) { 288 if (!ob || i >= WeakAliases_count(&ob->weak_aliases)) return 0; 289 const ObjWeakAlias* a = WeakAliases_at(&ob->weak_aliases, i); 290 if (sym_out) *sym_out = a->sym; 291 if (target_out) *target_out = a->target; 292 return 1; 293 } 294 295 /* ---- linked-image view ---- */ 296 297 struct ObjImage { 298 Heap* heap; 299 ObjKind kind; 300 u64 entry; 301 u64 image_base; 302 Sym interp; 303 Sym soname; 304 ObjSegment* segs; 305 u32 nsegs, cap_segs; 306 ObjImageDep* deps; 307 u32 ndeps, cap_deps; 308 Sym* rpaths; 309 u32 nrpaths, cap_rpaths; 310 ObjImageSym* dynsyms; 311 u32 ndynsyms, cap_dynsyms; 312 ObjImageReloc* dynrelocs; 313 u32 ndynrelocs, cap_dynrelocs; 314 ObjImageRaw* raws; 315 u32 nraws, cap_raws; 316 /* Undefined symbol names a DSO references (interned). Used by the linker's 317 * --gc-sections pass to keep executable-defined symbols a shared library 318 * needs (e.g. libc.so.7's `environ` / `__progname`) from being collected. */ 319 Sym* undefs; 320 u32 nundefs, cap_undefs; 321 }; 322 323 static void obj_image_free_(ObjBuilder* ob) { 324 ObjImage* im; 325 if (!ob || !ob->image) return; 326 im = ob->image; 327 /* The image owns each dep's imports[] array container (allocated from 328 * im->heap by the PE reader); the Sym values inside stay interned in the 329 * global pool and are not freed here. ELF/Mach-O deps carry imports==NULL. */ 330 if (im->deps) { 331 for (u32 i = 0; i < im->ndeps; ++i) { 332 const ObjImageDep* d = &im->deps[i]; 333 if (d->imports) 334 im->heap->free(im->heap, (void*)d->imports, 335 sizeof(*d->imports) * d->nimports); 336 } 337 } 338 if (im->segs) 339 im->heap->free(im->heap, im->segs, sizeof(*im->segs) * im->cap_segs); 340 if (im->deps) 341 im->heap->free(im->heap, im->deps, sizeof(*im->deps) * im->cap_deps); 342 if (im->rpaths) 343 im->heap->free(im->heap, im->rpaths, sizeof(*im->rpaths) * im->cap_rpaths); 344 if (im->dynsyms) 345 im->heap->free(im->heap, im->dynsyms, 346 sizeof(*im->dynsyms) * im->cap_dynsyms); 347 if (im->dynrelocs) 348 im->heap->free(im->heap, im->dynrelocs, 349 sizeof(*im->dynrelocs) * im->cap_dynrelocs); 350 if (im->raws) 351 im->heap->free(im->heap, im->raws, sizeof(*im->raws) * im->cap_raws); 352 if (im->undefs) 353 im->heap->free(im->heap, im->undefs, sizeof(*im->undefs) * im->cap_undefs); 354 ob->heap->free(ob->heap, im, sizeof(*im)); 355 ob->image = NULL; 356 } 357 358 const ObjImage* obj_image(const ObjBuilder* ob) { 359 return ob ? ob->image : NULL; 360 } 361 362 ObjImage* obj_image_ensure(ObjBuilder* ob, ObjKind kind) { 363 ObjImage* im; 364 if (!ob) return NULL; 365 if (ob->image) { 366 ob->image->kind = kind; 367 return ob->image; 368 } 369 im = (ObjImage*)ob->heap->alloc(ob->heap, sizeof(*im), _Alignof(ObjImage)); 370 if (!im) return NULL; 371 memset(im, 0, sizeof(*im)); 372 im->heap = ob->heap; 373 im->kind = kind; 374 ob->image = im; 375 return im; 376 } 377 378 void obj_image_set_entry(ObjImage* im, u64 entry) { 379 if (im) im->entry = entry; 380 } 381 void obj_image_set_base(ObjImage* im, u64 image_base) { 382 if (im) im->image_base = image_base; 383 } 384 void obj_image_set_interp(ObjImage* im, Sym interp) { 385 if (im) im->interp = interp; 386 } 387 void obj_image_set_soname(ObjImage* im, Sym soname) { 388 if (im) im->soname = soname; 389 } 390 391 void obj_image_add_segment(ObjImage* im, const ObjSegment* seg) { 392 if (!im || !seg) return; 393 if (VEC_GROW(im->heap, im->segs, im->cap_segs, im->nsegs + 1)) return; 394 im->segs[im->nsegs++] = *seg; 395 } 396 void obj_image_add_dep(ObjImage* im, const ObjImageDep* dep) { 397 ObjImageDep d; 398 if (!im || !dep) return; 399 if (VEC_GROW(im->heap, im->deps, im->cap_deps, im->ndeps + 1)) return; 400 d = *dep; 401 /* Deep-copy the imports[] name array into image-heap-owned memory so the 402 * reader may pass a transient (scratch/arena) array; obj_image_free_ 403 * releases this copy. The Sym values inside are global-interned and not 404 * owned here. ELF/Mach-O deps carry imports==NULL (nimports==0). */ 405 if (d.nimports && dep->imports) { 406 Sym* copy = (Sym*)im->heap->alloc(im->heap, sizeof(Sym) * d.nimports, 407 _Alignof(Sym)); 408 if (!copy) { 409 d.imports = NULL; 410 d.nimports = 0; 411 } else { 412 memcpy(copy, dep->imports, sizeof(Sym) * d.nimports); 413 d.imports = copy; 414 } 415 } else { 416 d.imports = NULL; 417 d.nimports = 0; 418 } 419 im->deps[im->ndeps++] = d; 420 } 421 void obj_image_add_rpath(ObjImage* im, Sym rpath) { 422 if (!im) return; 423 if (VEC_GROW(im->heap, im->rpaths, im->cap_rpaths, im->nrpaths + 1)) return; 424 im->rpaths[im->nrpaths++] = rpath; 425 } 426 void obj_image_add_dynsym(ObjImage* im, const ObjImageSym* sym) { 427 if (!im || !sym) return; 428 if (VEC_GROW(im->heap, im->dynsyms, im->cap_dynsyms, im->ndynsyms + 1)) 429 return; 430 im->dynsyms[im->ndynsyms++] = *sym; 431 } 432 void obj_image_add_dynreloc(ObjImage* im, const ObjImageReloc* rel) { 433 if (!im || !rel) return; 434 if (VEC_GROW(im->heap, im->dynrelocs, im->cap_dynrelocs, im->ndynrelocs + 1)) 435 return; 436 im->dynrelocs[im->ndynrelocs++] = *rel; 437 } 438 void obj_image_add_undef(ObjImage* im, Sym name) { 439 if (!im || !name) return; 440 if (VEC_GROW(im->heap, im->undefs, im->cap_undefs, im->nundefs + 1)) return; 441 im->undefs[im->nundefs++] = name; 442 } 443 void obj_image_add_raw(ObjImage* im, const ObjImageRaw* raw) { 444 if (!im || !raw) return; 445 if (VEC_GROW(im->heap, im->raws, im->cap_raws, im->nraws + 1)) return; 446 im->raws[im->nraws++] = *raw; 447 } 448 449 ObjKind obj_image_kind(const ObjImage* im) { 450 return im ? im->kind : OBJ_KIND_REL; 451 } 452 u64 obj_image_entry(const ObjImage* im) { return im ? im->entry : 0; } 453 u64 obj_image_base(const ObjImage* im) { return im ? im->image_base : 0; } 454 Sym obj_image_interp(const ObjImage* im) { return im ? im->interp : 0; } 455 Sym obj_image_soname(const ObjImage* im) { return im ? im->soname : 0; } 456 457 u32 obj_image_nsegments(const ObjImage* im) { return im ? im->nsegs : 0; } 458 const ObjSegment* obj_image_segment(const ObjImage* im, u32 idx) { 459 return (im && idx < im->nsegs) ? &im->segs[idx] : NULL; 460 } 461 u32 obj_image_ndeps(const ObjImage* im) { return im ? im->ndeps : 0; } 462 const ObjImageDep* obj_image_dep(const ObjImage* im, u32 idx) { 463 return (im && idx < im->ndeps) ? &im->deps[idx] : NULL; 464 } 465 u32 obj_image_nrpaths(const ObjImage* im) { return im ? im->nrpaths : 0; } 466 Sym obj_image_rpath(const ObjImage* im, u32 idx) { 467 return (im && idx < im->nrpaths) ? im->rpaths[idx] : 0; 468 } 469 u32 obj_image_ndynsyms(const ObjImage* im) { return im ? im->ndynsyms : 0; } 470 const ObjImageSym* obj_image_dynsym(const ObjImage* im, u32 idx) { 471 return (im && idx < im->ndynsyms) ? &im->dynsyms[idx] : NULL; 472 } 473 u32 obj_image_ndynrelocs(const ObjImage* im) { return im ? im->ndynrelocs : 0; } 474 const ObjImageReloc* obj_image_dynreloc(const ObjImage* im, u32 idx) { 475 return (im && idx < im->ndynrelocs) ? &im->dynrelocs[idx] : NULL; 476 } 477 u32 obj_image_nundefs(const ObjImage* im) { return im ? im->nundefs : 0; } 478 Sym obj_image_undef(const ObjImage* im, u32 idx) { 479 return (im && idx < im->nundefs) ? im->undefs[idx] : 0; 480 } 481 u32 obj_image_nraws(const ObjImage* im) { return im ? im->nraws : 0; } 482 const ObjImageRaw* obj_image_raw(const ObjImage* im, u32 idx) { 483 return (im && idx < im->nraws) ? &im->raws[idx] : NULL; 484 } 485 486 void obj_ext_set(ObjBuilder* ob, ObjExtKind kind, void* payload, 487 ObjExtFreeFn free_fn) { 488 if (!ob || (u32)kind >= OBJ_EXT_SLOT_COUNT) return; 489 if (ob->ext[kind].payload && ob->ext[kind].free_fn && 490 ob->ext[kind].payload != payload) { 491 ob->ext[kind].free_fn(ob->c, ob->ext[kind].payload); 492 } 493 ob->ext[kind].payload = payload; 494 ob->ext[kind].free_fn = free_fn; 495 } 496 497 void* obj_ext_get(const ObjBuilder* ob, ObjExtKind kind) { 498 if (!ob || (u32)kind >= OBJ_EXT_SLOT_COUNT) return NULL; 499 return ob->ext[kind].payload; 500 } 501 502 void obj_ext_clear(ObjBuilder* ob, ObjExtKind kind) { 503 if (!ob || (u32)kind >= OBJ_EXT_SLOT_COUNT) return; 504 if (ob->ext[kind].payload && ob->ext[kind].free_fn) { 505 ob->ext[kind].free_fn(ob->c, ob->ext[kind].payload); 506 } 507 ob->ext[kind].payload = NULL; 508 ob->ext[kind].free_fn = NULL; 509 } 510 511 /* ---- write side ---- */ 512 513 /* Pack (name, kind) into a nonzero hashmap key. The low bit is always set so 514 * the key is never 0 (the empty-slot sentinel), and name/kind occupy disjoint 515 * bit ranges so distinct (name, kind) pairs never collide. */ 516 static u64 sec_progbits_key(Sym name, SecKind kind) { 517 return (((u64)name) << 17) | (((u64)(u16)kind) << 1) | 1u; 518 } 519 520 ObjSecId obj_section(ObjBuilder* ob, Sym name, SecKind kind, u16 flags, 521 u32 align) { 522 /* Find-or-create by (name, kind, sem=PROGBITS). Repeated calls for the 523 * same logical section — e.g. one .rodata per FP/string literal, or one 524 * .data per static initializer — collapse onto a single Section and 525 * accumulate bytes into it instead of emitting a fan-out of identically- 526 * named output sections. Merge align (max) and flags (union) so a 527 * stricter requirement from a later caller wins. The PROGBITS find is an 528 * O(1) index lookup (sec_by_key), kept exact by obj_section_ex. */ 529 ObjSecId* hit = 530 SecKeyIndex_get(&ob->sec_by_key, sec_progbits_key(name, kind)); 531 if (hit) { 532 Section* s = Sections_at(&ob->sections, *hit); 533 if (s) { 534 if (align > s->align) s->align = align; 535 s->flags = (u16)(s->flags | flags); 536 /* Pad to align so the next obj_reserve / obj_write lands at an 537 * offset that satisfies this caller's alignment. Without this 538 * each contribution is laid out at whatever offset the prior 539 * write happened to leave, so a 4-byte global following a 6-byte 540 * string lands at .data+6 — and any LDST32 reloc against the 541 * containing section breaks at link time. */ 542 u32 a = align ? align : 1u; 543 if (a > 1u) { 544 u32 cur = buf_pos(&s->bytes); 545 u32 mis = cur & (a - 1u); 546 if (mis) { 547 u32 pad = a - mis; 548 u8* dst = buf_reserve(&s->bytes, pad); 549 if (dst) memset(dst, 0, pad); 550 } 551 } 552 return *hit; 553 } 554 } 555 return obj_section_ex(ob, name, kind, SSEM_PROGBITS, flags, align, 0, 556 OBJ_SEC_NONE, 0); 557 } 558 559 ObjSecId obj_section_ex(ObjBuilder* ob, Sym name, SecKind kind, SecSem sem, 560 u16 flags, u32 align, u32 entsize, u32 link, u32 info) { 561 u32 id; 562 Section* s = Sections_push(&ob->sections, &id); 563 if (!s) return OBJ_SEC_NONE; 564 s->name = name; 565 s->kind = (u16)kind; 566 s->flags = flags; 567 s->sem = (u16)sem; 568 s->ext_kind = OBJ_EXT_NONE; 569 s->align = align ? align : 1; 570 s->entsize = entsize; 571 s->link = (ObjSecId)link; 572 s->info = info; 573 s->group_id = OBJ_GROUP_NONE; 574 s->bss_size = 0; 575 s->addr = 0; 576 buf_init(&s->bytes, ob->heap); 577 /* Index PROGBITS sections so obj_section's find is O(1). try_insert keeps the 578 * first id for a (name, kind), matching the old scan's first-match semantics 579 * (and leaving distinct same-named COMDAT sections, created directly here, to 580 * resolve to the first — exactly as the linear scan did). */ 581 if (sem == SSEM_PROGBITS) 582 (void)SecKeyIndex_try_insert(&ob->sec_by_key, sec_progbits_key(name, kind), 583 (ObjSecId)id, NULL); 584 return (ObjSecId)id; 585 } 586 587 void obj_section_set_addr(ObjBuilder* ob, ObjSecId id, u64 addr) { 588 Section* s = Sections_at(&ob->sections, id); 589 if (s && id != OBJ_SEC_NONE) s->addr = addr; 590 } 591 592 void obj_section_set_flags(ObjBuilder* ob, ObjSecId id, u16 flags) { 593 Section* s = Sections_at(&ob->sections, id); 594 if (s && id != OBJ_SEC_NONE) s->flags = flags; 595 } 596 597 void obj_section_set_entsize(ObjBuilder* ob, ObjSecId id, u32 entsize) { 598 Section* s = Sections_at(&ob->sections, id); 599 if (s && id != OBJ_SEC_NONE) s->entsize = entsize; 600 } 601 602 void obj_section_set_align(ObjBuilder* ob, ObjSecId id, u32 align) { 603 Section* s = Sections_at(&ob->sections, id); 604 if (s && id != OBJ_SEC_NONE) s->align = align ? align : 1; 605 } 606 607 void obj_section_set_group(ObjBuilder* ob, ObjSecId id, ObjGroupId gid) { 608 Section* s = Sections_at(&ob->sections, id); 609 if (s && id != OBJ_SEC_NONE) s->group_id = gid; 610 } 611 612 void obj_section_set_link_info(ObjBuilder* ob, ObjSecId id, ObjSecId link, 613 u32 info) { 614 Section* s; 615 if (id == OBJ_SEC_NONE) return; 616 s = Sections_at(&ob->sections, id); 617 if (!s) return; 618 s->link = link; 619 s->info = info; 620 } 621 622 void obj_section_set_ext(ObjBuilder* ob, ObjSecId id, ObjExtKind ek, 623 u32 ext_type, u32 ext_flags) { 624 Section* s; 625 if (id == OBJ_SEC_NONE) return; 626 s = Sections_at(&ob->sections, id); 627 if (!s) return; 628 s->ext_kind = (u16)ek; 629 s->ext_type = ext_type; 630 s->ext_flags = ext_flags; 631 } 632 633 /* A NOBITS section (.bss / .tbss) stores no bytes — only a size. decl.c and 634 * obj_align_to already treat SEC_BSS this way regardless of sem; obj_write and 635 * obj_pos must agree so the MCEmitter path (the standalone assembler's 636 * `.zero`/`.skip` fills and label positions) advances and reports the bss_size 637 * cursor instead of a byte buffer that the emitters then ignore. Codegen never 638 * writes/positions a BSS section through these (it uses obj_reserve_bss and its 639 * own counter), so this only affects the assembler's path. */ 640 static int sec_is_nobits(const Section* s) { 641 return s->sem == SSEM_NOBITS || s->kind == SEC_BSS; 642 } 643 644 void obj_write(ObjBuilder* ob, ObjSecId id, const void* data, size_t n) { 645 Section* s; 646 if (id == OBJ_SEC_NONE) return; 647 s = Sections_at(&ob->sections, id); 648 if (!s) return; 649 if (sec_is_nobits(s)) { 650 s->bss_size += (u32)n; /* reserve zero-fill space; store nothing */ 651 return; 652 } 653 buf_write(&s->bytes, data, n); 654 } 655 656 /* See obj.h: the byte buffer for a PROGBITS section, NULL for NOBITS/.bss (so 657 * the caller falls back to obj_write's bss_size path) or invalid ids. Lets the 658 * MCEmitter hoist the per-emit Sections_at deref + nobits branch out of the hot 659 * loop, re-resolving only at set_section. */ 660 Buf* obj_section_bytes(ObjBuilder* ob, ObjSecId id) { 661 Section* s; 662 if (id == OBJ_SEC_NONE) return NULL; 663 s = Sections_at(&ob->sections, id); 664 if (!s || sec_is_nobits(s)) return NULL; 665 return &s->bytes; 666 } 667 668 u8* obj_reserve(ObjBuilder* ob, ObjSecId id, size_t n) { 669 Section* s; 670 if (id == OBJ_SEC_NONE) return NULL; 671 s = Sections_at(&ob->sections, id); 672 return s ? buf_reserve(&s->bytes, n) : NULL; 673 } 674 675 void obj_reserve_bss(ObjBuilder* ob, ObjSecId id, u32 size, u32 align) { 676 Section* s; 677 if (id == OBJ_SEC_NONE) return; 678 s = Sections_at(&ob->sections, id); 679 if (!s) return; 680 s->bss_size = size; 681 if (align) s->align = align; 682 } 683 684 u32 obj_align_to(ObjBuilder* ob, ObjSecId id, u32 align) { 685 Section* s; 686 u32 a, cur, base, pad; 687 if (id == OBJ_SEC_NONE) return 0; 688 s = Sections_at(&ob->sections, id); 689 if (!s) return 0; 690 a = align ? align : 1u; 691 /* Treat SEC_BSS like NOBITS even when sem is the default PROGBITS — 692 * decl.c creates .bss via the simple obj_section, but emit_macho / 693 * emit_elf both route SEC_BSS through the zerofill path regardless 694 * of sem, so the byte buf is ignored on output and only bss_size 695 * matters. */ 696 if (s->sem == SSEM_NOBITS || s->kind == SEC_BSS) { 697 base = (s->bss_size + (a - 1u)) & ~(a - 1u); 698 s->bss_size = base; 699 if (a > s->align) s->align = a; 700 return base; 701 } 702 cur = buf_pos(&s->bytes); 703 base = (cur + (a - 1u)) & ~(a - 1u); 704 pad = base - cur; 705 if (pad) { 706 u8* p = buf_reserve(&s->bytes, pad); 707 if (p) memset(p, 0, pad); 708 } 709 if (a > s->align) s->align = a; 710 return base; 711 } 712 713 u32 obj_pos(ObjBuilder* ob, ObjSecId id) { 714 Section* s; 715 if (id == OBJ_SEC_NONE) return 0; 716 s = Sections_at(&ob->sections, id); 717 if (!s) return 0; 718 return sec_is_nobits(s) ? s->bss_size : buf_pos(&s->bytes); 719 } 720 721 void obj_patch(ObjBuilder* ob, ObjSecId id, u32 ofs, const void* data, 722 size_t n) { 723 Section* s; 724 if (id == OBJ_SEC_NONE) return; 725 s = Sections_at(&ob->sections, id); 726 if (s) buf_patch(&s->bytes, ofs, data, n); 727 } 728 729 static ObjSymId obj_symbol_make(ObjBuilder* ob, Sym name, SymBind bind, 730 SymVis vis, SymKind kind, ObjSecId section_id, 731 u64 value, u64 size, u64 common_align, 732 int index_name) { 733 u32 id; 734 ObjSym* s = Symbols_push(&ob->symbols, &id); 735 if (!s) return OBJ_SYM_NONE; 736 s->name = name; 737 s->bind = (u16)bind; 738 s->kind = (u16)kind; 739 s->vis = (u8)vis; 740 s->ext_kind = OBJ_EXT_NONE; 741 s->section_id = section_id; 742 s->value = value; 743 s->size = size; 744 s->common_align = common_align; 745 s->atom_subordinate = 0; 746 /* First-wins: record the lowest id for this name so obj_symbol_find returns 747 * the same symbol the linear scan would. Later same-name symbols (legal for 748 * STB_LOCAL) do not overwrite. */ 749 if (index_name && name && !SymNameIndex_get(&ob->sym_by_name, name)) 750 (void)SymNameIndex_set(&ob->sym_by_name, name, (ObjSymId)id); 751 return (ObjSymId)id; 752 } 753 754 ObjSymId obj_symbol(ObjBuilder* ob, Sym name, SymBind bind, SymKind kind, 755 ObjSecId section_id, u64 value, u64 size) { 756 return obj_symbol_ex(ob, name, bind, SV_DEFAULT, kind, section_id, value, 757 size, 0); 758 } 759 760 ObjSymId obj_symbol_ex(ObjBuilder* ob, Sym name, SymBind bind, SymVis vis, 761 SymKind kind, ObjSecId section_id, u64 value, u64 size, 762 u64 common_align) { 763 return obj_symbol_make(ob, name, bind, vis, kind, section_id, value, size, 764 common_align, 1); 765 } 766 767 ObjSymId obj_symbol_defer(ObjBuilder* ob, Sym name, SymBind bind, SymVis vis, 768 SymKind kind, u64 size) { 769 ObjSymId id; 770 ObjSym* s; 771 id = obj_symbol_make(ob, name, bind, vis, kind, OBJ_SEC_NONE, 0, size, 0, 0); 772 if (id == OBJ_SYM_NONE) return OBJ_SYM_NONE; 773 s = Symbols_at(&ob->symbols, id); 774 if (s) s->removed = 1; 775 return id; 776 } 777 778 ObjSymId obj_symbol_find(ObjBuilder* ob, Sym name) { 779 /* Authoritative O(1) lookup — never a linear scan. Normal/live symbols are 780 * indexed when created or published, and obj_symbol_rename keeps the index 781 * exact. Deferred symbols deliberately stay out of this map until published. 782 */ 783 ObjSymId* hit; 784 if (!ob || !name) return OBJ_SYM_NONE; 785 hit = SymNameIndex_get(&ob->sym_by_name, name); 786 return hit ? *hit : OBJ_SYM_NONE; 787 } 788 789 void obj_symbol_define(ObjBuilder* ob, ObjSymId id, ObjSecId section_id, 790 u64 value, u64 size) { 791 ObjSym* s; 792 if (id == OBJ_SYM_NONE) return; 793 s = Symbols_at(&ob->symbols, id); 794 if (!s) return; 795 s->section_id = section_id; 796 s->value = value; 797 s->size = size; 798 if (s->kind == SK_UNDEF) s->kind = SK_OBJ; 799 } 800 801 void obj_symbol_define_live(ObjBuilder* ob, ObjSymId id, ObjSecId section_id, 802 u64 value, u64 size) { 803 ObjSym* s; 804 ObjSymId* slot; 805 obj_symbol_define(ob, id, section_id, value, size); 806 if (!ob || id == OBJ_SYM_NONE) return; 807 s = Symbols_at(&ob->symbols, id); 808 if (!s) return; 809 s->removed = 0; 810 if (s->name) { 811 slot = SymNameIndex_get(&ob->sym_by_name, s->name); 812 if (!slot || *slot > id) 813 (void)SymNameIndex_set(&ob->sym_by_name, s->name, id); 814 } 815 } 816 817 void obj_symbol_set_flags(ObjBuilder* ob, ObjSymId id, u16 flags) { 818 ObjSym* s; 819 if (id == OBJ_SYM_NONE) return; 820 s = Symbols_at(&ob->symbols, id); 821 if (!s) return; 822 s->flags = flags; 823 } 824 825 void obj_symbol_set_atom_subordinate(ObjBuilder* ob, ObjSymId id, 826 int subordinate) { 827 ObjSym* s; 828 if (id == OBJ_SYM_NONE) return; 829 s = Symbols_at(&ob->symbols, id); 830 if (!s) return; 831 s->atom_subordinate = subordinate ? 1u : 0u; 832 } 833 834 void obj_reloc(ObjBuilder* ob, ObjSecId section_id, u32 offset, RelocKind kind, 835 ObjSymId sym, i64 addend) { 836 obj_reloc_ex(ob, section_id, offset, kind, sym, addend, 1, 0); 837 } 838 839 void obj_reloc_ex(ObjBuilder* ob, ObjSecId section_id, u32 offset, 840 RelocKind kind, ObjSymId sym, i64 addend, int explicit_addend, 841 int pair) { 842 Reloc* r = Relocs_push(&ob->relocs, NULL); 843 if (!r) return; 844 r->section_id = section_id; 845 r->offset = offset; 846 r->kind = (u16)kind; 847 r->has_explicit_addend = (u8)(explicit_addend ? 1 : 0); 848 r->pair = (u8)pair; 849 r->sym = sym; 850 r->addend = addend; 851 ob->reloc_index_dirty = 1; /* invalidate the per-section reloc index */ 852 /* Any reloc against this symbol is enough to retain it through the 853 * emit-time UNDEF prune. See ObjSym::referenced. */ 854 obj_sym_mark_referenced(ob, sym); 855 } 856 857 void obj_sym_mark_referenced(ObjBuilder* ob, ObjSymId id) { 858 ObjSym* s; 859 if (id == OBJ_SYM_NONE) return; 860 s = Symbols_at(&ob->symbols, id); 861 if (s) s->referenced = 1; 862 } 863 864 void obj_sym_set_referenced(ObjBuilder* ob, ObjSymId id, int referenced) { 865 ObjSym* s; 866 if (id == OBJ_SYM_NONE) return; 867 s = Symbols_at(&ob->symbols, id); 868 if (s) s->referenced = referenced ? 1u : 0u; 869 } 870 871 ObjAtomId obj_atom_define(ObjBuilder* ob, ObjSecId section_id, u32 offset, 872 u32 size, ObjSymId signature, u32 flags) { 873 u32 id; 874 ObjAtom* a; 875 if (!ob || section_id == OBJ_SEC_NONE) return OBJ_ATOM_NONE; 876 a = Atoms_push(&ob->atoms, &id); 877 if (!a) return OBJ_ATOM_NONE; 878 a->section_id = section_id; 879 a->offset = offset; 880 a->size = size; 881 a->signature = signature; 882 a->flags = flags; 883 return (ObjAtomId)id; 884 } 885 886 ObjGroupId obj_group(ObjBuilder* ob, Sym name, ObjSymId signature, u32 flags) { 887 u32 id; 888 ObjGroup* g = Groups_push(&ob->groups, &id); 889 if (!g) return OBJ_GROUP_NONE; 890 g->name = name; 891 g->signature = signature; 892 g->flags = flags; 893 return (ObjGroupId)id; 894 } 895 896 void obj_group_add_section(ObjBuilder* ob, ObjGroupId gid, ObjSecId sec) { 897 ObjGroup* g; 898 ObjSecId* p; 899 if (gid == OBJ_GROUP_NONE) return; 900 g = Groups_at(&ob->groups, gid); 901 if (!g) return; 902 /* Linear realloc — group section counts are tiny (handful per group). */ 903 p = (ObjSecId*)ob->heap->realloc( 904 ob->heap, g->sections, sizeof(ObjSecId) * g->nsections, 905 sizeof(ObjSecId) * (g->nsections + 1), _Alignof(ObjSecId)); 906 if (!p) return; 907 p[g->nsections++] = sec; 908 g->sections = p; 909 } 910 911 void obj_finalize(ObjBuilder* ob) { 912 /* No flat-offset patching needed yet — section bytes are read out via 913 * buf_flatten on demand by emitters. Keep this hook in place: when a 914 * future writer wants intra-section fixups (e.g. label-to-offset 915 * resolution after the full section is written), this is where they 916 * land. */ 917 (void)ob; 918 } 919 920 /* ---- mutators (strip / objcopy support) ---- */ 921 922 void obj_section_remove(ObjBuilder* ob, ObjSecId id) { 923 Section* s; 924 if (!ob || id == OBJ_SEC_NONE) return; 925 s = Sections_at(&ob->sections, id); 926 if (!s) return; 927 s->removed = 1; 928 } 929 930 void obj_symbol_remove(ObjBuilder* ob, ObjSymId id) { 931 ObjSym* s; 932 if (!ob || id == OBJ_SYM_NONE) return; 933 s = Symbols_at(&ob->symbols, id); 934 if (!s) return; 935 s->removed = 1; 936 } 937 938 void obj_group_remove(ObjBuilder* ob, ObjGroupId id) { 939 ObjGroup* g; 940 if (!ob || id == OBJ_GROUP_NONE) return; 941 g = Groups_at(&ob->groups, id); 942 if (!g) return; 943 g->removed = 1; 944 } 945 946 void obj_section_rename(ObjBuilder* ob, ObjSecId id, Sym new_name) { 947 Section* s; 948 if (!ob || id == OBJ_SEC_NONE) return; 949 s = Sections_at(&ob->sections, id); 950 if (!s) return; 951 s->name = new_name; 952 } 953 954 void obj_symbol_rename(ObjBuilder* ob, ObjSymId id, Sym new_name) { 955 ObjSym* s; 956 Sym old; 957 ObjSymId* slot; 958 if (!ob || id == OBJ_SYM_NONE) return; 959 s = Symbols_at(&ob->symbols, id); 960 if (!s) return; 961 old = s->name; 962 s->name = new_name; 963 if (old == new_name) return; 964 /* Keep the name index exact so obj_symbol_find stays a pure hash lookup. 965 * If this symbol was the indexed entry for its old name, hand the entry to 966 * the next-lowest symbol still carrying that name (duplicate STB_LOCAL names 967 * are legal), or drop it. This is the only scan in the symbol-index path and 968 * it is confined to obj_symbol_rename — a cold objcopy-style operation, never 969 * the codegen/find hot path. */ 970 if (old) { 971 slot = SymNameIndex_get(&ob->sym_by_name, old); 972 if (slot && *slot == id) { 973 ObjSymId repl = OBJ_SYM_NONE; 974 u32 n = Symbols_count(&ob->symbols); 975 for (u32 i = 1; i < n; ++i) { 976 ObjSym* t = Symbols_at(&ob->symbols, i); 977 if (t && (ObjSymId)i != id && t->name == old) { 978 repl = (ObjSymId)i; 979 break; 980 } 981 } 982 if (repl != OBJ_SYM_NONE) 983 (void)SymNameIndex_set(&ob->sym_by_name, old, repl); 984 else 985 SymNameIndex_del(&ob->sym_by_name, old); 986 } 987 } 988 /* new_name resolves to the lowest id that carries it (first-match order). A 989 * rename can give an existing lower-id symbol this name, so lower an existing 990 * entry when warranted. */ 991 if (new_name) { 992 slot = SymNameIndex_get(&ob->sym_by_name, new_name); 993 if (!slot || *slot > id) 994 (void)SymNameIndex_set(&ob->sym_by_name, new_name, id); 995 } 996 } 997 998 void obj_symbol_set_bind(ObjBuilder* ob, ObjSymId id, SymBind bind) { 999 ObjSym* s; 1000 if (!ob || id == OBJ_SYM_NONE) return; 1001 s = Symbols_at(&ob->symbols, id); 1002 if (!s) return; 1003 s->bind = (u16)bind; 1004 } 1005 1006 void obj_symbol_set_vis(ObjBuilder* ob, ObjSymId id, SymVis vis) { 1007 ObjSym* s; 1008 if (!ob || id == OBJ_SYM_NONE) return; 1009 s = Symbols_at(&ob->symbols, id); 1010 if (!s) return; 1011 s->vis = (u8)vis; 1012 } 1013 1014 void obj_section_replace_bytes(ObjBuilder* ob, ObjSecId id, const u8* data, 1015 size_t n) { 1016 Section* s; 1017 if (!ob || id == OBJ_SEC_NONE) return; 1018 s = Sections_at(&ob->sections, id); 1019 if (!s) return; 1020 /* Drop the old chunked Buf and reinitialize empty, then write the new 1021 * bytes. Cheaper than scanning + patching when the replacement is 1022 * different-sized — which it usually is (objcopy --update-section). */ 1023 buf_fini(&s->bytes); 1024 buf_init(&s->bytes, ob->heap); 1025 s->bss_size = 0; 1026 if (data && n) buf_write(&s->bytes, data, n); 1027 } 1028 1029 void obj_sweep_dead(ObjBuilder* ob) { 1030 u32 nsec = Sections_count(&ob->sections); 1031 u32 nsym = Symbols_count(&ob->symbols); 1032 u32 nrel = Relocs_count(&ob->relocs); 1033 u32 ngrp = Groups_count(&ob->groups); 1034 u32 i; 1035 1036 /* Pass 1: cascade removed sections into their defining symbols. Also 1037 * absorbs the historical UNDEF-prune predicate: any non-referenced 1038 * global/weak symbol that lacks a defining section (and isn't an ABS 1039 * or COMMON definition, both of which legitimately have section_id == 1040 * OBJ_SEC_NONE) is a spurious extern from a header — drop it. 1041 * 1042 * The "no defining section" test matches macho_emit's sym_is_undef, 1043 * which is stronger than `kind == SK_UNDEF`: frontends mint SK_OBJ / 1044 * SK_TLS / SK_FUNC entries for extern decls and only set them to 1045 * SK_UNDEF for true references, so checking section_id catches both. */ 1046 for (i = 1; i < nsym; ++i) { 1047 ObjSym* s = Symbols_at(&ob->symbols, i); 1048 if (!s || s->removed) continue; 1049 if (s->section_id != OBJ_SEC_NONE) { 1050 const Section* sec = Sections_at(&ob->sections, s->section_id); 1051 if (sec && sec->removed) { 1052 s->removed = 1; 1053 continue; 1054 } 1055 } 1056 if (s->section_id == OBJ_SEC_NONE && s->kind != SK_ABS && 1057 s->kind != SK_COMMON && !s->referenced && 1058 (s->bind == SB_GLOBAL || s->bind == SB_WEAK)) { 1059 s->removed = 1; 1060 } 1061 } 1062 1063 /* Pass 2: drop relocs that became dangling. A reloc is dead if its 1064 * containing section, its target symbol, or the symbol's defining 1065 * section is gone. */ 1066 for (i = 0; i < nrel; ++i) { 1067 Reloc* r = Relocs_at(&ob->relocs, i); 1068 if (!r || r->removed) continue; 1069 if (r->section_id != OBJ_SEC_NONE) { 1070 const Section* sec = Sections_at(&ob->sections, r->section_id); 1071 if (!sec || sec->removed) { 1072 r->removed = 1; 1073 continue; 1074 } 1075 } 1076 if (r->sym != OBJ_SYM_NONE) { 1077 const ObjSym* ts = Symbols_at(&ob->symbols, r->sym); 1078 if (!ts || ts->removed) r->removed = 1; 1079 } 1080 } 1081 1082 { 1083 u32 natom = Atoms_count(&ob->atoms); 1084 for (i = 1; i < natom; ++i) { 1085 ObjAtom* a = Atoms_at(&ob->atoms, i); 1086 const Section* sec; 1087 const ObjSym* sig; 1088 if (!a || a->removed) continue; 1089 sec = Sections_at(&ob->sections, a->section_id); 1090 if (!sec || sec->removed) { 1091 a->removed = 1; 1092 continue; 1093 } 1094 if (a->signature != OBJ_SYM_NONE) { 1095 sig = Symbols_at(&ob->symbols, a->signature); 1096 if (!sig || sig->removed) a->removed = 1; 1097 } 1098 } 1099 } 1100 1101 /* Pass 3: compact each group's member list to drop removed sections; 1102 * tombstone the group if its list empties out or its signature symbol 1103 * is removed. Member list is rewritten in place — the storage stays 1104 * the same size, the trailing slots just become unused. */ 1105 for (i = 1; i < ngrp; ++i) { 1106 ObjGroup* g = Groups_at(&ob->groups, i); 1107 u32 w, r; 1108 if (!g || g->removed) continue; 1109 if (g->signature != OBJ_SYM_NONE) { 1110 const ObjSym* sig = Symbols_at(&ob->symbols, g->signature); 1111 if (!sig || sig->removed) { 1112 g->removed = 1; 1113 continue; 1114 } 1115 } 1116 w = 0; 1117 for (r = 0; r < g->nsections; ++r) { 1118 ObjSecId sid = g->sections[r]; 1119 const Section* sec = 1120 (sid != OBJ_SEC_NONE) ? Sections_at(&ob->sections, sid) : NULL; 1121 if (sec && !sec->removed) g->sections[w++] = sid; 1122 } 1123 g->nsections = w; 1124 if (w == 0) g->removed = 1; 1125 } 1126 1127 /* Pass 4: clear Section.link if it now points at a removed section. 1128 * (Section.info is type-dependent — leave it to the emitter, which 1129 * already inspects the sem to interpret it.) */ 1130 for (i = 1; i < nsec; ++i) { 1131 Section* s = Sections_at(&ob->sections, i); 1132 if (!s || s->removed) continue; 1133 if (s->link != OBJ_SEC_NONE) { 1134 const Section* lk = Sections_at(&ob->sections, s->link); 1135 if (!lk || lk->removed) s->link = OBJ_SEC_NONE; 1136 } 1137 } 1138 1139 /* Removed flags changed — the per-section reloc index must rebuild. */ 1140 ob->reloc_index_dirty = 1; 1141 } 1142 1143 /* ---- read side ---- */ 1144 1145 /* (Re)build the per-section reloc index: a counting sort of the live relocs 1146 * keyed by section_id, preserving ascending global order within each section. 1147 * O(n_relocs + n_sections). Idempotent while the index stays clean; callers 1148 * reach it through obj_reloc_count / obj_reloc_section. Cast away const at the 1149 * call sites — the index is a lazily-filled cache, not logical state. */ 1150 static void obj_reloc_index_ensure(ObjBuilder* ob) { 1151 u32 nsec, total, i, nlive; 1152 u32* off; 1153 if (ob->reloc_index_off && !ob->reloc_index_dirty) return; 1154 nsec = Sections_count(&ob->sections); 1155 total = Relocs_count(&ob->relocs); 1156 1157 if (!ob->reloc_index_off || ob->reloc_index_nsec != nsec) { 1158 if (ob->reloc_index_off) 1159 ob->heap->free(ob->heap, ob->reloc_index_off, 1160 sizeof(u32) * (ob->reloc_index_nsec + 1u)); 1161 off = (u32*)ob->heap->alloc(ob->heap, sizeof(u32) * (nsec + 1u), 1162 _Alignof(u32)); 1163 ob->reloc_index_off = off; 1164 ob->reloc_index_nsec = nsec; 1165 } else { 1166 off = ob->reloc_index_off; 1167 } 1168 memset(off, 0, sizeof(u32) * (nsec + 1u)); 1169 1170 /* Pass 1: tally live relocs into off[section_id + 1]. */ 1171 nlive = 0; 1172 for (i = 0; i < total; ++i) { 1173 const Reloc* r = Relocs_at(&ob->relocs, i); 1174 if (r->removed) continue; 1175 ++off[r->section_id + 1u]; 1176 ++nlive; 1177 } 1178 /* Prefix-sum: off[s] = start of section s's run; off[nsec] = nlive. */ 1179 for (i = 1; i <= nsec; ++i) off[i] += off[i - 1u]; 1180 1181 if (!ob->reloc_index || ob->reloc_index_len != nlive) { 1182 if (ob->reloc_index) 1183 ob->heap->free(ob->heap, ob->reloc_index, 1184 sizeof(u32) * ob->reloc_index_len); 1185 ob->reloc_index = nlive ? (u32*)ob->heap->alloc( 1186 ob->heap, sizeof(u32) * nlive, _Alignof(u32)) 1187 : NULL; 1188 ob->reloc_index_len = nlive; 1189 } 1190 1191 /* Pass 2: scatter global indices into per-section runs. A heap-temp cursor 1192 * (seeded from off[]) keeps the prefix offsets intact for the readers. */ 1193 if (nlive) { 1194 u32* cur = (u32*)ob->heap->alloc(ob->heap, sizeof(u32) * (nsec + 1u), 1195 _Alignof(u32)); 1196 memcpy(cur, off, sizeof(u32) * (nsec + 1u)); 1197 for (i = 0; i < total; ++i) { 1198 const Reloc* r = Relocs_at(&ob->relocs, i); 1199 if (r->removed) continue; 1200 ob->reloc_index[cur[r->section_id]++] = i; 1201 } 1202 ob->heap->free(ob->heap, cur, sizeof(u32) * (nsec + 1u)); 1203 } 1204 ob->reloc_index_dirty = 0; 1205 } 1206 1207 u32 obj_section_count(const ObjBuilder* ob) { 1208 return Sections_count(&ob->sections); 1209 } 1210 1211 const Section* obj_section_get(const ObjBuilder* ob, ObjSecId id) { 1212 if (id == OBJ_SEC_NONE) return NULL; 1213 return Sections_at(&ob->sections, id); 1214 } 1215 1216 u32 obj_reloc_count(const ObjBuilder* ob, ObjSecId id) { 1217 obj_reloc_index_ensure((ObjBuilder*)ob); 1218 if (id >= ob->reloc_index_nsec) return 0; 1219 return ob->reloc_index_off[id + 1u] - ob->reloc_index_off[id]; 1220 } 1221 1222 const u32* obj_reloc_section(const ObjBuilder* ob, ObjSecId id, u32* out_len) { 1223 obj_reloc_index_ensure((ObjBuilder*)ob); 1224 if (id >= ob->reloc_index_nsec) { 1225 if (out_len) *out_len = 0; 1226 return NULL; 1227 } 1228 if (out_len) 1229 *out_len = ob->reloc_index_off[id + 1u] - ob->reloc_index_off[id]; 1230 return ob->reloc_index + ob->reloc_index_off[id]; 1231 } 1232 1233 u32 obj_reloc_total(const ObjBuilder* ob) { return Relocs_count(&ob->relocs); } 1234 1235 const Reloc* obj_reloc_at(const ObjBuilder* ob, u32 idx) { 1236 return Relocs_at(&ob->relocs, idx); 1237 } 1238 1239 const ObjSym* obj_symbol_get(const ObjBuilder* ob, ObjSymId id) { 1240 if (id == OBJ_SYM_NONE) return NULL; 1241 return Symbols_at(&ob->symbols, id); 1242 } 1243 1244 u32 obj_atom_count(const ObjBuilder* ob) { return Atoms_count(&ob->atoms); } 1245 1246 const ObjAtom* obj_atom_get(const ObjBuilder* ob, ObjAtomId id) { 1247 if (id == OBJ_ATOM_NONE) return NULL; 1248 return Atoms_at(&ob->atoms, id); 1249 } 1250 1251 int obj_section_has_atoms(const ObjBuilder* ob, ObjSecId sid) { 1252 u32 n; 1253 if (!ob || sid == OBJ_SEC_NONE) return 0; 1254 n = Atoms_count(&ob->atoms); 1255 for (u32 i = 1; i < n; ++i) { 1256 const ObjAtom* a = Atoms_at(&ob->atoms, i); 1257 if (a && !a->removed && a->section_id == sid) return 1; 1258 } 1259 return 0; 1260 } 1261 1262 ObjAtomId obj_atom_find(const ObjBuilder* ob, ObjSecId sid, u32 offset) { 1263 u32 n; 1264 if (!ob || sid == OBJ_SEC_NONE) return OBJ_ATOM_NONE; 1265 n = Atoms_count(&ob->atoms); 1266 for (u32 i = 1; i < n; ++i) { 1267 const ObjAtom* a = Atoms_at(&ob->atoms, i); 1268 u64 begin, end; 1269 if (!a || a->removed || a->section_id != sid) continue; 1270 begin = a->offset; 1271 end = begin + a->size; 1272 if (a->size != 0 && (u64)offset >= begin && (u64)offset < end) 1273 return (ObjAtomId)i; 1274 } 1275 for (u32 i = 1; i < n; ++i) { 1276 const ObjAtom* a = Atoms_at(&ob->atoms, i); 1277 if (!a || a->removed || a->section_id != sid) continue; 1278 if (a->size == 0 && offset == a->offset) return (ObjAtomId)i; 1279 } 1280 return OBJ_ATOM_NONE; 1281 } 1282 1283 ObjAtomId obj_atom_find_symbol(const ObjBuilder* ob, ObjSymId sym) { 1284 const ObjSym* s; 1285 ObjAtomId aid; 1286 u32 n; 1287 if (!ob || sym == OBJ_SYM_NONE) return OBJ_ATOM_NONE; 1288 s = obj_symbol_get(ob, sym); 1289 if (!s || s->section_id == OBJ_SEC_NONE) return OBJ_ATOM_NONE; 1290 aid = obj_atom_find(ob, s->section_id, (u32)s->value); 1291 if (aid != OBJ_ATOM_NONE) return aid; 1292 n = Atoms_count(&ob->atoms); 1293 for (u32 i = 1; i < n; ++i) { 1294 const ObjAtom* a = Atoms_at(&ob->atoms, i); 1295 if (a && !a->removed && a->signature == sym) return (ObjAtomId)i; 1296 } 1297 return OBJ_ATOM_NONE; 1298 } 1299 1300 u32 obj_group_count(const ObjBuilder* ob) { return Groups_count(&ob->groups); } 1301 1302 const ObjGroup* obj_group_get(const ObjBuilder* ob, ObjGroupId id) { 1303 if (id == OBJ_GROUP_NONE) return NULL; 1304 return Groups_at(&ob->groups, id); 1305 } 1306 1307 ObjSymIter* obj_symiter_new(const ObjBuilder* ob) { 1308 ObjSymIter* it = 1309 (ObjSymIter*)ob->heap->alloc(ob->heap, sizeof(*it), _Alignof(ObjSymIter)); 1310 if (!it) return NULL; 1311 it->ob = ob; 1312 it->idx = 1; /* skip the id-0 sentinel */ 1313 return it; 1314 } 1315 1316 int obj_symiter_next(ObjSymIter* it, ObjSymEntry* out) { 1317 const ObjSym* s; 1318 if (!it) return 0; 1319 s = Symbols_at(&it->ob->symbols, it->idx); 1320 if (!s) return 0; 1321 out->id = it->idx; 1322 out->sym = s; 1323 it->idx++; 1324 return 1; 1325 } 1326 1327 void obj_symiter_free(ObjSymIter* it) { 1328 if (!it) return; 1329 ((Heap*)it->ob->heap)->free((Heap*)it->ob->heap, it, sizeof(*it)); 1330 } 1331 1332 struct ObjGroupIter { 1333 const ObjBuilder* ob; 1334 u32 idx; /* next index to return */ 1335 }; 1336 1337 ObjGroupIter* obj_groupiter_new(const ObjBuilder* ob) { 1338 ObjGroupIter* it = (ObjGroupIter*)ob->heap->alloc(ob->heap, sizeof(*it), 1339 _Alignof(ObjGroupIter)); 1340 if (!it) return NULL; 1341 it->ob = ob; 1342 it->idx = 1; /* skip the id-0 sentinel */ 1343 return it; 1344 } 1345 1346 int obj_groupiter_next(ObjGroupIter* it, ObjGroupEntry* out) { 1347 const ObjGroup* g; 1348 if (!it) return 0; 1349 g = Groups_at(&it->ob->groups, it->idx); 1350 if (!g) return 0; 1351 out->id = it->idx; 1352 out->group = g; 1353 it->idx++; 1354 return 1; 1355 } 1356 1357 void obj_groupiter_free(ObjGroupIter* it) { 1358 if (!it) return; 1359 ((Heap*)it->ob->heap)->free((Heap*)it->ob->heap, it, sizeof(*it)); 1360 } 1361 1362 /* Diagnostic spelling for a RelocKind. Drops the leading R_ from the enum 1363 * spelling so output reads like "RV_CALL" / "AARCH64_CALL26" — the same 1364 * spelling GNU objdump uses minus its arch prefix. */ 1365 const char* reloc_kind_name(RelocKind k) { 1366 switch (k) { 1367 #define _CASE(name) \ 1368 case name: \ 1369 return &(#name)[2] /* strip "R_" */ 1370 _CASE(R_NONE); 1371 _CASE(R_ABS32); 1372 _CASE(R_ABS64); 1373 _CASE(R_REL32); 1374 _CASE(R_REL64); 1375 _CASE(R_PC32); 1376 _CASE(R_PC64); 1377 _CASE(R_GOT32); 1378 _CASE(R_PLT32); 1379 _CASE(R_ABS8); 1380 _CASE(R_ABS16); 1381 _CASE(R_PREL16); 1382 _CASE(R_TPOFF64); 1383 _CASE(R_AARCH64_ADR_GOT_PAGE); 1384 _CASE(R_AARCH64_LD64_GOT_LO12_NC); 1385 _CASE(R_AARCH64_JUMP26); 1386 _CASE(R_AARCH64_CALL26); 1387 _CASE(R_AARCH64_CONDBR19); 1388 _CASE(R_AARCH64_TSTBR14); 1389 _CASE(R_AARCH64_LD_PREL_LO19); 1390 _CASE(R_AARCH64_ADR_PREL_LO21); 1391 _CASE(R_AARCH64_INTRA_LABEL_ADDR); 1392 _CASE(R_AARCH64_ADR_PREL_PG_HI21); 1393 _CASE(R_AARCH64_ADR_PREL_PG_HI21_NC); 1394 _CASE(R_AARCH64_ADD_ABS_LO12_NC); 1395 _CASE(R_AARCH64_LDST8_ABS_LO12_NC); 1396 _CASE(R_AARCH64_LDST16_ABS_LO12_NC); 1397 _CASE(R_AARCH64_LDST32_ABS_LO12_NC); 1398 _CASE(R_AARCH64_LDST64_ABS_LO12_NC); 1399 _CASE(R_AARCH64_LDST128_ABS_LO12_NC); 1400 _CASE(R_AARCH64_TLVP_LOAD_PAGE21); 1401 _CASE(R_AARCH64_TLVP_LOAD_PAGEOFF12); 1402 _CASE(R_AARCH64_TLSLE_ADD_TPREL_HI12); 1403 _CASE(R_AARCH64_TLSLE_ADD_TPREL_LO12); 1404 _CASE(R_AARCH64_TLSLE_ADD_TPREL_LO12_NC); 1405 _CASE(R_AARCH64_TLSLE_LDST8_TPREL_LO12); 1406 _CASE(R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC); 1407 _CASE(R_AARCH64_TLSLE_LDST16_TPREL_LO12); 1408 _CASE(R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC); 1409 _CASE(R_AARCH64_TLSLE_LDST32_TPREL_LO12); 1410 _CASE(R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC); 1411 _CASE(R_AARCH64_TLSLE_LDST64_TPREL_LO12); 1412 _CASE(R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC); 1413 _CASE(R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21); 1414 _CASE(R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC); 1415 _CASE(R_COFF_ADDR32NB); 1416 _CASE(R_AARCH64_POINTER_TO_GOT); 1417 _CASE(R_AARCH64_TLSDESC_ADR_PAGE21); 1418 _CASE(R_AARCH64_TLSDESC_LD64_LO12); 1419 _CASE(R_AARCH64_TLSDESC_ADD_LO12); 1420 _CASE(R_AARCH64_TLSDESC_CALL); 1421 _CASE(R_RV_TLS_GD_HI20); 1422 _CASE(R_AARCH64_GLOB_DAT); 1423 _CASE(R_AARCH64_JUMP_SLOT); 1424 _CASE(R_AARCH64_RELATIVE); 1425 _CASE(R_AARCH64_COPY); 1426 _CASE(R_X64_PC8); 1427 _CASE(R_X64_32S); 1428 _CASE(R_X64_PLT32); 1429 _CASE(R_X64_GOTPCREL); 1430 _CASE(R_X64_GOTPCRELX); 1431 _CASE(R_X64_REX_GOTPCRELX); 1432 _CASE(R_X64_GOTPC32); 1433 _CASE(R_X64_GOTOFF64); 1434 _CASE(R_X64_TPOFF32); 1435 _CASE(R_X64_DTPOFF32); 1436 _CASE(R_X64_DTPMOD64); 1437 _CASE(R_X64_DTPOFF64); 1438 _CASE(R_X64_TLSGD); 1439 _CASE(R_X64_TLSLD); 1440 _CASE(R_X64_GOTTPOFF); 1441 _CASE(R_X64_GLOB_DAT); 1442 _CASE(R_X64_JUMP_SLOT); 1443 _CASE(R_X64_RELATIVE); 1444 _CASE(R_X64_COPY); 1445 _CASE(R_X64_TLV); 1446 _CASE(R_RV_HI20); 1447 _CASE(R_RV_LO12_I); 1448 _CASE(R_RV_LO12_S); 1449 _CASE(R_RV_BRANCH); 1450 _CASE(R_RV_JAL); 1451 _CASE(R_RV_CALL); 1452 _CASE(R_RV_PCREL_HI20); 1453 _CASE(R_RV_PCREL_LO12_I); 1454 _CASE(R_RV_PCREL_LO12_S); 1455 _CASE(R_RV_INTRA_AUIPC_ADDI); 1456 _CASE(R_RV_GOT_HI20); 1457 _CASE(R_RV_TLS_GOT_HI20); 1458 _CASE(R_RV_TPREL_HI20); 1459 _CASE(R_RV_TPREL_LO12_I); 1460 _CASE(R_RV_TPREL_LO12_S); 1461 _CASE(R_RV_TPREL_ADD); 1462 _CASE(R_ADD8); 1463 _CASE(R_ADD16); 1464 _CASE(R_ADD32); 1465 _CASE(R_ADD64); 1466 _CASE(R_SUB8); 1467 _CASE(R_SUB16); 1468 _CASE(R_SUB32); 1469 _CASE(R_SUB64); 1470 _CASE(R_RV_ALIGN); 1471 _CASE(R_RV_RVC_BRANCH); 1472 _CASE(R_RV_RVC_JUMP); 1473 _CASE(R_RV_RELAX); 1474 _CASE(R_SUB6); 1475 _CASE(R_SET6); 1476 _CASE(R_SET_ULEB128); 1477 _CASE(R_SUB_ULEB128); 1478 _CASE(R_WASM_FUNCIDX); 1479 _CASE(R_WASM_TABLEIDX); 1480 _CASE(R_WASM_MEMOFS); 1481 _CASE(R_WASM_TYPEIDX); 1482 _CASE(R_COFF_SECREL); 1483 _CASE(R_COFF_SECTION); 1484 _CASE(R_COFF_AARCH64_SECREL_LOW12A); 1485 _CASE(R_COFF_AARCH64_SECREL_HIGH12A); 1486 _CASE(R_COFF_AARCH64_SECREL_LOW12L); 1487 _CASE(R_ARM_THM_CALL); 1488 _CASE(R_ARM_THM_JUMP24); 1489 _CASE(R_ARM_THM_JUMP19); 1490 _CASE(R_ARM_THM_MOVW_ABS_NC); 1491 _CASE(R_ARM_THM_MOVT_ABS); 1492 _CASE(R_ARM_THM_MOVW_PREL_NC); 1493 _CASE(R_ARM_THM_MOVT_PREL); 1494 _CASE(R_ARM_TLS_LE32); 1495 #undef _CASE 1496 } 1497 return "UNKNOWN"; 1498 } 1499 1500 /* ---- shared string-table builder (see obj.h ObjStrtab) ------------------ */ 1501 1502 static u32 obj_strtab_hash(const char* s, u32 len) { 1503 u32 h = 2166136261u; /* FNV-1a */ 1504 for (u32 i = 0; i < len; ++i) { 1505 h ^= (u8)s[i]; 1506 h *= 16777619u; 1507 } 1508 return h; 1509 } 1510 1511 void obj_strtab_init(ObjStrtab* t, Heap* h, int dedup) { 1512 memset(t, 0, sizeof *t); 1513 t->heap = h; 1514 t->dedup = dedup ? 1u : 0u; 1515 } 1516 1517 static void obj_strtab_reserve(ObjStrtab* t, u32 extra) { 1518 u32 ncap; 1519 u8* nd; 1520 if (t->len + extra <= t->cap) return; 1521 ncap = t->cap ? t->cap : 256u; 1522 while (t->len + extra > ncap) ncap *= 2u; 1523 nd = (u8*)t->heap->alloc(t->heap, ncap, 1); 1524 if (t->data) { 1525 memcpy(nd, t->data, t->len); 1526 t->heap->free(t->heap, t->data, t->cap); 1527 } 1528 t->data = nd; 1529 t->cap = ncap; 1530 } 1531 1532 void obj_strtab_put_raw(ObjStrtab* t, const void* bytes, u32 n) { 1533 if (!n) return; 1534 obj_strtab_reserve(t, n); 1535 memcpy(t->data + t->len, bytes, n); 1536 t->len += n; 1537 } 1538 1539 static void obj_strtab_index_grow(ObjStrtab* t) { 1540 u32 ncap = t->scap ? t->scap * 2u : 256u; 1541 u32 mask = ncap - 1u; 1542 ObjStrtabEnt* ns = (ObjStrtabEnt*)t->heap->alloc(t->heap, sizeof(*ns) * ncap, 1543 _Alignof(ObjStrtabEnt)); 1544 memset(ns, 0, sizeof(*ns) * ncap); 1545 for (u32 i = 0; i < t->scap; ++i) { 1546 u32 j; 1547 if (!t->slots[i].len) continue; 1548 j = t->slots[i].hash & mask; 1549 while (ns[j].len) j = (j + 1u) & mask; 1550 ns[j] = t->slots[i]; 1551 } 1552 if (t->slots) t->heap->free(t->heap, t->slots, sizeof(*t->slots) * t->scap); 1553 t->slots = ns; 1554 t->scap = ncap; 1555 } 1556 1557 static u32 obj_strtab_append(ObjStrtab* t, const char* s, u32 len) { 1558 u32 off = t->len; 1559 obj_strtab_reserve(t, len + 1u); 1560 memcpy(t->data + off, s, len); 1561 t->data[off + len] = 0; 1562 t->len += len + 1u; 1563 return off; 1564 } 1565 1566 u32 obj_strtab_add(ObjStrtab* t, const char* s, u32 len) { 1567 u32 h, mask, j, off; 1568 if (len == 0) return 0; 1569 if (!t->dedup) return obj_strtab_append(t, s, len); 1570 if ((t->sused + 1u) * 4u >= t->scap * 3u) obj_strtab_index_grow(t); 1571 h = obj_strtab_hash(s, len); 1572 mask = t->scap - 1u; 1573 j = h & mask; 1574 while (t->slots[j].len) { 1575 ObjStrtabEnt* e = &t->slots[j]; 1576 if (e->hash == h && e->len == len && memcmp(t->data + e->off, s, len) == 0) 1577 return e->off; 1578 j = (j + 1u) & mask; 1579 } 1580 off = obj_strtab_append(t, s, len); 1581 t->slots[j].hash = h; 1582 t->slots[j].off = off; 1583 t->slots[j].len = len; 1584 t->sused++; 1585 return off; 1586 } 1587 1588 u32 obj_strtab_size(const ObjStrtab* t) { return t->len; } 1589 u8* obj_strtab_data(ObjStrtab* t) { return t->data; } 1590 1591 void obj_strtab_fini(ObjStrtab* t) { 1592 if (t->data) t->heap->free(t->heap, t->data, t->cap); 1593 if (t->slots) t->heap->free(t->heap, t->slots, sizeof(*t->slots) * t->scap); 1594 memset(t, 0, sizeof *t); 1595 }