registry.c (17340B)
1 #include <kit/config.h> 2 #include <string.h> 3 4 #include "core/slice.h" 5 #include "obj/coff/coff.h" 6 #include "obj/elf/elf.h" 7 #include "obj/format.h" 8 #include "obj/macho/macho.h" 9 #include "obj/obj.h" 10 #include "obj/wasm/wasm.h" 11 12 #if KIT_LINK_ENABLED 13 void link_emit_elf(LinkImage*, Writer*); 14 void link_emit_macho(LinkImage*, Writer*); 15 void link_emit_coff(LinkImage*, Writer*); 16 void layout_dyn(Linker*, LinkImage*); 17 void link_dyn_state_free(LinkImage*); 18 #define OBJ_LINK_EMIT_ELF link_emit_elf 19 #define OBJ_LINK_EMIT_MACHO link_emit_macho 20 #define OBJ_LINK_EMIT_COFF link_emit_coff 21 #define OBJ_LAYOUT_DYN layout_dyn 22 #define OBJ_FREE_DYN link_dyn_state_free 23 #else 24 void obj_format_link_emit_disabled(LinkImage*, Writer*); 25 void obj_format_layout_dyn_disabled(Linker*, LinkImage*); 26 void obj_format_free_dyn_disabled(LinkImage*); 27 #define OBJ_LINK_EMIT_ELF obj_format_link_emit_disabled 28 #define OBJ_LINK_EMIT_MACHO obj_format_link_emit_disabled 29 #define OBJ_LINK_EMIT_COFF obj_format_link_emit_disabled 30 #define OBJ_LAYOUT_DYN obj_format_layout_dyn_disabled 31 #define OBJ_FREE_DYN obj_format_free_dyn_disabled 32 #endif 33 34 extern const ObjFormatEmuOps elf_emu_ops; 35 36 #if KIT_AR_ENABLED 37 int coff_classify_obj_input(Compiler*, ObjBuilder*, Sym* soname_out); 38 Sym coff_archive_hint(Compiler*, const char* archive_name); 39 ObjFormatArchiveAction coff_archive_member(Compiler*, 40 const ObjFormatArchiveMember*, 41 ObjBuilder** out); 42 #else 43 int obj_format_classify_obj_input_disabled(Compiler*, ObjBuilder*, 44 Sym* soname_out); 45 Sym obj_format_archive_hint_disabled(Compiler*, const char* archive_name); 46 ObjFormatArchiveAction obj_format_archive_member_disabled( 47 Compiler*, const ObjFormatArchiveMember*, ObjBuilder** out); 48 #define coff_classify_obj_input obj_format_classify_obj_input_disabled 49 #define coff_archive_hint obj_format_archive_hint_disabled 50 #define coff_archive_member obj_format_archive_member_disabled 51 #endif 52 53 #if KIT_LINK_ENABLED 54 void aa64_emit_macho_stub(u8* dst, u64 stub_vaddr, u64 got_slot_vaddr); 55 void aa64_emit_coff_iat_stub(u8* dst, u64 stub_vaddr, u64 iat_slot_vaddr); 56 void x64_emit_coff_iat_stub(u8* dst, u64 stub_vaddr, u64 iat_slot_vaddr); 57 /* COFF synthetic-input hook body. Needs Linker internals (LinkInput append, 58 * link_arch_desc_for for the __chkstk stub), so it lives in src/link; wired 59 * here as the only registry row that registers synth_inputs. */ 60 void link_synth_coff_ctor_dtor_list(Linker*); 61 #define OBJ_COFF_SYNTH_INPUTS link_synth_coff_ctor_dtor_list 62 #else 63 void obj_format_macho_stub_disabled(u8* dst, u64 stub_vaddr, 64 u64 got_slot_vaddr); 65 void obj_format_coff_stub_disabled(u8* dst, u64 stub_vaddr, u64 iat_slot_vaddr); 66 #define aa64_emit_macho_stub obj_format_macho_stub_disabled 67 #define aa64_emit_coff_iat_stub obj_format_coff_stub_disabled 68 #define x64_emit_coff_iat_stub obj_format_coff_stub_disabled 69 #define OBJ_COFF_SYNTH_INPUTS NULL 70 #endif 71 72 #if KIT_OBJ_ELF_ENABLED 73 static const ObjElfArchOps obj_elf_arch_ops[] = { 74 #if KIT_ARCH_AA64_ENABLED 75 { 76 .arch = KIT_ARCH_ARM_64, 77 .e_machine = EM_AARCH64, 78 .e_flags = 0, 79 .default_musl_interp = "/lib/ld-musl-aarch64.so.1", 80 .r_relative = ELF_R_AARCH64_RELATIVE, 81 .r_glob_dat = ELF_R_AARCH64_GLOB_DAT, 82 .r_jump_slot = ELF_R_AARCH64_JUMP_SLOT, 83 .r_irelative = ELF_R_AARCH64_IRELATIVE, 84 /* AAPCS64 variant-I: tp points at a 16-byte TCB ahead of the image. */ 85 .tls_tp_bias = 16u, 86 .reloc_to = elf_aarch64_reloc_to, 87 .reloc_from = elf_aarch64_reloc_from, 88 .reloc_name = elf_aarch64_reloc_name, 89 .float_abi_from_e_flags = NULL, 90 }, 91 #endif 92 #if KIT_ARCH_X64_ENABLED 93 { 94 .arch = KIT_ARCH_X86_64, 95 .e_machine = EM_X86_64, 96 .e_flags = 0, 97 .default_musl_interp = "/lib/ld-musl-x86_64.so.1", 98 .r_relative = ELF_R_X86_64_RELATIVE, 99 .r_glob_dat = ELF_R_X86_64_GLOB_DAT, 100 .r_jump_slot = ELF_R_X86_64_JUMP_SLOT, 101 .r_irelative = ELF_R_X86_64_IRELATIVE, 102 /* SysV variant-II: tp sits *past* the image; no positive TCB bias. */ 103 .tls_tp_bias = 0u, 104 .reloc_to = elf_x86_64_reloc_to, 105 .reloc_from = elf_x86_64_reloc_from, 106 .reloc_name = elf_x86_64_reloc_name, 107 .float_abi_from_e_flags = NULL, 108 }, 109 #endif 110 #if KIT_ARCH_RV64_ENABLED 111 { 112 .arch = KIT_ARCH_RV64, 113 .e_machine = EM_RISCV, 114 .e_flags = EF_RISCV_RVC | EF_RISCV_FLOAT_ABI_DOUBLE, 115 .default_musl_interp = "/lib/ld-musl-riscv64.so.1", 116 .r_relative = ELF_R_RISCV_RELATIVE, 117 .r_glob_dat = ELF_R_RISCV_64, 118 .r_jump_slot = ELF_R_RISCV_JUMP_SLOT, 119 .r_irelative = ELF_R_RISCV_IRELATIVE, 120 /* Variant-I: kit's freestanding start.c biases tp by a 16-byte TCB to 121 * match AArch64. Hosted RISC-V wants +0; that hosted-vs-freestanding 122 * split is applied by the caller (src/obj/elf/link.c). */ 123 .tls_tp_bias = 16u, 124 .reloc_to = elf_riscv64_reloc_to, 125 .reloc_from = elf_riscv64_reloc_from, 126 .reloc_name = elf_riscv_reloc_name, 127 .float_abi_from_e_flags = elf_riscv_float_abi_from_e_flags, 128 }, 129 #endif 130 #if KIT_ARCH_RV32_ENABLED 131 { 132 /* RV32 shares EM_RISCV with RV64; obj_elf_machine_class uses 133 * EI_CLASS to disambiguate. Default float ABI is ilp32f (SINGLE: 134 * float in FP regs, double always soft). Static-only — no musl 135 * interp; the dyn r_* fields are unused on the static path. */ 136 .arch = KIT_ARCH_RV32, 137 .e_machine = EM_RISCV, 138 .e_flags = EF_RISCV_RVC | EF_RISCV_FLOAT_ABI_SINGLE, 139 .default_musl_interp = NULL, 140 .r_relative = ELF_R_RISCV_RELATIVE, 141 .r_glob_dat = ELF_R_RISCV_32, 142 .r_jump_slot = ELF_R_RISCV_JUMP_SLOT, 143 .r_irelative = ELF_R_RISCV_IRELATIVE, 144 /* See RV64: freestanding +16 TCB; hosted split applied by caller. */ 145 .tls_tp_bias = 16u, 146 .reloc_to = elf_riscv32_reloc_to, 147 .reloc_from = elf_riscv32_reloc_from, 148 .reloc_name = elf_riscv_reloc_name, 149 .float_abi_from_e_flags = elf_riscv_float_abi_from_e_flags, 150 }, 151 #endif 152 #if !KIT_ARCH_AA64_ENABLED && !KIT_ARCH_X64_ENABLED && \ 153 !KIT_ARCH_RV64_ENABLED && !KIT_ARCH_RV32_ENABLED 154 {.arch = KIT_ARCH_WASM}, 155 #endif 156 }; 157 158 static const ObjElfArchOps* obj_elf_arch(KitArchKind arch) { 159 u32 i; 160 for (i = 0; i < (u32)(sizeof obj_elf_arch_ops / sizeof obj_elf_arch_ops[0]); 161 ++i) { 162 if (obj_elf_arch_ops[i].arch == arch) return &obj_elf_arch_ops[i]; 163 } 164 return NULL; 165 } 166 167 static const ObjElfArchOps* obj_elf_machine(u32 e_machine) { 168 u32 i; 169 for (i = 0; i < (u32)(sizeof obj_elf_arch_ops / sizeof obj_elf_arch_ops[0]); 170 ++i) { 171 if (obj_elf_arch_ops[i].e_machine && 172 obj_elf_arch_ops[i].e_machine == e_machine) 173 return &obj_elf_arch_ops[i]; 174 } 175 return NULL; 176 } 177 178 /* EI_CLASS-aware variant. EM_RISCV is shared by RV32 (ELFCLASS32) and 179 * RV64 (ELFCLASS64); selecting by e_machine alone would always pick the 180 * first table entry. For RISC-V we narrow the match by ptr-class so the 181 * reader resolves the correct reloc_from table; non-RISC-V archs (one 182 * entry per e_machine) match on e_machine as before. */ 183 const ObjElfArchOps* obj_elf_machine_class(u32 e_machine, u8 ei_class) { 184 u32 i; 185 for (i = 0; i < (u32)(sizeof obj_elf_arch_ops / sizeof obj_elf_arch_ops[0]); 186 ++i) { 187 const ObjElfArchOps* a = &obj_elf_arch_ops[i]; 188 if (!a->e_machine || a->e_machine != e_machine) continue; 189 if (e_machine == EM_RISCV) { 190 int want32 = (ei_class == ELFCLASS32); 191 int is_rv32 = (a->arch == KIT_ARCH_RV32); 192 if (want32 != is_rv32) continue; 193 } 194 return a; 195 } 196 return NULL; 197 } 198 #else 199 const ObjElfArchOps* obj_elf_machine_class(u32 e_machine, u8 ei_class) { 200 (void)e_machine; 201 (void)ei_class; 202 return NULL; 203 } 204 #endif 205 206 #if KIT_OBJ_MACHO_ENABLED 207 static const ObjMachoArchOps obj_macho_arch_ops[] = { 208 #if KIT_ARCH_AA64_ENABLED 209 { 210 .arch = KIT_ARCH_ARM_64, 211 .cputype = CPU_TYPE_ARM64, 212 .cpusubtype = CPU_SUBTYPE_ARM64_ALL, 213 .stub_size = 12u, 214 .emit_stub = aa64_emit_macho_stub, 215 .reloc_to = macho_aarch64_reloc_to, 216 .reloc_pcrel = macho_aarch64_reloc_pcrel, 217 .reloc_length = macho_aarch64_reloc_length, 218 .reloc_from = macho_aarch64_reloc_from, 219 }, 220 #endif 221 #if KIT_ARCH_X64_ENABLED 222 { 223 .arch = KIT_ARCH_X86_64, 224 .cputype = CPU_TYPE_X86_64, 225 .cpusubtype = CPU_SUBTYPE_X86_64_ALL, 226 .stub_size = 0u, 227 .emit_stub = NULL, 228 .reloc_to = macho_x86_64_reloc_to, 229 .reloc_pcrel = macho_x86_64_reloc_pcrel, 230 .reloc_length = macho_x86_64_reloc_length, 231 .reloc_from = macho_x86_64_reloc_from, 232 }, 233 #endif 234 #if !KIT_ARCH_AA64_ENABLED && !KIT_ARCH_X64_ENABLED 235 {.arch = KIT_ARCH_WASM}, 236 #endif 237 }; 238 239 static const ObjMachoArchOps* obj_macho_arch(KitArchKind arch) { 240 u32 i; 241 for (i = 0; 242 i < (u32)(sizeof obj_macho_arch_ops / sizeof obj_macho_arch_ops[0]); 243 ++i) { 244 if (obj_macho_arch_ops[i].arch == arch) return &obj_macho_arch_ops[i]; 245 } 246 return NULL; 247 } 248 249 static const ObjMachoArchOps* obj_macho_cputype(u32 cputype) { 250 u32 i; 251 for (i = 0; 252 i < (u32)(sizeof obj_macho_arch_ops / sizeof obj_macho_arch_ops[0]); 253 ++i) { 254 if (obj_macho_arch_ops[i].cputype && 255 obj_macho_arch_ops[i].cputype == cputype) 256 return &obj_macho_arch_ops[i]; 257 } 258 return NULL; 259 } 260 #endif 261 262 #if KIT_OBJ_COFF_ENABLED 263 static const ObjCoffArchOps obj_coff_arch_ops[] = { 264 #if KIT_ARCH_AA64_ENABLED 265 { 266 .arch = KIT_ARCH_ARM_64, 267 .machine = IMAGE_FILE_MACHINE_ARM64, 268 .stub_size = 12u, 269 .emit_iat_stub = aa64_emit_coff_iat_stub, 270 .reloc_to = coff_aarch64_reloc_to, 271 .reloc_from = coff_aarch64_reloc_from, 272 }, 273 #endif 274 #if KIT_ARCH_X64_ENABLED 275 { 276 .arch = KIT_ARCH_X86_64, 277 .machine = IMAGE_FILE_MACHINE_AMD64, 278 .stub_size = 6u, 279 .emit_iat_stub = x64_emit_coff_iat_stub, 280 .reloc_to = coff_x86_64_reloc_to, 281 .reloc_from = coff_x86_64_reloc_from, 282 }, 283 #endif 284 #if !KIT_ARCH_AA64_ENABLED && !KIT_ARCH_X64_ENABLED 285 {.arch = KIT_ARCH_WASM}, 286 #endif 287 }; 288 289 static const ObjCoffArchOps* obj_coff_arch(KitArchKind arch) { 290 u32 i; 291 for (i = 0; i < (u32)(sizeof obj_coff_arch_ops / sizeof obj_coff_arch_ops[0]); 292 ++i) { 293 if (obj_coff_arch_ops[i].arch == arch) return &obj_coff_arch_ops[i]; 294 } 295 return NULL; 296 } 297 298 static const ObjCoffArchOps* obj_coff_machine(u16 machine) { 299 u32 i; 300 if (machine == 0xA641u) machine = IMAGE_FILE_MACHINE_ARM64; 301 for (i = 0; i < (u32)(sizeof obj_coff_arch_ops / sizeof obj_coff_arch_ops[0]); 302 ++i) { 303 if (obj_coff_arch_ops[i].machine && obj_coff_arch_ops[i].machine == machine) 304 return &obj_coff_arch_ops[i]; 305 } 306 return NULL; 307 } 308 #endif 309 310 #if KIT_OBJ_WASM_ENABLED 311 static const ObjFormatImpl obj_format_impl_wasm = { 312 .kind = KIT_OBJ_WASM, 313 .bin_fmt = KIT_BIN_WASM, 314 .name = "wasm", 315 /* read_wasm parses a core module into sections + function symbols for 316 * inspection (objdump -f/-h/-t/-s/-d). It is not a linkable-object reader: 317 * tool-conventions `linking` / `reloc.*` support is still pending, so 318 * relocations are not recovered. */ 319 .read_name = "read_wasm", 320 .read_dso_name = NULL, 321 .emit = emit_wasm, 322 .read = read_wasm, 323 .read_dso = NULL, 324 .link_emit = NULL, 325 .c_label_prefix = "", 326 .default_entry_name = "_start", 327 .carries_file_only_debug = 0, 328 .builds_own_static_got = 0, 329 .weak_undef_pulls_archive_member = 0, 330 .tls_symbol_features = 0, 331 .alias_via_thunk = 0, 332 .weak_undef_attr = "weak", 333 }; 334 #endif 335 336 #if KIT_OBJ_ELF_ENABLED 337 static const ObjFormatImpl obj_format_impl_elf = { 338 .kind = KIT_OBJ_ELF, 339 .bin_fmt = KIT_BIN_ELF, 340 .name = "elf", 341 .read_name = "read_elf", 342 .read_dso_name = "read_elf_dso", 343 .emit = emit_elf, 344 .read = read_elf, 345 .read_dso = read_elf_dso, 346 .link_emit = OBJ_LINK_EMIT_ELF, 347 .layout_dyn = OBJ_LAYOUT_DYN, 348 .free_dyn = OBJ_FREE_DYN, 349 .emu = &elf_emu_ops, 350 .c_label_prefix = "", 351 .default_entry_name = "_start", 352 .carries_file_only_debug = 1, 353 .builds_own_static_got = 0, 354 .weak_undef_pulls_archive_member = 0, 355 .tls_symbol_features = 1, 356 .alias_via_thunk = 0, 357 .weak_undef_attr = "weak", 358 .elf_arch = obj_elf_arch, 359 .elf_machine = obj_elf_machine, 360 }; 361 #endif 362 363 #if KIT_OBJ_MACHO_ENABLED 364 static const ObjFormatImpl obj_format_impl_macho = { 365 .kind = KIT_OBJ_MACHO, 366 .bin_fmt = KIT_BIN_MACHO, 367 .name = "macho", 368 .read_name = "read_macho", 369 .read_dso_name = "read_macho_dso", 370 .emit = emit_macho, 371 .read = read_macho, 372 .read_dso = read_macho_dso, 373 .link_emit = OBJ_LINK_EMIT_MACHO, 374 .split_sections_as_atoms = 1, 375 .c_label_prefix = "_", 376 .default_entry_name = "_main", 377 .carries_file_only_debug = 1, 378 .builds_own_static_got = 1, 379 .weak_undef_pulls_archive_member = 0, 380 .tls_symbol_features = 1, 381 .alias_via_thunk = 1, 382 .weak_undef_attr = "weak_import", 383 .macho_arch = obj_macho_arch, 384 .macho_cputype = obj_macho_cputype, 385 }; 386 #endif 387 388 #if KIT_OBJ_COFF_ENABLED 389 static const ObjFormatImpl obj_format_impl_coff = { 390 .kind = KIT_OBJ_COFF, 391 .bin_fmt = KIT_BIN_COFF, 392 .name = "coff", 393 .read_name = "read_coff", 394 .read_dso_name = "read_coff_dso", 395 .emit = emit_coff, 396 .read = read_coff, 397 .read_dso = read_coff_dso, 398 .link_emit = OBJ_LINK_EMIT_COFF, 399 .c_label_prefix = "", 400 .default_entry_name = "mainCRTStartup", 401 .carries_file_only_debug = 0, 402 .builds_own_static_got = 0, 403 .weak_undef_pulls_archive_member = 1, 404 .tls_symbol_features = 0, 405 .alias_via_thunk = 0, 406 .weak_undef_attr = "weak", 407 .weak_extern_underscore_alias = 1, 408 /* synth_inputs: the COFF __CTOR_LIST__/__DTOR_LIST__ + __chkstk 409 * synthesizer (link_synth_coff_ctor_dtor_list) genuinely needs Linker 410 * internals (LinkInput append, link_arch_desc_for); it cannot be 411 * expressed via ObjBuilder/Compiler/obj APIs alone. Wired to the 412 * src/link body (NULL when the linker subsystem is compiled out). */ 413 .synth_inputs = OBJ_COFF_SYNTH_INPUTS, 414 .coff_arch = obj_coff_arch, 415 .coff_machine = obj_coff_machine, 416 .classify_obj_input = coff_classify_obj_input, 417 .archive_hint = coff_archive_hint, 418 .archive_member = coff_archive_member, 419 }; 420 #endif 421 422 static const ObjFormatImpl* const obj_format_impls[] = { 423 #if KIT_OBJ_ELF_ENABLED 424 &obj_format_impl_elf, 425 #endif 426 #if KIT_OBJ_COFF_ENABLED 427 &obj_format_impl_coff, 428 #endif 429 #if KIT_OBJ_MACHO_ENABLED 430 &obj_format_impl_macho, 431 #endif 432 #if KIT_OBJ_WASM_ENABLED 433 &obj_format_impl_wasm, 434 #endif 435 }; 436 437 const ObjFormatImpl* obj_format_lookup(ObjFmt fmt) { 438 u32 i; 439 for (i = 0; i < (u32)(sizeof obj_format_impls / sizeof obj_format_impls[0]); 440 ++i) { 441 if (obj_format_impls[i]->kind == fmt) return obj_format_impls[i]; 442 } 443 return NULL; 444 } 445 446 const ObjFormatImpl* obj_format_lookup_bin(KitBinFmt fmt) { 447 switch (fmt) { 448 case KIT_BIN_ELF: 449 return obj_format_lookup(KIT_OBJ_ELF); 450 case KIT_BIN_COFF: 451 return obj_format_lookup(KIT_OBJ_COFF); 452 case KIT_BIN_MACHO: 453 return obj_format_lookup(KIT_OBJ_MACHO); 454 case KIT_BIN_WASM: 455 return obj_format_lookup(KIT_OBJ_WASM); 456 default: 457 return NULL; 458 } 459 } 460 461 /* Name<->KitObjFmt table. The canonical name comes first; trailing 462 * entries are accepted aliases (objcopy/objdump bfdname spellings). The 463 * canonical name for a fmt is always the first row whose `fmt` matches. */ 464 typedef struct ObjFmtNameRow { 465 KitObjFmt fmt; 466 const char* name; 467 } ObjFmtNameRow; 468 469 static const ObjFmtNameRow obj_fmt_names[] = { 470 {KIT_OBJ_ELF, "elf"}, {KIT_OBJ_COFF, "coff"}, 471 {KIT_OBJ_COFF, "pe"}, {KIT_OBJ_MACHO, "macho"}, 472 {KIT_OBJ_WASM, "wasm"}, 473 }; 474 475 int obj_format_fmt_from_name(const char* name, KitObjFmt* out) { 476 u32 i; 477 if (!name) return 0; 478 for (i = 0; i < (u32)(sizeof obj_fmt_names / sizeof obj_fmt_names[0]); ++i) { 479 if (strcmp(obj_fmt_names[i].name, name) == 0) { 480 if (out) *out = obj_fmt_names[i].fmt; 481 return 1; 482 } 483 } 484 return 0; 485 } 486 487 const char* obj_format_fmt_name(KitObjFmt fmt) { 488 u32 i; 489 for (i = 0; i < (u32)(sizeof obj_fmt_names / sizeof obj_fmt_names[0]); ++i) { 490 if (obj_fmt_names[i].fmt == fmt) return obj_fmt_names[i].name; 491 } 492 return NULL; 493 } 494 495 int obj_format_dso_reader_for_bytes(const u8* data, size_t len, 496 KitBinFmt* bin_out, 497 ObjFormatDsoReader* out) { 498 const ObjFormatImpl* fmt; 499 KitBinFmt bin; 500 if (!out) return 0; 501 memset(out, 0, sizeof(*out)); 502 if (bin_out) *bin_out = KIT_BIN_UNKNOWN; 503 if (!data) return 0; 504 505 #if KIT_OBJ_MACHO_ENABLED 506 if (len >= 3 && data[0] == '-' && data[1] == '-' && data[2] == '-') { 507 out->format = &obj_format_impl_macho; 508 out->read = read_tbd; 509 out->name = "read_tbd"; 510 return 1; 511 } 512 #endif 513 514 bin = kit_detect_fmt(data, len); 515 if (bin_out) *bin_out = bin; 516 fmt = (bin == KIT_BIN_PE) ? obj_format_lookup(KIT_OBJ_COFF) 517 : obj_format_lookup_bin(bin); 518 if (!fmt || !fmt->read_dso) return 0; 519 out->format = fmt; 520 out->read = fmt->read_dso; 521 out->name = fmt->read_dso_name; 522 return 1; 523 }