kit

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

commit fe38baabffe432508c64e96d49fd1beba7370345
parent 93bc5574ad37395fd7281f02b8b8a921b7eebcbe
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Fri, 12 Jun 2026 17:32:55 -0700

Split hosted libc profiles by OS

Diffstat:
MMakefile | 2+-
Mdriver/env.h | 22++++++----------------
Mdriver/env/common.c | 47+++++++++++------------------------------------
Adriver/env/posix_dbg_stubs.c | 5+++++
Mdriver/lib/hosted.c | 760++++++-------------------------------------------------------------------------
Mdriver/lib/hosted.h | 57++++++++++++++-------------------------------------------
Minclude/kit/config.h | 94++++++++++++++++++++++++++++++++++++++++----------------------------------------
Ainclude/kit/os.h | 149+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mmk/driver_srcs.mk | 18+++++++++++-------
Mmk/lib_srcs.mk | 35+++++++++++++++++++++++++++++++++--
Msrc/api/target.c | 16+++++++---------
Msrc/emu/dl.c | 10++++++----
Msrc/emu/emu.c | 32+++++++++++++++++---------------
Msrc/emu/emu.h | 30+-----------------------------
Msrc/emu/runtime.c | 20+++++++++++---------
Msrc/emu/signal.c | 5+++--
Asrc/os/freebsd/hosted.c | 112+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/os/freebsd/os.c | 10++++++++++
Asrc/os/hosted.c | 227+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/os/hosted_internal.h | 30++++++++++++++++++++++++++++++
Asrc/os/linux/hosted.c | 207+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/os/linux/linux.c | 54++++++++++++++++++++++++++++--------------------------
Asrc/os/linux/os.c | 25+++++++++++++++++++++++++
Asrc/os/macos/hosted.c | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/os/macos/os.c | 10++++++++++
Msrc/os/registry.c | 34++++++++++++++++++++++++++++++----
Asrc/os/windows/hosted.c | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/os/windows/os.c | 10++++++++++
28 files changed, 1229 insertions(+), 959 deletions(-)

