kit

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

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 }