object_builder.c (13534B)
1 /* Public KitObjBuilder API: thin adapter over the internal obj_* surface. */ 2 3 #include <kit/object.h> 4 #include <string.h> 5 6 #include "core/core.h" 7 #include "core/heap.h" 8 #include "core/pool.h" 9 #include "core/slice.h" 10 #include "obj/format.h" 11 #include "obj/obj.h" 12 13 _Static_assert((uint32_t)KIT_RELOC_NONE == (uint32_t)R_NONE, 14 "public reloc NONE drift"); 15 _Static_assert((uint32_t)KIT_RELOC_ABS32 == (uint32_t)R_ABS32, 16 "public reloc ABS32 drift"); 17 _Static_assert((uint32_t)KIT_RELOC_ABS64 == (uint32_t)R_ABS64, 18 "public reloc ABS64 drift"); 19 _Static_assert((uint32_t)KIT_RELOC_REL32 == (uint32_t)R_REL32, 20 "public reloc REL32 drift"); 21 _Static_assert((uint32_t)KIT_RELOC_REL64 == (uint32_t)R_REL64, 22 "public reloc REL64 drift"); 23 _Static_assert((uint32_t)KIT_RELOC_PC32 == (uint32_t)R_PC32, 24 "public reloc PC32 drift"); 25 _Static_assert((uint32_t)KIT_RELOC_PC64 == (uint32_t)R_PC64, 26 "public reloc PC64 drift"); 27 _Static_assert((uint32_t)KIT_RELOC_GOT32 == (uint32_t)R_GOT32, 28 "public reloc GOT32 drift"); 29 _Static_assert((uint32_t)KIT_RELOC_PLT32 == (uint32_t)R_PLT32, 30 "public reloc PLT32 drift"); 31 _Static_assert((uint32_t)KIT_RELOC_X64_PLT32 == (uint32_t)R_X64_PLT32, 32 "public reloc X64_PLT32 drift"); 33 34 static ObjSecId pub_to_intern_sec(KitObjSection s) { 35 if (s == KIT_SECTION_NONE) return OBJ_SEC_NONE; 36 return (ObjSecId)(s + 1); 37 } 38 39 static KitObjSection intern_to_pub_sec(ObjSecId id) { 40 if (id == OBJ_SEC_NONE) return KIT_SECTION_NONE; 41 return (KitObjSection)(id - 1); 42 } 43 44 static ObjSymId pub_to_intern_sym(KitObjSymbol s) { 45 if (s == KIT_OBJ_SYMBOL_NONE) return OBJ_SYM_NONE; 46 return (ObjSymId)s; 47 } 48 49 static KitObjSymbol intern_to_pub_sym(ObjSymId id) { 50 if (id == OBJ_SYM_NONE) return KIT_OBJ_SYMBOL_NONE; 51 return (KitObjSymbol)id; 52 } 53 54 static ObjGroupId pub_to_intern_group(KitObjGroup g) { 55 if (g == KIT_OBJ_GROUP_NONE) return OBJ_GROUP_NONE; 56 return (ObjGroupId)g; 57 } 58 59 static KitObjGroup intern_to_pub_group(ObjGroupId id) { 60 if (id == OBJ_GROUP_NONE) return KIT_OBJ_GROUP_NONE; 61 return (KitObjGroup)id; 62 } 63 64 KitStatus kit_obj_builder_new(KitCompiler* c, KitObjBuilder** out) { 65 ObjBuilder* ob; 66 if (!out) return KIT_INVALID; 67 if (!c) return KIT_INVALID; 68 ob = obj_new(c); 69 if (!ob) return KIT_NOMEM; 70 *out = ob; 71 return KIT_OK; 72 } 73 74 void kit_obj_builder_free(KitObjBuilder* b) { 75 if (b) obj_free(b); 76 } 77 78 KitCompiler* kit_obj_builder_compiler(KitObjBuilder* b) { 79 return b ? (KitCompiler*)obj_compiler(b) : NULL; 80 } 81 82 KitStatus kit_obj_builder_section(KitObjBuilder* b, 83 const KitObjSectionDesc* desc, 84 KitObjSection* out) { 85 ObjSecId id; 86 if (!b || !desc || !out) return KIT_INVALID; 87 id = obj_section(b, (Sym)desc->name, (SecKind)desc->kind, (u16)desc->flags, 88 desc->align ? desc->align : 1u); 89 if (id == OBJ_SEC_NONE) return KIT_ERR; 90 if (desc->entsize) obj_section_set_entsize(b, id, desc->entsize); 91 *out = intern_to_pub_sec(id); 92 return KIT_OK; 93 } 94 95 KitStatus kit_obj_builder_section_group(KitObjBuilder* b, KitObjSection sec, 96 KitObjGroup grp) { 97 if (!b) return KIT_INVALID; 98 obj_section_set_group(b, pub_to_intern_sec(sec), pub_to_intern_group(grp)); 99 return KIT_OK; 100 } 101 102 KitStatus kit_obj_builder_pos(KitObjBuilder* b, KitObjSection sec, 103 uint64_t* out) { 104 if (!b || !out) return KIT_INVALID; 105 *out = obj_pos(b, pub_to_intern_sec(sec)); 106 return KIT_OK; 107 } 108 109 KitStatus kit_obj_builder_align(KitObjBuilder* b, KitObjSection sec, 110 uint32_t align, uint64_t* new_pos_out) { 111 u32 pos; 112 if (!b) return KIT_INVALID; 113 pos = obj_align_to(b, pub_to_intern_sec(sec), align ? align : 1u); 114 if (new_pos_out) *new_pos_out = pos; 115 return KIT_OK; 116 } 117 118 KitStatus kit_obj_builder_write(KitObjBuilder* b, KitObjSection sec, 119 const void* data, size_t n) { 120 if (!b) return KIT_INVALID; 121 obj_write(b, pub_to_intern_sec(sec), data, n); 122 return KIT_OK; 123 } 124 125 KitStatus kit_obj_builder_reserve(KitObjBuilder* b, KitObjSection sec, size_t n, 126 void** out) { 127 u8* p; 128 if (!b || !out) return KIT_INVALID; 129 p = obj_reserve(b, pub_to_intern_sec(sec), n); 130 if (!p) return KIT_NOMEM; 131 *out = p; 132 return KIT_OK; 133 } 134 135 KitStatus kit_obj_builder_reserve_bss(KitObjBuilder* b, KitObjSection sec, 136 uint64_t size, uint32_t align) { 137 if (!b) return KIT_INVALID; 138 obj_reserve_bss(b, pub_to_intern_sec(sec), (u32)size, align ? align : 1u); 139 return KIT_OK; 140 } 141 142 KitStatus kit_obj_builder_patch(KitObjBuilder* b, KitObjSection sec, 143 uint64_t offset, const void* data, size_t n) { 144 if (!b) return KIT_INVALID; 145 obj_patch(b, pub_to_intern_sec(sec), (u32)offset, data, n); 146 return KIT_OK; 147 } 148 149 KitStatus kit_obj_builder_symbol(KitObjBuilder* b, const KitObjSymbolDesc* desc, 150 KitObjSymbol* out) { 151 ObjSymId id; 152 if (!b || !desc || !out) return KIT_INVALID; 153 id = obj_symbol(b, (Sym)desc->name, (SymBind)desc->bind, (SymKind)desc->kind, 154 pub_to_intern_sec(desc->section), desc->value, desc->size); 155 if (id == OBJ_SYM_NONE) return KIT_ERR; 156 *out = intern_to_pub_sym(id); 157 return KIT_OK; 158 } 159 160 KitStatus kit_obj_builder_symbol_define(KitObjBuilder* b, KitObjSymbol sym, 161 KitObjSection section, uint64_t value, 162 uint64_t size) { 163 if (!b) return KIT_INVALID; 164 obj_symbol_define(b, pub_to_intern_sym(sym), pub_to_intern_sec(section), 165 value, size); 166 return KIT_OK; 167 } 168 169 KitStatus kit_obj_builder_reloc(KitObjBuilder* b, const KitObjRelocDesc* desc) { 170 if (!b || !desc) return KIT_INVALID; 171 /* Public KitRelocKind.code is the raw internal RelocKind value 172 * (single shared numeric space). */ 173 obj_reloc(b, pub_to_intern_sec(desc->section), (u32)desc->offset, 174 (RelocKind)desc->kind.code, pub_to_intern_sym(desc->symbol), 175 desc->addend); 176 return KIT_OK; 177 } 178 179 KitStatus kit_obj_builder_group(KitObjBuilder* b, KitSym name, 180 KitObjSymbol signature, uint32_t flags, 181 KitObjGroup* out) { 182 ObjGroupId id; 183 if (!b || !out) return KIT_INVALID; 184 id = obj_group(b, (Sym)name, pub_to_intern_sym(signature), flags); 185 if (id == OBJ_GROUP_NONE) return KIT_ERR; 186 *out = intern_to_pub_group(id); 187 return KIT_OK; 188 } 189 190 KitStatus kit_obj_builder_group_add_section(KitObjBuilder* b, KitObjGroup grp, 191 KitObjSection sec) { 192 if (!b) return KIT_INVALID; 193 obj_group_add_section(b, pub_to_intern_group(grp), pub_to_intern_sec(sec)); 194 return KIT_OK; 195 } 196 197 KitStatus kit_obj_builder_finalize(KitObjBuilder* b) { 198 if (!b) return KIT_INVALID; 199 obj_finalize(b); 200 return KIT_OK; 201 } 202 203 /* ---- mutators ---- */ 204 205 KitStatus kit_obj_builder_remove_section(KitObjBuilder* b, KitObjSection sec) { 206 if (!b) return KIT_INVALID; 207 obj_section_remove(b, pub_to_intern_sec(sec)); 208 return KIT_OK; 209 } 210 211 KitStatus kit_obj_builder_remove_symbol(KitObjBuilder* b, KitObjSymbol sym) { 212 if (!b) return KIT_INVALID; 213 obj_symbol_remove(b, pub_to_intern_sym(sym)); 214 return KIT_OK; 215 } 216 217 KitStatus kit_obj_builder_remove_group(KitObjBuilder* b, KitObjGroup grp) { 218 if (!b) return KIT_INVALID; 219 obj_group_remove(b, pub_to_intern_group(grp)); 220 return KIT_OK; 221 } 222 223 KitStatus kit_obj_builder_rename_section(KitObjBuilder* b, KitObjSection sec, 224 KitSym new_name) { 225 if (!b) return KIT_INVALID; 226 obj_section_rename(b, pub_to_intern_sec(sec), (Sym)new_name); 227 return KIT_OK; 228 } 229 230 KitStatus kit_obj_builder_rename_symbol(KitObjBuilder* b, KitObjSymbol sym, 231 KitSym new_name) { 232 if (!b) return KIT_INVALID; 233 obj_symbol_rename(b, pub_to_intern_sym(sym), (Sym)new_name); 234 return KIT_OK; 235 } 236 237 KitStatus kit_obj_builder_symbol_set_bind(KitObjBuilder* b, KitObjSymbol sym, 238 KitSymBind bind) { 239 if (!b) return KIT_INVALID; 240 obj_symbol_set_bind(b, pub_to_intern_sym(sym), (SymBind)bind); 241 return KIT_OK; 242 } 243 244 KitStatus kit_obj_builder_symbol_set_vis(KitObjBuilder* b, KitObjSymbol sym, 245 KitSymVis vis) { 246 if (!b) return KIT_INVALID; 247 obj_symbol_set_vis(b, pub_to_intern_sym(sym), (SymVis)vis); 248 return KIT_OK; 249 } 250 251 KitStatus kit_obj_builder_section_replace_bytes(KitObjBuilder* b, 252 KitObjSection sec, 253 const void* data, size_t n) { 254 if (!b) return KIT_INVALID; 255 obj_section_replace_bytes(b, pub_to_intern_sec(sec), (const u8*)data, n); 256 return KIT_OK; 257 } 258 259 /* ---- strip pass (shared by `strip` and `objcopy --strip-*`) ---- */ 260 261 static int strip_id_in_set(ObjSymId id, const ObjSymId* arr, u32 n) { 262 u32 i; 263 for (i = 0; i < n; ++i) 264 if (arr[i] == id) return 1; 265 return 0; 266 } 267 268 static int strip_name_in_keep(Slice name, const KitSlice* keep, u32 nkeep) { 269 u32 i; 270 if (!name.len) return 0; 271 for (i = 0; i < nkeep; ++i) 272 if (slice_eq(name, keep[i])) return 1; 273 return 0; 274 } 275 276 /* The needed set: every symbol still targeted by a relocation whose host 277 * section is not being dropped (debug sections are about to go). Mirrors 278 * kit_obj_reloc_live_symbols but reads the builder directly, so the strip pass 279 * needs only the builder handle. */ 280 static KitStatus strip_collect_needed(ObjBuilder* ob, Heap* h, ObjSymId** out, 281 u32* n_out, u32* cap_out) { 282 ObjSymId* arr = NULL; 283 u32 n = 0, cap = 0; 284 u32 total = obj_reloc_total(ob); 285 u32 i; 286 for (i = 0; i < total; ++i) { 287 const Reloc* r = obj_reloc_at(ob, i); 288 if (!r || r->sym == OBJ_SYM_NONE) continue; 289 if (r->section_id != OBJ_SEC_NONE) { 290 const Section* hs = obj_section_get(ob, r->section_id); 291 if (hs && hs->kind == SEC_DEBUG) continue; 292 } 293 if (strip_id_in_set(r->sym, arr, n)) continue; 294 if (n >= cap) { 295 u32 newcap = cap ? cap * 2u : 32u; 296 ObjSymId* nb = 297 (ObjSymId*)h->alloc(h, (size_t)newcap * sizeof(*nb), _Alignof(ObjSymId)); 298 if (!nb) { 299 if (arr) h->free(h, arr, (size_t)cap * sizeof(*arr)); 300 return KIT_NOMEM; 301 } 302 if (arr) { 303 memcpy(nb, arr, (size_t)n * sizeof(*arr)); 304 h->free(h, arr, (size_t)cap * sizeof(*arr)); 305 } 306 arr = nb; 307 cap = newcap; 308 } 309 arr[n++] = r->sym; 310 } 311 *out = arr; 312 *n_out = n; 313 *cap_out = cap; 314 return KIT_OK; 315 } 316 317 KitStatus kit_obj_builder_strip(KitObjBuilder* b, int level, 318 const KitSlice* keep_names, uint32_t nkeep) { 319 ObjBuilder* ob = (ObjBuilder*)b; 320 Compiler* c; 321 Heap* h; 322 u32 nsec, i; 323 int filter_syms; 324 ObjSymId* needed = NULL; 325 u32 nneeded = 0, cap_needed = 0; 326 ObjSymIter* sit; 327 ObjSymEntry e; 328 KitStatus st; 329 330 if (!b) return KIT_INVALID; 331 if (nkeep && !keep_names) return KIT_INVALID; 332 c = obj_compiler(ob); 333 if (!c) return KIT_INVALID; 334 h = c->ctx->heap; 335 filter_syms = 336 (level == KIT_STRIP_UNNEEDED || level == KIT_STRIP_ALL); 337 338 /* Step 1: drop debug sections (every level does this). */ 339 nsec = obj_section_count(ob); 340 for (i = 0; i < nsec; ++i) { 341 const Section* sec = obj_section_get(ob, (ObjSecId)(i + 1)); 342 if (sec && sec->kind == SEC_DEBUG) obj_section_remove(ob, (ObjSecId)(i + 1)); 343 } 344 345 if (!filter_syms) return KIT_OK; 346 347 /* Step 2: compute the needed (reloc-reachable, non-debug) sym set. */ 348 st = strip_collect_needed(ob, h, &needed, &nneeded, &cap_needed); 349 if (st != KIT_OK) return st; 350 351 /* Step 3: walk symbols and apply keep-list + needed-set policy. 352 * Keep undefined externals so the .o stays linkable; keep names on the 353 * keep-list; keep symbols a surviving reloc targets; drop the rest. */ 354 sit = obj_symiter_new(ob); 355 if (!sit) { 356 if (needed) h->free(h, needed, (size_t)cap_needed * sizeof(*needed)); 357 return KIT_NOMEM; 358 } 359 while (obj_symiter_next(sit, &e)) { 360 const ObjSym* s = e.sym; 361 Slice name; 362 if (!s) continue; 363 name = s->name ? pool_slice(c->global, s->name) : SLICE_LIT(""); 364 if (nkeep && strip_name_in_keep(name, keep_names, nkeep)) continue; 365 if (s->kind == SK_UNDEF) continue; 366 if (strip_id_in_set(e.id, needed, nneeded)) continue; 367 obj_symbol_remove(ob, e.id); 368 } 369 obj_symiter_free(sit); 370 371 if (needed) h->free(h, needed, (size_t)cap_needed * sizeof(*needed)); 372 return KIT_OK; 373 } 374 375 KitStatus kit_obj_builder_find_symbol(const KitObjBuilder* b, KitSym name, 376 KitObjSymbol* out) { 377 ObjSymId id; 378 if (!b || !out) return KIT_INVALID; 379 id = obj_symbol_find((ObjBuilder*)b, (Sym)name); 380 *out = intern_to_pub_sym(id); 381 return id != OBJ_SYM_NONE ? KIT_OK : KIT_NOT_FOUND; 382 } 383 384 KitStatus kit_obj_builder_emit(KitObjBuilder* b, KitWriter* w) { 385 Compiler* c; 386 if (!b || !w) return KIT_INVALID; 387 c = obj_compiler(b); 388 if (!c) return KIT_INVALID; 389 return kit_obj_builder_emit_as(b, c->target.obj, w); 390 } 391 392 KitStatus kit_obj_builder_emit_as(KitObjBuilder* b, KitObjFmt fmt, 393 KitWriter* w) { 394 Compiler* c; 395 const ObjFormatImpl* impl; 396 if (!b || !w) return KIT_INVALID; 397 c = obj_compiler(b); 398 if (!c) return KIT_INVALID; 399 impl = obj_format_lookup(fmt); 400 if (!impl || !impl->emit) return KIT_UNSUPPORTED; 401 impl->emit(c, b, w); 402 return kit_writer_status(w); 403 }