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 }