diff --git a/Makefile b/Makefile @@ -143,7 +143,7 @@ $(BUILD_DIR)/driver/env/%.o: driver/env/%.c Makefile $(BUILD_CONFIG) # =========================================================================== RT_CC ?= $(BIN) cc -RT_AR ?= $(BIN) ar +RT_AR ?= $(if $(filter 1,$(KIT_TOOL_AR_ENABLED)),$(BIN) ar,$(AR)) RT_AS ?= $(BIN) as RT_AS_COMPILE_FLAGS ?= diff --git a/driver/env.h b/driver/env.h @@ -5,6 +5,8 @@ #include <kit/core.h> #include <kit/dbg.h> #include <kit/jit.h> +#include <kit/os.h> +#include <stdarg.h> #include <stddef.h> #include <stdint.h> @@ -87,23 +89,10 @@ KitTargetSpec driver_host_target(void); * DRIVER_HOSTED_MAX_INCDIRS must stay >= the plan's DRIVER_HOSTED_MAX_INCLUDES * (driver/lib/hosted.h): every emitted incdir becomes one owned plan include. * ---------------------------------------------------------------------- */ -#define DRIVER_HOSTED_MAX_INCDIRS 4 -#define DRIVER_HOSTED_MAX_LIBDIRS 8 +#define DRIVER_HOSTED_MAX_INCDIRS KIT_OS_HOSTED_MAX_INCDIRS +#define DRIVER_HOSTED_MAX_LIBDIRS KIT_OS_HOSTED_MAX_LIBDIRS -typedef struct DriverHostedDirs { - DriverEnv* env; - /* The single sysroot root these dirs came from (an explicit --sysroot/ - * KIT_SYSROOT, or a host probe that resolves to one tree, e.g. the macOS - * SDK). NULL when the dirs come from a multi-dir source with no single root - * (the Linux/FreeBSD live-system probe). Borrowed; not freed by fini. */ - const char* root; - char* incdirs[DRIVER_HOSTED_MAX_INCDIRS]; - size_t incdir_sizes[DRIVER_HOSTED_MAX_INCDIRS]; - uint32_t nincdirs; - char* libdirs[DRIVER_HOSTED_MAX_LIBDIRS]; - size_t libdir_sizes[DRIVER_HOSTED_MAX_LIBDIRS]; - uint32_t nlibdirs; -} DriverHostedDirs; +typedef KitOsHostedDirs DriverHostedDirs; /* Append an include/library directory, heap-duplicated from `dir`. The _join * forms join `base` + `sub` with a single '/' separator first. A NULL/empty dir @@ -250,6 +239,7 @@ int driver_walk_regular_files(DriverEnv*, const char* root, DriverWalkFileFn, /* Diagnostic printing to host stderr. Format is `"<tool>: <fmt>\n"`. */ void driver_errf(const char* tool, const char* fmt, ...); +void driver_verrf(const char* tool, const char* fmt, va_list ap); /* Raw hosted stderr log. Used by optional metrics so libkit stays callback- * only and freestanding. */ diff --git a/driver/env/common.c b/driver/env/common.c @@ -186,55 +186,26 @@ void driver_release_bytes(const KitFileIO* io, DriverLoad* lf) { /* ---------------- hosted dir lists ---------------- */ -/* Mechanical only: join `a` (+ optional `/sub`) via driver_path_join and dup - * into the list. No per-OS policy lives here -- producers (driver/lib/hosted.c - * expansion and the per-host driver_default_hosted_dirs probes) supply the - * paths. */ -static int hd_store(DriverEnv* env, char** arr, size_t* sizes, uint32_t* n, - uint32_t cap, const char* a, const char* b) { - size_t bytes; - char* out; - if (!a || !a[0]) return 0; /* empty base -> successful no-op */ - if (*n >= cap) return 1; /* loud overflow -- never a silent drop */ - out = driver_path_join(env, a, b, &bytes); - if (!out) return 1; - arr[*n] = out; - sizes[*n] = bytes; - (*n)++; - return 0; -} - int driver_hosted_dirs_add_inc(DriverHostedDirs* d, const char* dir) { - return hd_store(d->env, d->incdirs, d->incdir_sizes, &d->nincdirs, - DRIVER_HOSTED_MAX_INCDIRS, dir, NULL); + return kit_os_hosted_dirs_add_inc(d, dir); } int driver_hosted_dirs_add_lib(DriverHostedDirs* d, const char* dir) { - return hd_store(d->env, d->libdirs, d->libdir_sizes, &d->nlibdirs, - DRIVER_HOSTED_MAX_LIBDIRS, dir, NULL); + return kit_os_hosted_dirs_add_lib(d, dir); } int driver_hosted_dirs_add_inc_join(DriverHostedDirs* d, const char* base, const char* sub) { - return hd_store(d->env, d->incdirs, d->incdir_sizes, &d->nincdirs, - DRIVER_HOSTED_MAX_INCDIRS, base, sub); + return kit_os_hosted_dirs_add_inc_join(d, base, sub); } int driver_hosted_dirs_add_lib_join(DriverHostedDirs* d, const char* base, const char* sub) { - return hd_store(d->env, d->libdirs, d->libdir_sizes, &d->nlibdirs, - DRIVER_HOSTED_MAX_LIBDIRS, base, sub); + return kit_os_hosted_dirs_add_lib_join(d, base, sub); } void driver_hosted_dirs_fini(DriverHostedDirs* d) { - uint32_t i; - if (!d || !d->env) return; - for (i = 0; i < d->nincdirs; ++i) - driver_free(d->env, d->incdirs[i], d->incdir_sizes[i]); - for (i = 0; i < d->nlibdirs; ++i) - driver_free(d->env, d->libdirs[i], d->libdir_sizes[i]); - d->nincdirs = 0; - d->nlibdirs = 0; + kit_os_hosted_dirs_fini(d); } /* ---------------- string predicates ---------------- */ @@ -350,10 +321,14 @@ char* driver_path_join(DriverEnv* env, const char* a, const char* b, void driver_errf(const char* tool, const char* fmt, ...) { va_list ap; - fprintf(stderr, "%.*s: ", KIT_SLICE_ARG(kit_slice_cstr(tool))); va_start(ap, fmt); - vfprintf(stderr, fmt, ap); + driver_verrf(tool, fmt, ap); va_end(ap); +} + +void driver_verrf(const char* tool, const char* fmt, va_list ap) { + fprintf(stderr, "%.*s: ", KIT_SLICE_ARG(kit_slice_cstr(tool))); + vfprintf(stderr, fmt, ap); fputc('\n', stderr); } diff --git a/driver/env/posix_dbg_stubs.c b/driver/env/posix_dbg_stubs.c @@ -0,0 +1,5 @@ +#include "env_posix.h" + +KitDbgOs g_dbg_os_posix = {0}; + +int posix_dbg_caller_is_worker(void) { return 0; } diff --git a/driver/lib/hosted.c b/driver/lib/hosted.c @@ -1,704 +1,67 @@ #include "hosted.h" -#include <stddef.h> -#include <stdint.h> +#include <stdarg.h> #include <string.h> -static int hosted_add_input(DriverHostedInput* items, uint32_t* n, uint32_t cap, - uint8_t kind, char* path, size_t path_size) { - DriverHostedInput* it; - if (*n >= cap) return 1; - it = &items[*n]; - it->kind = kind; - it->path = path; - it->owned_path = path; - it->owned_size = path_size; - (*n)++; - return 0; -} - -/* ---------------- libdir search ---------------- */ - -/* Return a freshly-owned `<libdir>/file` for the first libdir that has it, or - * NULL when none do (or on OOM -- the caller treats both as "not found"). */ -static char* hosted_find_in_libdirs(DriverEnv* env, - const DriverHostedDirs* dirs, - const char* file, size_t* out_size) { - uint32_t i; - for (i = 0; i < dirs->nlibdirs; ++i) { - size_t size = 0; - char* path = driver_path_join(env, dirs->libdirs[i], file, &size); - if (!path) return NULL; - if (driver_path_exists(path)) { - *out_size = size; - return path; - } - driver_free(env, path, size); - } - return NULL; -} - -static int hosted_libdir_has(DriverEnv* env, const DriverHostedDirs* dirs, - const char* file) { - size_t size = 0; - char* path = hosted_find_in_libdirs(env, dirs, file, &size); - if (!path) return 0; - driver_free(env, path, size); - return 1; -} - -/* Search the libdir list for a required crt/libc file, binding the first hit - * as an owned input. The bound file path persists in the plan (freed by - * driver_hosted_plan_fini); the dir list itself is transient scratch. */ -static int hosted_add_required_search(DriverHostedInput* items, uint32_t* n, - uint32_t cap, - const DriverHostedRequest* req, - const DriverHostedDirs* dirs, - const char* file, uint8_t kind) { - size_t size = 0; - char* path = hosted_find_in_libdirs(req->env, dirs, file, &size); - if (!path) { - driver_errf(req->tool, - "hosted profile missing required file: %.*s (searched %u " - "library dir(s))", - KIT_SLICE_ARG(kit_slice_cstr(file)), (unsigned)dirs->nlibdirs); - return 1; - } - if (hosted_add_input(items, n, cap, kind, path, size) != 0) { - driver_errf(req->tool, "too many hosted inputs"); - driver_free(req->env, path, size); - return 1; - } - return 0; -} - -/* ---------------- include dirs ---------------- */ - -/* Promote one include dir into the plan as an owned copy, skipping it silently - * when it does not exist. The copy is required: plan->system_includes outlives - * the transient DriverHostedDirs (it feeds the preprocessor). */ -static int hosted_add_existing_include(DriverHostedPlan* plan, DriverEnv* env, - const char* dir) { - size_t len, bytes; - char* path; - if (plan->nsystem_includes >= DRIVER_HOSTED_MAX_INCLUDES) return 1; - if (!driver_path_exists(dir)) return 0; - len = driver_strlen(dir); - bytes = len + 1u; - path = driver_alloc(env, bytes); - if (!path) return 1; - driver_memcpy(path, dir, len); - path[len] = '\0'; - plan->system_includes[plan->nsystem_includes] = path; - plan->owned_system_includes[plan->nsystem_includes] = path; - plan->owned_system_include_sizes[plan->nsystem_includes] = bytes; - plan->nsystem_includes++; - return 0; -} - -static int hosted_add_incdirs(DriverHostedPlan* plan, DriverEnv* env, - const DriverHostedDirs* dirs) { - uint32_t i; - for (i = 0; i < dirs->nincdirs; ++i) { - if (hosted_add_existing_include(plan, env, dirs->incdirs[i]) != 0) return 1; - } - return 0; -} - -/* ---------------- defines ---------------- */ - -static int hosted_add_define(DriverHostedPlan* plan, const char* name, - const char* body) { - if (plan->ndefines >= DRIVER_HOSTED_MAX_DEFINES) return 1; - plan->defines[plan->ndefines].name = kit_slice_cstr(name); - plan->defines[plan->ndefines].body = kit_slice_cstr(body); - plan->ndefines++; - return 0; -} - -static int hosted_add_clang_compat_defines(DriverHostedPlan* plan) { - if (hosted_add_define(plan, "__clang__", "1") != 0 || - hosted_add_define(plan, "__clang_major__", "17") != 0 || - hosted_add_define(plan, "__clang_minor__", "0") != 0 || - hosted_add_define(plan, "__clang_patchlevel__", "0") != 0 || - hosted_add_define(plan, "__GNUC__", "4") != 0 || - hosted_add_define(plan, "__GNUC_MINOR__", "2") != 0 || - hosted_add_define(plan, "__GNUC_PATCHLEVEL__", "1") != 0 || - hosted_add_define(plan, "__has_builtin(x)", "0") != 0 || - hosted_add_define(plan, "__has_include(x)", "0") != 0 || - hosted_add_define(plan, "__has_include_next(x)", "0") != 0 || - hosted_add_define(plan, "__has_feature(x)", "0") != 0 || - hosted_add_define(plan, "__has_extension(x)", "0") != 0 || - hosted_add_define(plan, "__has_attribute(x)", "0") != 0) - return 1; - return 0; -} - -static int hosted_add_darwin_defines(DriverHostedPlan* plan) { - /* __APPLE_CC__ is what the SDK's <TargetConditionals.h> actually keys on: - * its compiler-detection ladder treats us as "GCC/clang on Mac OS X" only - * when __GNUC__ AND one of __APPLE_CC__/__APPLE_CPP__/__MACOS_CLASSIC__ are - * defined. Without it the header can't map __arm64__/__x86_64__ onto a - * TARGET_CPU_* and hits its `#error unknown compiler`. 6000 is the value - * modern Apple clang advertises. */ - if (hosted_add_clang_compat_defines(plan) != 0 || - hosted_add_define(plan, "__APPLE__", "1") != 0 || - hosted_add_define(plan, "__APPLE_CC__", "6000") != 0 || - hosted_add_define(plan, "__MACH__", "1") != 0 || - hosted_add_define(plan, "__DYNAMIC__", "1") != 0) - return 1; - return 0; -} - -static int hosted_add_linux_defines(DriverHostedPlan* plan, int gnu) { - if (hosted_add_clang_compat_defines(plan) != 0 || - hosted_add_define(plan, "__linux__", "1") != 0 || - hosted_add_define(plan, "__linux", "1") != 0 || - hosted_add_define(plan, "linux", "1") != 0 || - hosted_add_define(plan, "__ELF__", "1") != 0) - return 1; - if (gnu && hosted_add_define(plan, "__gnu_linux__", "1") != 0) return 1; - return 0; -} - -static const char* freebsd_version_str(uint8_t major) { - /* Static strings indexed by major version; 0 = unspecified → "15". */ - static const char* const tab[21] = {"15", "1", "2", "3", "4", "5", "6", - "7", "8", "9", "10", "11", "12", "13", - "14", "15", "16", "17", "18", "19", "20"}; - return (major < 21) ? tab[major] : "15"; -} - -static int hosted_add_freebsd_defines(DriverHostedPlan* plan, - uint8_t version_major) { - /* __FreeBSD__ must be present and version-encoded or the base headers fail to - * compile. The version is derived from the triple; 0 falls back to 15. */ - if (hosted_add_clang_compat_defines(plan) != 0 || - hosted_add_define(plan, "__FreeBSD__", - freebsd_version_str(version_major)) != 0 || - hosted_add_define(plan, "__ELF__", "1") != 0 || - hosted_add_define(plan, "__unix__", "1") != 0 || - hosted_add_define(plan, "__unix", "1") != 0 || - hosted_add_define(plan, "unix", "1") != 0) - return 1; - return 0; -} - -/* ---------------- interpreters ---------------- */ - -static const char* hosted_glibc_interp(KitArchKind arch) { - switch (arch) { - case KIT_ARCH_ARM_64: - return "/lib/ld-linux-aarch64.so.1"; - case KIT_ARCH_X86_64: - return "/lib64/ld-linux-x86-64.so.2"; - case KIT_ARCH_RV64: - return "/lib/ld-linux-riscv64-lp64d.so.1"; - default: - return NULL; - } -} - -static const char* hosted_musl_interp(KitArchKind arch) { - switch (arch) { - case KIT_ARCH_ARM_64: - return "/lib/ld-musl-aarch64.so.1"; - case KIT_ARCH_X86_64: - return "/lib/ld-musl-x86_64.so.1"; - case KIT_ARCH_RV64: - return "/lib/ld-musl-riscv64.so.1"; - default: - return NULL; - } -} - -/* ---------------- per-OS resolvers ---------------- - * Each consumes a DriverHostedDirs (include roots + library search dirs). An - * empty dir list means no sysroot was given and no host default was found, so - * the resolver emits its "requires --sysroot/KIT_SYSROOT" error. */ - -static int hosted_resolve_darwin(const DriverHostedRequest* req, - const DriverHostedDirs* dirs, - DriverHostedPlan* plan) { - if (dirs->nlibdirs == 0) { - driver_errf(req->tool, - "Darwin hosted profile requires a macOS SDK; pass --sysroot, " - "set KIT_SYSROOT, or install the Command Line Tools (try: " - "--sysroot \"$(xcrun --sdk macosx --show-sdk-path)\")"); - return 1; - } - plan->profile_name = "macos-libSystem"; - if (hosted_add_darwin_defines(plan) != 0 || - hosted_add_incdirs(plan, req->env, dirs) != 0) { - driver_errf(req->tool, "out of memory"); - return 1; - } - if (!req->link_inputs) return 0; - { - size_t size = 0; - char* libsystem = - hosted_find_in_libdirs(req->env, dirs, "libSystem.tbd", &size); - if (!libsystem) - libsystem = - hosted_find_in_libdirs(req->env, dirs, "libSystem.dylib", &size); - if (!libsystem) { - driver_errf(req->tool, - "hosted profile missing required file: " - "libSystem.tbd or libSystem.dylib"); - return 1; - } - if (hosted_add_input(plan->after, &plan->nafter, DRIVER_HOSTED_MAX_AFTER, - DRIVER_HOSTED_INPUT_DSO, libsystem, size) != 0) { - driver_free(req->env, libsystem, size); - driver_errf(req->tool, "too many hosted inputs"); - return 1; - } - } - return 0; -} - -static int hosted_resolve_linux_musl_static(const DriverHostedRequest* req, - const DriverHostedDirs* dirs, - DriverHostedPlan* plan) { - plan->profile_name = "linux-musl-static"; - if (hosted_add_linux_defines(plan, 0) != 0 || - hosted_add_incdirs(plan, req->env, dirs) != 0) { - driver_errf(req->tool, "out of memory"); - return 1; - } - if (!req->link_inputs) return 0; - if (hosted_add_required_search(plan->before, &plan->nbefore, - DRIVER_HOSTED_MAX_BEFORE, req, dirs, "crt1.o", - DRIVER_HOSTED_INPUT_OBJECT) != 0 || - hosted_add_required_search(plan->before, &plan->nbefore, - DRIVER_HOSTED_MAX_BEFORE, req, dirs, "crti.o", - DRIVER_HOSTED_INPUT_OBJECT) != 0) - return 1; - if (hosted_add_required_search(plan->after, &plan->nafter, - DRIVER_HOSTED_MAX_AFTER, req, dirs, "libc.a", - DRIVER_HOSTED_INPUT_ARCHIVE) != 0) - return 1; - if (hosted_add_required_search(plan->final, &plan->nfinal, - DRIVER_HOSTED_MAX_FINAL, req, dirs, "crtn.o", - DRIVER_HOSTED_INPUT_OBJECT) != 0) - return 1; - return 0; -} - -static int hosted_resolve_linux_musl_dynamic(const DriverHostedRequest* req, - const DriverHostedDirs* dirs, - DriverHostedPlan* plan) { - const char* interp = hosted_musl_interp(req->target.arch); - if (!interp) { - driver_errf(req->tool, "no hosted musl profile for target architecture"); - return 1; - } - plan->profile_name = "linux-musl-dynamic"; - plan->interp_path = interp; - if (hosted_add_linux_defines(plan, 0) != 0 || - hosted_add_incdirs(plan, req->env, dirs) != 0) { - driver_errf(req->tool, "out of memory"); - return 1; - } - if (!req->link_inputs) return 0; - if (hosted_add_required_search(plan->before, &plan->nbefore, - DRIVER_HOSTED_MAX_BEFORE, req, dirs, "Scrt1.o", - DRIVER_HOSTED_INPUT_OBJECT) != 0 || - hosted_add_required_search(plan->before, &plan->nbefore, - DRIVER_HOSTED_MAX_BEFORE, req, dirs, "crti.o", - DRIVER_HOSTED_INPUT_OBJECT) != 0) - return 1; - if (hosted_add_required_search(plan->after, &plan->nafter, - DRIVER_HOSTED_MAX_AFTER, req, dirs, "libc.so", - DRIVER_HOSTED_INPUT_DSO) != 0) - return 1; - if (hosted_add_required_search(plan->final, &plan->nfinal, - DRIVER_HOSTED_MAX_FINAL, req, dirs, "crtn.o", - DRIVER_HOSTED_INPUT_OBJECT) != 0) - return 1; - return 0; +static char* driver_hosted_path_join(void* user, const char* a, const char* b, + size_t* out_size) { + return driver_path_join((DriverEnv*)user, a, b, out_size); } -static int hosted_resolve_linux_glibc_dynamic(const DriverHostedRequest* req, - const DriverHostedDirs* dirs, - DriverHostedPlan* plan) { - const char* interp = hosted_glibc_interp(req->target.arch); - if (!interp) { - driver_errf(req->tool, "no hosted glibc profile for target architecture"); - return 1; - } - plan->profile_name = "linux-glibc-dynamic"; - plan->interp_path = interp; - /* The arch multiarch include (include/<triple>) is already in the dir list, - * so glibc adds the same include set as the musl profiles. */ - if (hosted_add_linux_defines(plan, 1) != 0 || - hosted_add_incdirs(plan, req->env, dirs) != 0) { - driver_errf(req->tool, "out of memory"); - return 1; - } - if (!req->link_inputs) return 0; - if (hosted_add_required_search(plan->before, &plan->nbefore, - DRIVER_HOSTED_MAX_BEFORE, req, dirs, "Scrt1.o", - DRIVER_HOSTED_INPUT_OBJECT) != 0 || - hosted_add_required_search(plan->before, &plan->nbefore, - DRIVER_HOSTED_MAX_BEFORE, req, dirs, "crti.o", - DRIVER_HOSTED_INPUT_OBJECT) != 0) - return 1; - if (hosted_add_required_search(plan->after, &plan->nafter, - DRIVER_HOSTED_MAX_AFTER, req, dirs, - "libc.so.6", DRIVER_HOSTED_INPUT_DSO) != 0 || - hosted_add_required_search( - plan->after, &plan->nafter, DRIVER_HOSTED_MAX_AFTER, req, dirs, - "libc_nonshared.a", DRIVER_HOSTED_INPUT_ARCHIVE) != 0) - return 1; - if (hosted_add_required_search(plan->final, &plan->nfinal, - DRIVER_HOSTED_MAX_FINAL, req, dirs, "crtn.o", - DRIVER_HOSTED_INPUT_OBJECT) != 0) - return 1; - return 0; +static int driver_hosted_path_exists(void* user, const char* path) { + (void)user; + return driver_path_exists(path); } -static int hosted_resolve_linux(const DriverHostedRequest* req, - const DriverHostedDirs* dirs, - DriverHostedPlan* plan) { - int has_libc_a, has_libc_so, has_libc_so6, has_glibc_nonshared; - if (dirs->nlibdirs == 0) { - driver_errf(req->tool, - "Linux hosted profile requires --sysroot or KIT_SYSROOT"); - return 1; - } - /* Booleans mean "exists in some libdir". With a single sysroot libdir this is - * bit-identical to the historical single-dir probe; with the multi-dir host - * probe, glibc's split (crt + libc_nonshared.a in /usr/lib/<triple>, - * libc.so.6 in /lib/<triple>) is handled by the per-file ordered search. */ - has_libc_a = hosted_libdir_has(req->env, dirs, "libc.a"); - has_libc_so = hosted_libdir_has(req->env, dirs, "libc.so"); - has_libc_so6 = hosted_libdir_has(req->env, dirs, "libc.so.6"); - has_glibc_nonshared = hosted_libdir_has(req->env, dirs, "libc_nonshared.a"); - if (!req->static_link && has_libc_so6 && has_glibc_nonshared) - return hosted_resolve_linux_glibc_dynamic(req, dirs, plan); - if (!req->static_link && has_libc_so) - return hosted_resolve_linux_musl_dynamic(req, dirs, plan); - if (has_libc_a && !(has_libc_so6 && has_glibc_nonshared)) - return hosted_resolve_linux_musl_static(req, dirs, plan); - driver_errf(req->tool, - "no supported Linux hosted libc found (searched %u library " - "dir(s))", - (unsigned)dirs->nlibdirs); - return 1; +static void* driver_hosted_alloc(void* user, size_t size) { + return driver_alloc((DriverEnv*)user, size); } -/* FreeBSD base-system hosted profile. libc binds libc.so.7 directly -- - * /usr/lib/libc.so is a GNU ld linker script kit's linker cannot parse. */ -static int hosted_resolve_freebsd(const DriverHostedRequest* req, - const DriverHostedDirs* dirs, - DriverHostedPlan* plan) { - int static_link; - if (dirs->nlibdirs == 0) { - driver_errf(req->tool, - "FreeBSD hosted profile requires --sysroot or KIT_SYSROOT"); - return 1; - } - static_link = req->static_link && hosted_libdir_has(req->env, dirs, "libc.a"); - plan->profile_name = static_link ? "freebsd-static" : "freebsd-dynamic"; - if (!static_link) plan->interp_path = "/libexec/ld-elf.so.1"; - if (hosted_add_freebsd_defines(plan, req->target.os_version_major) != 0 || - hosted_add_incdirs(plan, req->env, dirs) != 0) { - driver_errf(req->tool, "out of memory"); - return 1; - } - if (!req->link_inputs) return 0; - if (hosted_add_required_search(plan->before, &plan->nbefore, - DRIVER_HOSTED_MAX_BEFORE, req, dirs, - static_link ? "crt1.o" : "Scrt1.o", - DRIVER_HOSTED_INPUT_OBJECT) != 0 || - hosted_add_required_search(plan->before, &plan->nbefore, - DRIVER_HOSTED_MAX_BEFORE, req, dirs, "crti.o", - DRIVER_HOSTED_INPUT_OBJECT) != 0) - return 1; - if (static_link) { - /* FreeBSD 15 split the raw syscall stubs out of libc into libsys; the - * compiler builtins / soft-float helpers (e.g. rv64's binary128 __multf3, - * which libc references because the RISC-V psABI makes long double a - * 128-bit quad) live in libcompiler_rt.a (a.k.a. libgcc.a). libc, libsys - * and libcompiler_rt are mutually recursive, so after the first libc.a we - * append the ones the sysroot provides and re-list libc.a to pick up the - * back-references they introduce -- kit resolves each archive against the - * inputs before it and has no --start-group. */ - int has_libsys = hosted_libdir_has(req->env, dirs, "libsys.a"); - int has_crt = hosted_libdir_has(req->env, dirs, "libcompiler_rt.a"); - if (hosted_add_required_search(plan->after, &plan->nafter, - DRIVER_HOSTED_MAX_AFTER, req, dirs, "libc.a", - DRIVER_HOSTED_INPUT_ARCHIVE) != 0) - return 1; - if (has_libsys && - hosted_add_required_search( - plan->after, &plan->nafter, DRIVER_HOSTED_MAX_AFTER, req, dirs, - "libsys.a", DRIVER_HOSTED_INPUT_ARCHIVE) != 0) - return 1; - if (has_crt && hosted_add_required_search(plan->after, &plan->nafter, - DRIVER_HOSTED_MAX_AFTER, req, - dirs, "libcompiler_rt.a", - DRIVER_HOSTED_INPUT_ARCHIVE) != 0) - return 1; - if ((has_libsys || has_crt) && - hosted_add_required_search(plan->after, &plan->nafter, - DRIVER_HOSTED_MAX_AFTER, req, dirs, "libc.a", - DRIVER_HOSTED_INPUT_ARCHIVE) != 0) - return 1; - } else { - if (hosted_add_required_search(plan->after, &plan->nafter, - DRIVER_HOSTED_MAX_AFTER, req, dirs, - "libc.so.7", DRIVER_HOSTED_INPUT_DSO) != 0) - return 1; - if (hosted_libdir_has(req->env, dirs, "libsys.so.7") && - hosted_add_required_search(plan->after, &plan->nafter, - DRIVER_HOSTED_MAX_AFTER, req, dirs, - "libsys.so.7", DRIVER_HOSTED_INPUT_DSO) != 0) - return 1; - } - if (hosted_add_required_search(plan->final, &plan->nfinal, - DRIVER_HOSTED_MAX_FINAL, req, dirs, "crtn.o", - DRIVER_HOSTED_INPUT_OBJECT) != 0) - return 1; - return 0; +static void driver_hosted_free(void* user, void* ptr, size_t size) { + driver_free((DriverEnv*)user, ptr, size); } -static int hosted_resolve_windows_mingw(const DriverHostedRequest* req, - const DriverHostedDirs* dirs, - DriverHostedPlan* plan) { - if (dirs->nlibdirs == 0) { - driver_errf(req->tool, - "Windows hosted profile requires --sysroot or KIT_SYSROOT"); - return 1; - } - plan->profile_name = "windows-mingw-ucrt"; - if (hosted_add_incdirs(plan, req->env, dirs) != 0) { - driver_errf(req->tool, "out of memory"); - return 1; - } - if (!req->link_inputs) return 0; - if (hosted_add_required_search(plan->before, &plan->nbefore, - DRIVER_HOSTED_MAX_BEFORE, req, dirs, "crt2.o", - DRIVER_HOSTED_INPUT_OBJECT) != 0 || - hosted_add_required_search(plan->before, &plan->nbefore, - DRIVER_HOSTED_MAX_BEFORE, req, dirs, - "crtbegin.o", DRIVER_HOSTED_INPUT_OBJECT) != 0) - return 1; - if (hosted_add_required_search( - plan->after, &plan->nafter, DRIVER_HOSTED_MAX_AFTER, req, dirs, - "libmingw32.a", DRIVER_HOSTED_INPUT_ARCHIVE) != 0 || - hosted_add_required_search( - plan->after, &plan->nafter, DRIVER_HOSTED_MAX_AFTER, req, dirs, - "libmoldname.a", DRIVER_HOSTED_INPUT_ARCHIVE) != 0 || - hosted_add_required_search( - plan->after, &plan->nafter, DRIVER_HOSTED_MAX_AFTER, req, dirs, - "libmingwex.a", DRIVER_HOSTED_INPUT_ARCHIVE) != 0 || - /* winpthreads provides mingw's POSIX time/clock/threading entry points - * (nanosleep64, clock_gettime64, ...). <time.h> pulls in pthread_time.h's - * inline wrappers that call these, so it belongs in the default mingw - * runtime set (llvm-mingw ships it as a core lib). Static archive -> no - * libwinpthread-1.dll dependency; archive semantics keep it out of links - * that reference none of its members. */ - hosted_add_required_search( - plan->after, &plan->nafter, DRIVER_HOSTED_MAX_AFTER, req, dirs, - "libwinpthread.a", DRIVER_HOSTED_INPUT_ARCHIVE) != 0 || - hosted_add_required_search( - plan->after, &plan->nafter, DRIVER_HOSTED_MAX_AFTER, req, dirs, - "libucrt.a", DRIVER_HOSTED_INPUT_ARCHIVE) != 0 || - hosted_add_required_search( - plan->after, &plan->nafter, DRIVER_HOSTED_MAX_AFTER, req, dirs, - "libadvapi32.a", DRIVER_HOSTED_INPUT_ARCHIVE) != 0 || - hosted_add_required_search( - plan->after, &plan->nafter, DRIVER_HOSTED_MAX_AFTER, req, dirs, - "libshell32.a", DRIVER_HOSTED_INPUT_ARCHIVE) != 0 || - hosted_add_required_search( - plan->after, &plan->nafter, DRIVER_HOSTED_MAX_AFTER, req, dirs, - "libuser32.a", DRIVER_HOSTED_INPUT_ARCHIVE) != 0 || - hosted_add_required_search( - plan->after, &plan->nafter, DRIVER_HOSTED_MAX_AFTER, req, dirs, - "libkernel32.a", DRIVER_HOSTED_INPUT_ARCHIVE) != 0 || - /* Deliberate second pass over the mingw/ucrt runtime core (a manual - * --start-group/--end-group): these archives are mutually recursive -- - * libucrt pulls libmingwex/libmoldname members which in turn pull more - * libucrt members, and winpthread/mingw32 close the cycle. Because - * archives are scanned in order with lazy member pulls, one pass leaves - * late-discovered undefs unresolved; re-listing the core set lets the - * linker pull the members the first pass missed. This is NOT a verbatim - * duplicate of the list above (the system import libs are not repeated). - */ - hosted_add_required_search( - plan->after, &plan->nafter, DRIVER_HOSTED_MAX_AFTER, req, dirs, - "libmingw32.a", DRIVER_HOSTED_INPUT_ARCHIVE) != 0 || - hosted_add_required_search( - plan->after, &plan->nafter, DRIVER_HOSTED_MAX_AFTER, req, dirs, - "libmoldname.a", DRIVER_HOSTED_INPUT_ARCHIVE) != 0 || - hosted_add_required_search( - plan->after, &plan->nafter, DRIVER_HOSTED_MAX_AFTER, req, dirs, - "libmingwex.a", DRIVER_HOSTED_INPUT_ARCHIVE) != 0 || - hosted_add_required_search( - plan->after, &plan->nafter, DRIVER_HOSTED_MAX_AFTER, req, dirs, - "libwinpthread.a", DRIVER_HOSTED_INPUT_ARCHIVE) != 0 || - hosted_add_required_search( - plan->after, &plan->nafter, DRIVER_HOSTED_MAX_AFTER, req, dirs, - "libucrt.a", DRIVER_HOSTED_INPUT_ARCHIVE) != 0 || - hosted_add_required_search( - plan->after, &plan->nafter, DRIVER_HOSTED_MAX_AFTER, req, dirs, - "libkernel32.a", DRIVER_HOSTED_INPUT_ARCHIVE) != 0) - return 1; - if (hosted_add_required_search(plan->final, &plan->nfinal, - DRIVER_HOSTED_MAX_FINAL, req, dirs, "crtend.o", - DRIVER_HOSTED_INPUT_OBJECT) != 0) - return 1; - return 0; -} - -/* ---------------- sysroot expansion (Producer A) ---------------- */ - -static const char* hosted_linux_inc_triple_sub(KitArchKind arch) { - switch (arch) { - case KIT_ARCH_ARM_64: - return "usr/include/aarch64-linux-gnu"; - case KIT_ARCH_X86_64: - return "usr/include/x86_64-linux-gnu"; - case KIT_ARCH_RV64: - return "usr/include/riscv64-linux-gnu"; - default: - return NULL; - } -} - -/* Expand an explicit --sysroot/KIT_SYSROOT into the dir list, per target-OS - * layout. Mirrors the per-host probes' shape so both producers converge on the - * same resolver contract. Dirs are added unconditionally (existence is checked - * when the resolver consumes them); returns nonzero only on alloc/overflow. - * One function per hosted OS; selected by the HostedProfile table below. */ - -static int hosted_sysroot_layout_darwin(DriverHostedDirs* dirs, - KitTargetSpec target, - const char* sysroot) { - (void)target; - if (driver_hosted_dirs_add_inc_join(dirs, sysroot, "usr/include") != 0 || - driver_hosted_dirs_add_lib_join(dirs, sysroot, "usr/lib") != 0) - return 1; - return 0; -} - -static int hosted_sysroot_layout_linux(DriverHostedDirs* dirs, - KitTargetSpec target, - const char* sysroot) { - /* Standard FHS sysroot (matching darwin/freebsd/windows): libc + kernel - * headers under usr/include (+ the per-arch multiarch subdir that glibc uses - * for its bits headers), libraries + crt + the gcc runtime under usr/lib, and - * lib/lib64 for the dynamic loader. The same tree is consumed unchanged by a - * standard `clang --sysroot` cross-link — see the libc Containerfiles. */ - const char* triple = hosted_linux_inc_triple_sub(target.arch); - if (driver_hosted_dirs_add_inc_join(dirs, sysroot, "usr/include") != 0) - return 1; - if (triple && driver_hosted_dirs_add_inc_join(dirs, sysroot, triple) != 0) - return 1; - if (driver_hosted_dirs_add_lib_join(dirs, sysroot, "usr/lib") != 0) return 1; - if (driver_hosted_dirs_add_lib_join(dirs, sysroot, "lib") != 0) return 1; - if (driver_hosted_dirs_add_lib_join(dirs, sysroot, "lib64") != 0) return 1; - return 0; +static void driver_hosted_vdiagf(void* user, const char* tool, + const char* fmt, va_list ap) { + (void)user; + driver_verrf(tool, fmt, ap); } -static int hosted_sysroot_layout_freebsd(DriverHostedDirs* dirs, - KitTargetSpec target, - const char* sysroot) { - (void)target; - if (driver_hosted_dirs_add_inc_join(dirs, sysroot, "usr/include") != 0 || - driver_hosted_dirs_add_lib_join(dirs, sysroot, "usr/lib") != 0 || - driver_hosted_dirs_add_lib_join(dirs, sysroot, "lib") != 0) - return 1; - return 0; -} - -static int hosted_sysroot_layout_windows(DriverHostedDirs* dirs, - KitTargetSpec target, - const char* sysroot) { - (void)target; - if (driver_hosted_dirs_add_inc_join(dirs, sysroot, "include") != 0 || - driver_hosted_dirs_add_lib_join(dirs, sysroot, "lib") != 0) - return 1; - return 0; -} - -/* ---------------- hosted-profile registry ---------------- * - * - * One row per hosted (OS, object-format) pairing, mirroring the - * src/{arch,obj,abi}/registry.c tables. A new hosted OS is a new row: its - * crt/libc resolver and its --sysroot directory layout. The dispatcher and - * the sysroot expander both go through hosted_profile_for so the (os,obj) - * decision lives in exactly one place. */ -typedef int (*HostedResolveFn)(const DriverHostedRequest*, - const DriverHostedDirs*, DriverHostedPlan*); -typedef int (*HostedSysrootLayoutFn)(DriverHostedDirs*, KitTargetSpec, - const char*); - -typedef struct HostedProfile { - KitOSKind os; - KitObjFmt obj; - HostedResolveFn resolve; - HostedSysrootLayoutFn sysroot_layout; -} HostedProfile; - -static const HostedProfile hosted_profiles[] = { - {KIT_OS_MACOS, KIT_OBJ_MACHO, hosted_resolve_darwin, - hosted_sysroot_layout_darwin}, - {KIT_OS_LINUX, KIT_OBJ_ELF, hosted_resolve_linux, - hosted_sysroot_layout_linux}, - {KIT_OS_FREEBSD, KIT_OBJ_ELF, hosted_resolve_freebsd, - hosted_sysroot_layout_freebsd}, - {KIT_OS_WINDOWS, KIT_OBJ_COFF, hosted_resolve_windows_mingw, - hosted_sysroot_layout_windows}, +static const KitOsHostedHost driver_hosted_host = { + .path_join = driver_hosted_path_join, + .path_exists = driver_hosted_path_exists, + .alloc = driver_hosted_alloc, + .free = driver_hosted_free, + .vdiagf = driver_hosted_vdiagf, }; -/* The crt/libc resolve dispatch keys on the full (os, obj) pairing -- a - * matching OS with a foreign object format is not a hosted profile. */ -static const HostedProfile* hosted_profile_for(KitTargetSpec target) { - size_t i; - for (i = 0; i < sizeof hosted_profiles / sizeof hosted_profiles[0]; ++i) { - if (hosted_profiles[i].os == target.os && - hosted_profiles[i].obj == target.obj) - return &hosted_profiles[i]; - } - return NULL; +static const KitOsHostedOps* hosted_ops_for(KitTargetSpec target) { + const KitOsImpl* os = kit_os_lookup(target.os); + if (!os || !os->hosted || os->hosted->obj != target.obj) return NULL; + return os->hosted; } -/* The sysroot directory layout keys on OS alone (each hosted OS has a single - * canonical object format), matching the historical os-only expansion. */ -static const HostedProfile* hosted_profile_for_os(KitOSKind os) { - size_t i; - for (i = 0; i < sizeof hosted_profiles / sizeof hosted_profiles[0]; ++i) { - if (hosted_profiles[i].os == os) return &hosted_profiles[i]; - } - return NULL; +static const KitOsHostedOps* hosted_ops_for_os(KitOSKind os_kind) { + const KitOsImpl* os = kit_os_lookup(os_kind); + return os ? os->hosted : NULL; } -/* Expand an explicit sysroot into the dir list via the target's profile. - * Unknown targets leave the dir list empty (the dispatcher emits the error). */ static int hosted_dirs_from_sysroot(DriverHostedDirs* dirs, KitTargetSpec target, const char* sysroot) { - const HostedProfile* profile = hosted_profile_for_os(target.os); - dirs->root = - sysroot; /* a single explicit sysroot; -print-sysroot reports it */ - if (!profile) - return 0; /* unsupported target; the dispatcher emits the error */ - return profile->sysroot_layout(dirs, target, sysroot); + const KitOsHostedOps* ops = hosted_ops_for_os(target.os); + dirs->root = sysroot; + if (!ops) return 0; + return ops->sysroot_layout(dirs, target, sysroot); } -/* ---------------- orchestration ---------------- */ - int driver_hosted_dirs_resolve(const DriverHostedRequest* req, DriverHostedDirs* out) { const char* sysroot; if (!req || !req->env || !out) return 1; memset(out, 0, sizeof(*out)); - out->env = req->env; - /* KIT_SYSROOT: the single, portable, explicit env override. Works on every - * OS and applies to any target including cross-compiles, exactly like - * --sysroot. */ + out->host = &driver_hosted_host; + out->host_user = req->env; + sysroot = (req->sysroot && req->sysroot[0]) ? req->sysroot : NULL; if (!sysroot) { const char* env_sysroot = driver_getenv("KIT_SYSROOT"); @@ -710,11 +73,6 @@ int driver_hosted_dirs_resolve(const DriverHostedRequest* req, return 1; } } else { - /* Host probe: auto-discover the host's own includes/libs. Gated on the - * target matching the host OS *and* arch so it never fires for any - * cross-compile -- a host SDK is meaningless for a foreign platform. - * Best-effort: leaves dirs empty when nothing is found, and the resolver - * then emits its "requires --sysroot" error. */ KitTargetSpec host = driver_host_target(); if (req->target.os == host.os && req->target.arch == host.arch) (void)driver_default_hosted_dirs(req->env, req->target, out); @@ -726,7 +84,8 @@ int driver_hosted_resolve(const DriverHostedRequest* req, DriverHostedPlan* out) { DriverHostedPlan zero = {0}; DriverHostedDirs dirs; - const HostedProfile* profile; + KitOsHostedRequest os_req; + const KitOsHostedOps* ops; int rc; if (!req || !out || !req->env || !req->tool) return 1; *out = zero; @@ -734,16 +93,22 @@ int driver_hosted_resolve(const DriverHostedRequest* req, driver_errf(req->tool, "out of memory"); return 1; } - profile = hosted_profile_for(req->target); - if (profile) { - rc = profile->resolve(req, &dirs, out); - } else { + ops = hosted_ops_for(req->target); + if (!ops) { driver_errf(req->tool, "no hosted libc profile for target"); - rc = 1; + driver_hosted_dirs_fini(&dirs); + return 1; } + memset(&os_req, 0, sizeof(os_req)); + os_req.host = &driver_hosted_host; + os_req.host_user = req->env; + os_req.tool = req->tool; + os_req.target = req->target; + os_req.static_link = req->static_link; + os_req.link_inputs = req->link_inputs; + + rc = ops->resolve(&os_req, &dirs, out); if (rc == 0) { - /* Transfer libdir ownership from dirs into the plan so callers can add - * them to their lib search path for user-specified -l resolution. */ uint32_t j; for (j = 0; j < dirs.nlibdirs && j < DRIVER_HOSTED_MAX_LIB_SEARCH_DIRS; ++j) { @@ -760,28 +125,5 @@ int driver_hosted_resolve(const DriverHostedRequest* req, } void driver_hosted_plan_fini(DriverEnv* env, DriverHostedPlan* plan) { - uint32_t i; - if (!env || !plan) return; - for (i = 0; i < plan->nbefore; ++i) { - if (plan->before[i].owned_path) - driver_free(env, plan->before[i].owned_path, plan->before[i].owned_size); - } - for (i = 0; i < plan->nafter; ++i) { - if (plan->after[i].owned_path) - driver_free(env, plan->after[i].owned_path, plan->after[i].owned_size); - } - for (i = 0; i < plan->nfinal; ++i) { - if (plan->final[i].owned_path) - driver_free(env, plan->final[i].owned_path, plan->final[i].owned_size); - } - for (i = 0; i < plan->nsystem_includes; ++i) { - if (plan->owned_system_includes[i]) - driver_free(env, plan->owned_system_includes[i], - plan->owned_system_include_sizes[i]); - } - for (i = 0; i < plan->nlib_search_dirs; ++i) { - if (plan->lib_search_dirs[i]) - driver_free(env, plan->lib_search_dirs[i], plan->lib_search_dir_sizes[i]); - } - memset(plan, 0, sizeof(*plan)); + kit_os_hosted_plan_fini(&driver_hosted_host, env, plan); } diff --git a/driver/lib/hosted.h b/driver/lib/hosted.h @@ -2,53 +2,24 @@ #define KIT_DRIVER_HOSTED_H #include <kit/compile.h> +#include <kit/os.h> #include <stdint.h> #include "driver.h" -typedef enum DriverHostedInputKind { - DRIVER_HOSTED_INPUT_OBJECT, - DRIVER_HOSTED_INPUT_ARCHIVE, - DRIVER_HOSTED_INPUT_DSO, -} DriverHostedInputKind; - -typedef struct DriverHostedInput { - uint8_t kind; /* DriverHostedInputKind */ - uint8_t pad[3]; - const char* path; - char* owned_path; - size_t owned_size; -} DriverHostedInput; - -#define DRIVER_HOSTED_MAX_BEFORE 4 -#define DRIVER_HOSTED_MAX_AFTER 16 -#define DRIVER_HOSTED_MAX_FINAL 2 -#define DRIVER_HOSTED_MAX_INCLUDES 4 -#define DRIVER_HOSTED_MAX_DEFINES 20 -#define DRIVER_HOSTED_MAX_LIB_SEARCH_DIRS 8 - -typedef struct DriverHostedPlan { - const char* profile_name; - const char* interp_path; - DriverHostedInput before[DRIVER_HOSTED_MAX_BEFORE]; - uint32_t nbefore; - DriverHostedInput after[DRIVER_HOSTED_MAX_AFTER]; - uint32_t nafter; - DriverHostedInput final[DRIVER_HOSTED_MAX_FINAL]; - uint32_t nfinal; - const char* system_includes[DRIVER_HOSTED_MAX_INCLUDES]; - char* owned_system_includes[DRIVER_HOSTED_MAX_INCLUDES]; - size_t owned_system_include_sizes[DRIVER_HOSTED_MAX_INCLUDES]; - uint32_t nsystem_includes; - KitDefine defines[DRIVER_HOSTED_MAX_DEFINES]; - uint32_t ndefines; - /* Library search directories from the hosted dirs resolution; added to the - * driver's lib search path so user-specified -l flags (e.g. -lm, -lpthread) - * can be found. Ownership is transferred from DriverHostedDirs. */ - char* lib_search_dirs[DRIVER_HOSTED_MAX_LIB_SEARCH_DIRS]; - size_t lib_search_dir_sizes[DRIVER_HOSTED_MAX_LIB_SEARCH_DIRS]; - uint32_t nlib_search_dirs; -} DriverHostedPlan; +typedef KitOsHostedInputKind DriverHostedInputKind; +typedef KitOsHostedInput DriverHostedInput; +typedef KitOsHostedPlan DriverHostedPlan; + +#define DRIVER_HOSTED_INPUT_OBJECT KIT_OS_HOSTED_INPUT_OBJECT +#define DRIVER_HOSTED_INPUT_ARCHIVE KIT_OS_HOSTED_INPUT_ARCHIVE +#define DRIVER_HOSTED_INPUT_DSO KIT_OS_HOSTED_INPUT_DSO +#define DRIVER_HOSTED_MAX_BEFORE KIT_OS_HOSTED_MAX_BEFORE +#define DRIVER_HOSTED_MAX_AFTER KIT_OS_HOSTED_MAX_AFTER +#define DRIVER_HOSTED_MAX_FINAL KIT_OS_HOSTED_MAX_FINAL +#define DRIVER_HOSTED_MAX_INCLUDES KIT_OS_HOSTED_MAX_INCLUDES +#define DRIVER_HOSTED_MAX_DEFINES KIT_OS_HOSTED_MAX_DEFINES +#define DRIVER_HOSTED_MAX_LIB_SEARCH_DIRS KIT_OS_HOSTED_MAX_LIB_SEARCH_DIRS typedef struct DriverHostedRequest { DriverEnv* env; diff --git a/include/kit/config.h b/include/kit/config.h @@ -25,18 +25,18 @@ /* Backend architectures. */ #define KIT_ARCH_AA64_ENABLED 1 -#define KIT_ARCH_X64_ENABLED 1 -#define KIT_ARCH_RV32_ENABLED 1 -#define KIT_ARCH_RV64_ENABLED 1 -#define KIT_ARCH_WASM_ENABLED 1 -#define KIT_ARCH_C_TARGET_ENABLED 1 +#define KIT_ARCH_X64_ENABLED 0 +#define KIT_ARCH_RV32_ENABLED 0 +#define KIT_ARCH_RV64_ENABLED 0 +#define KIT_ARCH_WASM_ENABLED 0 +#define KIT_ARCH_C_TARGET_ENABLED 0 /* Object/image formats. Each gates emit + read + link-image paths and * the matching arch-side reloc tables. */ -#define KIT_OBJ_ELF_ENABLED 1 +#define KIT_OBJ_ELF_ENABLED 0 #define KIT_OBJ_MACHO_ENABLED 1 -#define KIT_OBJ_COFF_ENABLED 1 -#define KIT_OBJ_WASM_ENABLED 1 +#define KIT_OBJ_COFF_ENABLED 0 +#define KIT_OBJ_WASM_ENABLED 0 /* Language frontends. * @@ -50,12 +50,12 @@ #define KIT_LANG_ASM_ENABLED 1 #define KIT_LANG_CPP_ENABLED 1 #define KIT_LANG_C_ENABLED 1 -#define KIT_LANG_TOY_ENABLED 1 -#define KIT_LANG_WASM_ENABLED 1 +#define KIT_LANG_TOY_ENABLED 0 +#define KIT_LANG_WASM_ENABLED 0 /* Optimizer pipeline. -O0/direct codegen is always available; -O1 and above * require this flag and the matching src/opt sources. */ -#define KIT_OPT_ENABLED 1 +#define KIT_OPT_ENABLED 0 /* Optional library subsystems. These are kept separate from driver tool flags: * libkit embedders care mostly about whether a public subsystem and its @@ -66,29 +66,29 @@ * subsystems. The build asserts the dependencies that are required by the * current layout. */ #define KIT_AR_ENABLED 1 -#define KIT_DISASM_ENABLED 1 -#define KIT_DWARF_ENABLED 1 +#define KIT_DISASM_ENABLED 0 +#define KIT_DWARF_ENABLED 0 #define KIT_LINK_ENABLED 1 -#define KIT_JIT_ENABLED 1 -#define KIT_DBG_ENABLED 1 -#define KIT_EMU_ENABLED 1 +#define KIT_JIT_ENABLED 0 +#define KIT_DBG_ENABLED 0 +#define KIT_EMU_ENABLED 0 /* Code distribution: the content-addressed store (CAS) and signed `.kpkg` * packaging. CAS is the self-verifying content model; PKG layers signed * manifests + the vendored crypto/compression on top, so it requires CAS. */ -#define KIT_CAS_ENABLED 1 -#define KIT_PKG_ENABLED 1 +#define KIT_CAS_ENABLED 0 +#define KIT_PKG_ENABLED 0 /* Standalone general-purpose compression (kit/compress.h + the `compress` * tool): the gzip and LZ4-frame codecs surfaced independently of packaging. * Reuses the deflate + lz4 codec sources that PKG also pulls in, and adds the * LZ4 frame layer. */ -#define KIT_COMPRESS_ENABLED 1 +#define KIT_COMPRESS_ENABLED 0 /* Threaded-bytecode interpreter for the optimizer IR. Runs kit IR * directly (host-identity) or over the emu address space; requires the * optimizer pipeline (it consumes the O1 PReg-path Func). */ -#define KIT_INTERP_ENABLED 1 +#define KIT_INTERP_ENABLED 0 /* Interpreter dispatch: direct-threaded (computed goto) by default. The engine * additionally requires the compiler to support labels-as-values — GCC, clang, @@ -103,34 +103,34 @@ /* kit multi-call driver tools. These flags control both dispatch/help and * the driver/<tool>.c objects included in the kit binary. */ #define KIT_TOOL_CC_ENABLED 1 -#define KIT_TOOL_CHECK_ENABLED 1 -#define KIT_TOOL_BUILD_EXE_ENABLED 1 -#define KIT_TOOL_BUILD_LIB_ENABLED 1 -#define KIT_TOOL_BUILD_OBJ_ENABLED 1 -#define KIT_TOOL_INSTALL_ENABLED 1 -#define KIT_TOOL_CPP_ENABLED 1 +#define KIT_TOOL_CHECK_ENABLED 0 +#define KIT_TOOL_BUILD_EXE_ENABLED 0 +#define KIT_TOOL_BUILD_LIB_ENABLED 0 +#define KIT_TOOL_BUILD_OBJ_ENABLED 0 +#define KIT_TOOL_INSTALL_ENABLED 0 +#define KIT_TOOL_CPP_ENABLED 0 #define KIT_TOOL_AS_ENABLED 1 #define KIT_TOOL_LD_ENABLED 1 -#define KIT_TOOL_AR_ENABLED 1 -#define KIT_TOOL_RANLIB_ENABLED 1 -#define KIT_TOOL_STRIP_ENABLED 1 -#define KIT_TOOL_OBJCOPY_ENABLED 1 -#define KIT_TOOL_OBJDUMP_ENABLED 1 -#define KIT_TOOL_DBG_ENABLED 1 -#define KIT_TOOL_RUN_ENABLED 1 -#define KIT_TOOL_EMU_ENABLED 1 -#define KIT_TOOL_NM_ENABLED 1 -#define KIT_TOOL_SIZE_ENABLED 1 -#define KIT_TOOL_ADDR2LINE_ENABLED 1 -#define KIT_TOOL_SYMBOLIZE_ENABLED 1 -#define KIT_TOOL_STRINGS_ENABLED 1 -#define KIT_TOOL_CAS_ENABLED 1 -#define KIT_TOOL_PKG_ENABLED 1 -#define KIT_TOOL_XXD_ENABLED 1 -#define KIT_TOOL_CMP_ENABLED 1 -#define KIT_TOOL_HASH_ENABLED 1 -#define KIT_TOOL_COMPRESS_ENABLED 1 -#define KIT_TOOL_DISAS_ENABLED 1 -#define KIT_TOOL_MC_ENABLED 1 +#define KIT_TOOL_AR_ENABLED 0 +#define KIT_TOOL_RANLIB_ENABLED 0 +#define KIT_TOOL_STRIP_ENABLED 0 +#define KIT_TOOL_OBJCOPY_ENABLED 0 +#define KIT_TOOL_OBJDUMP_ENABLED 0 +#define KIT_TOOL_DBG_ENABLED 0 +#define KIT_TOOL_RUN_ENABLED 0 +#define KIT_TOOL_EMU_ENABLED 0 +#define KIT_TOOL_NM_ENABLED 0 +#define KIT_TOOL_SIZE_ENABLED 0 +#define KIT_TOOL_ADDR2LINE_ENABLED 0 +#define KIT_TOOL_SYMBOLIZE_ENABLED 0 +#define KIT_TOOL_STRINGS_ENABLED 0 +#define KIT_TOOL_CAS_ENABLED 0 +#define KIT_TOOL_PKG_ENABLED 0 +#define KIT_TOOL_XXD_ENABLED 0 +#define KIT_TOOL_CMP_ENABLED 0 +#define KIT_TOOL_HASH_ENABLED 0 +#define KIT_TOOL_COMPRESS_ENABLED 0 +#define KIT_TOOL_DISAS_ENABLED 0 +#define KIT_TOOL_MC_ENABLED 0 #endif /* KIT_CONFIG_H */ diff --git a/include/kit/os.h b/include/kit/os.h @@ -0,0 +1,149 @@ +#ifndef KIT_OS_H +#define KIT_OS_H + +#include <kit/compile.h> +#include <kit/core.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> + +typedef struct EmuFaultEvent EmuFaultEvent; +typedef struct EmuLoadedImage EmuLoadedImage; +typedef struct EmuLoadOptions EmuLoadOptions; +typedef struct EmuProcess EmuProcess; +typedef struct EmuSyscallRequest EmuSyscallRequest; +typedef struct EmuSyscallResult EmuSyscallResult; +typedef struct EmuThread EmuThread; + +typedef struct KitOsHostedHost { + char* (*path_join)(void* user, const char* a, const char* b, + size_t* out_size); + int (*path_exists)(void* user, const char* path); + void* (*alloc)(void* user, size_t size); + void (*free)(void* user, void* ptr, size_t size); + void (*vdiagf)(void* user, const char* tool, const char* fmt, va_list ap); +} KitOsHostedHost; + +typedef enum KitOsHostedInputKind { + KIT_OS_HOSTED_INPUT_OBJECT, + KIT_OS_HOSTED_INPUT_ARCHIVE, + KIT_OS_HOSTED_INPUT_DSO, +} KitOsHostedInputKind; + +typedef struct KitOsHostedInput { + uint8_t kind; /* KitOsHostedInputKind */ + uint8_t pad[3]; + const char* path; + char* owned_path; + size_t owned_size; +} KitOsHostedInput; + +#define KIT_OS_HOSTED_MAX_BEFORE 4 +#define KIT_OS_HOSTED_MAX_AFTER 16 +#define KIT_OS_HOSTED_MAX_FINAL 2 +#define KIT_OS_HOSTED_MAX_INCLUDES 4 +#define KIT_OS_HOSTED_MAX_DEFINES 20 +#define KIT_OS_HOSTED_MAX_LIB_SEARCH_DIRS 8 +#define KIT_OS_HOSTED_MAX_INCDIRS 4 +#define KIT_OS_HOSTED_MAX_LIBDIRS 8 + +typedef struct KitOsHostedPlan { + const char* profile_name; + const char* interp_path; + KitOsHostedInput before[KIT_OS_HOSTED_MAX_BEFORE]; + uint32_t nbefore; + KitOsHostedInput after[KIT_OS_HOSTED_MAX_AFTER]; + uint32_t nafter; + KitOsHostedInput final[KIT_OS_HOSTED_MAX_FINAL]; + uint32_t nfinal; + const char* system_includes[KIT_OS_HOSTED_MAX_INCLUDES]; + char* owned_system_includes[KIT_OS_HOSTED_MAX_INCLUDES]; + size_t owned_system_include_sizes[KIT_OS_HOSTED_MAX_INCLUDES]; + uint32_t nsystem_includes; + KitDefine defines[KIT_OS_HOSTED_MAX_DEFINES]; + uint32_t ndefines; + char* lib_search_dirs[KIT_OS_HOSTED_MAX_LIB_SEARCH_DIRS]; + size_t lib_search_dir_sizes[KIT_OS_HOSTED_MAX_LIB_SEARCH_DIRS]; + uint32_t nlib_search_dirs; +} KitOsHostedPlan; + +typedef struct KitOsHostedDirs { + const KitOsHostedHost* host; + void* host_user; + const char* root; + char* incdirs[KIT_OS_HOSTED_MAX_INCDIRS]; + size_t incdir_sizes[KIT_OS_HOSTED_MAX_INCDIRS]; + uint32_t nincdirs; + char* libdirs[KIT_OS_HOSTED_MAX_LIBDIRS]; + size_t libdir_sizes[KIT_OS_HOSTED_MAX_LIBDIRS]; + uint32_t nlibdirs; +} KitOsHostedDirs; + +typedef struct KitOsHostedRequest { + const KitOsHostedHost* host; + void* host_user; + const char* tool; + KitTargetSpec target; + int static_link; + int link_inputs; +} KitOsHostedRequest; + +typedef int (*KitOsHostedResolveFn)(const KitOsHostedRequest*, + const KitOsHostedDirs*, + KitOsHostedPlan*); +typedef int (*KitOsHostedSysrootLayoutFn)(KitOsHostedDirs*, KitTargetSpec, + const char*); + +typedef struct KitOsHostedOps { + KitObjFmt obj; + int default_profile; + int needs_sysroot_libdir; + KitOsHostedResolveFn resolve; + KitOsHostedSysrootLayoutFn sysroot_layout; +} KitOsHostedOps; + +typedef struct KitOsEmuOps { + KitStatus (*init_process_private)(KitCompiler*, EmuProcess*); + void (*destroy_process_private)(KitCompiler*, EmuProcess*); + KitStatus (*init_thread_private)(KitCompiler*, EmuProcess*, EmuThread*); + void (*destroy_thread_private)(KitCompiler*, EmuThread*); + KitStatus (*init_process)(KitCompiler*, EmuProcess*, const EmuLoadOptions*, + const EmuLoadedImage*); + KitStatus (*init_thread)(KitCompiler*, EmuProcess*, EmuThread*); + KitStatus (*decode_syscall)(EmuProcess*, EmuThread*, EmuSyscallRequest* out); + KitStatus (*encode_syscall_result)(EmuProcess*, EmuThread*, + const EmuSyscallResult*); + uint64_t (*syscall_next_pc)(EmuProcess*, EmuThread*, + const EmuSyscallRequest*, uint64_t next_pc); + KitStatus (*find_map_region)(EmuProcess*, uint64_t nbytes, uint64_t align, + uint32_t purpose, uint64_t* out); + void (*note_map_region)(EmuProcess*, uint64_t base, uint64_t nbytes, + uint32_t purpose); + KitStatus (*default_syscall)(void* user, EmuProcess*, EmuThread*, + const EmuSyscallRequest*, + EmuSyscallResult* out); + KitStatus (*deliver_fault)(EmuProcess*, EmuThread*, const EmuFaultEvent*, + uint64_t* next_pc_out); +} KitOsEmuOps; + +typedef struct KitOsImpl { + KitOSKind kind; + const char* name; + const KitOsHostedOps* hosted; + const KitOsEmuOps* emu; +} KitOsImpl; + +const KitOsImpl* kit_os_lookup(KitOSKind kind); + +int kit_os_hosted_dirs_add_inc(KitOsHostedDirs* dirs, const char* dir); +int kit_os_hosted_dirs_add_lib(KitOsHostedDirs* dirs, const char* dir); +int kit_os_hosted_dirs_add_inc_join(KitOsHostedDirs* dirs, const char* base, + const char* sub); +int kit_os_hosted_dirs_add_lib_join(KitOsHostedDirs* dirs, const char* base, + const char* sub); +void kit_os_hosted_dirs_fini(KitOsHostedDirs* dirs); + +void kit_os_hosted_plan_fini(const KitOsHostedHost* host, void* host_user, + KitOsHostedPlan* plan); + +#endif diff --git a/mk/driver_srcs.mk b/mk/driver_srcs.mk @@ -11,7 +11,16 @@ tool-cmd = $(if $(filter 1,$(KIT_TOOL_$(1)_ENABLED)),driver/cmd/$(2).c) # A shared driver/lib TU: include $(2) if ANY of the named tools is enabled. need-any = $(if $(filter 1,$(foreach f,$(1),$(KIT_TOOL_$(f)_ENABLED))),$(2)) -DRIVER_SRCS = driver/main.c driver/lib/target.c $(DRIVER_ENV_SRCS) +DRIVER_ENV_SRCS_EFFECTIVE = $(DRIVER_ENV_SRCS) +DRIVER_NEED_POSIX_DBG = $(filter 1,$(KIT_TOOL_DBG_ENABLED) $(KIT_TOOL_RUN_ENABLED)) +ifneq ($(HOST_OS),windows) +ifeq ($(DRIVER_NEED_POSIX_DBG),) +DRIVER_ENV_SRCS_EFFECTIVE := $(filter-out driver/env/posix_dbg.c $(DRIVER_ENV_UCTX_SRC),$(DRIVER_ENV_SRCS_EFFECTIVE)) \ + driver/env/posix_dbg_stubs.c +endif +endif + +DRIVER_SRCS = driver/main.c driver/lib/target.c $(DRIVER_ENV_SRCS_EFFECTIVE) # One entry per subcommand. cc.c serves both `cc` and `check`; the final # $(sort) below dedupes it. The cas/pkg tools additionally pull in @@ -72,12 +81,7 @@ DRIVER_SRCS += $(call need-any,RUN,driver/lib/wasm_run.c) DRIVER_SRCS += $(call need-any,CC CHECK BUILD_EXE BUILD_LIB BUILD_OBJ,driver/lib/link_inputs.c) DRIVER_SRCS += $(call need-any,CAS PKG,driver/lib/dist_host.c) DRIVER_SRCS += $(call need-any,ADDR2LINE SYMBOLIZE,driver/lib/dwarfsym.c) -# backtrace.c (FP-walk kernel + symbolized printer) is consumed by the dbg/run -# tools AND by posix_dbg.c's run crash guard, which is part of DRIVER_ENV_SRCS -# and so links into every POSIX build regardless of tool selection. Compile it -# unconditionally so a tools-trimmed build (DBG/RUN off) still resolves the -# driver_bt_* references without relying on linker dead-stripping. -DRIVER_SRCS += driver/lib/backtrace.c +DRIVER_SRCS += $(call need-any,DBG RUN,driver/lib/backtrace.c) DRIVER_SRCS := $(sort $(DRIVER_SRCS)) DRIVER_OBJS = $(patsubst driver/%.c,$(BUILD_DIR)/driver/%.o,$(DRIVER_SRCS)) diff --git a/mk/lib_srcs.mk b/mk/lib_srcs.mk @@ -39,13 +39,16 @@ LIB_SRCS_ASM_CORE = $(wildcard src/asm/*.c) LIB_SRCS_CG_CORE = $(wildcard src/cg/*.c) LIB_SRCS_CORE = $(wildcard src/core/*.c) LIB_SRCS_OBJ_CORE = $(filter-out src/obj/%_stubs.c,$(wildcard src/obj/*.c)) +LIB_SRCS_OS_CORE = src/os/registry.c +LIB_SRCS_OS_HOSTED_CORE = src/os/hosted.c LIB_SRCS_NONARCH = $(LIB_SRCS_ABI_CORE) \ $(LIB_SRCS_API_CORE) \ $(LIB_SRCS_ARCH_CORE) \ $(LIB_SRCS_ASM_CORE) \ $(LIB_SRCS_CG_CORE) \ $(LIB_SRCS_CORE) \ - $(LIB_SRCS_OBJ_CORE) + $(LIB_SRCS_OBJ_CORE) \ + $(LIB_SRCS_OS_CORE) # These source lists use `:=` (not `=`) so each `find` runs exactly once at # parse time. With recursive `=`, every reference below (LIB_SRCS is rebuilt @@ -80,6 +83,19 @@ LIB_SRCS_OBJ_ELF := $(shell find src/obj/elf -name '*.c' 2>/dev/null) LIB_SRCS_OBJ_MACHO := $(shell find src/obj/macho -name '*.c' 2>/dev/null) LIB_SRCS_OBJ_COFF := $(shell find src/obj/coff -name '*.c' 2>/dev/null) LIB_SRCS_OBJ_WASM := $(shell find src/obj/wasm -name '*.c' 2>/dev/null) +ifneq ($(KIT_ARCH_AA64_ENABLED),1) +LIB_SRCS_OBJ_ELF := $(filter-out %/reloc_aarch64.c,$(LIB_SRCS_OBJ_ELF)) +LIB_SRCS_OBJ_MACHO := $(filter-out %/reloc_aarch64.c,$(LIB_SRCS_OBJ_MACHO)) +LIB_SRCS_OBJ_COFF := $(filter-out %/reloc_aarch64.c,$(LIB_SRCS_OBJ_COFF)) +endif +ifneq ($(KIT_ARCH_X64_ENABLED),1) +LIB_SRCS_OBJ_ELF := $(filter-out %/reloc_x86_64.c,$(LIB_SRCS_OBJ_ELF)) +LIB_SRCS_OBJ_MACHO := $(filter-out %/reloc_x86_64.c,$(LIB_SRCS_OBJ_MACHO)) +LIB_SRCS_OBJ_COFF := $(filter-out %/reloc_x86_64.c,$(LIB_SRCS_OBJ_COFF)) +endif +ifeq ($(filter 1,$(KIT_ARCH_RV32_ENABLED) $(KIT_ARCH_RV64_ENABLED)),) +LIB_SRCS_OBJ_ELF := $(filter-out %/reloc_riscv32.c %/reloc_riscv64.c,$(LIB_SRCS_OBJ_ELF)) +endif ifneq ($(KIT_LINK_ENABLED),1) LIB_SRCS_OBJ_ELF := $(filter-out %/link.c %/link_dyn.c,$(LIB_SRCS_OBJ_ELF)) LIB_SRCS_OBJ_MACHO := $(filter-out %/link.c,$(LIB_SRCS_OBJ_MACHO)) @@ -127,7 +143,7 @@ LIB_SRCS_VENDOR_PKG = vendor/monocypher/monocypher-ed25519.c LIB_SRCS_DEBUG := $(shell find src/debug -name '*.c' 2>/dev/null) LIB_SRCS_DBG := $(shell find src/dbg -name '*.c' 2>/dev/null) LIB_SRCS_EMU := $(shell find src/emu -name '*.c' 2>/dev/null) \ - $(shell find src/os -name '*.c' 2>/dev/null) + src/os/linux/linux.c LIB_SRCS_LINK := $(shell find src/link -name '*.c' 2>/dev/null) ifneq ($(KIT_JIT_ENABLED),1) LIB_SRCS_LINK := $(filter-out %/link_jit.c,$(LIB_SRCS_LINK)) @@ -211,6 +227,21 @@ endif ifeq ($(KIT_OBJ_COFF_ENABLED),1) LIB_SRCS += $(LIB_SRCS_OBJ_COFF) endif +ifneq ($(filter 1,$(KIT_OBJ_ELF_ENABLED) $(KIT_OBJ_MACHO_ENABLED) $(KIT_OBJ_COFF_ENABLED)),) +LIB_SRCS += $(LIB_SRCS_OS_HOSTED_CORE) +endif +ifneq ($(filter 1,$(KIT_OBJ_ELF_ENABLED) $(KIT_EMU_ENABLED)),) +LIB_SRCS += src/os/linux/os.c +endif +ifeq ($(KIT_OBJ_ELF_ENABLED),1) +LIB_SRCS += src/os/linux/hosted.c src/os/freebsd/os.c src/os/freebsd/hosted.c +endif +ifeq ($(KIT_OBJ_MACHO_ENABLED),1) +LIB_SRCS += src/os/macos/os.c src/os/macos/hosted.c +endif +ifeq ($(KIT_OBJ_COFF_ENABLED),1) +LIB_SRCS += src/os/windows/os.c src/os/windows/hosted.c +endif ifneq ($(filter 1,$(KIT_ARCH_AA64_ENABLED) $(KIT_ARCH_C_TARGET_ENABLED)),) ifneq ($(filter 1,$(KIT_OBJ_ELF_ENABLED) $(KIT_OBJ_MACHO_ENABLED) $(KIT_OBJ_COFF_ENABLED)),) LIB_SRCS += $(LIB_SRC_ABI_AAPCS64) diff --git a/src/api/target.c b/src/api/target.c @@ -9,6 +9,7 @@ #include <kit/target.h> +#include <kit/os.h> #include <stddef.h> #include <stdint.h> #include <stdio.h> @@ -112,18 +113,15 @@ void kit_target_default_obj_ext(KitTargetSpec target, const char** ext_out, } int kit_target_needs_sysroot_libdir(KitTargetSpec target) { - /* Windows targets fold `<sysroot>/lib` into the library search path (the - * mingw import-library tree). The POSIX hosted profiles enumerate their - * libdirs through the hosted resolver instead. */ - return target.os == KIT_OS_WINDOWS ? 1 : 0; + const KitOsImpl* os = kit_os_lookup(target.os); + if (!os || !os->hosted || os->hosted->obj != target.obj) return 0; + return os->hosted->needs_sysroot_libdir; } int kit_target_default_hosted_profile(KitTargetSpec target) { - /* Windows-COFF is the one target whose hosted libc profile is engaged by - * default (given a sysroot and no -nostdlib): the mingw/ucrt import - * libraries are mandatory to produce a runnable PE. Other targets stay - * freestanding unless the user opts in (-lc / explicit sysroot wiring). */ - return target.os == KIT_OS_WINDOWS && target.obj == KIT_OBJ_COFF ? 1 : 0; + const KitOsImpl* os = kit_os_lookup(target.os); + if (!os || !os->hosted || os->hosted->obj != target.obj) return 0; + return os->hosted->default_profile; } bool kit_target_from_triple(const char* triple, KitTargetSpec* out) { diff --git a/src/emu/dl.c b/src/emu/dl.c @@ -322,8 +322,10 @@ KitStatus emu_dl_init_process(Compiler* c, EmuProcess* process) { if (!c || !process) return KIT_INVALID; img = &process->image; if (img->import_thunk_size) return KIT_OK; - if (!process->os || !process->os->emu_find_map_region) return KIT_UNSUPPORTED; - if (process->os->emu_find_map_region(process, EMU_IMPORT_THUNK_RESERVE, + if (!process->os || !process->os->emu || + !process->os->emu->find_map_region) + return KIT_UNSUPPORTED; + if (process->os->emu->find_map_region(process, EMU_IMPORT_THUNK_RESERVE, img->addr_space.page_size, EMU_OS_MAP_DL_THUNKS, &base) != KIT_OK) return KIT_ERR; @@ -333,8 +335,8 @@ KitStatus emu_dl_init_process(Compiler* c, EmuProcess* process) { img->import_thunk_base = base; img->import_thunk_size = EMU_IMPORT_THUNK_RESERVE; img->import_thunk_next = base; - if (process->os->emu_note_map_region) - process->os->emu_note_map_region(process, base, EMU_IMPORT_THUNK_RESERVE, + if (process->os->emu->note_map_region) + process->os->emu->note_map_region(process, base, EMU_IMPORT_THUNK_RESERVE, EMU_OS_MAP_DL_THUNKS); return KIT_OK; } diff --git a/src/emu/emu.c b/src/emu/emu.c @@ -208,10 +208,10 @@ static KitStatus emu_resolve_config(Compiler* c, const KitEmuOptions* opts, if (target_format != obj_format) return KIT_UNSUPPORTED; arch = arch_lookup(target.arch); - os = os_lookup(target.os); + os = kit_os_lookup(target.os); if (!arch || !arch->decode || !arch->decode->decode_block || !arch->emu || !arch->emu->cpu_new || !arch->emu->block_fn_type || - !arch->emu->lift_block || !os) { + !arch->emu->lift_block || !os || !os->emu) { return KIT_UNSUPPORTED; } @@ -279,7 +279,7 @@ KitStatus kit_emu_new(KitCompiler* c, const KitEmuOptions* opts, KitEmu** out) { e->process.bindings.syscall = emu_public_syscall_adapter; e->process.bindings.user = e; } else { - e->process.bindings.syscall = resolved.os->emu_default_syscall; + e->process.bindings.syscall = resolved.os->emu->default_syscall; e->process.bindings.user = NULL; } if (e->bindings.resolve_import) { @@ -293,13 +293,13 @@ KitStatus kit_emu_new(KitCompiler* c, const KitEmuOptions* opts, KitEmu** out) { load_opts.bindings = &e->process.bindings; e->main_thread.process = &e->process; - if (resolved.os->emu_init_process_private && - resolved.os->emu_init_process_private(c, &e->process) != KIT_OK) { + if (resolved.os->emu->init_process_private && + resolved.os->emu->init_process_private(c, &e->process) != KIT_OK) { compiler_panic(c, SRCLOC_NONE, "emu: failed to initialize OS process state"); } - if (resolved.os->emu_init_thread_private && - resolved.os->emu_init_thread_private(c, &e->process, &e->main_thread) != + if (resolved.os->emu->init_thread_private && + resolved.os->emu->init_thread_private(c, &e->process, &e->main_thread) != KIT_OK) { compiler_panic(c, SRCLOC_NONE, "emu: failed to initialize OS thread state"); } @@ -310,8 +310,8 @@ KitStatus kit_emu_new(KitCompiler* c, const KitEmuOptions* opts, KitEmu** out) { if (st != KIT_OK) { compiler_panic(c, SRCLOC_NONE, "emu: failed to load guest executable"); } - if (resolved.os->emu_init_process && - resolved.os->emu_init_process(c, &e->process, &load_opts, + if (resolved.os->emu->init_process && + resolved.os->emu->init_process(c, &e->process, &load_opts, &e->process.image) != KIT_OK) { compiler_panic(c, SRCLOC_NONE, "emu: failed to initialize guest process"); } @@ -322,8 +322,8 @@ KitStatus kit_emu_new(KitCompiler* c, const KitEmuOptions* opts, KitEmu** out) { emu_cpu_set_thread(e->main_thread.cpu, &e->main_thread); if (!e->main_thread.cpu || emu_loaded_image_attach_cpu(e->main_thread.cpu, &e->process.image) != 0 || - (resolved.os->emu_init_thread && - resolved.os->emu_init_thread(c, &e->process, &e->main_thread) != + (resolved.os->emu->init_thread && + resolved.os->emu->init_thread(c, &e->process, &e->main_thread) != KIT_OK)) { compiler_panic(c, SRCLOC_NONE, "emu: failed to initialize guest CPU state"); } @@ -377,12 +377,14 @@ void kit_emu_free(KitEmu* e) { while (e->njits) kit_jit_free(e->jits[--e->njits]); if (e->jits) heap->free(heap, e->jits, sizeof(*e->jits) * e->jits_cap); if (e->cache) emu_cache_free(e->cache); - if (e->process.os && e->process.os->emu_destroy_thread_private) - e->process.os->emu_destroy_thread_private(e->c, &e->main_thread); + if (e->process.os && e->process.os->emu && + e->process.os->emu->destroy_thread_private) + e->process.os->emu->destroy_thread_private(e->c, &e->main_thread); if (e->main_thread.cpu) emu_cpu_free(e->main_thread.cpu); emu_tls_destroy_process(e->c, &e->process); - if (e->process.os && e->process.os->emu_destroy_process_private) - e->process.os->emu_destroy_process_private(e->c, &e->process); + if (e->process.os && e->process.os->emu && + e->process.os->emu->destroy_process_private) + e->process.os->emu->destroy_process_private(e->c, &e->process); emu_unload_image(e->c, &e->process.image); heap->free(heap, e, sizeof(*e)); diff --git a/src/emu/emu.h b/src/emu/emu.h @@ -13,6 +13,7 @@ #include <kit/cg.h> #include <kit/emu.h> #include <kit/jit.h> +#include <kit/os.h> #include "arch/arch.h" #include "core/core.h" @@ -22,7 +23,6 @@ typedef struct LinkImage LinkImage; typedef struct Linker Linker; typedef struct EmuCPUState EmuCPUState; typedef struct ObjFormatImpl ObjFormatImpl; -typedef struct KitOsImpl KitOsImpl; typedef struct EmuProcess EmuProcess; typedef struct EmuThread EmuThread; typedef struct EmuExternalBindings EmuExternalBindings; @@ -326,34 +326,6 @@ struct EmuThread { void* os_private; }; -struct KitOsImpl { - KitOSKind kind; - const char* name; - KitStatus (*emu_init_process_private)(Compiler*, EmuProcess*); - void (*emu_destroy_process_private)(Compiler*, EmuProcess*); - KitStatus (*emu_init_thread_private)(Compiler*, EmuProcess*, EmuThread*); - void (*emu_destroy_thread_private)(Compiler*, EmuThread*); - KitStatus (*emu_init_process)(Compiler*, EmuProcess*, const EmuLoadOptions*, - const EmuLoadedImage*); - KitStatus (*emu_init_thread)(Compiler*, EmuProcess*, EmuThread*); - KitStatus (*emu_decode_syscall)(EmuProcess*, EmuThread*, - EmuSyscallRequest* out); - KitStatus (*emu_encode_syscall_result)(EmuProcess*, EmuThread*, - const EmuSyscallResult*); - u64 (*emu_syscall_next_pc)(EmuProcess*, EmuThread*, const EmuSyscallRequest*, - u64 next_pc); - KitStatus (*emu_find_map_region)(EmuProcess*, u64 nbytes, u64 align, - u32 purpose, u64* out); - void (*emu_note_map_region)(EmuProcess*, u64 base, u64 nbytes, u32 purpose); - KitStatus (*emu_default_syscall)(void* user, EmuProcess*, EmuThread*, - const EmuSyscallRequest*, - EmuSyscallResult* out); - KitStatus (*emu_deliver_fault)(EmuProcess*, EmuThread*, const EmuFaultEvent*, - u64* next_pc_out); -}; - -const KitOsImpl* os_lookup(KitOSKind); - #define EMU_OS_MAP_MMAP 1u #define EMU_OS_MAP_DL_THUNKS 2u #define EMU_OS_MAP_TLS 3u diff --git a/src/emu/runtime.c b/src/emu/runtime.c @@ -307,8 +307,8 @@ static void emu_syscall_decoded(EmuThread* thread, s = emu_thread_cpu(thread); process = thread ? thread->process : NULL; - if (!s || !thread || !process || !req || !process->os || - !process->os->emu_encode_syscall_result || !process->bindings.syscall) { + if (!s || !thread || !process || !req || !process->os || !process->os->emu || + !process->os->emu->encode_syscall_result || !process->bindings.syscall) { emu_cpu_trap_fault(s); return; } @@ -321,7 +321,7 @@ static void emu_syscall_decoded(EmuThread* thread, if (emu_cpu_trap_reason(s) == EMU_TRAP_EXIT) return; if (!(result.flags & EMU_SYSCALL_RESULT_SKIP_ENCODE)) { - st = process->os->emu_encode_syscall_result(process, thread, &result); + st = process->os->emu->encode_syscall_result(process, thread, &result); if (st != KIT_OK) emu_cpu_trap_fault(s); } } @@ -330,11 +330,12 @@ void emu_syscall(EmuThread* thread) { EmuCPUState* s = emu_thread_cpu(thread); EmuProcess* process = thread ? thread->process : NULL; EmuSyscallRequest req; - if (!s || !process || !process->os || !process->os->emu_decode_syscall) { + if (!s || !process || !process->os || !process->os->emu || + !process->os->emu->decode_syscall) { emu_cpu_trap_fault(s); return; } - if (process->os->emu_decode_syscall(process, thread, &req) != KIT_OK) { + if (process->os->emu->decode_syscall(process, thread, &req) != KIT_OK) { emu_cpu_trap_fault(s); return; } @@ -345,18 +346,19 @@ u64 emu_syscall_next(EmuThread* thread, u64 next_pc) { EmuCPUState* s = emu_thread_cpu(thread); EmuProcess* process = thread ? thread->process : NULL; EmuSyscallRequest req; - if (!s || !process || !process->os || !process->os->emu_decode_syscall) { + if (!s || !process || !process->os || !process->os->emu || + !process->os->emu->decode_syscall) { emu_cpu_trap_fault(s); return next_pc; } - if (process->os->emu_decode_syscall(process, thread, &req) != KIT_OK) { + if (process->os->emu->decode_syscall(process, thread, &req) != KIT_OK) { emu_cpu_trap_fault(s); return next_pc; } emu_syscall_decoded(thread, &req); - if (process->os->emu_syscall_next_pc && + if (process->os->emu->syscall_next_pc && emu_cpu_trap_reason(s) == EMU_TRAP_NONE) - return process->os->emu_syscall_next_pc(process, thread, &req, next_pc); + return process->os->emu->syscall_next_pc(process, thread, &req, next_pc); return next_pc; } diff --git a/src/emu/signal.c b/src/emu/signal.c @@ -3,10 +3,11 @@ KitStatus emu_fault_deliver(EmuProcess* process, EmuThread* thread, const EmuFaultEvent* ev, u64* next_pc_out) { if (!process || !thread || !ev || !next_pc_out) return KIT_INVALID; - if (!process->os || !process->os->emu_deliver_fault) { + if (!process->os || !process->os->emu || + !process->os->emu->deliver_fault) { emu_cpu_trap_fault(emu_thread_cpu(thread)); *next_pc_out = ev->pc ? ev->pc : ev->next_pc; return KIT_OK; } - return process->os->emu_deliver_fault(process, thread, ev, next_pc_out); + return process->os->emu->deliver_fault(process, thread, ev, next_pc_out); } diff --git a/src/os/freebsd/hosted.c b/src/os/freebsd/hosted.c @@ -0,0 +1,112 @@ +#include "os/hosted_internal.h" + +static const char* freebsd_version_str(uint8_t major) { + static const char* const tab[21] = {"15", "1", "2", "3", "4", "5", "6", + "7", "8", "9", "10", "11", "12", "13", + "14", "15", "16", "17", "18", "19", "20"}; + return (major < 21) ? tab[major] : "15"; +} + +static int hosted_add_freebsd_defines(KitOsHostedPlan* plan, + uint8_t version_major) { + if (kit_os_hosted_add_clang_compat_defines(plan) != 0 || + kit_os_hosted_add_define(plan, "__FreeBSD__", + freebsd_version_str(version_major)) != 0 || + kit_os_hosted_add_define(plan, "__ELF__", "1") != 0 || + kit_os_hosted_add_define(plan, "__unix__", "1") != 0 || + kit_os_hosted_add_define(plan, "__unix", "1") != 0 || + kit_os_hosted_add_define(plan, "unix", "1") != 0) + return 1; + return 0; +} + +static int hosted_resolve_freebsd(const KitOsHostedRequest* req, + const KitOsHostedDirs* dirs, + KitOsHostedPlan* plan) { + int static_link; + if (dirs->nlibdirs == 0) { + kit_os_hosted_errf(req->host, req->host_user, req->tool, + "FreeBSD hosted profile requires --sysroot or " + "KIT_SYSROOT"); + return 1; + } + static_link = req->static_link && + kit_os_hosted_libdir_has(req->host, req->host_user, dirs, + "libc.a"); + plan->profile_name = static_link ? "freebsd-static" : "freebsd-dynamic"; + if (!static_link) plan->interp_path = "/libexec/ld-elf.so.1"; + if (hosted_add_freebsd_defines(plan, req->target.os_version_major) != 0 || + kit_os_hosted_add_incdirs(plan, req->host, req->host_user, dirs) != 0) { + kit_os_hosted_errf(req->host, req->host_user, req->tool, "out of memory"); + return 1; + } + if (!req->link_inputs) return 0; + if (kit_os_hosted_add_required_search( + plan->before, &plan->nbefore, KIT_OS_HOSTED_MAX_BEFORE, req, dirs, + static_link ? "crt1.o" : "Scrt1.o", + KIT_OS_HOSTED_INPUT_OBJECT) != 0 || + kit_os_hosted_add_required_search( + plan->before, &plan->nbefore, KIT_OS_HOSTED_MAX_BEFORE, req, dirs, + "crti.o", KIT_OS_HOSTED_INPUT_OBJECT) != 0) + return 1; + if (static_link) { + int has_libsys = kit_os_hosted_libdir_has(req->host, req->host_user, dirs, + "libsys.a"); + int has_crt = kit_os_hosted_libdir_has(req->host, req->host_user, dirs, + "libcompiler_rt.a"); + if (kit_os_hosted_add_required_search( + plan->after, &plan->nafter, KIT_OS_HOSTED_MAX_AFTER, req, dirs, + "libc.a", KIT_OS_HOSTED_INPUT_ARCHIVE) != 0) + return 1; + if (has_libsys && + kit_os_hosted_add_required_search( + plan->after, &plan->nafter, KIT_OS_HOSTED_MAX_AFTER, req, dirs, + "libsys.a", KIT_OS_HOSTED_INPUT_ARCHIVE) != 0) + return 1; + if (has_crt && + kit_os_hosted_add_required_search( + plan->after, &plan->nafter, KIT_OS_HOSTED_MAX_AFTER, req, dirs, + "libcompiler_rt.a", KIT_OS_HOSTED_INPUT_ARCHIVE) != 0) + return 1; + if ((has_libsys || has_crt) && + kit_os_hosted_add_required_search( + plan->after, &plan->nafter, KIT_OS_HOSTED_MAX_AFTER, req, dirs, + "libc.a", KIT_OS_HOSTED_INPUT_ARCHIVE) != 0) + return 1; + } else { + if (kit_os_hosted_add_required_search( + plan->after, &plan->nafter, KIT_OS_HOSTED_MAX_AFTER, req, dirs, + "libc.so.7", KIT_OS_HOSTED_INPUT_DSO) != 0) + return 1; + if (kit_os_hosted_libdir_has(req->host, req->host_user, dirs, + "libsys.so.7") && + kit_os_hosted_add_required_search( + plan->after, &plan->nafter, KIT_OS_HOSTED_MAX_AFTER, req, dirs, + "libsys.so.7", KIT_OS_HOSTED_INPUT_DSO) != 0) + return 1; + } + if (kit_os_hosted_add_required_search( + plan->final, &plan->nfinal, KIT_OS_HOSTED_MAX_FINAL, req, dirs, + "crtn.o", KIT_OS_HOSTED_INPUT_OBJECT) != 0) + return 1; + return 0; +} + +static int hosted_sysroot_layout_freebsd(KitOsHostedDirs* dirs, + KitTargetSpec target, + const char* sysroot) { + (void)target; + if (kit_os_hosted_dirs_add_inc_join(dirs, sysroot, "usr/include") != 0 || + kit_os_hosted_dirs_add_lib_join(dirs, sysroot, "usr/lib") != 0 || + kit_os_hosted_dirs_add_lib_join(dirs, sysroot, "lib") != 0) + return 1; + return 0; +} + +const KitOsHostedOps kit_os_freebsd_hosted_ops = { + .obj = KIT_OBJ_ELF, + .default_profile = 0, + .needs_sysroot_libdir = 0, + .resolve = hosted_resolve_freebsd, + .sysroot_layout = hosted_sysroot_layout_freebsd, +}; diff --git a/src/os/freebsd/os.c b/src/os/freebsd/os.c @@ -0,0 +1,10 @@ +#include <kit/os.h> + +extern const KitOsHostedOps kit_os_freebsd_hosted_ops; + +const KitOsImpl kit_os_freebsd_impl = { + .kind = KIT_OS_FREEBSD, + .name = "freebsd", + .hosted = &kit_os_freebsd_hosted_ops, + .emu = NULL, +}; diff --git a/src/os/hosted.c b/src/os/hosted.c @@ -0,0 +1,227 @@ +#include "os/hosted_internal.h" + +#include <stdarg.h> +#include <string.h> + +void kit_os_hosted_errf(const KitOsHostedHost* host, void* host_user, + const char* tool, const char* fmt, ...) { + va_list ap; + if (!host || !host->vdiagf) return; + va_start(ap, fmt); + host->vdiagf(host_user, tool, fmt, ap); + va_end(ap); +} + +int kit_os_hosted_add_input(KitOsHostedInput* items, uint32_t* n, uint32_t cap, + uint8_t kind, char* path, size_t path_size) { + KitOsHostedInput* it; + if (*n >= cap) return 1; + it = &items[*n]; + it->kind = kind; + it->path = path; + it->owned_path = path; + it->owned_size = path_size; + (*n)++; + return 0; +} + +static int hosted_store(const KitOsHostedHost* host, void* host_user, + char** arr, size_t* sizes, uint32_t* n, uint32_t cap, + const char* a, const char* b) { + size_t bytes; + char* out; + if (!a || !a[0]) return 0; + if (*n >= cap || !host || !host->path_join) return 1; + out = host->path_join(host_user, a, b, &bytes); + if (!out) return 1; + arr[*n] = out; + sizes[*n] = bytes; + (*n)++; + return 0; +} + +int kit_os_hosted_dirs_add_inc(KitOsHostedDirs* dirs, const char* dir) { + if (!dirs) return 1; + return hosted_store(dirs->host, dirs->host_user, dirs->incdirs, + dirs->incdir_sizes, &dirs->nincdirs, + KIT_OS_HOSTED_MAX_INCDIRS, dir, NULL); +} + +int kit_os_hosted_dirs_add_lib(KitOsHostedDirs* dirs, const char* dir) { + if (!dirs) return 1; + return hosted_store(dirs->host, dirs->host_user, dirs->libdirs, + dirs->libdir_sizes, &dirs->nlibdirs, + KIT_OS_HOSTED_MAX_LIBDIRS, dir, NULL); +} + +int kit_os_hosted_dirs_add_inc_join(KitOsHostedDirs* dirs, const char* base, + const char* sub) { + if (!dirs) return 1; + return hosted_store(dirs->host, dirs->host_user, dirs->incdirs, + dirs->incdir_sizes, &dirs->nincdirs, + KIT_OS_HOSTED_MAX_INCDIRS, base, sub); +} + +int kit_os_hosted_dirs_add_lib_join(KitOsHostedDirs* dirs, const char* base, + const char* sub) { + if (!dirs) return 1; + return hosted_store(dirs->host, dirs->host_user, dirs->libdirs, + dirs->libdir_sizes, &dirs->nlibdirs, + KIT_OS_HOSTED_MAX_LIBDIRS, base, sub); +} + +void kit_os_hosted_dirs_fini(KitOsHostedDirs* dirs) { + uint32_t i; + if (!dirs || !dirs->host || !dirs->host->free) return; + for (i = 0; i < dirs->nincdirs; ++i) + dirs->host->free(dirs->host_user, dirs->incdirs[i], dirs->incdir_sizes[i]); + for (i = 0; i < dirs->nlibdirs; ++i) + dirs->host->free(dirs->host_user, dirs->libdirs[i], dirs->libdir_sizes[i]); + dirs->nincdirs = 0; + dirs->nlibdirs = 0; +} + +char* kit_os_hosted_find_in_libdirs(const KitOsHostedHost* host, + void* host_user, + const KitOsHostedDirs* dirs, + const char* file, size_t* out_size) { + uint32_t i; + if (!host || !host->path_join || !host->path_exists || !host->free || !dirs) + return NULL; + for (i = 0; i < dirs->nlibdirs; ++i) { + size_t size = 0; + char* path = host->path_join(host_user, dirs->libdirs[i], file, &size); + if (!path) return NULL; + if (host->path_exists(host_user, path)) { + if (out_size) *out_size = size; + return path; + } + host->free(host_user, path, size); + } + return NULL; +} + +int kit_os_hosted_libdir_has(const KitOsHostedHost* host, void* host_user, + const KitOsHostedDirs* dirs, const char* file) { + size_t size = 0; + char* path = kit_os_hosted_find_in_libdirs(host, host_user, dirs, file, &size); + if (!path) return 0; + host->free(host_user, path, size); + return 1; +} + +int kit_os_hosted_add_required_search(KitOsHostedInput* items, uint32_t* n, + uint32_t cap, + const KitOsHostedRequest* req, + const KitOsHostedDirs* dirs, + const char* file, uint8_t kind) { + size_t size = 0; + char* path = kit_os_hosted_find_in_libdirs(req->host, req->host_user, dirs, + file, &size); + if (!path) { + kit_os_hosted_errf(req->host, req->host_user, req->tool, + "hosted profile missing required file: %s (searched %u " + "library dir(s))", + file, (unsigned)dirs->nlibdirs); + return 1; + } + if (kit_os_hosted_add_input(items, n, cap, kind, path, size) != 0) { + kit_os_hosted_errf(req->host, req->host_user, req->tool, + "too many hosted inputs"); + req->host->free(req->host_user, path, size); + return 1; + } + return 0; +} + +static int hosted_add_existing_include(KitOsHostedPlan* plan, + const KitOsHostedHost* host, + void* host_user, const char* dir) { + size_t len, bytes; + char* path; + if (plan->nsystem_includes >= KIT_OS_HOSTED_MAX_INCLUDES) return 1; + if (!host || !host->path_exists || !host->alloc) return 1; + if (!host->path_exists(host_user, dir)) return 0; + len = strlen(dir); + bytes = len + 1u; + path = host->alloc(host_user, bytes); + if (!path) return 1; + memcpy(path, dir, len); + path[len] = '\0'; + plan->system_includes[plan->nsystem_includes] = path; + plan->owned_system_includes[plan->nsystem_includes] = path; + plan->owned_system_include_sizes[plan->nsystem_includes] = bytes; + plan->nsystem_includes++; + return 0; +} + +int kit_os_hosted_add_incdirs(KitOsHostedPlan* plan, + const KitOsHostedHost* host, void* host_user, + const KitOsHostedDirs* dirs) { + uint32_t i; + for (i = 0; i < dirs->nincdirs; ++i) { + if (hosted_add_existing_include(plan, host, host_user, dirs->incdirs[i]) != + 0) + return 1; + } + return 0; +} + +int kit_os_hosted_add_define(KitOsHostedPlan* plan, const char* name, + const char* body) { + if (plan->ndefines >= KIT_OS_HOSTED_MAX_DEFINES) return 1; + plan->defines[plan->ndefines].name = kit_slice_cstr(name); + plan->defines[plan->ndefines].body = kit_slice_cstr(body); + plan->ndefines++; + return 0; +} + +int kit_os_hosted_add_clang_compat_defines(KitOsHostedPlan* plan) { + if (kit_os_hosted_add_define(plan, "__clang__", "1") != 0 || + kit_os_hosted_add_define(plan, "__clang_major__", "17") != 0 || + kit_os_hosted_add_define(plan, "__clang_minor__", "0") != 0 || + kit_os_hosted_add_define(plan, "__clang_patchlevel__", "0") != 0 || + kit_os_hosted_add_define(plan, "__GNUC__", "4") != 0 || + kit_os_hosted_add_define(plan, "__GNUC_MINOR__", "2") != 0 || + kit_os_hosted_add_define(plan, "__GNUC_PATCHLEVEL__", "1") != 0 || + kit_os_hosted_add_define(plan, "__has_builtin(x)", "0") != 0 || + kit_os_hosted_add_define(plan, "__has_include(x)", "0") != 0 || + kit_os_hosted_add_define(plan, "__has_include_next(x)", "0") != 0 || + kit_os_hosted_add_define(plan, "__has_feature(x)", "0") != 0 || + kit_os_hosted_add_define(plan, "__has_extension(x)", "0") != 0 || + kit_os_hosted_add_define(plan, "__has_attribute(x)", "0") != 0) + return 1; + return 0; +} + +void kit_os_hosted_plan_fini(const KitOsHostedHost* host, void* host_user, + KitOsHostedPlan* plan) { + uint32_t i; + if (!host || !host->free || !plan) return; + for (i = 0; i < plan->nbefore; ++i) { + if (plan->before[i].owned_path) + host->free(host_user, plan->before[i].owned_path, + plan->before[i].owned_size); + } + for (i = 0; i < plan->nafter; ++i) { + if (plan->after[i].owned_path) + host->free(host_user, plan->after[i].owned_path, + plan->after[i].owned_size); + } + for (i = 0; i < plan->nfinal; ++i) { + if (plan->final[i].owned_path) + host->free(host_user, plan->final[i].owned_path, + plan->final[i].owned_size); + } + for (i = 0; i < plan->nsystem_includes; ++i) { + if (plan->owned_system_includes[i]) + host->free(host_user, plan->owned_system_includes[i], + plan->owned_system_include_sizes[i]); + } + for (i = 0; i < plan->nlib_search_dirs; ++i) { + if (plan->lib_search_dirs[i]) + host->free(host_user, plan->lib_search_dirs[i], + plan->lib_search_dir_sizes[i]); + } + memset(plan, 0, sizeof(*plan)); +} diff --git a/src/os/hosted_internal.h b/src/os/hosted_internal.h @@ -0,0 +1,30 @@ +#ifndef KIT_OS_HOSTED_INTERNAL_H +#define KIT_OS_HOSTED_INTERNAL_H + +#include <kit/os.h> + +void kit_os_hosted_errf(const KitOsHostedHost* host, void* host_user, + const char* tool, const char* fmt, ...); + +int kit_os_hosted_add_input(KitOsHostedInput* items, uint32_t* n, + uint32_t cap, uint8_t kind, char* path, + size_t path_size); +char* kit_os_hosted_find_in_libdirs(const KitOsHostedHost* host, + void* host_user, + const KitOsHostedDirs* dirs, + const char* file, size_t* out_size); +int kit_os_hosted_libdir_has(const KitOsHostedHost* host, void* host_user, + const KitOsHostedDirs* dirs, const char* file); +int kit_os_hosted_add_required_search(KitOsHostedInput* items, uint32_t* n, + uint32_t cap, + const KitOsHostedRequest* req, + const KitOsHostedDirs* dirs, + const char* file, uint8_t kind); +int kit_os_hosted_add_incdirs(KitOsHostedPlan* plan, + const KitOsHostedHost* host, void* host_user, + const KitOsHostedDirs* dirs); +int kit_os_hosted_add_define(KitOsHostedPlan* plan, const char* name, + const char* body); +int kit_os_hosted_add_clang_compat_defines(KitOsHostedPlan* plan); + +#endif diff --git a/src/os/linux/hosted.c b/src/os/linux/hosted.c @@ -0,0 +1,207 @@ +#include "os/hosted_internal.h" + +static int hosted_add_linux_defines(KitOsHostedPlan* plan, int gnu) { + if (kit_os_hosted_add_clang_compat_defines(plan) != 0 || + kit_os_hosted_add_define(plan, "__linux__", "1") != 0 || + kit_os_hosted_add_define(plan, "__linux", "1") != 0 || + kit_os_hosted_add_define(plan, "linux", "1") != 0 || + kit_os_hosted_add_define(plan, "__ELF__", "1") != 0) + return 1; + if (gnu && kit_os_hosted_add_define(plan, "__gnu_linux__", "1") != 0) + return 1; + return 0; +} + +static const char* hosted_glibc_interp(KitArchKind arch) { + switch (arch) { + case KIT_ARCH_ARM_64: + return "/lib/ld-linux-aarch64.so.1"; + case KIT_ARCH_X86_64: + return "/lib64/ld-linux-x86-64.so.2"; + case KIT_ARCH_RV64: + return "/lib/ld-linux-riscv64-lp64d.so.1"; + default: + return NULL; + } +} + +static const char* hosted_musl_interp(KitArchKind arch) { + switch (arch) { + case KIT_ARCH_ARM_64: + return "/lib/ld-musl-aarch64.so.1"; + case KIT_ARCH_X86_64: + return "/lib/ld-musl-x86_64.so.1"; + case KIT_ARCH_RV64: + return "/lib/ld-musl-riscv64.so.1"; + default: + return NULL; + } +} + +static int hosted_resolve_linux_musl_static(const KitOsHostedRequest* req, + const KitOsHostedDirs* dirs, + KitOsHostedPlan* plan) { + plan->profile_name = "linux-musl-static"; + if (hosted_add_linux_defines(plan, 0) != 0 || + kit_os_hosted_add_incdirs(plan, req->host, req->host_user, dirs) != 0) { + kit_os_hosted_errf(req->host, req->host_user, req->tool, "out of memory"); + return 1; + } + if (!req->link_inputs) return 0; + if (kit_os_hosted_add_required_search( + plan->before, &plan->nbefore, KIT_OS_HOSTED_MAX_BEFORE, req, dirs, + "crt1.o", KIT_OS_HOSTED_INPUT_OBJECT) != 0 || + kit_os_hosted_add_required_search( + plan->before, &plan->nbefore, KIT_OS_HOSTED_MAX_BEFORE, req, dirs, + "crti.o", KIT_OS_HOSTED_INPUT_OBJECT) != 0) + return 1; + if (kit_os_hosted_add_required_search( + plan->after, &plan->nafter, KIT_OS_HOSTED_MAX_AFTER, req, dirs, + "libc.a", KIT_OS_HOSTED_INPUT_ARCHIVE) != 0) + return 1; + if (kit_os_hosted_add_required_search( + plan->final, &plan->nfinal, KIT_OS_HOSTED_MAX_FINAL, req, dirs, + "crtn.o", KIT_OS_HOSTED_INPUT_OBJECT) != 0) + return 1; + return 0; +} + +static int hosted_resolve_linux_musl_dynamic(const KitOsHostedRequest* req, + const KitOsHostedDirs* dirs, + KitOsHostedPlan* plan) { + const char* interp = hosted_musl_interp(req->target.arch); + if (!interp) { + kit_os_hosted_errf(req->host, req->host_user, req->tool, + "no hosted musl profile for target architecture"); + return 1; + } + plan->profile_name = "linux-musl-dynamic"; + plan->interp_path = interp; + if (hosted_add_linux_defines(plan, 0) != 0 || + kit_os_hosted_add_incdirs(plan, req->host, req->host_user, dirs) != 0) { + kit_os_hosted_errf(req->host, req->host_user, req->tool, "out of memory"); + return 1; + } + if (!req->link_inputs) return 0; + if (kit_os_hosted_add_required_search( + plan->before, &plan->nbefore, KIT_OS_HOSTED_MAX_BEFORE, req, dirs, + "Scrt1.o", KIT_OS_HOSTED_INPUT_OBJECT) != 0 || + kit_os_hosted_add_required_search( + plan->before, &plan->nbefore, KIT_OS_HOSTED_MAX_BEFORE, req, dirs, + "crti.o", KIT_OS_HOSTED_INPUT_OBJECT) != 0) + return 1; + if (kit_os_hosted_add_required_search( + plan->after, &plan->nafter, KIT_OS_HOSTED_MAX_AFTER, req, dirs, + "libc.so", KIT_OS_HOSTED_INPUT_DSO) != 0) + return 1; + if (kit_os_hosted_add_required_search( + plan->final, &plan->nfinal, KIT_OS_HOSTED_MAX_FINAL, req, dirs, + "crtn.o", KIT_OS_HOSTED_INPUT_OBJECT) != 0) + return 1; + return 0; +} + +static int hosted_resolve_linux_glibc_dynamic(const KitOsHostedRequest* req, + const KitOsHostedDirs* dirs, + KitOsHostedPlan* plan) { + const char* interp = hosted_glibc_interp(req->target.arch); + if (!interp) { + kit_os_hosted_errf(req->host, req->host_user, req->tool, + "no hosted glibc profile for target architecture"); + return 1; + } + plan->profile_name = "linux-glibc-dynamic"; + plan->interp_path = interp; + if (hosted_add_linux_defines(plan, 1) != 0 || + kit_os_hosted_add_incdirs(plan, req->host, req->host_user, dirs) != 0) { + kit_os_hosted_errf(req->host, req->host_user, req->tool, "out of memory"); + return 1; + } + if (!req->link_inputs) return 0; + if (kit_os_hosted_add_required_search( + plan->before, &plan->nbefore, KIT_OS_HOSTED_MAX_BEFORE, req, dirs, + "Scrt1.o", KIT_OS_HOSTED_INPUT_OBJECT) != 0 || + kit_os_hosted_add_required_search( + plan->before, &plan->nbefore, KIT_OS_HOSTED_MAX_BEFORE, req, dirs, + "crti.o", KIT_OS_HOSTED_INPUT_OBJECT) != 0) + return 1; + if (kit_os_hosted_add_required_search( + plan->after, &plan->nafter, KIT_OS_HOSTED_MAX_AFTER, req, dirs, + "libc.so.6", KIT_OS_HOSTED_INPUT_DSO) != 0 || + kit_os_hosted_add_required_search( + plan->after, &plan->nafter, KIT_OS_HOSTED_MAX_AFTER, req, dirs, + "libc_nonshared.a", KIT_OS_HOSTED_INPUT_ARCHIVE) != 0) + return 1; + if (kit_os_hosted_add_required_search( + plan->final, &plan->nfinal, KIT_OS_HOSTED_MAX_FINAL, req, dirs, + "crtn.o", KIT_OS_HOSTED_INPUT_OBJECT) != 0) + return 1; + return 0; +} + +static int hosted_resolve_linux(const KitOsHostedRequest* req, + const KitOsHostedDirs* dirs, + KitOsHostedPlan* plan) { + int has_libc_a, has_libc_so, has_libc_so6, has_glibc_nonshared; + if (dirs->nlibdirs == 0) { + kit_os_hosted_errf(req->host, req->host_user, req->tool, + "Linux hosted profile requires --sysroot or " + "KIT_SYSROOT"); + return 1; + } + has_libc_a = + kit_os_hosted_libdir_has(req->host, req->host_user, dirs, "libc.a"); + has_libc_so = + kit_os_hosted_libdir_has(req->host, req->host_user, dirs, "libc.so"); + has_libc_so6 = + kit_os_hosted_libdir_has(req->host, req->host_user, dirs, "libc.so.6"); + has_glibc_nonshared = kit_os_hosted_libdir_has( + req->host, req->host_user, dirs, "libc_nonshared.a"); + if (!req->static_link && has_libc_so6 && has_glibc_nonshared) + return hosted_resolve_linux_glibc_dynamic(req, dirs, plan); + if (!req->static_link && has_libc_so) + return hosted_resolve_linux_musl_dynamic(req, dirs, plan); + if (has_libc_a && !(has_libc_so6 && has_glibc_nonshared)) + return hosted_resolve_linux_musl_static(req, dirs, plan); + kit_os_hosted_errf(req->host, req->host_user, req->tool, + "no supported Linux hosted libc found (searched %u " + "library dir(s))", + (unsigned)dirs->nlibdirs); + return 1; +} + +static const char* hosted_linux_inc_triple_sub(KitArchKind arch) { + switch (arch) { + case KIT_ARCH_ARM_64: + return "usr/include/aarch64-linux-gnu"; + case KIT_ARCH_X86_64: + return "usr/include/x86_64-linux-gnu"; + case KIT_ARCH_RV64: + return "usr/include/riscv64-linux-gnu"; + default: + return NULL; + } +} + +static int hosted_sysroot_layout_linux(KitOsHostedDirs* dirs, + KitTargetSpec target, + const char* sysroot) { + const char* triple = hosted_linux_inc_triple_sub(target.arch); + if (kit_os_hosted_dirs_add_inc_join(dirs, sysroot, "usr/include") != 0) + return 1; + if (triple && kit_os_hosted_dirs_add_inc_join(dirs, sysroot, triple) != 0) + return 1; + if (kit_os_hosted_dirs_add_lib_join(dirs, sysroot, "usr/lib") != 0) + return 1; + if (kit_os_hosted_dirs_add_lib_join(dirs, sysroot, "lib") != 0) return 1; + if (kit_os_hosted_dirs_add_lib_join(dirs, sysroot, "lib64") != 0) return 1; + return 0; +} + +const KitOsHostedOps kit_os_linux_hosted_ops = { + .obj = KIT_OBJ_ELF, + .default_profile = 0, + .needs_sysroot_libdir = 0, + .resolve = hosted_resolve_linux, + .sysroot_layout = hosted_sysroot_layout_linux, +}; diff --git a/src/os/linux/linux.c b/src/os/linux/linux.c @@ -360,16 +360,17 @@ static KitStatus linux_init_thread(Compiler* c, EmuProcess* process, u64 nbytes = linux_round_up(m->memsz ? m->memsz : m->filesz, page_size); u64 base = 0; if (!nbytes) continue; - if (!process->os || !process->os->emu_find_map_region || - process->os->emu_find_map_region(process, nbytes, page_size, + if (!process->os || !process->os->emu || + !process->os->emu->find_map_region || + process->os->emu->find_map_region(process, nbytes, page_size, EMU_OS_MAP_TLS, &base) != KIT_OK) return KIT_ERR; if (emu_addr_space_map(&process->image.addr_space, base, nbytes, EMU_MEM_READ | EMU_MEM_WRITE, EMU_MAP_ANON) != KIT_OK) return KIT_ERR; - if (process->os->emu_note_map_region) - process->os->emu_note_map_region(process, base, nbytes, EMU_OS_MAP_TLS); + if (process->os->emu->note_map_region) + process->os->emu->note_map_region(process, base, nbytes, EMU_OS_MAP_TLS); if (emu_tls_copy_module_image(process, m, base) != KIT_OK) return KIT_ERR; if (emu_tls_blocks_add(c, &ts->tls_blocks, m->module_id, base, m->memsz) != KIT_OK) @@ -574,8 +575,9 @@ static KitStatus linux_default_syscall(void* user, EmuProcess* process, as, map_at, length, linux_emu_perms(a2), linux_emu_perms(a2) ? EMU_MAP_ANON : EMU_MAP_GUARD); if (st == KIT_OK) { - if (process->os && process->os->emu_note_map_region) - process->os->emu_note_map_region(process, map_at, length, + if (process->os && process->os->emu && + process->os->emu->note_map_region) + process->os->emu->note_map_region(process, map_at, length, EMU_OS_MAP_MMAP); ret = (i64)map_at; } else { @@ -589,8 +591,9 @@ static KitStatus linux_default_syscall(void* user, EmuProcess* process, if (addr) { st = emu_addr_space_find_gap(as, length, as->page_size, min_va, 0x0000800000000000ull, &map_at); - } else if (process->os && process->os->emu_find_map_region) { - st = process->os->emu_find_map_region(process, length, as->page_size, + } else if (process->os && process->os->emu && + process->os->emu->find_map_region) { + st = process->os->emu->find_map_region(process, length, as->page_size, EMU_OS_MAP_MMAP, &map_at); } else { st = KIT_UNSUPPORTED; @@ -606,8 +609,9 @@ static KitStatus linux_default_syscall(void* user, EmuProcess* process, if (st != KIT_OK) { ret = -LINUX_ENOMEM; } else { - if (process->os && process->os->emu_note_map_region) - process->os->emu_note_map_region(process, map_at, length, + if (process->os && process->os->emu && + process->os->emu->note_map_region) + process->os->emu->note_map_region(process, map_at, length, EMU_OS_MAP_MMAP); ret = (i64)map_at; } @@ -817,20 +821,18 @@ static u64 linux_syscall_next_pc(EmuProcess* process, EmuThread* thread, return next_pc; } -const KitOsImpl linux_os_impl = { - .kind = KIT_OS_LINUX, - .name = "linux", - .emu_init_process_private = linux_init_process_private, - .emu_destroy_process_private = linux_destroy_process_private, - .emu_init_thread_private = linux_init_thread_private, - .emu_destroy_thread_private = linux_destroy_thread_private, - .emu_init_process = linux_init_process, - .emu_init_thread = linux_init_thread, - .emu_decode_syscall = linux_decode_syscall, - .emu_encode_syscall_result = linux_encode_syscall_result, - .emu_syscall_next_pc = linux_syscall_next_pc, - .emu_find_map_region = linux_find_map_region, - .emu_note_map_region = linux_note_map_region, - .emu_default_syscall = linux_default_syscall, - .emu_deliver_fault = linux_deliver_fault, +const KitOsEmuOps kit_os_linux_emu_ops = { + .init_process_private = linux_init_process_private, + .destroy_process_private = linux_destroy_process_private, + .init_thread_private = linux_init_thread_private, + .destroy_thread_private = linux_destroy_thread_private, + .init_process = linux_init_process, + .init_thread = linux_init_thread, + .decode_syscall = linux_decode_syscall, + .encode_syscall_result = linux_encode_syscall_result, + .syscall_next_pc = linux_syscall_next_pc, + .find_map_region = linux_find_map_region, + .note_map_region = linux_note_map_region, + .default_syscall = linux_default_syscall, + .deliver_fault = linux_deliver_fault, }; diff --git a/src/os/linux/os.c b/src/os/linux/os.c @@ -0,0 +1,25 @@ +#include <kit/config.h> +#include <kit/os.h> + +#if KIT_OBJ_ELF_ENABLED +extern const KitOsHostedOps kit_os_linux_hosted_ops; +#endif + +#if KIT_EMU_ENABLED +extern const KitOsEmuOps kit_os_linux_emu_ops; +#endif + +const KitOsImpl kit_os_linux_impl = { + .kind = KIT_OS_LINUX, + .name = "linux", +#if KIT_OBJ_ELF_ENABLED + .hosted = &kit_os_linux_hosted_ops, +#else + .hosted = NULL, +#endif +#if KIT_EMU_ENABLED + .emu = &kit_os_linux_emu_ops, +#else + .emu = NULL, +#endif +}; diff --git a/src/os/macos/hosted.c b/src/os/macos/hosted.c @@ -0,0 +1,73 @@ +#include "os/hosted_internal.h" + +static int hosted_add_darwin_defines(KitOsHostedPlan* plan) { + if (kit_os_hosted_add_clang_compat_defines(plan) != 0 || + kit_os_hosted_add_define(plan, "__APPLE__", "1") != 0 || + kit_os_hosted_add_define(plan, "__APPLE_CC__", "6000") != 0 || + kit_os_hosted_add_define(plan, "__MACH__", "1") != 0 || + kit_os_hosted_add_define(plan, "__DYNAMIC__", "1") != 0) + return 1; + return 0; +} + +static int hosted_resolve_darwin(const KitOsHostedRequest* req, + const KitOsHostedDirs* dirs, + KitOsHostedPlan* plan) { + if (dirs->nlibdirs == 0) { + kit_os_hosted_errf( + req->host, req->host_user, req->tool, + "Darwin hosted profile requires a macOS SDK; pass --sysroot, set " + "KIT_SYSROOT, or install the Command Line Tools (try: --sysroot " + "\"$(xcrun --sdk macosx --show-sdk-path)\")"); + return 1; + } + plan->profile_name = "macos-libSystem"; + if (hosted_add_darwin_defines(plan) != 0 || + kit_os_hosted_add_incdirs(plan, req->host, req->host_user, dirs) != 0) { + kit_os_hosted_errf(req->host, req->host_user, req->tool, "out of memory"); + return 1; + } + if (!req->link_inputs) return 0; + { + size_t size = 0; + char* libsystem = kit_os_hosted_find_in_libdirs( + req->host, req->host_user, dirs, "libSystem.tbd", &size); + if (!libsystem) + libsystem = kit_os_hosted_find_in_libdirs( + req->host, req->host_user, dirs, "libSystem.dylib", &size); + if (!libsystem) { + kit_os_hosted_errf(req->host, req->host_user, req->tool, + "hosted profile missing required file: " + "libSystem.tbd or libSystem.dylib"); + return 1; + } + if (kit_os_hosted_add_input(plan->after, &plan->nafter, + KIT_OS_HOSTED_MAX_AFTER, + KIT_OS_HOSTED_INPUT_DSO, libsystem, size) != + 0) { + req->host->free(req->host_user, libsystem, size); + kit_os_hosted_errf(req->host, req->host_user, req->tool, + "too many hosted inputs"); + return 1; + } + } + return 0; +} + +static int hosted_sysroot_layout_darwin(KitOsHostedDirs* dirs, + KitTargetSpec target, + const char* sysroot) { + (void)target; + if (kit_os_hosted_dirs_add_inc_join(dirs, sysroot, "usr/include") != 0 || + kit_os_hosted_dirs_add_lib_join(dirs, sysroot, "usr/lib") != 0) + return 1; + return 0; +} + +const KitOsHostedOps kit_os_macos_hosted_ops = { + .obj = KIT_OBJ_MACHO, + .default_profile = 0, + .needs_sysroot_libdir = 0, + .resolve = hosted_resolve_darwin, + .sysroot_layout = hosted_sysroot_layout_darwin, +}; diff --git a/src/os/macos/os.c b/src/os/macos/os.c @@ -0,0 +1,10 @@ +#include <kit/os.h> + +extern const KitOsHostedOps kit_os_macos_hosted_ops; + +const KitOsImpl kit_os_macos_impl = { + .kind = KIT_OS_MACOS, + .name = "macos", + .hosted = &kit_os_macos_hosted_ops, + .emu = NULL, +}; diff --git a/src/os/registry.c b/src/os/registry.c @@ -1,11 +1,37 @@ -#include "emu/emu.h" +#include <kit/config.h> +#include <kit/os.h> -extern const KitOsImpl linux_os_impl; +#if KIT_OBJ_MACHO_ENABLED +extern const KitOsImpl kit_os_macos_impl; +#endif +#if KIT_OBJ_ELF_ENABLED || KIT_EMU_ENABLED +extern const KitOsImpl kit_os_linux_impl; +#endif +#if KIT_OBJ_ELF_ENABLED +extern const KitOsImpl kit_os_freebsd_impl; +#endif +#if KIT_OBJ_COFF_ENABLED +extern const KitOsImpl kit_os_windows_impl; +#endif -const KitOsImpl* os_lookup(KitOSKind kind) { +const KitOsImpl* kit_os_lookup(KitOSKind kind) { switch (kind) { +#if KIT_OBJ_MACHO_ENABLED + case KIT_OS_MACOS: + return &kit_os_macos_impl; +#endif +#if KIT_OBJ_ELF_ENABLED || KIT_EMU_ENABLED case KIT_OS_LINUX: - return &linux_os_impl; + return &kit_os_linux_impl; +#endif +#if KIT_OBJ_ELF_ENABLED + case KIT_OS_FREEBSD: + return &kit_os_freebsd_impl; +#endif +#if KIT_OBJ_COFF_ENABLED + case KIT_OS_WINDOWS: + return &kit_os_windows_impl; +#endif default: return NULL; } diff --git a/src/os/windows/hosted.c b/src/os/windows/hosted.c @@ -0,0 +1,94 @@ +#include "os/hosted_internal.h" + +static int hosted_resolve_windows_mingw(const KitOsHostedRequest* req, + const KitOsHostedDirs* dirs, + KitOsHostedPlan* plan) { + if (dirs->nlibdirs == 0) { + kit_os_hosted_errf(req->host, req->host_user, req->tool, + "Windows hosted profile requires --sysroot or " + "KIT_SYSROOT"); + return 1; + } + plan->profile_name = "windows-mingw-ucrt"; + if (kit_os_hosted_add_incdirs(plan, req->host, req->host_user, dirs) != 0) { + kit_os_hosted_errf(req->host, req->host_user, req->tool, "out of memory"); + return 1; + } + if (!req->link_inputs) return 0; + if (kit_os_hosted_add_required_search( + plan->before, &plan->nbefore, KIT_OS_HOSTED_MAX_BEFORE, req, dirs, + "crt2.o", KIT_OS_HOSTED_INPUT_OBJECT) != 0 || + kit_os_hosted_add_required_search( + plan->before, &plan->nbefore, KIT_OS_HOSTED_MAX_BEFORE, req, dirs, + "crtbegin.o", KIT_OS_HOSTED_INPUT_OBJECT) != 0) + return 1; + if (kit_os_hosted_add_required_search( + plan->after, &plan->nafter, KIT_OS_HOSTED_MAX_AFTER, req, dirs, + "libmingw32.a", KIT_OS_HOSTED_INPUT_ARCHIVE) != 0 || + kit_os_hosted_add_required_search( + plan->after, &plan->nafter, KIT_OS_HOSTED_MAX_AFTER, req, dirs, + "libmoldname.a", KIT_OS_HOSTED_INPUT_ARCHIVE) != 0 || + kit_os_hosted_add_required_search( + plan->after, &plan->nafter, KIT_OS_HOSTED_MAX_AFTER, req, dirs, + "libmingwex.a", KIT_OS_HOSTED_INPUT_ARCHIVE) != 0 || + kit_os_hosted_add_required_search( + plan->after, &plan->nafter, KIT_OS_HOSTED_MAX_AFTER, req, dirs, + "libwinpthread.a", KIT_OS_HOSTED_INPUT_ARCHIVE) != 0 || + kit_os_hosted_add_required_search( + plan->after, &plan->nafter, KIT_OS_HOSTED_MAX_AFTER, req, dirs, + "libucrt.a", KIT_OS_HOSTED_INPUT_ARCHIVE) != 0 || + kit_os_hosted_add_required_search( + plan->after, &plan->nafter, KIT_OS_HOSTED_MAX_AFTER, req, dirs, + "libadvapi32.a", KIT_OS_HOSTED_INPUT_ARCHIVE) != 0 || + kit_os_hosted_add_required_search( + plan->after, &plan->nafter, KIT_OS_HOSTED_MAX_AFTER, req, dirs, + "libshell32.a", KIT_OS_HOSTED_INPUT_ARCHIVE) != 0 || + kit_os_hosted_add_required_search( + plan->after, &plan->nafter, KIT_OS_HOSTED_MAX_AFTER, req, dirs, + "libuser32.a", KIT_OS_HOSTED_INPUT_ARCHIVE) != 0 || + kit_os_hosted_add_required_search( + plan->after, &plan->nafter, KIT_OS_HOSTED_MAX_AFTER, req, dirs, + "libkernel32.a", KIT_OS_HOSTED_INPUT_ARCHIVE) != 0 || + kit_os_hosted_add_required_search( + plan->after, &plan->nafter, KIT_OS_HOSTED_MAX_AFTER, req, dirs, + "libmingw32.a", KIT_OS_HOSTED_INPUT_ARCHIVE) != 0 || + kit_os_hosted_add_required_search( + plan->after, &plan->nafter, KIT_OS_HOSTED_MAX_AFTER, req, dirs, + "libmoldname.a", KIT_OS_HOSTED_INPUT_ARCHIVE) != 0 || + kit_os_hosted_add_required_search( + plan->after, &plan->nafter, KIT_OS_HOSTED_MAX_AFTER, req, dirs, + "libmingwex.a", KIT_OS_HOSTED_INPUT_ARCHIVE) != 0 || + kit_os_hosted_add_required_search( + plan->after, &plan->nafter, KIT_OS_HOSTED_MAX_AFTER, req, dirs, + "libwinpthread.a", KIT_OS_HOSTED_INPUT_ARCHIVE) != 0 || + kit_os_hosted_add_required_search( + plan->after, &plan->nafter, KIT_OS_HOSTED_MAX_AFTER, req, dirs, + "libucrt.a", KIT_OS_HOSTED_INPUT_ARCHIVE) != 0 || + kit_os_hosted_add_required_search( + plan->after, &plan->nafter, KIT_OS_HOSTED_MAX_AFTER, req, dirs, + "libkernel32.a", KIT_OS_HOSTED_INPUT_ARCHIVE) != 0) + return 1; + if (kit_os_hosted_add_required_search( + plan->final, &plan->nfinal, KIT_OS_HOSTED_MAX_FINAL, req, dirs, + "crtend.o", KIT_OS_HOSTED_INPUT_OBJECT) != 0) + return 1; + return 0; +} + +static int hosted_sysroot_layout_windows(KitOsHostedDirs* dirs, + KitTargetSpec target, + const char* sysroot) { + (void)target; + if (kit_os_hosted_dirs_add_inc_join(dirs, sysroot, "include") != 0 || + kit_os_hosted_dirs_add_lib_join(dirs, sysroot, "lib") != 0) + return 1; + return 0; +} + +const KitOsHostedOps kit_os_windows_hosted_ops = { + .obj = KIT_OBJ_COFF, + .default_profile = 1, + .needs_sysroot_libdir = 1, + .resolve = hosted_resolve_windows_mingw, + .sysroot_layout = hosted_sysroot_layout_windows, +}; diff --git a/src/os/windows/os.c b/src/os/windows/os.c @@ -0,0 +1,10 @@ +#include <kit/os.h> + +extern const KitOsHostedOps kit_os_windows_hosted_ops; + +const KitOsImpl kit_os_windows_impl = { + .kind = KIT_OS_WINDOWS, + .name = "windows", + .hosted = &kit_os_windows_hosted_ops, + .emu = NULL, +};