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:
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,
+};