runtime.c (37065B)
1 #include "runtime.h" 2 3 #include <kit/archive.h> 4 #include <kit/compile.h> 5 #include <kit/core.h> 6 #include <kit/preprocess.h> 7 #include <stdint.h> 8 #include <string.h> 9 10 typedef struct RuntimeVariant { 11 const char* key; 12 KitArchKind arch; 13 KitOSKind os; 14 KitObjFmt obj; 15 uint8_t ptr_size; 16 uint8_t ptr_align; 17 const char* abi_include; 18 uint8_t has_int128; 19 uint8_t ldbl128; 20 const char* const* sources; 21 uint32_t nsources; 22 /* Float-ABI axis (orthogonal to XLEN). A single arch+ptr_size can have 23 * several float ABIs (rv32 ilp32 soft vs ilp32f single), each needing its 24 * own runtime build, so the ABI is part of the variant identity. DEFAULT (0) 25 * means "wildcard" — it matches any target.float_abi (every non-RISC-V 26 * target and rv64, whose runtime is float-ABI-agnostic, leave it 0). */ 27 uint8_t float_abi; /* KitFloatAbi */ 28 /* -march / -mabi the runtime is compiled with. NULL falls back to the arch 29 * defaults (correct for every existing variant). rv32 sets them explicitly 30 * because the default profile (rv32imafc/ilp32f) is wrong for the soft 31 * ilp32 build. */ 32 const char* isa; 33 const char* abi; 34 } RuntimeVariant; 35 36 static const char* const kRtSrcX64[] = { 37 "assert/assert.c", "int/int.c", 38 "int/si_div.c", "fp/fp.c", 39 "mem/mem.c", "string/string.c", 40 "ctype/ctype.c", "stdlib/stdlib.c", 41 "stdlib/qsort.c", "stdio/printf.c", 42 "atomic/atomic_freestanding.c", 43 "cache/clear_cache.c", "kit/ifunc_init.c", 44 "int64/int64.c", "coro/x86_64.c", 45 "coro/coro.c", "stack/backtrace.c", 46 "stack/print_backtrace.c", 47 }; 48 49 static const char* const kRtSrcX64Windows[] = { 50 "int/int.c", 51 "int/si_div.c", 52 "fp/fp.c", 53 "atomic/atomic_freestanding.c", 54 "cache/clear_cache.c", 55 "kit/ifunc_init.c", 56 "int64/int64.c", 57 "stack/chkstk_x86_64_win.c", 58 "coro/x86_64_win.c", 59 "coro/coro.c", 60 }; 61 62 static const char* const kRtSrcAarch64Elf[] = { 63 "assert/assert.c", "int/int.c", 64 "int/si_div.c", "fp/fp.c", 65 "mem/mem.c", "string/string.c", 66 "ctype/ctype.c", "stdlib/stdlib.c", 67 "stdlib/qsort.c", "stdio/printf.c", 68 "atomic/atomic_freestanding.c", 69 "cache/clear_cache.c", "kit/ifunc_init.c", 70 "int64/int64.c", "coro/aarch64.c", 71 "coro/coro.c", "fp_tf/fp_tf.c", 72 "fp_ti/fp_ti.c", "coro/aarch64_elf.s", 73 "stack/backtrace.c", "stack/print_backtrace.c", 74 }; 75 76 static const char* const kRtSrcAarch64Darwin[] = { 77 "assert/assert.c", "int/int.c", 78 "int/si_div.c", "fp/fp.c", 79 "mem/mem.c", "string/string.c", 80 "ctype/ctype.c", "stdlib/stdlib.c", 81 "stdlib/qsort.c", "stdio/printf.c", 82 "atomic/atomic_freestanding.c", 83 "cache/clear_cache.c", "kit/ifunc_init.c", 84 "int64/int64.c", "coro/aarch64.c", 85 "coro/coro.c", "coro/aarch64_macho.s", 86 "stack/backtrace.c", "stack/print_backtrace.c", 87 }; 88 89 static const char* const kRtSrcAarch64Windows[] = { 90 "int/int.c", 91 "int/si_div.c", 92 "fp/fp.c", 93 "atomic/atomic_freestanding.c", 94 "cache/clear_cache.c", 95 "kit/ifunc_init.c", 96 "int64/int64.c", 97 "coro/aarch64.c", 98 "coro/coro.c", 99 }; 100 101 static const char* const kRtSrcRv64Elf[] = { 102 "assert/assert.c", "int/int.c", 103 "int/si_div.c", "fp/fp.c", 104 "mem/mem.c", "string/string.c", 105 "ctype/ctype.c", "stdlib/stdlib.c", 106 "stdlib/qsort.c", "stdio/printf.c", 107 "atomic/atomic_freestanding.c", 108 "cache/clear_cache.c", "kit/ifunc_init.c", 109 "int64/int64.c", "coro/riscv64.c", 110 "coro/coro.c", "fp_tf/fp_tf.c", 111 "fp_ti/fp_ti.c", "stack/backtrace.c", 112 "stack/print_backtrace.c", 113 }; 114 115 /* rv32 freestanding runtime: ilp32 integer layout (int32/int32.c for the 116 * 64-bit-on-32-bit helpers — __muldi3/__ashldi3/...; int/int.c for the i64 117 * div/mod) and soft double (fp/fp.c). Shared by the ilp32 (soft) and ilp32f 118 * (hardware single-float) variants; only the -march/-mabi the sources are 119 * compiled with differ, captured per-variant in the table below. */ 120 static const char* const kRtSrcRv32Elf[] = { 121 "assert/assert.c", "int/int.c", 122 "int/si_div.c", "fp/fp.c", 123 "mem/mem.c", "string/string.c", 124 "ctype/ctype.c", "stdlib/stdlib.c", 125 "stdlib/qsort.c", "stdio/printf.c", 126 "atomic/atomic_freestanding.c", 127 "cache/clear_cache.c", "kit/ifunc_init.c", 128 "int32/int32.c", "coro/riscv32.c", 129 "coro/coro.c", "stack/backtrace.c", 130 "stack/print_backtrace.c", 131 }; 132 133 static const RuntimeVariant kRtVariants[] = { 134 {"x86_64-linux", KIT_ARCH_X86_64, KIT_OS_LINUX, KIT_OBJ_ELF, 8, 8, 135 "lib/include/lp64_le", 1, 0, kRtSrcX64, 136 (uint32_t)(sizeof(kRtSrcX64) / sizeof(kRtSrcX64[0])), 137 KIT_FLOAT_ABI_DEFAULT, NULL, NULL}, 138 /* FreeBSD ELF runtime mirrors the Linux ELF runtime per-arch: the 139 * compiler-rt helpers and coroutine asm are ABI/ELF-based, not kernel 140 * based, so the same source set and data model apply. */ 141 {"x86_64-freebsd", KIT_ARCH_X86_64, KIT_OS_FREEBSD, KIT_OBJ_ELF, 8, 8, 142 "lib/include/lp64_le", 1, 0, kRtSrcX64, 143 (uint32_t)(sizeof(kRtSrcX64) / sizeof(kRtSrcX64[0])), 144 KIT_FLOAT_ABI_DEFAULT, NULL, NULL}, 145 {"x86_64-apple-darwin", KIT_ARCH_X86_64, KIT_OS_MACOS, KIT_OBJ_MACHO, 8, 8, 146 "lib/include/lp64_le", 1, 0, kRtSrcX64, 147 (uint32_t)(sizeof(kRtSrcX64) / sizeof(kRtSrcX64[0])), 148 KIT_FLOAT_ABI_DEFAULT, NULL, NULL}, 149 {"x86_64-elf", KIT_ARCH_X86_64, KIT_OS_FREESTANDING, KIT_OBJ_ELF, 8, 8, 150 "lib/include/lp64_le", 1, 0, kRtSrcX64, 151 (uint32_t)(sizeof(kRtSrcX64) / sizeof(kRtSrcX64[0])), 152 KIT_FLOAT_ABI_DEFAULT, NULL, NULL}, 153 {"x86_64-pc-windows", KIT_ARCH_X86_64, KIT_OS_WINDOWS, KIT_OBJ_COFF, 8, 8, 154 "lib/include/llp64_le", 1, 0, kRtSrcX64Windows, 155 (uint32_t)(sizeof(kRtSrcX64Windows) / sizeof(kRtSrcX64Windows[0])), 156 KIT_FLOAT_ABI_DEFAULT, NULL, NULL}, 157 {"aarch64-linux", KIT_ARCH_ARM_64, KIT_OS_LINUX, KIT_OBJ_ELF, 8, 8, 158 "lib/include/lp64_le", 1, 1, kRtSrcAarch64Elf, 159 (uint32_t)(sizeof(kRtSrcAarch64Elf) / sizeof(kRtSrcAarch64Elf[0])), 160 KIT_FLOAT_ABI_DEFAULT, NULL, NULL}, 161 {"aarch64-freebsd", KIT_ARCH_ARM_64, KIT_OS_FREEBSD, KIT_OBJ_ELF, 8, 8, 162 "lib/include/lp64_le", 1, 1, kRtSrcAarch64Elf, 163 (uint32_t)(sizeof(kRtSrcAarch64Elf) / sizeof(kRtSrcAarch64Elf[0])), 164 KIT_FLOAT_ABI_DEFAULT, NULL, NULL}, 165 {"aarch64-elf", KIT_ARCH_ARM_64, KIT_OS_FREESTANDING, KIT_OBJ_ELF, 8, 8, 166 "lib/include/lp64_le", 1, 1, kRtSrcAarch64Elf, 167 (uint32_t)(sizeof(kRtSrcAarch64Elf) / sizeof(kRtSrcAarch64Elf[0])), 168 KIT_FLOAT_ABI_DEFAULT, NULL, NULL}, 169 {"aarch64-apple-darwin", KIT_ARCH_ARM_64, KIT_OS_MACOS, KIT_OBJ_MACHO, 8, 8, 170 "lib/include/lp64_le", 1, 0, kRtSrcAarch64Darwin, 171 (uint32_t)(sizeof(kRtSrcAarch64Darwin) / sizeof(kRtSrcAarch64Darwin[0])), 172 KIT_FLOAT_ABI_DEFAULT, NULL, NULL}, 173 {"aarch64-windows", KIT_ARCH_ARM_64, KIT_OS_WINDOWS, KIT_OBJ_COFF, 8, 8, 174 "lib/include/llp64_le", 1, 0, kRtSrcAarch64Windows, 175 (uint32_t)(sizeof(kRtSrcAarch64Windows) / sizeof(kRtSrcAarch64Windows[0])), 176 KIT_FLOAT_ABI_DEFAULT, NULL, NULL}, 177 {"riscv64-linux", KIT_ARCH_RV64, KIT_OS_LINUX, KIT_OBJ_ELF, 8, 8, 178 "lib/include/lp64_le", 1, 1, kRtSrcRv64Elf, 179 (uint32_t)(sizeof(kRtSrcRv64Elf) / sizeof(kRtSrcRv64Elf[0])), 180 KIT_FLOAT_ABI_DEFAULT, NULL, NULL}, 181 {"riscv64-freebsd", KIT_ARCH_RV64, KIT_OS_FREEBSD, KIT_OBJ_ELF, 8, 8, 182 "lib/include/lp64_le", 1, 1, kRtSrcRv64Elf, 183 (uint32_t)(sizeof(kRtSrcRv64Elf) / sizeof(kRtSrcRv64Elf[0])), 184 KIT_FLOAT_ABI_DEFAULT, NULL, NULL}, 185 {"riscv64-elf", KIT_ARCH_RV64, KIT_OS_FREESTANDING, KIT_OBJ_ELF, 8, 8, 186 "lib/include/lp64_le", 1, 1, kRtSrcRv64Elf, 187 (uint32_t)(sizeof(kRtSrcRv64Elf) / sizeof(kRtSrcRv64Elf[0])), 188 KIT_FLOAT_ABI_DEFAULT, NULL, NULL}, 189 /* rv32 freestanding. ilp32 (pure soft float) and ilp32f (hardware single 190 * float, soft double) share one arch+ptr_size, so float_abi is part of the 191 * variant identity and each is built with its own -march/-mabi. Keys match 192 * the `make rt` variant dirs (riscv32-elf / riscv32-elf-hardfloat) so a 193 * checkout shares build/rt with the Makefile. */ 194 {"riscv32-elf", KIT_ARCH_RV32, KIT_OS_FREESTANDING, KIT_OBJ_ELF, 4, 4, 195 "lib/include/ilp32_le", 0, 0, kRtSrcRv32Elf, 196 (uint32_t)(sizeof(kRtSrcRv32Elf) / sizeof(kRtSrcRv32Elf[0])), 197 KIT_FLOAT_ABI_SOFT, "rv32imac", "ilp32"}, 198 {"riscv32-elf-hardfloat", KIT_ARCH_RV32, KIT_OS_FREESTANDING, KIT_OBJ_ELF, 199 4, 4, "lib/include/ilp32_le", 0, 0, kRtSrcRv32Elf, 200 (uint32_t)(sizeof(kRtSrcRv32Elf) / sizeof(kRtSrcRv32Elf[0])), 201 KIT_FLOAT_ABI_SINGLE, "rv32imafc", "ilp32f"}, 202 }; 203 204 static char* rt_dup(DriverEnv* env, const char* s, size_t* out_size) { 205 size_t len = driver_strlen(s); 206 char* p = (char*)driver_alloc(env, len + 1u); 207 if (!p) return NULL; 208 driver_memcpy(p, s, len + 1u); 209 if (out_size) *out_size = len + 1u; 210 return p; 211 } 212 213 static char* rt_join(DriverEnv* env, const char* a, const char* b, 214 size_t* out_size) { 215 size_t la = driver_strlen(a); 216 size_t lb = driver_strlen(b); 217 int slash = la > 0 && a[la - 1u] != '/'; 218 size_t n = la + (slash ? 1u : 0u) + lb + 1u; 219 char* p = (char*)driver_alloc(env, n); 220 if (!p) return NULL; 221 driver_memcpy(p, a, la); 222 if (slash) p[la++] = '/'; 223 driver_memcpy(p + la, b, lb); 224 p[la + lb] = '\0'; 225 if (out_size) *out_size = n; 226 return p; 227 } 228 229 static char* rt_join_slot(DriverEnv* env, char** slot, size_t* size_slot, 230 const char* a, const char* b) { 231 char* p = rt_join(env, a, b, size_slot); 232 *slot = p; 233 return p; 234 } 235 236 static void rt_store_const_ptr(const char** slot, const char* value) { 237 *slot = value; 238 } 239 240 static void rt_free_str(DriverEnv* env, char** p, size_t* n) { 241 if (*p) driver_free(env, *p, *n); 242 *p = NULL; 243 *n = 0; 244 } 245 246 static int rt_has_layout(const char* rt_root) { 247 char inc[4096]; 248 char lib[4096]; 249 size_t n = driver_strlen(rt_root); 250 if (n + 13u >= sizeof(inc)) return 0; 251 driver_memcpy(inc, rt_root, n); 252 inc[n] = '/'; 253 driver_memcpy(inc + n + 1u, "include", 8u); 254 driver_memcpy(lib, rt_root, n); 255 lib[n] = '/'; 256 driver_memcpy(lib + n + 1u, "lib", 4u); 257 return driver_path_exists(inc) && driver_path_exists(lib); 258 } 259 260 static int rt_set_layout(DriverEnv* env, DriverRuntimeSupport* out, 261 const char* support_root, const char* rt_root) { 262 out->support_root = rt_dup(env, support_root, &out->support_root_size); 263 out->rt_root = rt_dup(env, rt_root, &out->rt_root_size); 264 out->include_dir = rt_join(env, rt_root, "include", &out->include_dir_size); 265 if (!out->support_root || !out->rt_root || !out->include_dir) { 266 driver_runtime_support_fini(env, out); 267 return 1; 268 } 269 return 0; 270 } 271 272 static int rt_try_support_root(DriverEnv* env, const char* root, 273 DriverRuntimeSupport* out) { 274 char* rt_root; 275 size_t rt_root_size = 0; 276 int ok; 277 278 rt_root = rt_join(env, root, "rt", &rt_root_size); 279 if (!rt_root) return 1; 280 ok = rt_has_layout(rt_root) && rt_set_layout(env, out, root, rt_root) == 0; 281 driver_free(env, rt_root, rt_root_size); 282 return ok ? 0 : 1; 283 } 284 285 /* Directory-separator test for splitting a program path. On Windows the image 286 * path (argv[0] / GetModuleFileNameW) uses '\\', so binary-relative rt 287 * discovery must accept it as well as '/'; otherwise kit.exe never finds its 288 * <bindir>/support/rt or <bindir>/../rt and falls back to the cwd-only ./rt. */ 289 static int rt_is_path_sep(char c) { 290 #if defined(_WIN32) 291 return c == '/' || c == '\\'; 292 #else 293 return c == '/'; 294 #endif 295 } 296 297 static int rt_try_argv0_support(DriverEnv* env, const char* argv0, 298 DriverRuntimeSupport* out) { 299 const char* slash; 300 size_t dir_len; 301 char* dir; 302 char* support; 303 size_t dir_size; 304 size_t support_size; 305 int rc; 306 307 if (!argv0) return 1; 308 slash = argv0 + driver_strlen(argv0); 309 while (slash > argv0 && !rt_is_path_sep(slash[-1])) --slash; 310 if (slash == argv0) return 1; 311 dir_len = (size_t)(slash - argv0); 312 if (dir_len == 0) return 1; 313 314 dir_size = dir_len + 1u; 315 dir = (char*)driver_alloc(env, dir_size); 316 if (!dir) return 1; 317 driver_memcpy(dir, argv0, dir_len); 318 dir[dir_len] = '\0'; 319 320 support = rt_join(env, dir, "support", &support_size); 321 driver_free(env, dir, dir_size); 322 if (!support) return 1; 323 rc = rt_try_support_root(env, support, out); 324 driver_free(env, support, support_size); 325 return rc; 326 } 327 328 static int rt_try_argv0_checkout_root(DriverEnv* env, const char* argv0, 329 DriverRuntimeSupport* out) { 330 const char* slash; 331 size_t dir_len; 332 char* dir; 333 char* parent; 334 size_t dir_size; 335 size_t parent_size; 336 int rc; 337 338 if (!argv0) return 1; 339 slash = argv0 + driver_strlen(argv0); 340 while (slash > argv0 && !rt_is_path_sep(slash[-1])) --slash; 341 if (slash == argv0) return 1; 342 dir_len = (size_t)(slash - argv0); 343 if (dir_len == 0) return 1; 344 345 dir_size = dir_len + 1u; 346 dir = (char*)driver_alloc(env, dir_size); 347 if (!dir) return 1; 348 driver_memcpy(dir, argv0, dir_len); 349 dir[dir_len] = '\0'; 350 351 parent = rt_join(env, dir, "..", &parent_size); 352 driver_free(env, dir, dir_size); 353 if (!parent) return 1; 354 rc = rt_try_support_root(env, parent, out); 355 driver_free(env, parent, parent_size); 356 return rc; 357 } 358 359 int driver_runtime_resolve(DriverEnv* env, const char* explicit_support_dir, 360 const char* argv0, DriverRuntimeSupport* out) { 361 int rc; 362 DriverRuntimeSupport zero = {0}; 363 *out = zero; 364 365 char* self = NULL; 366 size_t self_size = 0; 367 const char* tool = argv0; 368 369 if (explicit_support_dir) { 370 rc = rt_try_support_root(env, explicit_support_dir, out); 371 } else if (rt_try_support_root(env, ".", out) == 0) { 372 rc = 0; 373 } else if (rt_try_argv0_checkout_root(env, argv0, out) == 0) { 374 rc = 0; 375 } else if (rt_try_argv0_support(env, argv0, out) == 0) { 376 /* rt found as a <bindir>/support/rt sibling: this is a distribution 377 * install, not a build tree. Mark it so the on-demand rt archive lands 378 * in the user cache dir rather than polluting the install. */ 379 rc = 0; 380 out->install_layout = 1; 381 } else if (driver_self_exe_path(env, &self, &self_size) == 0 && self) { 382 /* argv[0] wasn't a usable path for binary-relative discovery — a bare 383 * program name when kit is on PATH, a relative invocation, or a tool 384 * symlink whose directory holds no rt. Retry against the real image path 385 * (GetModuleFileNameW on Windows, /proc/self/exe on Linux, ...). */ 386 tool = self; 387 if (rt_try_argv0_checkout_root(env, self, out) == 0) { 388 rc = 0; 389 } else if (rt_try_argv0_support(env, self, out) == 0) { 390 rc = 0; 391 out->install_layout = 1; 392 } else { 393 rc = 1; 394 } 395 } else { 396 rc = 1; 397 } 398 /* Own the located image path: it outlives `self`'s free below and the 399 * caller's argv, and is stat'd later for rt-archive cache invalidation. */ 400 if (rc == 0) out->tool_path = rt_dup(env, tool, &out->tool_path_size); 401 if (self) driver_free(env, self, self_size); 402 return rc; 403 } 404 405 void driver_runtime_support_fini(DriverEnv* env, DriverRuntimeSupport* s) { 406 rt_free_str(env, &s->include_dir, &s->include_dir_size); 407 rt_free_str(env, &s->rt_root, &s->rt_root_size); 408 rt_free_str(env, &s->support_root, &s->support_root_size); 409 if (s->tool_path && s->tool_path_size) { 410 driver_free(env, (void*)s->tool_path, s->tool_path_size); 411 s->tool_path = NULL; 412 s->tool_path_size = 0; 413 } 414 } 415 416 int driver_runtime_add_freestanding_headers(const DriverRuntimeSupport* s, 417 DriverCflags* cf) { 418 uint32_t i; 419 if (!s || !s->include_dir || !cf) return 1; 420 for (i = cf->nsystem_include_dirs; i > 0; --i) 421 cf->system_include_dirs[i] = cf->system_include_dirs[i - 1u]; 422 cf->system_include_dirs[0] = s->include_dir; 423 cf->nsystem_include_dirs++; 424 return 0; 425 } 426 427 int driver_runtime_append_freestanding_headers(const DriverRuntimeSupport* s, 428 DriverCflags* cf) { 429 uint32_t i; 430 if (!s || !s->include_dir || !cf) return 1; 431 i = cf->nsystem_include_dirs; 432 cf->system_include_dirs[i] = s->include_dir; 433 cf->nsystem_include_dirs = i + 1u; 434 return 0; 435 } 436 437 static const RuntimeVariant* rt_variant_for_target(KitTargetSpec target) { 438 uint32_t i; 439 for (i = 0; i < (uint32_t)(sizeof(kRtVariants) / sizeof(kRtVariants[0])); 440 ++i) { 441 const RuntimeVariant* v = &kRtVariants[i]; 442 /* A variant with float_abi DEFAULT is float-ABI-agnostic and matches any 443 * target (every non-RISC-V variant and rv64). A variant that pins a float 444 * ABI (the two rv32 entries) matches only that ABI, so ilp32 vs ilp32f 445 * targets select distinct runtimes. */ 446 if (target.arch == v->arch && target.os == v->os && target.obj == v->obj && 447 target.ptr_size == v->ptr_size && target.ptr_align == v->ptr_align && 448 (v->float_abi == KIT_FLOAT_ABI_DEFAULT || 449 v->float_abi == target.float_abi)) 450 return v; 451 } 452 return NULL; 453 } 454 455 int driver_runtime_has_variant(KitTargetSpec target) { 456 return rt_variant_for_target(target) != NULL; 457 } 458 459 static int rt_prepare_pp(DriverEnv* env, const DriverRuntimeSupport* support, 460 const RuntimeVariant* variant, int assembler, 461 KitPreprocessOptions* pp, char*** owned_dirs, 462 size_t** owned_sizes, uint32_t* owned_count) { 463 static const KitSlice def_int128_1 = KIT_SLICE_LIT("1"); 464 static const KitSlice def_int128_0 = KIT_SLICE_LIT("0"); 465 char** dirs = NULL; 466 size_t* sizes = NULL; 467 const char** include_dirs; 468 const char** system_dirs; 469 KitDefine* defs; 470 uint32_t ninc = variant->ldbl128 ? 4u : 3u; 471 uint32_t nsys = 2u; 472 uint32_t ndefs = 1u + (variant->ldbl128 ? 1u : 0u) + (assembler ? 1u : 0u); 473 uint32_t d = 0; 474 KitPreprocessOptions z = {0}; 475 476 *pp = z; 477 *owned_dirs = NULL; 478 *owned_sizes = NULL; 479 *owned_count = 0; 480 481 include_dirs = (const char**)driver_alloc_zeroed( 482 env, (size_t)ninc * sizeof(*include_dirs)); 483 system_dirs = (const char**)driver_alloc_zeroed( 484 env, (size_t)nsys * sizeof(*system_dirs)); 485 defs = (KitDefine*)driver_alloc_zeroed(env, (size_t)ndefs * sizeof(*defs)); 486 dirs = 487 (char**)driver_alloc_zeroed(env, (size_t)(ninc + nsys) * sizeof(*dirs)); 488 sizes = 489 (size_t*)driver_alloc_zeroed(env, (size_t)(ninc + nsys) * sizeof(*sizes)); 490 if (!include_dirs || !system_dirs || !defs || !dirs || !sizes) { 491 if (include_dirs) 492 driver_free(env, (void*)include_dirs, 493 (size_t)ninc * sizeof(*include_dirs)); 494 if (system_dirs) 495 driver_free(env, (void*)system_dirs, (size_t)nsys * sizeof(*system_dirs)); 496 if (defs) driver_free(env, defs, (size_t)ndefs * sizeof(*defs)); 497 if (dirs) driver_free(env, dirs, (size_t)(ninc + nsys) * sizeof(*dirs)); 498 if (sizes) driver_free(env, sizes, (size_t)(ninc + nsys) * sizeof(*sizes)); 499 return 1; 500 } 501 502 rt_join_slot(env, &dirs[0], &sizes[0], support->rt_root, 503 "lib/include/common"); 504 rt_store_const_ptr(&include_dirs[0], dirs[0]); 505 rt_join_slot(env, &dirs[1], &sizes[1], support->rt_root, "lib/impl"); 506 rt_store_const_ptr(&include_dirs[1], dirs[1]); 507 rt_join_slot(env, &dirs[2], &sizes[2], support->rt_root, 508 variant->abi_include); 509 rt_store_const_ptr(&include_dirs[2], dirs[2]); 510 if (variant->ldbl128) { 511 rt_join_slot(env, &dirs[3], &sizes[3], support->rt_root, 512 "lib/include/lp64_le_ldbl128"); 513 rt_store_const_ptr(&include_dirs[3], dirs[3]); 514 rt_join_slot(env, &dirs[4], &sizes[4], support->rt_root, "include"); 515 rt_store_const_ptr(&system_dirs[0], dirs[4]); 516 rt_join_slot(env, &dirs[5], &sizes[5], support->rt_root, "include/libc"); 517 rt_store_const_ptr(&system_dirs[1], dirs[5]); 518 d = 6; 519 } else { 520 rt_join_slot(env, &dirs[3], &sizes[3], support->rt_root, "include"); 521 rt_store_const_ptr(&system_dirs[0], dirs[3]); 522 rt_join_slot(env, &dirs[4], &sizes[4], support->rt_root, "include/libc"); 523 rt_store_const_ptr(&system_dirs[1], dirs[4]); 524 d = 5; 525 } 526 for (uint32_t i = 0; i < d; ++i) { 527 if (!dirs[i]) { 528 uint32_t j; 529 for (j = 0; j < d; ++j) 530 if (dirs[j]) driver_free(env, dirs[j], sizes[j]); 531 driver_free(env, (void*)include_dirs, 532 (size_t)ninc * sizeof(*include_dirs)); 533 driver_free(env, (void*)system_dirs, (size_t)nsys * sizeof(*system_dirs)); 534 driver_free(env, defs, (size_t)ndefs * sizeof(*defs)); 535 driver_free(env, dirs, (size_t)(ninc + nsys) * sizeof(*dirs)); 536 driver_free(env, sizes, (size_t)(ninc + nsys) * sizeof(*sizes)); 537 return 1; 538 } 539 } 540 541 defs[0].name = KIT_SLICE_LIT("HAS_INT128"); 542 defs[0].body = variant->has_int128 ? def_int128_1 : def_int128_0; 543 uint32_t i = 1; 544 if (variant->ldbl128) { 545 defs[i].name = KIT_SLICE_LIT("KITRT_LDBL128"); 546 defs[i].body = KIT_SLICE_LIT("1"); 547 ++i; 548 } 549 if (assembler) { 550 defs[i].name = KIT_SLICE_LIT("__ASSEMBLER__"); 551 defs[i].body = KIT_SLICE_LIT("1"); 552 } 553 554 pp->include_dirs = include_dirs; 555 pp->ninclude_dirs = ninc; 556 pp->system_include_dirs = system_dirs; 557 pp->nsystem_include_dirs = nsys; 558 pp->defines = defs; 559 pp->ndefines = ndefs; 560 *owned_dirs = dirs; 561 *owned_sizes = sizes; 562 *owned_count = d; 563 return 0; 564 } 565 566 static void rt_free_pp(DriverEnv* env, KitPreprocessOptions* pp, 567 char** owned_dirs, size_t* owned_sizes, 568 uint32_t owned_count) { 569 uint32_t i; 570 for (i = 0; i < owned_count; ++i) 571 if (owned_dirs[i]) driver_free(env, owned_dirs[i], owned_sizes[i]); 572 if (owned_dirs) 573 driver_free(env, owned_dirs, (size_t)owned_count * sizeof(*owned_dirs)); 574 if (owned_sizes) 575 driver_free(env, owned_sizes, (size_t)owned_count * sizeof(*owned_sizes)); 576 if (pp->include_dirs) 577 driver_free(env, (void*)pp->include_dirs, 578 (size_t)pp->ninclude_dirs * sizeof(*pp->include_dirs)); 579 if (pp->system_include_dirs) 580 driver_free( 581 env, (void*)pp->system_include_dirs, 582 (size_t)pp->nsystem_include_dirs * sizeof(*pp->system_include_dirs)); 583 if (pp->defines) 584 driver_free(env, (void*)pp->defines, 585 (size_t)pp->ndefines * sizeof(*pp->defines)); 586 } 587 588 static int rt_compile_source(DriverEnv* env, 589 const DriverRuntimeSupport* support, 590 const RuntimeVariant* variant, const char* tool, 591 KitCompiler* compiler, const char* rel, 592 KitArInput* member, KitWriter** obj_writer) { 593 KitContext ctx = driver_env_to_context(env); 594 char* lib_path = NULL; 595 char* src_path = NULL; 596 size_t lib_path_size = 0; 597 size_t src_path_size = 0; 598 DriverLoad src_load = {0}; 599 KitSlice input = {0}; 600 KitWriter* writer = NULL; 601 KitWriter* pp_writer = NULL; 602 const uint8_t* obj_data; 603 size_t obj_len = 0; 604 KitStatus st; 605 int is_asm; 606 int preprocess_asm; 607 int rc = 1; 608 609 *obj_writer = NULL; 610 lib_path = rt_join(env, support->rt_root, "lib", &lib_path_size); 611 if (!lib_path) goto out; 612 src_path = rt_join(env, lib_path, rel, &src_path_size); 613 if (!src_path) goto out; 614 if (driver_load_bytes(ctx.file_io, tool, src_path, &src_load, &input) != 0) 615 goto out; 616 if (kit_writer_mem(ctx.heap, &writer) != KIT_OK) goto out; 617 618 is_asm = driver_has_suffix(rel, ".s") || driver_has_suffix(rel, ".S"); 619 preprocess_asm = driver_has_suffix(rel, ".S"); 620 if (is_asm) { 621 KitAsmCompileOptions aopts = {0}; 622 KitSlice asm_input = input; 623 if (preprocess_asm) { 624 KitPreprocessOptions pp; 625 char** owned_dirs = NULL; 626 size_t* owned_sizes = NULL; 627 uint32_t owned_count = 0; 628 if (rt_prepare_pp(env, support, variant, 1, &pp, &owned_dirs, 629 &owned_sizes, &owned_count) != 0) 630 goto out; 631 if (kit_writer_mem(ctx.heap, &pp_writer) != KIT_OK) { 632 rt_free_pp(env, &pp, owned_dirs, owned_sizes, owned_count); 633 goto out; 634 } 635 st = kit_cpp_preprocess(compiler, &pp, kit_slice_cstr(src_path), &input, 636 pp_writer); 637 rt_free_pp(env, &pp, owned_dirs, owned_sizes, owned_count); 638 if (st != KIT_OK || kit_writer_status(pp_writer) != KIT_OK) goto out; 639 asm_input.data = kit_writer_mem_bytes(pp_writer, &asm_input.len); 640 } 641 { 642 KitCompileSessionOptions sopts; 643 KitCompileSession* session = NULL; 644 KitSourceInput sin; 645 KitObjBuilder* ob = NULL; 646 memset(&sopts, 0, sizeof(sopts)); 647 sopts.lang = KIT_LANG_ASM; 648 sopts.compile.code = aopts.code; 649 sopts.compile.diagnostics = aopts.diagnostics; 650 sopts.compile.language_options = &aopts; 651 memset(&sin, 0, sizeof(sin)); 652 sin.name = kit_slice_cstr(src_path); 653 sin.bytes = asm_input; 654 sin.lang = KIT_LANG_ASM; 655 st = kit_compile_session_new(compiler, &sopts, &session); 656 if (st == KIT_OK) st = kit_compile_session_compile(session, &sin, &ob); 657 if (st == KIT_OK) st = kit_obj_builder_emit(ob, writer); 658 kit_obj_builder_free(ob); 659 kit_compile_session_free(session); 660 } 661 } else { 662 KitCCompileOptions copts = {0}; 663 KitPreprocessOptions pp = {0}; 664 KitCompileSessionOptions sopts; 665 KitCompileSession* session = NULL; 666 KitSourceInput sin; 667 KitObjBuilder* ob = NULL; 668 char** owned_dirs = NULL; 669 size_t* owned_sizes = NULL; 670 uint32_t owned_count = 0; 671 if (rt_prepare_pp(env, support, variant, 0, &pp, &owned_dirs, &owned_sizes, 672 &owned_count) != 0) 673 goto out; 674 memset(&sopts, 0, sizeof(sopts)); 675 sopts.lang = KIT_LANG_C; 676 sopts.compile.code = copts.code; 677 sopts.compile.diagnostics = copts.diagnostics; 678 sopts.compile.preprocess = pp; 679 memset(&sin, 0, sizeof(sin)); 680 sin.name = kit_slice_cstr(src_path); 681 sin.bytes = input; 682 sin.lang = KIT_LANG_C; 683 st = kit_compile_session_new(compiler, &sopts, &session); 684 if (st == KIT_OK) st = kit_compile_session_compile(session, &sin, &ob); 685 if (st == KIT_OK) st = kit_obj_builder_emit(ob, writer); 686 kit_obj_builder_free(ob); 687 kit_compile_session_free(session); 688 rt_free_pp(env, &pp, owned_dirs, owned_sizes, owned_count); 689 } 690 if (st != KIT_OK || kit_writer_status(writer) != KIT_OK) { 691 driver_errf(tool, "failed to build runtime source: %.*s", 692 KIT_SLICE_ARG(kit_slice_cstr(src_path))); 693 goto out; 694 } 695 696 obj_data = kit_writer_mem_bytes(writer, &obj_len); 697 member->name = kit_slice_cstr(driver_basename(rel)); 698 member->bytes.data = obj_data; 699 member->bytes.len = obj_len; 700 *obj_writer = writer; 701 writer = NULL; 702 rc = 0; 703 704 out: 705 if (pp_writer) kit_writer_close(pp_writer); 706 if (writer) kit_writer_close(writer); 707 driver_release_bytes(ctx.file_io, &src_load); 708 if (src_path) driver_free(env, src_path, src_path_size); 709 if (lib_path) driver_free(env, lib_path, lib_path_size); 710 return rc; 711 } 712 713 static int rt_build_archive(DriverEnv* env, const DriverRuntimeSupport* support, 714 const RuntimeVariant* variant, const char* tool, 715 uint64_t epoch, const char* archive_path) { 716 KitContext ctx = driver_env_to_context(env); 717 KitTarget* resolved_target = NULL; 718 KitCompiler* compiler = NULL; 719 KitWriter* archive_writer = NULL; 720 KitArInput* members = NULL; 721 KitWriter** obj_writers = NULL; 722 KitArWriteOptions ar_opts = {0}; 723 KitTargetSpec target; 724 uint32_t i; 725 int rc = 1; 726 727 members = (KitArInput*)driver_alloc_zeroed( 728 env, (size_t)variant->nsources * sizeof(*members)); 729 obj_writers = (KitWriter**)driver_alloc_zeroed( 730 env, (size_t)variant->nsources * sizeof(*obj_writers)); 731 if (!members || !obj_writers) { 732 driver_errf(tool, "out of memory"); 733 goto out; 734 } 735 736 target.arch = variant->arch; 737 target.os = variant->os; 738 target.obj = variant->obj; 739 target.ptr_size = variant->ptr_size; 740 target.ptr_align = variant->ptr_align; 741 target.big_endian = 0; 742 target.pic = KIT_PIC_NONE; 743 target.code_model = KIT_CM_DEFAULT; 744 target.float_abi = KIT_FLOAT_ABI_DEFAULT; /* resolved from abi below */ 745 746 { 747 KitTargetOptions topts; 748 memset(&topts, 0, sizeof topts); 749 topts.spec = target; 750 /* Build the runtime with the variant's -march/-mabi. NULL leaves the arch 751 * defaults (every non-rv32 variant); rv32 pins them so the soft ilp32 and 752 * hard ilp32f archives are each compiled correctly, and kit_target_new 753 * resolves spec.float_abi from the ABI string to match the call sites. */ 754 if (variant->isa) topts.isa = kit_slice_cstr(variant->isa); 755 if (variant->abi) topts.abi = kit_slice_cstr(variant->abi); 756 if (kit_target_new(&ctx, &topts, &resolved_target) != KIT_OK || 757 driver_compiler_new(resolved_target, &ctx, &compiler) != KIT_OK) { 758 driver_errf(tool, "failed to initialize compiler for runtime"); 759 goto out; 760 } 761 } 762 763 for (i = 0; i < variant->nsources; ++i) { 764 if (rt_compile_source(env, support, variant, tool, compiler, 765 variant->sources[i], &members[i], 766 &obj_writers[i]) != 0) 767 goto out; 768 } 769 770 if (ctx.file_io->open_writer(ctx.file_io->user, archive_path, 771 &archive_writer) != KIT_OK) { 772 driver_errf(tool, "failed to open runtime archive: %.*s", 773 KIT_SLICE_ARG(kit_slice_cstr(archive_path))); 774 goto out; 775 } 776 777 ar_opts.epoch = epoch; 778 ar_opts.long_names = 1; 779 if (kit_ar_write(archive_writer, members, variant->nsources, &ar_opts) != 780 KIT_OK) { 781 driver_errf(tool, "failed to write runtime archive: %.*s", 782 KIT_SLICE_ARG(kit_slice_cstr(archive_path))); 783 goto out; 784 } 785 rc = 0; 786 787 out: 788 if (archive_writer) kit_writer_close(archive_writer); 789 if (compiler) driver_compiler_free(compiler); 790 kit_target_free(resolved_target); 791 if (obj_writers) { 792 for (i = 0; i < variant->nsources; ++i) 793 if (obj_writers[i]) kit_writer_close(obj_writers[i]); 794 driver_free(env, obj_writers, 795 (size_t)variant->nsources * sizeof(*obj_writers)); 796 } 797 if (members) 798 driver_free(env, members, (size_t)variant->nsources * sizeof(*members)); 799 return rc; 800 } 801 802 static int rt_is_archive_stale(DriverEnv* env, 803 const DriverRuntimeSupport* support, 804 const RuntimeVariant* variant, 805 const char* archive_path) { 806 int64_t archive_mtime; 807 int64_t tool_mtime; 808 uint32_t i; 809 if (driver_path_mtime_ns(archive_path, &archive_mtime) != 0) return 1; 810 if (support->tool_path && 811 driver_path_mtime_ns(support->tool_path, &tool_mtime) == 0 && 812 tool_mtime > archive_mtime) 813 return 1; 814 for (i = 0; i < variant->nsources; ++i) { 815 char* lib_path; 816 char* src_path; 817 size_t lib_path_size = 0; 818 size_t src_path_size = 0; 819 int64_t src_mtime; 820 int stale = 0; 821 lib_path = rt_join(env, support->rt_root, "lib", &lib_path_size); 822 if (!lib_path) return 1; 823 src_path = rt_join(env, lib_path, variant->sources[i], &src_path_size); 824 driver_free(env, lib_path, lib_path_size); 825 if (!src_path) return 1; 826 if (driver_path_mtime_ns(src_path, &src_mtime) != 0 || 827 src_mtime > archive_mtime) 828 stale = 1; 829 driver_free(env, src_path, src_path_size); 830 if (stale) return 1; 831 } 832 return 0; 833 } 834 835 static char* rt_archive_dir_for_root(DriverEnv* env, const char* root, 836 const RuntimeVariant* variant, 837 size_t* out_size) { 838 char* build_rt; 839 char* dir = NULL; 840 size_t build_rt_size = 0; 841 size_t dir_size = 0; 842 build_rt = rt_join(env, root, "build/rt", &build_rt_size); 843 if (!build_rt) return NULL; 844 dir = rt_join(env, build_rt, variant->key, &dir_size); 845 driver_free(env, build_rt, build_rt_size); 846 if (out_size) *out_size = dir ? dir_size : 0; 847 return dir; 848 } 849 850 static int rt_archive_try_dir(DriverEnv* env, const char* tool, 851 const DriverRuntimeSupport* support, 852 const RuntimeVariant* variant, uint64_t epoch, 853 const char* cache_dir, char** out_path, 854 size_t* out_path_size) { 855 char* archive_path; 856 size_t archive_path_size = 0; 857 858 archive_path = rt_join(env, cache_dir, "libkit_rt.a", &archive_path_size); 859 if (!archive_path) { 860 driver_errf(tool, "out of memory"); 861 return 1; 862 } 863 864 if (!driver_path_exists(archive_path) || 865 rt_is_archive_stale(env, support, variant, archive_path)) { 866 if (driver_mkdir_p(env, cache_dir) != 0) { 867 driver_free(env, archive_path, archive_path_size); 868 return 2; 869 } 870 if (rt_build_archive(env, support, variant, tool, epoch, archive_path) != 871 0) { 872 driver_errf(tool, "compiler runtime for %.*s could not be built", 873 KIT_SLICE_ARG(kit_slice_cstr(variant->key))); 874 driver_errf(tool, "support dir: %.*s", 875 KIT_SLICE_ARG(kit_slice_cstr(support->support_root))); 876 driver_free(env, archive_path, archive_path_size); 877 return 1; 878 } 879 } 880 881 *out_path = archive_path; 882 *out_path_size = archive_path_size; 883 return 0; 884 } 885 886 int driver_runtime_ensure_archive(DriverEnv* env, const char* tool, 887 const DriverRuntimeSupport* support, 888 KitTargetSpec target, uint64_t epoch, 889 char** out_path, size_t* out_path_size) { 890 const RuntimeVariant* variant = rt_variant_for_target(target); 891 const char* diag_tool = tool ? tool : "rt"; 892 char* in_tree_dir = NULL; /* <support_root>/build/rt/<variant> */ 893 char* cache_dir = NULL; /* <env->cache_dir>/<variant> */ 894 size_t in_tree_dir_size = 0; 895 size_t cache_dir_size = 0; 896 char* primary_dir; 897 char* fallback_dir; 898 int primary_rc; 899 int fallback_rc = 1; 900 901 *out_path = NULL; 902 *out_path_size = 0; 903 904 if (!variant) { 905 driver_errf(diag_tool, "compiler runtime is not available for this target"); 906 return 1; 907 } 908 909 /* In-tree location, shared with `make rt` when support_root is a checkout. */ 910 in_tree_dir = rt_archive_dir_for_root(env, support->support_root, variant, 911 &in_tree_dir_size); 912 if (!in_tree_dir) { 913 driver_errf(diag_tool, "out of memory"); 914 return 1; 915 } 916 /* User cache location, outside any support/install tree. */ 917 if (env->cache_dir) { 918 cache_dir = rt_join(env, env->cache_dir, variant->key, &cache_dir_size); 919 if (!cache_dir) { 920 driver_free(env, in_tree_dir, in_tree_dir_size); 921 driver_errf(diag_tool, "out of memory"); 922 return 1; 923 } 924 } 925 926 /* A distribution install is not a build tree: prefer the user cache dir and 927 * keep the in-tree dir only as a fallback so the build never writes into the 928 * install. A checkout (or explicit --support-dir) keeps the historical 929 * in-tree-first order, sharing `make rt`'s build/rt cache per checkout. */ 930 if (support->install_layout && cache_dir) { 931 primary_dir = cache_dir; 932 fallback_dir = in_tree_dir; 933 } else { 934 primary_dir = in_tree_dir; 935 fallback_dir = cache_dir; 936 } 937 938 primary_rc = rt_archive_try_dir(env, diag_tool, support, variant, epoch, 939 primary_dir, out_path, out_path_size); 940 if (primary_rc == 0) { 941 if (cache_dir) driver_free(env, cache_dir, cache_dir_size); 942 driver_free(env, in_tree_dir, in_tree_dir_size); 943 return 0; 944 } 945 946 if (primary_rc != 2) { 947 if (cache_dir) driver_free(env, cache_dir, cache_dir_size); 948 driver_free(env, in_tree_dir, in_tree_dir_size); 949 return 1; 950 } 951 952 if (fallback_dir) { 953 fallback_rc = rt_archive_try_dir(env, diag_tool, support, variant, epoch, 954 fallback_dir, out_path, out_path_size); 955 } 956 957 if (fallback_rc == 2 || !fallback_dir) { 958 driver_errf(diag_tool, "failed to create runtime cache: %.*s", 959 KIT_SLICE_ARG(kit_slice_cstr(primary_dir))); 960 if (fallback_dir) { 961 driver_errf(diag_tool, "failed to create runtime cache: %.*s", 962 KIT_SLICE_ARG(kit_slice_cstr(fallback_dir))); 963 } 964 } 965 if (cache_dir) driver_free(env, cache_dir, cache_dir_size); 966 driver_free(env, in_tree_dir, in_tree_dir_size); 967 return fallback_rc == 0 ? 0 : 1; 968 } 969 970 int driver_runtime_prepare_archive(DriverEnv* env, const char* tool, 971 const DriverRuntimeSupport* support, 972 KitTargetSpec target, uint64_t epoch, 973 DriverRuntimeArchive* out) { 974 DriverRuntimeArchive z = {0}; 975 if (!out) return 1; 976 *out = z; 977 if (driver_runtime_ensure_archive(env, tool, support, target, epoch, 978 &out->path, &out->path_size) != 0) 979 return 1; 980 out->whole_archive = 0; 981 out->link_mode = KIT_LM_STATIC; 982 out->group_id = 0; 983 return 0; 984 } 985 986 void driver_runtime_archive_fini(DriverEnv* env, DriverRuntimeArchive* a) { 987 if (!a) return; 988 if (a->path) driver_free(env, a->path, a->path_size); 989 a->path = NULL; 990 a->path_size = 0; 991 a->whole_archive = 0; 992 a->link_mode = 0; 993 a->group_id = 0; 994 }