kit

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

dl.c (13398B)


      1 #include <string.h>
      2 
      3 #include "core/slice.h"
      4 #include "emu/emu.h"
      5 #include "obj/format.h"
      6 #include "obj/reloc_apply.h"
      7 
      8 #define EMU_IMPORT_THUNK_RESERVE 0x1000ull
      9 
     10 static int slice_is_null(KitSlice s) { return !s.data && s.len == 0; }
     11 
     12 KitStatus emu_apply_reloc_bytes(Compiler* c, RelocKind kind, u8* P_bytes, u64 S,
     13                                 i64 A, u64 P) {
     14   if (!P_bytes) return KIT_INVALID;
     15   link_reloc_apply(c, kind, P_bytes, S, A, P);
     16   return KIT_OK;
     17 }
     18 
     19 KitStatus emu_dl_lookup_symbol(EmuProcess* process, KitSlice symbol,
     20                                u64* out_addr) {
     21   EmuLoadedImage* img;
     22   const ObjFormatEmuOps* fmt;
     23   u32 oi;
     24   if (!process || !out_addr) return KIT_INVALID;
     25   img = &process->image;
     26   fmt = process->obj_format ? process->obj_format->emu : NULL;
     27   if (!fmt || !fmt->dyn_symbol_lookup) return KIT_UNSUPPORTED;
     28   *out_addr = 0;
     29   for (oi = 0; oi < img->link_map.nobjects; ++oi) {
     30     EmuLoadedObject* obj = &img->link_map.objects[oi];
     31     EmuDynSymbol sym;
     32     if (fmt->dyn_symbol_lookup(process, obj, symbol, &sym) == KIT_OK &&
     33         sym.defined) {
     34       *out_addr = obj->load_bias + sym.value;
     35       return KIT_OK;
     36     }
     37   }
     38   return KIT_NOT_FOUND;
     39 }
     40 
     41 static KitStatus ensure_import_binding_cap(Compiler* c, EmuLoadedImage* img,
     42                                            u32 need) {
     43   Heap* heap = c->ctx->heap;
     44   u32 old_cap;
     45   u32 new_cap;
     46   EmuImportBinding* grown;
     47   if (img->import_bindings_cap >= need) return KIT_OK;
     48   old_cap = img->import_bindings_cap;
     49   new_cap = old_cap ? old_cap * 2u : 8u;
     50   while (new_cap < need) new_cap *= 2u;
     51   grown = (EmuImportBinding*)heap->realloc(
     52       heap, img->import_bindings, sizeof(*img->import_bindings) * old_cap,
     53       sizeof(*img->import_bindings) * new_cap, _Alignof(EmuImportBinding));
     54   if (!grown) return KIT_ERR;
     55   memset(grown + old_cap, 0, sizeof(*grown) * (new_cap - old_cap));
     56   img->import_bindings = grown;
     57   img->import_bindings_cap = new_cap;
     58   return KIT_OK;
     59 }
     60 
     61 static KitEmuImportSignature default_u64_sig(void) {
     62   KitEmuImportSignature sig;
     63   memset(&sig, 0, sizeof(sig));
     64   sig.abi = KIT_EMU_IMPORT_ABI_GUEST_C;
     65   sig.result = KIT_EMU_VALUE_U64;
     66   sig.nargs = 1u;
     67   sig.args[0] = KIT_EMU_VALUE_U64;
     68   return sig;
     69 }
     70 
     71 static u32 import_thunk_size(const EmuProcess* process) {
     72   if (!process || !process->arch || !process->arch->emu ||
     73       !process->arch->emu->import_thunk_size)
     74     return 0;
     75   return process->arch->emu->import_thunk_size;
     76 }
     77 
     78 static KitStatus emit_import_thunk(EmuProcess* process, u64 thunk) {
     79   if (!process || !process->arch || !process->arch->emu ||
     80       !process->arch->emu->emit_import_thunk)
     81     return KIT_UNSUPPORTED;
     82   return process->arch->emu->emit_import_thunk(process, thunk);
     83 }
     84 
     85 static KitStatus add_import_binding(Compiler* c, EmuProcess* process,
     86                                     EmuLoadedImage* img,
     87                                     const EmuDynamicImport* req,
     88                                     const KitEmuResolvedImport* resolved,
     89                                     u64* out_addr) {
     90   EmuImportBinding* b;
     91   u64 thunk;
     92   u32 thunk_size;
     93   if (resolved->guest_addr) {
     94     *out_addr = resolved->guest_addr;
     95     return KIT_OK;
     96   }
     97   if (!resolved->host_fn) return KIT_NOT_FOUND;
     98   thunk_size = import_thunk_size(process);
     99   if (!thunk_size) return KIT_UNSUPPORTED;
    100   if (img->import_thunk_next + thunk_size >
    101       img->import_thunk_base + img->import_thunk_size)
    102     return KIT_NOMEM;
    103   if (ensure_import_binding_cap(c, img, img->nimport_bindings + 1u) != KIT_OK)
    104     return KIT_ERR;
    105   thunk = img->import_thunk_next;
    106   img->import_thunk_next += thunk_size;
    107   if (emit_import_thunk(process, thunk) != KIT_OK) return KIT_ERR;
    108   b = &img->import_bindings[img->nimport_bindings++];
    109   memset(b, 0, sizeof(*b));
    110   b->object_name = req->object_name;
    111   b->symbol_name = req->symbol_name;
    112   b->got_vaddr = req->got_vaddr;
    113   b->thunk_vaddr = thunk;
    114   b->resolved_guest_addr = resolved->guest_addr;
    115   b->resolved_host_fn = resolved->host_fn;
    116   b->flags = resolved->flags;
    117   b->signature = resolved->signature.nargs || resolved->signature.result
    118                      ? resolved->signature
    119                      : req->signature;
    120   if (!b->signature.nargs && !b->signature.result)
    121     b->signature = default_u64_sig();
    122   *out_addr = thunk;
    123   return KIT_OK;
    124 }
    125 
    126 KitStatus emu_dl_resolve_import_thunk(EmuProcess* process, u64 target,
    127                                       EmuImportBinding** out) {
    128   EmuLoadedImage* img;
    129   u32 i;
    130   if (out) *out = NULL;
    131   if (!process || !out) return KIT_INVALID;
    132   img = &process->image;
    133   if (!img->import_thunk_size || target < img->import_thunk_base ||
    134       target >= img->import_thunk_base + img->import_thunk_size)
    135     return KIT_NOT_FOUND;
    136   for (i = 0; i < img->nimport_bindings; ++i) {
    137     EmuImportBinding* b = &img->import_bindings[i];
    138     if (b->thunk_vaddr == target && b->resolved_host_fn) {
    139       *out = b;
    140       return KIT_OK;
    141     }
    142   }
    143   return KIT_NOT_FOUND;
    144 }
    145 
    146 KitStatus emu_call_host_import(EmuThread* thread, EmuImportBinding* b,
    147                                const u64* args, u32 nargs, u64* result_out) {
    148   KitEmuImportSignature sig;
    149   if (result_out) *result_out = 0;
    150   if (!thread || !b || !b->resolved_host_fn) return KIT_INVALID;
    151   sig = b->signature;
    152   if (!sig.nargs && !sig.result) sig = default_u64_sig();
    153   b->signature = sig;
    154   if (sig.nargs > nargs || sig.nargs > 3u) return KIT_UNSUPPORTED;
    155   if (sig.nargs == 0u) {
    156     if (sig.result != KIT_EMU_VALUE_VOID) {
    157       u64 (*fn0)(void) = (u64 (*)(void))b->resolved_host_fn;
    158       if (result_out) *result_out = fn0();
    159     } else {
    160       ((void (*)(void))b->resolved_host_fn)();
    161     }
    162   } else if (sig.nargs == 1u) {
    163     u64 (*fn1)(u64) = (u64 (*)(u64))b->resolved_host_fn;
    164     if (result_out) *result_out = fn1(args[0]);
    165   } else if (sig.nargs == 2u) {
    166     u64 (*fn2)(u64, u64) = (u64 (*)(u64, u64))b->resolved_host_fn;
    167     if (result_out) *result_out = fn2(args[0], args[1]);
    168   } else if (sig.nargs == 3u) {
    169     u64 (*fn3)(u64, u64, u64) = (u64 (*)(u64, u64, u64))b->resolved_host_fn;
    170     if (result_out) *result_out = fn3(args[0], args[1], args[2]);
    171   }
    172   return KIT_OK;
    173 }
    174 
    175 static KitStatus load_needed_objects(Compiler* c, EmuProcess* process,
    176                                      const EmuLoadOptions* opts,
    177                                      const ObjFormatEmuOps* fmt) {
    178   EmuLoadedImage* img = &process->image;
    179   u32 oi;
    180   if (!fmt->dyn_needed_iter || !fmt->dyn_needed_next) return KIT_OK;
    181   for (oi = 0; oi < img->link_map.nobjects; ++oi) {
    182     EmuLoadedObject* obj = &img->link_map.objects[oi];
    183     EmuDynNeededIter it;
    184     KitSlice needed;
    185     fmt->dyn_needed_iter(obj, &it);
    186     while (fmt->dyn_needed_next(process, &it, &needed)) {
    187       KitSlice bytes = KIT_SLICE_NULL;
    188       u32 loaded = 0;
    189       u32 k;
    190       if (slice_is_null(needed) || !opts->bindings ||
    191           !opts->bindings->resolve_object)
    192         continue;
    193       for (k = 0; k < img->link_map.nobjects; ++k) {
    194         if (kit_slice_eq(img->link_map.objects[k].name, needed) ||
    195             kit_slice_eq(img->link_map.objects[k].soname, needed)) {
    196           loaded = 1;
    197           break;
    198         }
    199       }
    200       if (loaded) continue;
    201       if (opts->bindings->resolve_object(opts->bindings->user, process, needed,
    202                                          &bytes) != KIT_OK ||
    203           !bytes.data)
    204         return KIT_NOT_FOUND;
    205       if (!fmt->map_object ||
    206           fmt->map_object(c, process, img, needed, bytes, 0, &k) != KIT_OK)
    207         return KIT_ERR;
    208     }
    209   }
    210   return KIT_OK;
    211 }
    212 
    213 static KitStatus resolve_reloc_symbol(Compiler* c, EmuProcess* process,
    214                                       const EmuLoadOptions* opts,
    215                                       const ObjFormatEmuOps* fmt,
    216                                       EmuLoadedObject* obj, u64 sym_idx,
    217                                       u64 patch_addr, EmuDynamicImport* req,
    218                                       u64* value_out) {
    219   EmuLoadedImage* img = &process->image;
    220   EmuDynSymbol sym;
    221   KitStatus st;
    222   (void)c;
    223   if (!fmt->dyn_symbol_by_index ||
    224       fmt->dyn_symbol_by_index(process, obj, sym_idx, &sym) != KIT_OK)
    225     return KIT_INVALID;
    226   memset(req, 0, sizeof(*req));
    227   req->object_name = obj->imports.nneeded ? obj->imports.needed[0] : obj->name;
    228   req->symbol_name = sym.name;
    229   req->got_vaddr = patch_addr;
    230   st = emu_dl_lookup_symbol(process, sym.name, value_out);
    231   if (st == KIT_OK) return KIT_OK;
    232   if (opts->bindings && opts->bindings->resolve_import) {
    233     KitEmuResolvedImport resolved;
    234     memset(&resolved, 0, sizeof(resolved));
    235     st = opts->bindings->resolve_import(opts->bindings->user, process, req,
    236                                         &resolved);
    237     if (st == KIT_OK)
    238       st = add_import_binding(c, process, img, req, &resolved, value_out);
    239   }
    240   return st;
    241 }
    242 
    243 static KitStatus apply_reloc_table(Compiler* c, EmuProcess* process,
    244                                    const EmuLoadOptions* opts,
    245                                    const ObjFormatEmuOps* fmt,
    246                                    EmuLoadedObject* obj,
    247                                    EmuDynRelocTableKind table) {
    248   EmuLoadedImage* img = &process->image;
    249   EmuDynRelocIter it;
    250   EmuDynReloc reloc;
    251   if (!fmt->reloc_iter || !fmt->reloc_next || !fmt->reloc_classify)
    252     return KIT_OK;
    253   fmt->reloc_iter(obj, table, &it);
    254   while (fmt->reloc_next(process, &it, &reloc)) {
    255     u64 value = 0;
    256     u8* patch;
    257     RelocKind kind;
    258     u32 kind_u;
    259     EmuDynRelocClass cls;
    260     patch = emu_addr_space_ptr(&img->addr_space, reloc.patch_addr,
    261                                reloc.width ? reloc.width : 8u, EMU_MEM_WRITE);
    262     if (!patch) return KIT_INVALID;
    263 
    264     if (fmt->reloc_classify(process, obj, &reloc, &cls, &kind_u) != KIT_OK)
    265       return KIT_UNSUPPORTED;
    266     kind = (RelocKind)kind_u;
    267     if (cls == EMU_DYN_RELOC_RELATIVE) {
    268       value = obj->load_bias;
    269     } else if (cls == EMU_DYN_RELOC_SYMBOLIC ||
    270                cls == EMU_DYN_RELOC_IMPORT_SLOT) {
    271       EmuDynamicImport req;
    272       KitStatus st =
    273           resolve_reloc_symbol(c, process, opts, fmt, obj, reloc.symbol_index,
    274                                reloc.patch_addr, &req, &value);
    275       if (st != KIT_OK) {
    276         if (cls == EMU_DYN_RELOC_IMPORT_SLOT) {
    277           u32 thunk_size = import_thunk_size(process);
    278           if (!thunk_size) return KIT_UNSUPPORTED;
    279           if (img->import_thunk_next + thunk_size >
    280               img->import_thunk_base + img->import_thunk_size)
    281             return KIT_NOMEM;
    282           value = img->import_thunk_next;
    283           img->import_thunk_next += thunk_size;
    284           if (emit_import_thunk(process, value) != KIT_OK) return KIT_ERR;
    285         } else {
    286           return st;
    287         }
    288       }
    289     } else if (cls == EMU_DYN_RELOC_NONE) {
    290       continue;
    291     }
    292 
    293     if (emu_apply_reloc_bytes(c, kind, patch, value, reloc.addend,
    294                               reloc.patch_addr) != KIT_OK)
    295       return KIT_ERR;
    296     emu_addr_space_invalidate(&img->addr_space, reloc.patch_addr,
    297                               reloc.width ? reloc.width : 8u);
    298   }
    299   return KIT_OK;
    300 }
    301 
    302 static KitStatus apply_dynamic_relocs(Compiler* c, EmuProcess* process,
    303                                       const EmuLoadOptions* opts,
    304                                       const ObjFormatEmuOps* fmt) {
    305   EmuLoadedImage* img = &process->image;
    306   u32 oi;
    307   for (oi = 0; oi < img->link_map.nobjects; ++oi) {
    308     EmuLoadedObject* obj = &img->link_map.objects[oi];
    309     KitStatus st;
    310     st =
    311         apply_reloc_table(c, process, opts, fmt, obj, EMU_DYN_RELOC_TABLE_MAIN);
    312     if (st != KIT_OK) return st;
    313     st = apply_reloc_table(c, process, opts, fmt, obj, EMU_DYN_RELOC_TABLE_PLT);
    314     if (st != KIT_OK) return st;
    315   }
    316   return KIT_OK;
    317 }
    318 
    319 KitStatus emu_dl_init_process(Compiler* c, EmuProcess* process) {
    320   EmuLoadedImage* img;
    321   u64 base = 0;
    322   if (!c || !process) return KIT_INVALID;
    323   img = &process->image;
    324   if (img->import_thunk_size) return KIT_OK;
    325   if (!process->os || !process->os->emu_find_map_region) return KIT_UNSUPPORTED;
    326   if (process->os->emu_find_map_region(process, EMU_IMPORT_THUNK_RESERVE,
    327                                        img->addr_space.page_size,
    328                                        EMU_OS_MAP_DL_THUNKS, &base) != KIT_OK)
    329     return KIT_ERR;
    330   if (emu_addr_space_map(&img->addr_space, base, EMU_IMPORT_THUNK_RESERVE,
    331                          EMU_MEM_READ | EMU_MEM_EXEC, EMU_MAP_ANON) != KIT_OK)
    332     return KIT_ERR;
    333   img->import_thunk_base = base;
    334   img->import_thunk_size = EMU_IMPORT_THUNK_RESERVE;
    335   img->import_thunk_next = base;
    336   if (process->os->emu_note_map_region)
    337     process->os->emu_note_map_region(process, base, EMU_IMPORT_THUNK_RESERVE,
    338                                      EMU_OS_MAP_DL_THUNKS);
    339   return KIT_OK;
    340 }
    341 
    342 KitStatus emu_dl_load_dependencies_and_relocate(Compiler* c,
    343                                                 EmuProcess* process,
    344                                                 const EmuLoadOptions* opts,
    345                                                 const ObjFormatEmuOps* fmt) {
    346   KitStatus st;
    347   if (!c || !process || !opts || !fmt) return KIT_INVALID;
    348   process->dl_policy.global_scope_head =
    349       process->image.link_map.global_scope_head;
    350   st = load_needed_objects(c, process, opts, fmt);
    351   if (st != KIT_OK) return st;
    352   st = emu_tls_rebuild_modules(c, process);
    353   if (st != KIT_OK) return st;
    354   return apply_dynamic_relocs(c, process, opts, fmt);
    355 }