kit

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

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 }