ld.c (116595B)
1 #include <kit/core.h> 2 #include <kit/link.h> 3 #include <kit/object.h> 4 #include <stdint.h> 5 #include <string.h> 6 7 #include "driver.h" 8 #include "hosted.h" 9 #include "lib_resolve.h" 10 #include "link_flags.h" 11 #include "link_inputs.h" 12 #include "runtime.h" 13 14 /* `kit ld` — link object/archive inputs into an executable, shared 15 * library, or relocatable object. The driver loads each input via 16 * env.file_io, optionally parses a `-T` linker script into the structured 17 * form, and calls the public link APIs directly so the full link surface 18 * (per-archive flags, group cycling, build-id, soname/rpath/exports) is 19 * reachable without thickening the convenience KitOptions struct. 20 * 21 * Supported flags: 22 * -o out output path (required, exactly one) 23 * -e symbol entry symbol 24 * -T script.ld linker script (parsed, not raw) 25 * --support-dir DIR kit support root for compiler rt 26 * --sysroot DIR / -syslibroot DIR hosted C runtime/sysroot root 27 * -L dir library search path (-l targets) 28 * -F dir framework search path 29 * -l c enable hosted CRT/libc expansion 30 * -l name resolves via -L (.so preferred unless 31 * -Bstatic/-static) 32 * -framework name resolves via -F / SDK framework dirs 33 * -static / -pie / -no-pie target.pic 34 * -shared emit a shared library / dylib 35 * -r / --relocatable emit a relocatable partial-link object 36 * -soname NAME DT_SONAME / LC_ID_DYLIB 37 * -rpath DIR DT_RPATH/DT_RUNPATH entry (repeatable) 38 * -rpath-link DIR shared-lib search at link time 39 * (repeatable; accepted, currently advisory) 40 * --enable-new-dtags rpath entries emit as DT_RUNPATH 41 * (default) 42 * --disable-new-dtags rpath entries emit as DT_RPATH 43 * -E / --export-dynamic promote all defined globals to the 44 * dynamic symbol table 45 * --eh-frame-hdr accepted for GNU ld compatibility 46 * --fix-cortex-a53-843419 accepted for GNU ld compatibility 47 * --whole-archive / --no-whole-archive 48 * positional state for following .a 49 * --gc-sections / --no-gc-sections drop unreferenced sections 50 * -Bstatic / -Bdynamic positional link-mode for following .a 51 * --as-needed / --no-as-needed positional link-mode for following .a 52 * --start-group / --end-group cyclic-resolution group of archives 53 * -z OPT / -zOPT GNU linker option compatibility 54 * --build-id={none|sha256|uuid|0xHEX} 55 * -m i386pep PE/COFF emulation selector (x86_64) 56 * --dynamicbase / --nxcompat accepted for PE GNU ld compatibility 57 */ 58 59 #define LD_TOOL "ld" 60 61 typedef struct LdOptions { 62 DriverEnv* env; 63 const char* driver_path; 64 size_t argv_bound; 65 66 KitTargetSpec target; 67 68 const char* output_path; /* -o */ 69 int output_seen; 70 const char* script_path; /* -T */ 71 int no_default_libs; /* -nostdlib / -nodefaultlibs / --no-default-libs */ 72 int nostdlib; /* -nostdlib: no CRT startup or default libraries */ 73 int nostartfiles; /* -nostartfiles: caller supplies CRT startup */ 74 int pic_explicit; /* -static / -pie / -no-pie / -shared seen */ 75 int target_explicit; /* -target / --target seen */ 76 const char* support_dir; /* --support-dir */ 77 const char* sysroot; /* --sysroot / KIT_SYSROOT */ 78 int pie; /* -pie was requested */ 79 80 /* Shared linker-flag model: entry, pe_subsystem, interp/soname/rpath, the 81 * -Wl, comma flags (defsym/section-start/build-id/map/symbols/cref/...), and 82 * the owned FLAG-string pool that backs them. Populated via the 83 * driver_link_flags_record_* family and consumed by 84 * driver_link_flags_fill_options. */ 85 DriverLinkFlags lf; 86 87 /* Shared link-input model: object/archive/dso arrays, the ordered link-item 88 * list, the -L/-F search paths, and the positional archive flag state 89 * (cur_whole_archive/cur_link_mode/cur_group_id). ld resolves -l/-framework 90 * eagerly into archives/dsos rather than via the pending-lib model, to 91 * preserve GNU GROUP / positional link ordering. */ 92 DriverLinkInputSet inputs; 93 94 int lib_dirs_precollected; /* first pass collected argv -L / --library-path */ 95 char** owned_paths; /* INPUT-path strings: sysroot-rewritten -L/-F dirs and 96 * hosted libdir strings (the FLAG strings live in lf). */ 97 size_t* owned_path_sizes; 98 uint32_t nowned_paths; 99 size_t cap_owned_paths; /* grows independently of argv_bound */ 100 101 /* Shared-library output state. */ 102 int shared; /* -shared */ 103 int relocatable; /* -r / --relocatable */ 104 const char** rpath_links; /* -rpath-link DIR (advisory) */ 105 uint32_t nrpath_links; 106 int export_dynamic; /* -E / --export-dynamic */ 107 int static_link; /* -static: hosted libc should pick static profile */ 108 int wants_hosted_libc; /* libc request: expand crt + libc via hosted resolver */ 109 int windows_ucrt_target; /* *-windows-gnullvm: MinGW UCRT hosted profile */ 110 int explicit_crt_start; /* caller supplied crt1/Scrt1/rcrt1-style start */ 111 int has_compiler_runtime; /* caller supplied compiler builtins/runtime */ 112 DriverHostedPlan hosted; 113 /* Sink for the hosted profile's system includes/defines required by the 114 * shared driver_link_inputs_apply_hosted contract. ld never compiles, so 115 * these are populated but unused (only the plan's lib dirs + crt inputs + 116 * interp matter to the linker). */ 117 DriverCflags cf; 118 119 uint8_t next_group_id; /* increments on --start-group / GROUP() */ 120 121 /* Opt-in: treat `/...` arguments as MSVC link.exe flags. Off by 122 * default so legacy paths like `/usr/lib/foo.o` remain inputs. */ 123 int ms_link_driver; 124 } LdOptions; 125 126 static void ld_usage(void) { 127 driver_errf(LD_TOOL, "%.*s", 128 KIT_SLICE_ARG(KIT_SLICE_LIT( 129 "usage: kit ld -o out [options...] inputs.o|inputs.a...\n" 130 " kit ld --help for full option reference"))); 131 } 132 133 void driver_help_ld(void) { 134 driver_printf( 135 "%.*s", 136 KIT_SLICE_ARG(KIT_SLICE_LIT( 137 "kit ld — link objects and archives into native-format outputs\n" 138 "\n" 139 "USAGE\n" 140 " kit ld -o OUT [options] inputs.o ... inputs.a ...\n" 141 " kit ld -shared -o libfoo.so [options] inputs.o ...\n" 142 " kit ld -r -o partial.o inputs.o ...\n" 143 "\n" 144 "DESCRIPTION\n" 145 " Loads each input directly, optionally parses a -T linker script,\n" 146 " and emits an executable (default), partial-link object (-r), or\n" 147 " ELF shared library (-shared). The full link surface is exposed:\n" 148 " per-archive flags,\n" 149 " cyclic-resolution groups, build-id, soname/rpath/exports.\n" 150 "\n" 151 "INPUTS AND FORMATS\n" 152 " Relocatable ELF, Mach-O, and COFF objects and POSIX ar archives\n" 153 " are accepted. An explicit -target is authoritative; otherwise\n" 154 " the first target-bearing input selects the output target. The\n" 155 " public link boundary validates raw objects, builders, every\n" 156 " archive member, and dynamic/import inputs before creating output.\n" 157 " ELF supports executable, shared, and partial-link output. Mach-O\n" 158 " and PE/COFF support executable and partial-link shapes; -shared\n" 159 " is ELF-only.\n" 160 "\n" 161 "OUTPUT\n" 162 " -o PATH Output path (required, exactly one)\n" 163 " -shared Emit a position-independent ELF shared\n" 164 " library instead of an executable\n" 165 " -r, --relocatable Emit a relocatable partial-link object\n" 166 "\n" 167 "ENTRY / SCRIPT\n" 168 " -e SYMBOL Entry symbol\n" 169 " --subsystem NAME PE subsystem: console or windows\n" 170 " -T SCRIPT.ld Use a linker script (parsed, not raw)\n" 171 "\n" 172 "TARGET\n" 173 " -static Non-PIC, non-PIE\n" 174 " -pie Position-independent executable\n" 175 " -no-pie Disable PIE\n" 176 " -target TRIPLE Authoritative output target\n" 177 " --support-dir DIR kit support root for compiler " 178 "runtime\n" 179 " --sysroot DIR hosted C runtime/sysroot root\n" 180 " (target is otherwise auto-detected from the first object input)\n" 181 " Support is resolved from the canonical executable path; a\n" 182 " relocated release discovers its sibling support automatically.\n" 183 " --support-dir remains an authoritative override. -l c engages\n" 184 " hosted resolution; native macOS discovers its SDK automatically.\n" 185 " Other cross-hosted links need --sysroot unless the caller supplies\n" 186 " its own startup objects and system libraries.\n" 187 "\n" 188 "LIBRARY RESOLUTION\n" 189 " -L DIR Add library search path\n" 190 " -l c Add hosted CRT objects and libc\n" 191 " -l NAME Resolve via -L (.so preferred unless " 192 "static)\n" 193 "\n" 194 "POSITIONAL ARCHIVE STATE (apply to following .a inputs)\n" 195 " --whole-archive Pull every member of following " 196 "archives\n" 197 " --no-whole-archive Reset (default behaviour)\n" 198 " -Bstatic Force static link mode\n" 199 " -Bdynamic Force dynamic link mode\n" 200 " --as-needed Link only if a real reference exists\n" 201 " --no-as-needed Reset to dynamic\n" 202 " --start-group ...\n" 203 " --end-group Cyclic-resolution archive group\n" 204 " Outside a group, archives are searched left to right: place an\n" 205 " object that references a symbol before the archive defining it.\n"))); 206 driver_printf( 207 "%.*s", 208 KIT_SLICE_ARG(KIT_SLICE_LIT( 209 "\n" 210 "SHARED-LIBRARY OPTIONS (require -shared)\n" 211 " -soname NAME DT_SONAME / LC_ID_DYLIB\n" 212 " -soname=NAME equivalent attached form\n" 213 " -rpath DIR DT_RPATH/DT_RUNPATH entry (repeatable)\n" 214 " -rpath=DIR attached form\n" 215 " -rpath-link DIR Link-time-only search path (advisory)\n" 216 " --enable-new-dtags rpaths land in DT_RUNPATH (default)\n" 217 " --disable-new-dtags rpaths land in DT_RPATH\n" 218 "\n" 219 "SECTION GC\n" 220 " --gc-sections Drop sections unreferenced from the " 221 "entry\n" 222 " symbol, init/fini arrays, " 223 "SHF_GNU_RETAIN,\n" 224 " and __start_/__stop_ section " 225 "references\n" 226 " --no-gc-sections Disable section GC (default)\n" 227 " -E, --export-dynamic Promote defined globals into dynsym\n" 228 " (no-op for -shared; recorded for exe)\n" 229 " --eh-frame-hdr Accepted for GNU ld compatibility\n" 230 " -S, --strip-debug Omit debug info from linked output\n" 231 " --no-undefined Reject unresolved symbols\n" 232 " --allow-undefined Permit unresolved strong symbols\n" 233 " -z defs Same as --no-undefined\n" 234 " --map FILE, -Map FILE Write a deterministic link map\n" 235 " --symbols FILE Write post-link absolute symbols\n" 236 " --symbols-format=nm Symbol output format (default)\n" 237 "\n" 238 "BUILD ID\n" 239 " --build-id Same as --build-id=sha256\n" 240 " --build-id=MODE none | sha256 | uuid | 0xHEX\n" 241 "\n" 242 "EXAMPLES\n" 243 " # Hosted link with a user-supplied sysroot.\n" 244 " SYSROOT=/replace/with/hosted-sysroot\n" 245 " kit ld --sysroot \"$SYSROOT\" -l c -o hello hello.o\n" 246 " # Archive order: main.o references symbols in libfoo.a.\n" 247 " kit ld -o app main.o libfoo.a\n" 248 " kit ld -r -o combined.o a.o b.o\n" 249 " kit ld -shared -soname libfoo.so.1 -o libfoo.so foo.pic.o\n" 250 " # Freestanding final link; link.ld must define the memory map.\n" 251 " kit ld -T link.ld \\\n" 252 " -e _start -o kernel.elf start.o\n" 253 "\n" 254 "GETTING HELP\n" 255 " -h, --help Show this help and exit\n" 256 "\n" 257 "EXIT CODES\n" 258 " 0 success 1 link error 2 bad usage\n"))); 259 } 260 261 /* ---------- argv-sized scratch arrays ---------- */ 262 263 static int ld_alloc_arrays(LdOptions* o, int argc) { 264 size_t bound = (size_t)argc + 32u; 265 o->argv_bound = bound; 266 o->owned_paths = driver_alloc_zeroed(o->env, bound * sizeof(*o->owned_paths)); 267 o->owned_path_sizes = 268 driver_alloc_zeroed(o->env, bound * sizeof(*o->owned_path_sizes)); 269 o->cap_owned_paths = bound; 270 o->rpath_links = driver_alloc_zeroed(o->env, bound * sizeof(*o->rpath_links)); 271 if (!o->owned_paths || !o->owned_path_sizes || !o->rpath_links) { 272 driver_errf(LD_TOOL, "out of memory"); 273 return 1; 274 } 275 if (driver_link_flags_init(&o->lf, o->env, LD_TOOL, (uint32_t)bound) != 0) 276 return 1; 277 if (driver_link_inputs_init(&o->inputs, o->env, LD_TOOL, bound) != 0) 278 return 1; 279 /* Sized for the hosted profile's includes/defines only (ld parses no -D/-I); 280 * see the cf comment in LdOptions. */ 281 if (driver_cflags_init(&o->cf, o->env, 282 (int)(DRIVER_HOSTED_MAX_DEFINES + 283 DRIVER_HOSTED_MAX_INCLUDES)) != 0) { 284 driver_errf(LD_TOOL, "out of memory"); 285 return 1; 286 } 287 return 0; 288 } 289 290 /* ---------- positional archive bookkeeping ---------- */ 291 292 static int ld_str_prefix(const char* s, const char* prefix) { 293 size_t n = driver_strlen(prefix); 294 return driver_strneq(s, prefix, n); 295 } 296 297 static const char* ld_basename(const char* path) { 298 const char* slash = strrchr(path, '/'); 299 return slash ? slash + 1 : path; 300 } 301 302 static int ld_is_compiler_runtime_archive(const char* path) { 303 const char* base = ld_basename(path); 304 if ((ld_str_prefix(base, "libcompiler_builtins") && 305 (driver_has_suffix(base, ".rlib") || driver_has_suffix(base, ".a"))) || 306 (ld_str_prefix(base, "libclang_rt.builtins") && 307 driver_has_suffix(base, ".a")) || 308 driver_streq(base, "libgcc.a") || driver_streq(base, "libgcc_eh.a")) { 309 return 1; 310 } 311 return 0; 312 } 313 314 static int ld_is_compiler_runtime_libname(const char* name) { 315 return driver_streq(name, "gcc") || driver_streq(name, "gcc_eh") || 316 driver_streq(name, "compiler_builtins") || 317 ld_str_prefix(name, "clang_rt.builtins"); 318 } 319 320 static int ld_is_crt_start_object(const char* path) { 321 const char* base = ld_basename(path); 322 return driver_streq(base, "crt1.o") || driver_streq(base, "Scrt1.o") || 323 driver_streq(base, "rcrt1.o") || driver_streq(base, "gcrt1.o") || 324 driver_streq(base, "crt0.o"); 325 } 326 327 static void ld_note_object_path(LdOptions* o, const char* path) { 328 if (ld_is_crt_start_object(path)) o->explicit_crt_start = 1; 329 } 330 331 /* Fill the next free archive slot in the shared input set (without ordering) 332 * and return its index, noting compiler-runtime archives along the way. */ 333 static uint32_t ld_add_archive_slot(LdOptions* o, const char* path, int owned, 334 size_t owned_size, uint8_t whole_archive, 335 uint8_t link_mode, uint8_t group_id) { 336 DriverArchiveInput* a = &o->inputs.archives[o->inputs.narchives++]; 337 if (ld_is_compiler_runtime_archive(path)) o->has_compiler_runtime = 1; 338 a->path = path; 339 a->owned = owned; 340 a->owned_size = owned_size; 341 a->whole_archive = whole_archive; 342 a->link_mode = link_mode; 343 a->group_id = group_id; 344 return o->inputs.narchives - 1u; 345 } 346 347 static uint32_t ld_add_dso_slot(LdOptions* o, const char* path, int owned, 348 size_t owned_size) { 349 DriverDsoInput* d = &o->inputs.dsos[o->inputs.ndsos++]; 350 d->path = path; 351 d->owned = owned; 352 d->owned_size = owned_size; 353 return o->inputs.ndsos - 1u; 354 } 355 356 static uint32_t ld_add_object_slot(LdOptions* o, const char* path) { 357 ld_note_object_path(o, path); 358 o->inputs.object_files[o->inputs.nobject_files++] = path; 359 return o->inputs.nobject_files - 1u; 360 } 361 362 static void ld_push_object(LdOptions* o, const char* path) { 363 uint32_t idx = ld_add_object_slot(o, path); 364 driver_link_inputs_push(&o->inputs, DRIVER_LINK_OBJECT, idx); 365 } 366 367 static void ld_push_archive(LdOptions* o, const char* path, int owned, 368 size_t owned_size) { 369 uint32_t idx = ld_add_archive_slot( 370 o, path, owned, owned_size, o->inputs.cur_whole_archive, 371 o->inputs.cur_link_mode, o->inputs.cur_group_id); 372 driver_link_inputs_push(&o->inputs, DRIVER_LINK_ARCHIVE, idx); 373 } 374 375 static void ld_push_dso(LdOptions* o, const char* path, int owned, 376 size_t owned_size) { 377 uint32_t idx = ld_add_dso_slot(o, path, owned, owned_size); 378 driver_link_inputs_push(&o->inputs, DRIVER_LINK_DSO, idx); 379 } 380 381 static int ld_order_capacity(LdOptions* o, uint32_t nmore) { 382 if (o->inputs.nlink_items + nmore <= o->argv_bound) return 0; 383 driver_errf(LD_TOOL, "too many linker inputs"); 384 return 1; 385 } 386 387 static int ld_archive_capacity(LdOptions* o) { 388 if (o->inputs.narchives < o->argv_bound) return 0; 389 driver_errf(LD_TOOL, "too many archive inputs"); 390 return 1; 391 } 392 393 static int ld_dso_capacity(LdOptions* o) { 394 if (o->inputs.ndsos < o->argv_bound) return 0; 395 driver_errf(LD_TOOL, "too many shared-object inputs"); 396 return 1; 397 } 398 399 static int ld_object_capacity(LdOptions* o) { 400 if (o->inputs.nobject_files < o->argv_bound) return 0; 401 driver_errf(LD_TOOL, "too many object inputs"); 402 return 1; 403 } 404 405 /* Filename ends in `.so` (with no further extension) or in `.so.N` 406 * for some run of digits and dots. */ 407 static int driver_is_so_filename(const char* path) { 408 size_t n = driver_strlen(path); 409 size_t i; 410 /* Walk from the end: trim trailing ".N" / ".N.N" sequences if any, 411 * then check that we land on ".so". */ 412 i = n; 413 while (i > 0) { 414 /* Strip a trailing ".<digits>" cluster (e.g. ".1", ".26"). */ 415 size_t end = i; 416 size_t j = i; 417 while (j > 0) { 418 char c = path[j - 1]; 419 if (c >= '0' && c <= '9') { 420 --j; 421 continue; 422 } 423 break; 424 } 425 if (j < end && j > 0 && path[j - 1] == '.') { 426 i = j - 1; 427 continue; 428 } 429 break; 430 } 431 if (i >= 3 && path[i - 3] == '.' && path[i - 2] == 's' && path[i - 1] == 'o') 432 return 1; 433 return 0; 434 } 435 436 static char* ld_join2(DriverEnv* env, const char* a, const char* b, 437 size_t* out_size) { 438 size_t alen = driver_strlen(a); 439 size_t blen = driver_strlen(b); 440 size_t slash = (alen > 0 && a[alen - 1] != '/') ? 1u : 0u; 441 size_t bytes = alen + slash + blen + 1u; 442 char* out = driver_alloc(env, bytes); 443 size_t off = 0; 444 if (!out) return NULL; 445 if (alen) { 446 driver_memcpy(out + off, a, alen); 447 off += alen; 448 } 449 if (slash) out[off++] = '/'; 450 if (blen) { 451 driver_memcpy(out + off, b, blen); 452 off += blen; 453 } 454 out[off] = '\0'; 455 if (out_size) *out_size = bytes; 456 return out; 457 } 458 459 /* Ensure room for one more owned string. The owned-string pool is NOT bounded 460 * by argc: a single -Wl token (--section-start / --defsym) mints two or three 461 * owned cstrings, so a fixed argv+N cap would reject valid input. Double the 462 * two parallel arrays together when full. */ 463 static int ld_grow_owned(LdOptions* o) { 464 size_t nc; 465 char** np; 466 size_t* ns; 467 if (o->nowned_paths < o->cap_owned_paths) return 0; 468 nc = o->cap_owned_paths ? o->cap_owned_paths * 2u : 8u; 469 if (nc <= o->cap_owned_paths) { 470 driver_errf(LD_TOOL, "out of memory"); 471 return 1; 472 } 473 np = driver_alloc_zeroed(o->env, nc * sizeof(*np)); 474 ns = driver_alloc_zeroed(o->env, nc * sizeof(*ns)); 475 if (!np || !ns) { 476 if (np) driver_free(o->env, np, nc * sizeof(*np)); 477 if (ns) driver_free(o->env, ns, nc * sizeof(*ns)); 478 driver_errf(LD_TOOL, "out of memory"); 479 return 1; 480 } 481 if (o->owned_paths) { 482 driver_memcpy(np, o->owned_paths, o->nowned_paths * sizeof(*np)); 483 driver_free(o->env, o->owned_paths, o->cap_owned_paths * sizeof(*np)); 484 } 485 if (o->owned_path_sizes) { 486 driver_memcpy(ns, o->owned_path_sizes, o->nowned_paths * sizeof(*ns)); 487 driver_free(o->env, o->owned_path_sizes, o->cap_owned_paths * sizeof(*ns)); 488 } 489 o->owned_paths = np; 490 o->owned_path_sizes = ns; 491 o->cap_owned_paths = nc; 492 return 0; 493 } 494 495 static int ld_own_path(LdOptions* o, char* path, size_t size, 496 const char** out) { 497 if (!path) { 498 driver_errf(LD_TOOL, "out of memory"); 499 return 1; 500 } 501 if (ld_grow_owned(o) != 0) { 502 driver_free(o->env, path, size); 503 return 1; 504 } 505 o->owned_paths[o->nowned_paths] = path; 506 o->owned_path_sizes[o->nowned_paths] = size; 507 o->nowned_paths++; 508 if (out) *out = path; 509 return 0; 510 } 511 512 static int ld_add_lib_dir(LdOptions* o, const char* dir) { 513 if (o->inputs.nlib_search_paths >= o->argv_bound) { 514 driver_errf(LD_TOOL, "too many library search paths"); 515 return 1; 516 } 517 o->inputs.lib_search_paths[o->inputs.nlib_search_paths++] = dir; 518 return 0; 519 } 520 521 static int ld_add_framework_dir(LdOptions* o, const char* dir) { 522 if (o->inputs.nframework_search_paths >= o->argv_bound) { 523 driver_errf(LD_TOOL, "too many framework search paths"); 524 return 1; 525 } 526 o->inputs.framework_search_paths[o->inputs.nframework_search_paths++] = dir; 527 return 0; 528 } 529 530 static int ld_add_sysroot_libdir(LdOptions* o) { 531 char* path; 532 size_t size; 533 const char* owned; 534 if (!o->sysroot || !o->sysroot[0]) return 0; 535 path = ld_join2(o->env, o->sysroot, "lib", &size); 536 if (ld_own_path(o, path, size, &owned) != 0) return 1; 537 if (ld_add_lib_dir(o, owned) != 0) return 1; 538 path = ld_join2(o->env, o->sysroot, "usr/lib", &size); 539 if (ld_own_path(o, path, size, &owned) != 0) return 1; 540 if (ld_add_lib_dir(o, owned) != 0) return 1; 541 if (o->target.os == KIT_OS_WINDOWS) { 542 path = ld_join2(o->env, o->sysroot, "lib/windows", &size); 543 if (ld_own_path(o, path, size, &owned) != 0) return 1; 544 if (ld_add_lib_dir(o, owned) != 0) return 1; 545 } 546 return 0; 547 } 548 549 static int ld_add_sysroot_framework_dirs(LdOptions* o) { 550 char* path; 551 size_t size; 552 const char* owned; 553 if (!driver_target_uses_framework_dirs(o->target)) return 0; 554 if (!o->sysroot || !o->sysroot[0]) return 0; 555 path = ld_join2(o->env, o->sysroot, "System/Library/Frameworks", &size); 556 if (ld_own_path(o, path, size, &owned) != 0) return 1; 557 if (ld_add_framework_dir(o, owned) != 0) return 1; 558 path = 559 ld_join2(o->env, o->sysroot, "System/Library/PrivateFrameworks", &size); 560 if (ld_own_path(o, path, size, &owned) != 0) return 1; 561 if (ld_add_framework_dir(o, owned) != 0) return 1; 562 return 0; 563 } 564 565 static int ld_sysroot_rewrite_path(LdOptions* o, const char* path, 566 const char** out) { 567 const char* tail; 568 char* joined; 569 size_t size; 570 if (!path || path[0] != '=' || !o->sysroot || !o->sysroot[0]) { 571 *out = path; 572 return 0; 573 } 574 tail = path + 1; 575 if (tail[0] == '/') tail++; 576 joined = ld_join2(o->env, o->sysroot, tail, &size); 577 return ld_own_path(o, joined, size, out); 578 } 579 580 static int ld_note_library_request(LdOptions* o, const char* name) { 581 if (ld_is_compiler_runtime_libname(name)) o->has_compiler_runtime = 1; 582 if (driver_streq(name, "c") && !o->nostdlib && !o->nostartfiles && 583 !o->explicit_crt_start) { 584 o->wants_hosted_libc = 1; 585 return 1; 586 } 587 if (o->windows_ucrt_target && 588 (driver_streq(name, "msvcrt") || driver_streq(name, "ucrt")) && 589 !o->nostdlib && !o->nostartfiles && !o->explicit_crt_start) { 590 o->wants_hosted_libc = 1; 591 return 1; 592 } 593 return 0; 594 } 595 596 static const char* ld_windows_runtime_alias(LdOptions* o, const char* name) { 597 if (o->target.os != KIT_OS_WINDOWS) return NULL; 598 if (driver_streq(name, "gcc_eh")) return "unwind"; 599 if (!driver_streq(name, "gcc")) return NULL; 600 switch (o->target.arch) { 601 case KIT_ARCH_X86_64: 602 return "clang_rt.builtins-x86_64"; 603 case KIT_ARCH_ARM_64: 604 return "clang_rt.builtins-aarch64"; 605 default: 606 return NULL; 607 } 608 } 609 610 static LibResolveKind ld_kind_for_exact_lib(const char* leaf) { 611 if (driver_has_suffix(leaf, ".tbd")) return LIB_RESOLVE_KIND_TBD; 612 if (driver_has_suffix(leaf, ".so") || driver_has_suffix(leaf, ".dylib")) 613 return LIB_RESOLVE_KIND_SHARED; 614 return LIB_RESOLVE_KIND_ARCHIVE; 615 } 616 617 static int ld_resolve_exact_library(LdOptions* o, const char* leaf, 618 char** out_path, size_t* out_size, 619 LibResolveKind* out_kind) { 620 uint32_t i; 621 if (!leaf || !leaf[0]) return 1; 622 for (i = 0; i < o->inputs.nlib_search_paths; ++i) { 623 size_t size = 0; 624 char* cand = 625 driver_path_join(o->env, o->inputs.lib_search_paths[i], leaf, &size); 626 if (!cand) return 1; 627 if (driver_path_exists(cand)) { 628 *out_path = cand; 629 *out_size = size; 630 if (out_kind) *out_kind = ld_kind_for_exact_lib(leaf); 631 return 0; 632 } 633 driver_free(o->env, cand, size); 634 } 635 if (driver_path_exists(leaf)) { 636 size_t n = driver_strlen(leaf); 637 char* cand = driver_alloc(o->env, n + 1u); 638 if (!cand) return 1; 639 driver_memcpy(cand, leaf, n + 1u); 640 *out_path = cand; 641 *out_size = n + 1u; 642 if (out_kind) *out_kind = ld_kind_for_exact_lib(leaf); 643 return 0; 644 } 645 return 1; 646 } 647 648 static int ld_resolve_library(LdOptions* o, const char* name, 649 LibResolveMode mode, LibResolveOS resolve_os, 650 char** out_path, size_t* out_size, 651 LibResolveKind* out_kind) { 652 const char* alias; 653 if (name && name[0] == ':') 654 return ld_resolve_exact_library(o, name + 1, out_path, out_size, out_kind); 655 if (driver_lib_resolve_for_os(o->env, name, mode, resolve_os, 656 o->inputs.lib_search_paths, 657 o->inputs.nlib_search_paths, out_path, out_size, 658 out_kind) == 0) 659 return 0; 660 if (resolve_os != LIB_RESOLVE_OS_WINDOWS) return 1; 661 alias = ld_windows_runtime_alias(o, name); 662 if (!alias) return 1; 663 return driver_lib_resolve_for_os(o->env, alias, mode, resolve_os, 664 o->inputs.lib_search_paths, 665 o->inputs.nlib_search_paths, out_path, 666 out_size, out_kind); 667 } 668 669 static int ld_resolve_framework(LdOptions* o, const char* name, 670 char** out_path, size_t* out_size) { 671 LibResolveKind kind; 672 return driver_framework_resolve(o->env, name, o->inputs.framework_search_paths, 673 o->inputs.nframework_search_paths, out_path, 674 out_size, &kind); 675 } 676 677 static int ld_push_framework(LdOptions* o, const char* name) { 678 char* resolved; 679 size_t resolved_size; 680 if (!name || !name[0]) { 681 driver_errf(LD_TOOL, "-framework requires an argument"); 682 return 1; 683 } 684 if (ld_resolve_framework(o, name, &resolved, &resolved_size) != 0) { 685 driver_errf(LD_TOOL, "cannot find -framework %.*s", 686 KIT_SLICE_ARG(kit_slice_cstr(name))); 687 return 1; 688 } 689 ld_push_dso(o, resolved, 1, resolved_size); 690 return 0; 691 } 692 693 static int ld_tok_eq(const char* tok, size_t n, const char* lit) { 694 size_t ln = driver_strlen(lit); 695 return n == ln && driver_strneq(tok, lit, ln); 696 } 697 698 static int ld_tok_prefix(const char* tok, size_t n, const char* lit) { 699 size_t ln = driver_strlen(lit); 700 return n >= ln && driver_strneq(tok, lit, ln); 701 } 702 703 static int ld_span_to_owned_cstr(LdOptions* o, const char* s, size_t n, 704 const char** out) { 705 size_t bytes = n + 1u; 706 char* buf; 707 if (bytes == 0) { 708 driver_errf(LD_TOOL, "out of memory"); 709 return 1; 710 } 711 buf = driver_alloc(o->env, bytes); 712 if (!buf) { 713 driver_errf(LD_TOOL, "out of memory"); 714 return 1; 715 } 716 if (n) driver_memcpy(buf, s, n); 717 buf[n] = '\0'; 718 return ld_own_path(o, buf, bytes, out); 719 } 720 721 static int ld_set_target_triple(LdOptions* o, const char* triple) { 722 KitTargetSpec t; 723 uint8_t pic; 724 if (!triple) { 725 driver_errf(LD_TOOL, "-target requires an argument"); 726 return 1; 727 } 728 if (driver_target_from_triple(triple, &t) != 0) { 729 driver_err_unknown_target(LD_TOOL, triple); 730 return 1; 731 } 732 o->windows_ucrt_target = strstr(triple, "windows-gnullvm") != NULL; 733 pic = o->target.pic; 734 o->target = t; 735 if (o->pic_explicit) 736 o->target.pic = pic; 737 else 738 o->target.pic = driver_default_pic(o->target.obj, o->target.os); 739 o->target_explicit = 1; 740 return 0; 741 } 742 743 static int ld_set_gnu_emulation(LdOptions* o, const char* emu) { 744 uint8_t pic; 745 KitTargetSpec t; 746 if (!emu) { 747 driver_errf(LD_TOOL, "-m requires an argument"); 748 return 1; 749 } 750 if (driver_streq(emu, "i386pep")) { 751 memset(&t, 0, sizeof t); 752 t.arch = KIT_ARCH_X86_64; 753 t.os = KIT_OS_WINDOWS; 754 t.obj = KIT_OBJ_COFF; 755 t.ptr_size = 8; 756 t.ptr_align = 8; 757 } else if (driver_streq(emu, "arm64pe")) { 758 memset(&t, 0, sizeof t); 759 t.arch = KIT_ARCH_ARM_64; 760 t.os = KIT_OS_WINDOWS; 761 t.obj = KIT_OBJ_COFF; 762 t.ptr_size = 8; 763 t.ptr_align = 8; 764 } else { 765 driver_errf(LD_TOOL, "unsupported GNU ld emulation: %.*s", 766 KIT_SLICE_ARG(kit_slice_cstr(emu))); 767 return 1; 768 } 769 if (o->target_explicit) return 0; 770 pic = o->target.pic; 771 o->target = t; 772 if (o->pic_explicit) 773 o->target.pic = pic; 774 else 775 o->target.pic = driver_default_pic(o->target.obj, o->target.os); 776 return 0; 777 } 778 779 static int ld_is_pe_gnu_noop(const char* tok, size_t n) { 780 return ld_tok_eq(tok, n, "--dynamicbase") || 781 ld_tok_eq(tok, n, "--disable-auto-image-base") || 782 ld_tok_eq(tok, n, "--enable-auto-image-base") || 783 ld_tok_eq(tok, n, "--high-entropy-va") || 784 ld_tok_eq(tok, n, "--nxcompat"); 785 } 786 787 static int ld_is_cc_driver_noop(const char* tok, size_t n) { 788 return ld_tok_eq(tok, n, "-m32") || ld_tok_eq(tok, n, "-m64") || 789 ld_tok_eq(tok, n, "-fno-use-linker-plugin") || 790 ld_tok_eq(tok, n, "-nolibc") || 791 ld_tok_prefix(tok, n, "--unwindlib="); 792 } 793 794 static int ld_parse_wl(LdOptions* o, const char* arg) { 795 const char* p = arg; 796 int expect_rpath = 0; 797 int expect_soname = 0; 798 int expect_interp = 0; 799 int expect_z = 0; 800 int expect_emulation = 0; 801 int expect_map = 0; 802 int expect_symbols = 0; 803 int expect_defsym = 0; 804 int expect_section_start = 0; 805 int expect_cref = 0; 806 int expect_orphan = 0; 807 int expect_framework = 0; 808 int expect_framework_dir = 0; 809 while (*p) { 810 const char* tok = p; 811 size_t n = 0; 812 while (p[n] && p[n] != ',') ++n; 813 p = tok + n + (tok[n] == ',' ? 1u : 0u); 814 815 if (expect_rpath || expect_soname || expect_interp || expect_z || 816 expect_emulation || expect_map || expect_symbols || expect_defsym || 817 expect_section_start || expect_cref || expect_orphan || 818 expect_framework || expect_framework_dir) { 819 if (expect_defsym) { 820 if (driver_link_flags_record_defsym(&o->lf, tok, n) != 0) return 1; 821 } else if (expect_section_start) { 822 if (driver_link_flags_record_section_start(&o->lf, tok, n) != 0) 823 return 1; 824 } else if (expect_framework) { 825 const char* owned; 826 if (ld_span_to_owned_cstr(o, tok, n, &owned) != 0) return 1; 827 if (ld_push_framework(o, owned) != 0) return 1; 828 } else if (expect_framework_dir) { 829 const char* owned; 830 if (ld_span_to_owned_cstr(o, tok, n, &owned) != 0) return 1; 831 if (ld_add_framework_dir(o, owned) != 0) return 1; 832 } else if (expect_cref) { 833 if (driver_link_flags_record_cref(&o->lf, tok, n) != 0) return 1; 834 } else if (expect_orphan) { 835 if (driver_link_flags_record_orphan_handling(&o->lf, tok, n) != 0) 836 return 1; 837 } else if (expect_rpath) { 838 const char* owned; 839 if (ld_span_to_owned_cstr(o, tok, n, &owned) != 0) return 1; 840 o->lf.rpaths[o->lf.nrpaths++] = owned; 841 } else if (expect_soname) { 842 const char* owned; 843 if (ld_span_to_owned_cstr(o, tok, n, &owned) != 0) return 1; 844 o->lf.soname = owned; 845 } else if (expect_interp) { 846 const char* owned; 847 if (ld_span_to_owned_cstr(o, tok, n, &owned) != 0) return 1; 848 o->lf.interp_path = owned; 849 } else if (expect_z) { 850 if (driver_link_flags_record_z(&o->lf, tok, n) != 0) return 1; 851 } else if (expect_emulation) { 852 const char* owned; 853 if (ld_span_to_owned_cstr(o, tok, n, &owned) != 0) return 1; 854 if (ld_set_gnu_emulation(o, owned) != 0) return 1; 855 } else if (expect_map) { 856 if (driver_link_flags_record_map(&o->lf, tok, n) != 0) return 1; 857 } else if (expect_symbols) { 858 if (driver_link_flags_record_symbols(&o->lf, tok, n) != 0) return 1; 859 } 860 expect_rpath = expect_soname = expect_interp = expect_z = 861 expect_emulation = expect_map = expect_symbols = expect_defsym = 862 expect_section_start = expect_cref = expect_orphan = 863 expect_framework = expect_framework_dir = 0; 864 continue; 865 } 866 867 if (ld_tok_eq(tok, n, "-dead_strip") || 868 ld_tok_eq(tok, n, "--gc-sections")) { 869 o->lf.gc_sections = 1; 870 continue; 871 } 872 if (ld_tok_eq(tok, n, "--no-gc-sections")) { 873 o->lf.gc_sections = 0; 874 continue; 875 } 876 if (ld_tok_eq(tok, n, "--no-undefined")) { 877 o->lf.allow_undefined = 0; 878 continue; 879 } 880 if (ld_tok_eq(tok, n, "--allow-undefined") || 881 ld_tok_eq(tok, n, "--allow-shlib-undefined")) { 882 o->lf.allow_undefined = 1; 883 continue; 884 } 885 if (ld_tok_eq(tok, n, "--map") || ld_tok_eq(tok, n, "-Map")) { 886 expect_map = 1; 887 continue; 888 } 889 if (ld_tok_prefix(tok, n, "--map=")) { 890 if (driver_link_flags_record_map(&o->lf, tok + 6, n - 6u) != 0) return 1; 891 continue; 892 } 893 if (ld_tok_prefix(tok, n, "-Map=")) { 894 if (n == 5) { 895 driver_errf(LD_TOOL, "-Map requires a non-empty path"); 896 return 1; 897 } 898 if (driver_link_flags_record_map(&o->lf, tok + 5, n - 5u) != 0) return 1; 899 continue; 900 } 901 if (ld_tok_eq(tok, n, "--symbols")) { 902 expect_symbols = 1; 903 continue; 904 } 905 if (ld_tok_prefix(tok, n, "--symbols=")) { 906 if (driver_link_flags_record_symbols(&o->lf, tok + 10, n - 10u) != 0) 907 return 1; 908 continue; 909 } 910 if (ld_tok_prefix(tok, n, "--symbols-format=")) { 911 if (driver_link_flags_record_symbols_format(&o->lf, tok + 17, n - 17u) != 912 0) 913 return 1; 914 continue; 915 } 916 if (ld_tok_eq(tok, n, "-Bstatic")) { 917 o->inputs.cur_link_mode = KIT_LM_STATIC; 918 continue; 919 } 920 if (ld_tok_eq(tok, n, "-Bdynamic")) { 921 o->inputs.cur_link_mode = KIT_LM_DYNAMIC; 922 continue; 923 } 924 if (ld_tok_eq(tok, n, "--as-needed")) { 925 o->inputs.cur_link_mode = KIT_LM_AS_NEEDED; 926 continue; 927 } 928 if (ld_tok_eq(tok, n, "--no-as-needed")) { 929 o->inputs.cur_link_mode = KIT_LM_DYNAMIC; 930 continue; 931 } 932 if (ld_tok_eq(tok, n, "--whole-archive")) { 933 o->inputs.cur_whole_archive = 1; 934 continue; 935 } 936 if (ld_tok_eq(tok, n, "--no-whole-archive")) { 937 o->inputs.cur_whole_archive = 0; 938 continue; 939 } 940 if (ld_tok_eq(tok, n, "-z")) { 941 expect_z = 1; 942 continue; 943 } 944 if (n > 2 && tok[0] == '-' && tok[1] == 'z') { 945 if (driver_link_flags_record_z(&o->lf, tok + 2, n - 2) != 0) return 1; 946 continue; 947 } 948 if (ld_tok_eq(tok, n, "--eh-frame-hdr") || 949 ld_tok_eq(tok, n, "--fix-cortex-a53-843419")) 950 continue; 951 if (ld_is_cc_driver_noop(tok, n)) continue; 952 if (ld_is_pe_gnu_noop(tok, n)) continue; 953 if (ld_tok_eq(tok, n, "-m")) { 954 expect_emulation = 1; 955 continue; 956 } 957 if (ld_tok_eq(tok, n, "-nostdlib")) { 958 o->no_default_libs = 1; 959 o->nostdlib = 1; 960 o->nostartfiles = 1; 961 continue; 962 } 963 if (ld_tok_eq(tok, n, "-nostartfiles")) { 964 o->nostartfiles = 1; 965 continue; 966 } 967 if (ld_tok_eq(tok, n, "-nodefaultlibs") || 968 ld_tok_eq(tok, n, "--no-default-libs")) { 969 o->no_default_libs = 1; 970 continue; 971 } 972 if (ld_tok_eq(tok, n, "-S") || ld_tok_eq(tok, n, "--strip-debug")) { 973 o->lf.strip_debug = 1; 974 continue; 975 } 976 if (ld_tok_eq(tok, n, "-E") || ld_tok_eq(tok, n, "--export-dynamic")) { 977 o->export_dynamic = 1; 978 continue; 979 } 980 if (ld_tok_eq(tok, n, "--enable-new-dtags")) { 981 o->lf.new_dtags = 1; 982 continue; 983 } 984 if (ld_tok_eq(tok, n, "--disable-new-dtags")) { 985 o->lf.new_dtags = 0; 986 continue; 987 } 988 if (ld_tok_eq(tok, n, "-rpath")) { 989 expect_rpath = 1; 990 continue; 991 } 992 if (ld_tok_eq(tok, n, "-framework")) { 993 expect_framework = 1; 994 continue; 995 } 996 if (ld_tok_eq(tok, n, "-F")) { 997 expect_framework_dir = 1; 998 continue; 999 } 1000 if (n > 2 && tok[0] == '-' && tok[1] == 'F') { 1001 const char* owned; 1002 if (ld_span_to_owned_cstr(o, tok + 2, n - 2u, &owned) != 0) return 1; 1003 if (ld_add_framework_dir(o, owned) != 0) return 1; 1004 continue; 1005 } 1006 if (ld_tok_prefix(tok, n, "-rpath=")) { 1007 const char* owned; 1008 if (ld_span_to_owned_cstr(o, tok + 7, n - 7u, &owned) != 0) return 1; 1009 o->lf.rpaths[o->lf.nrpaths++] = owned; 1010 continue; 1011 } 1012 if (ld_tok_eq(tok, n, "-soname")) { 1013 expect_soname = 1; 1014 continue; 1015 } 1016 if (ld_tok_prefix(tok, n, "-soname=")) { 1017 const char* owned; 1018 if (ld_span_to_owned_cstr(o, tok + 8, n - 8u, &owned) != 0) return 1; 1019 o->lf.soname = owned; 1020 continue; 1021 } 1022 if (ld_tok_eq(tok, n, "-dynamic-linker") || 1023 ld_tok_eq(tok, n, "--dynamic-linker")) { 1024 expect_interp = 1; 1025 continue; 1026 } 1027 if (ld_tok_prefix(tok, n, "-dynamic-linker=")) { 1028 const char* owned; 1029 if (ld_span_to_owned_cstr(o, tok + 16, n - 16u, &owned) != 0) return 1; 1030 o->lf.interp_path = owned; 1031 continue; 1032 } 1033 /* -Tdata / -Tbss section base overrides. */ 1034 if (ld_tok_eq(tok, n, "-Tdata") || ld_tok_eq(tok, n, "-Tbss")) { 1035 const char* secname = ld_tok_eq(tok, n, "-Tdata") ? ".data" : ".bss"; 1036 const char* atok = p; 1037 size_t an = 0; 1038 const char* addr_owned; 1039 if (!*atok) { 1040 driver_errf(LD_TOOL, "%.*s requires an address", (int)n, tok); 1041 return 1; 1042 } 1043 while (atok[an] && atok[an] != ',') ++an; 1044 p = atok + an + (atok[an] == ',' ? 1u : 0u); 1045 if (ld_span_to_owned_cstr(o, atok, an, &addr_owned) != 0) return 1; 1046 if (driver_link_flags_record_section_addr(&o->lf, secname, addr_owned) != 1047 0) 1048 return 1; 1049 continue; 1050 } 1051 if (ld_tok_prefix(tok, n, "-Tdata=")) { 1052 const char* addr_owned; 1053 if (ld_span_to_owned_cstr(o, tok + 7, n - 7u, &addr_owned) != 0) return 1; 1054 if (driver_link_flags_record_section_addr(&o->lf, ".data", addr_owned) != 1055 0) 1056 return 1; 1057 continue; 1058 } 1059 if (ld_tok_prefix(tok, n, "-Tbss=")) { 1060 const char* addr_owned; 1061 if (ld_span_to_owned_cstr(o, tok + 6, n - 6u, &addr_owned) != 0) return 1; 1062 if (driver_link_flags_record_section_addr(&o->lf, ".bss", addr_owned) != 1063 0) 1064 return 1; 1065 continue; 1066 } 1067 if (ld_tok_prefix(tok, n, "--defsym=")) { 1068 if (driver_link_flags_record_defsym(&o->lf, tok + 9, n - 9u) != 0) 1069 return 1; 1070 continue; 1071 } 1072 if (ld_tok_eq(tok, n, "--defsym")) { 1073 expect_defsym = 1; 1074 continue; 1075 } 1076 if (ld_tok_prefix(tok, n, "--section-start=")) { 1077 if (driver_link_flags_record_section_start(&o->lf, tok + 16, n - 16u) != 0) 1078 return 1; 1079 continue; 1080 } 1081 if (ld_tok_eq(tok, n, "--section-start")) { 1082 expect_section_start = 1; 1083 continue; 1084 } 1085 if (ld_tok_prefix(tok, n, "--cref=")) { 1086 if (driver_link_flags_record_cref(&o->lf, tok + 7, n - 7u) != 0) return 1; 1087 continue; 1088 } 1089 if (ld_tok_eq(tok, n, "--cref")) { 1090 expect_cref = 1; 1091 continue; 1092 } 1093 if (ld_tok_prefix(tok, n, "--orphan-handling=")) { 1094 if (driver_link_flags_record_orphan_handling(&o->lf, tok + 18, n - 18u) != 1095 0) 1096 return 1; 1097 continue; 1098 } 1099 if (ld_tok_eq(tok, n, "--orphan-handling")) { 1100 expect_orphan = 1; 1101 continue; 1102 } 1103 if (ld_tok_eq(tok, n, "--fatal-warnings")) { 1104 o->lf.fatal_warnings = 1; 1105 continue; 1106 } 1107 if (ld_tok_eq(tok, n, "--no-fatal-warnings")) { 1108 o->lf.fatal_warnings = 0; 1109 continue; 1110 } 1111 if (ld_tok_eq(tok, n, "--print-memory-usage")) { 1112 o->lf.print_memory_usage = 1; 1113 continue; 1114 } 1115 1116 driver_errf(LD_TOOL, "unsupported -Wl, token: %.*s", (int)n, tok); 1117 return 1; 1118 } 1119 if (expect_rpath || expect_soname || expect_interp || expect_z || 1120 expect_emulation || expect_map || expect_symbols || expect_defsym || 1121 expect_section_start || expect_cref || expect_orphan || 1122 expect_framework || expect_framework_dir) { 1123 driver_errf(LD_TOOL, "-Wl option requires another comma argument"); 1124 return 1; 1125 } 1126 return 0; 1127 } 1128 1129 /* ---------- GNU input-script expansion (.so text scripts) ---------- */ 1130 1131 typedef struct LdInputScript { 1132 LdOptions* o; 1133 const char* script_path; 1134 const char* script_dir; 1135 const char* p; 1136 const char* end; 1137 uint32_t order_pos; 1138 uint32_t insert_pos; 1139 uint8_t saw_input_directive; 1140 uint8_t added; 1141 } LdInputScript; 1142 1143 static int ld_is_space_char(char c) { 1144 return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || 1145 c == '\v'; 1146 } 1147 1148 static int ld_is_ident_char(char c) { 1149 return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || 1150 (c >= '0' && c <= '9') || c == '_'; 1151 } 1152 1153 static char ld_ascii_upper(char c) { 1154 return (c >= 'a' && c <= 'z') ? (char)(c - 'a' + 'A') : c; 1155 } 1156 1157 static int ld_span_eq_ci(const char* s, size_t n, const char* lit) { 1158 size_t ln = driver_strlen(lit); 1159 size_t i; 1160 if (n != ln) return 0; 1161 for (i = 0; i < n; ++i) 1162 if (ld_ascii_upper(s[i]) != ld_ascii_upper(lit[i])) return 0; 1163 return 1; 1164 } 1165 1166 static void ld_script_skip_ws(LdInputScript* s) { 1167 for (;;) { 1168 while (s->p < s->end && ld_is_space_char(*s->p)) ++s->p; 1169 if (s->p + 1 < s->end && s->p[0] == '/' && s->p[1] == '*') { 1170 s->p += 2; 1171 while (s->p + 1 < s->end && !(s->p[0] == '*' && s->p[1] == '/')) ++s->p; 1172 if (s->p + 1 < s->end) s->p += 2; 1173 continue; 1174 } 1175 if (s->p < s->end && *s->p == '#') { 1176 while (s->p < s->end && *s->p != '\n') ++s->p; 1177 continue; 1178 } 1179 if (s->p < s->end && (*s->p == ';' || *s->p == ',')) { 1180 ++s->p; 1181 continue; 1182 } 1183 break; 1184 } 1185 } 1186 1187 static int ld_script_try_kw(LdInputScript* s, const char* kw) { 1188 const char* p; 1189 size_t n = driver_strlen(kw); 1190 ld_script_skip_ws(s); 1191 if ((size_t)(s->end - s->p) < n) return 0; 1192 if (!ld_span_eq_ci(s->p, n, kw)) return 0; 1193 p = s->p + n; 1194 if (p < s->end && ld_is_ident_char(*p)) return 0; 1195 s->p = p; 1196 return 1; 1197 } 1198 1199 static void ld_script_skip_balanced(LdInputScript* s) { 1200 int depth = 0; 1201 if (s->p >= s->end || *s->p != '(') return; 1202 while (s->p < s->end) { 1203 char c = *s->p++; 1204 if (c == '"' || c == '\'') { 1205 char q = c; 1206 while (s->p < s->end) { 1207 c = *s->p++; 1208 if (c == '\\' && s->p < s->end) { 1209 ++s->p; 1210 continue; 1211 } 1212 if (c == q) break; 1213 } 1214 continue; 1215 } 1216 if (c == '(') { 1217 ++depth; 1218 } else if (c == ')') { 1219 --depth; 1220 if (depth == 0) return; 1221 } 1222 } 1223 } 1224 1225 static int ld_script_next_token(LdInputScript* s, const char** out, 1226 size_t* out_len) { 1227 const char* start; 1228 char quote; 1229 ld_script_skip_ws(s); 1230 if (s->p >= s->end || *s->p == ')') return 0; 1231 if (*s->p == '(') return 0; 1232 quote = *s->p; 1233 if (quote == '"' || quote == '\'') { 1234 ++s->p; 1235 start = s->p; 1236 while (s->p < s->end && *s->p != quote) { 1237 if (*s->p == '\\' && s->p + 1 < s->end) 1238 s->p += 2; 1239 else 1240 ++s->p; 1241 } 1242 *out = start; 1243 *out_len = (size_t)(s->p - start); 1244 if (s->p < s->end) ++s->p; 1245 return 1; 1246 } 1247 start = s->p; 1248 while (s->p < s->end && !ld_is_space_char(*s->p) && *s->p != '(' && 1249 *s->p != ')' && *s->p != ';' && *s->p != ',') 1250 ++s->p; 1251 if (s->p == start) { 1252 ++s->p; 1253 return 0; 1254 } 1255 *out = start; 1256 *out_len = (size_t)(s->p - start); 1257 return 1; 1258 } 1259 1260 static int ld_path_has_slash(const char* s) { 1261 while (*s) { 1262 if (*s == '/' || *s == '\\') return 1; 1263 ++s; 1264 } 1265 return 0; 1266 } 1267 1268 static int ld_script_dirname(LdOptions* o, const char* path, const char** out) { 1269 const char* slash = strrchr(path, '/'); 1270 size_t n; 1271 if (!slash) { 1272 *out = ""; 1273 return 0; 1274 } 1275 n = (size_t)(slash - path); 1276 if (n == 0) n = 1; /* root directory */ 1277 return ld_span_to_owned_cstr(o, path, n, out); 1278 } 1279 1280 static int ld_script_resolve_file(LdInputScript* s, const char* name, 1281 const char** out_path, int* out_owned, 1282 size_t* out_size) { 1283 LdOptions* o = s->o; 1284 const char* rewritten; 1285 uint32_t i; 1286 *out_path = NULL; 1287 *out_owned = 0; 1288 *out_size = 0; 1289 1290 if (name[0] == '/' || name[0] == '=' || ld_path_has_slash(name)) { 1291 if (ld_sysroot_rewrite_path(o, name, &rewritten) != 0) return 1; 1292 if (!driver_path_exists(rewritten)) { 1293 driver_errf(LD_TOOL, "%.*s: linker script input not found: %.*s", 1294 KIT_SLICE_ARG(kit_slice_cstr(s->script_path)), 1295 KIT_SLICE_ARG(kit_slice_cstr(rewritten))); 1296 return 1; 1297 } 1298 *out_path = rewritten; 1299 return 0; 1300 } 1301 1302 if (s->script_dir && s->script_dir[0]) { 1303 size_t size = 0; 1304 char* cand = driver_path_join(o->env, s->script_dir, name, &size); 1305 if (!cand) { 1306 driver_errf(LD_TOOL, "out of memory"); 1307 return 1; 1308 } 1309 if (driver_path_exists(cand)) { 1310 *out_path = cand; 1311 *out_owned = 1; 1312 *out_size = size; 1313 return 0; 1314 } 1315 driver_free(o->env, cand, size); 1316 } 1317 1318 for (i = 0; i < o->inputs.nlib_search_paths; ++i) { 1319 size_t size = 0; 1320 char* cand = 1321 driver_path_join(o->env, o->inputs.lib_search_paths[i], name, &size); 1322 if (!cand) { 1323 driver_errf(LD_TOOL, "out of memory"); 1324 return 1; 1325 } 1326 if (driver_path_exists(cand)) { 1327 *out_path = cand; 1328 *out_owned = 1; 1329 *out_size = size; 1330 return 0; 1331 } 1332 driver_free(o->env, cand, size); 1333 } 1334 1335 if (driver_path_exists(name)) { 1336 *out_path = name; 1337 return 0; 1338 } 1339 1340 driver_errf(LD_TOOL, "%.*s: linker script input not found: %.*s", 1341 KIT_SLICE_ARG(kit_slice_cstr(s->script_path)), 1342 KIT_SLICE_ARG(kit_slice_cstr(name))); 1343 return 1; 1344 } 1345 1346 /* The GNU INPUT()/GROUP() expander replaces the DSO-script link item at 1347 * `order_pos` with the script's first input, then inserts the rest just after 1348 * it — preserving the script's position in the overall link order. */ 1349 static int ld_script_add_order(LdInputScript* s, uint8_t kind, uint32_t index) { 1350 if (!s->added) { 1351 s->o->inputs.link_items[s->order_pos].kind = kind; 1352 s->o->inputs.link_items[s->order_pos].index = index; 1353 s->insert_pos = s->order_pos + 1u; 1354 s->added = 1; 1355 return 0; 1356 } 1357 if (ld_order_capacity(s->o, 1) != 0) return 1; 1358 driver_link_inputs_insert(&s->o->inputs, s->insert_pos, kind, index); 1359 s->insert_pos++; 1360 return 0; 1361 } 1362 1363 static int ld_script_add_path(LdInputScript* s, const char* path, int owned, 1364 size_t owned_size, int as_needed, 1365 uint8_t group_id) { 1366 LdOptions* o = s->o; 1367 if (driver_has_suffix(path, ".a") || driver_has_suffix(path, ".rlib")) { 1368 uint32_t idx; 1369 if (ld_archive_capacity(o) != 0) goto fail; 1370 idx = ld_add_archive_slot( 1371 o, path, owned, owned_size, o->inputs.cur_whole_archive, 1372 as_needed ? KIT_LM_AS_NEEDED : o->inputs.cur_link_mode, group_id); 1373 return ld_script_add_order(s, DRIVER_LINK_ARCHIVE, idx); 1374 } 1375 if (driver_is_so_filename(path) || driver_has_suffix(path, ".dylib") || 1376 driver_has_suffix(path, ".tbd")) { 1377 uint32_t idx; 1378 if (as_needed) goto skip; 1379 if (ld_dso_capacity(o) != 0) goto fail; 1380 idx = ld_add_dso_slot(o, path, owned, owned_size); 1381 return ld_script_add_order(s, DRIVER_LINK_DSO, idx); 1382 } 1383 { 1384 uint32_t idx; 1385 const char* keep = path; 1386 if (owned) { 1387 if (ld_own_path(o, (char*)path, owned_size, &keep) != 0) return 1; 1388 owned = 0; 1389 owned_size = 0; 1390 } 1391 if (ld_object_capacity(o) != 0) return 1; 1392 idx = ld_add_object_slot(o, keep); 1393 return ld_script_add_order(s, DRIVER_LINK_OBJECT, idx); 1394 } 1395 1396 skip: 1397 if (owned) driver_free(o->env, (void*)path, owned_size); 1398 return 0; 1399 fail: 1400 if (owned) driver_free(o->env, (void*)path, owned_size); 1401 return 1; 1402 } 1403 1404 static int ld_script_add_token(LdInputScript* s, const char* tok, size_t n, 1405 int as_needed, uint8_t group_id) { 1406 LdOptions* o = s->o; 1407 const char* owned_tok = NULL; 1408 const char* path = NULL; 1409 int owned_path = 0; 1410 size_t path_size = 0; 1411 1412 if (n == 0) return 0; 1413 1414 if (n > 2 && tok[0] == '-' && tok[1] == 'l' && tok[2] != ':') { 1415 char* resolved = NULL; 1416 size_t resolved_size = 0; 1417 LibResolveKind kind; 1418 LibResolveMode mode = (o->inputs.cur_link_mode == KIT_LM_STATIC) 1419 ? LIB_RESOLVE_STATIC_ONLY 1420 : LIB_RESOLVE_DYNAMIC_PREFER; 1421 LibResolveOS resolve_os = (o->target.os == KIT_OS_WINDOWS) 1422 ? LIB_RESOLVE_OS_WINDOWS 1423 : LIB_RESOLVE_OS_POSIX; 1424 if (ld_span_to_owned_cstr(o, tok + 2, n - 2u, &owned_tok) != 0) return 1; 1425 if (ld_resolve_library(o, owned_tok, mode, resolve_os, &resolved, 1426 &resolved_size, &kind) != 0) { 1427 driver_errf(LD_TOOL, "%.*s: cannot resolve linker script input -l%.*s", 1428 KIT_SLICE_ARG(kit_slice_cstr(s->script_path)), 1429 KIT_SLICE_ARG(kit_slice_cstr(owned_tok))); 1430 return 1; 1431 } 1432 if ((kind == LIB_RESOLVE_KIND_SHARED || kind == LIB_RESOLVE_KIND_TBD) && 1433 as_needed) { 1434 driver_free(o->env, resolved, resolved_size); 1435 return 0; 1436 } 1437 return ld_script_add_path(s, resolved, 1, resolved_size, as_needed, 1438 group_id); 1439 } 1440 1441 if (n > 3 && tok[0] == '-' && tok[1] == 'l' && tok[2] == ':') { 1442 tok += 3; 1443 n -= 3; 1444 } else if (tok[0] == '-') { 1445 driver_errf(LD_TOOL, "%.*s: unsupported linker script token: %.*s", 1446 KIT_SLICE_ARG(kit_slice_cstr(s->script_path)), (int)n, tok); 1447 return 1; 1448 } 1449 1450 if (ld_span_to_owned_cstr(o, tok, n, &owned_tok) != 0) return 1; 1451 if (ld_script_resolve_file(s, owned_tok, &path, &owned_path, &path_size) != 0) 1452 return 1; 1453 return ld_script_add_path(s, path, owned_path, path_size, as_needed, 1454 group_id); 1455 } 1456 1457 static int ld_script_parse_list(LdInputScript* s, int as_needed, 1458 uint8_t group_id, int group_directive); 1459 1460 static int ld_script_parse_nested(LdInputScript* s, int as_needed, 1461 uint8_t group_id) { 1462 if (ld_script_try_kw(s, "AS_NEEDED")) 1463 return ld_script_parse_list(s, 1, group_id, 0) == 0 ? 1 : -1; 1464 if (ld_script_try_kw(s, "INPUT")) 1465 return ld_script_parse_list(s, as_needed, group_id, 0) == 0 ? 1 : -1; 1466 if (ld_script_try_kw(s, "GROUP")) 1467 return ld_script_parse_list(s, as_needed, group_id, 1) == 0 ? 1 : -1; 1468 return 0; 1469 } 1470 1471 static int ld_script_parse_list(LdInputScript* s, int as_needed, 1472 uint8_t group_id, int group_directive) { 1473 LdOptions* o = s->o; 1474 ld_script_skip_ws(s); 1475 if (s->p >= s->end || *s->p != '(') { 1476 driver_errf(LD_TOOL, "%.*s: expected '(' in linker script input list", 1477 KIT_SLICE_ARG(kit_slice_cstr(s->script_path))); 1478 return 1; 1479 } 1480 ++s->p; 1481 s->saw_input_directive = 1; 1482 if (group_directive && group_id == 0) { 1483 if (o->next_group_id == UINT8_MAX) { 1484 driver_errf(LD_TOOL, "too many GROUP directives in linker scripts"); 1485 return 1; 1486 } 1487 group_id = ++o->next_group_id; 1488 } 1489 for (;;) { 1490 const char* tok; 1491 size_t n; 1492 ld_script_skip_ws(s); 1493 if (s->p >= s->end) { 1494 driver_errf(LD_TOOL, "%.*s: unterminated linker script input list", 1495 KIT_SLICE_ARG(kit_slice_cstr(s->script_path))); 1496 return 1; 1497 } 1498 if (*s->p == ')') { 1499 ++s->p; 1500 return 0; 1501 } 1502 { 1503 int nested = ld_script_parse_nested(s, as_needed, group_id); 1504 if (nested < 0) return 1; 1505 if (nested > 0) continue; 1506 } 1507 ld_script_skip_ws(s); 1508 if (s->p < s->end && *s->p == ')') continue; 1509 if (!ld_script_next_token(s, &tok, &n)) { 1510 driver_errf(LD_TOOL, "%.*s: malformed linker script input", 1511 KIT_SLICE_ARG(kit_slice_cstr(s->script_path))); 1512 return 1; 1513 } 1514 if (ld_script_add_token(s, tok, n, as_needed, group_id) != 0) return 1; 1515 } 1516 } 1517 1518 static int ld_script_parse_input(LdInputScript* s) { 1519 while (s->p < s->end) { 1520 const char* tok; 1521 size_t n; 1522 ld_script_skip_ws(s); 1523 if (s->p >= s->end) break; 1524 if (ld_script_try_kw(s, "INPUT")) { 1525 if (ld_script_parse_list(s, 0, 0, 0) != 0) return 1; 1526 continue; 1527 } 1528 if (ld_script_try_kw(s, "GROUP")) { 1529 if (ld_script_parse_list(s, 0, 0, 1) != 0) return 1; 1530 continue; 1531 } 1532 if (ld_script_try_kw(s, "AS_NEEDED")) { 1533 if (ld_script_parse_list(s, 1, 0, 0) != 0) return 1; 1534 continue; 1535 } 1536 if (!ld_script_next_token(s, &tok, &n)) { 1537 if (s->p < s->end && *s->p == '(') 1538 ld_script_skip_balanced(s); 1539 else if (s->p < s->end) 1540 ++s->p; 1541 continue; 1542 } 1543 ld_script_skip_ws(s); 1544 if (s->p < s->end && *s->p == '(') ld_script_skip_balanced(s); 1545 } 1546 if (s->saw_input_directive && !s->added) { 1547 driver_errf(LD_TOOL, "%.*s: linker script did not add any inputs", 1548 KIT_SLICE_ARG(kit_slice_cstr(s->script_path))); 1549 return 1; 1550 } 1551 return 0; 1552 } 1553 1554 static int ld_try_expand_dso_script(LdOptions* o, uint32_t order_pos, 1555 int* changed) { 1556 const KitFileIO* io = &o->env->file_io; 1557 const DriverLinkItem* ord = &o->inputs.link_items[order_pos]; 1558 const char* path; 1559 KitFileData fd; 1560 LdInputScript s; 1561 const char* dir = NULL; 1562 int rc = 0; 1563 if (ord->kind != DRIVER_LINK_DSO) return 0; 1564 if (ord->index >= o->inputs.ndsos) return 0; 1565 path = o->inputs.dsos[ord->index].path; 1566 if (!path || !io->read_all) return 0; 1567 memset(&fd, 0, sizeof fd); 1568 if (io->read_all(io->user, path, &fd) != KIT_OK) { 1569 driver_errf(LD_TOOL, "failed to read: %.*s", 1570 KIT_SLICE_ARG(kit_slice_cstr(path))); 1571 return 1; 1572 } 1573 if (kit_detect_fmt(fd.data, fd.size) != KIT_BIN_UNKNOWN) { 1574 if (io->release) io->release(io->user, &fd); 1575 return 0; 1576 } 1577 if (ld_script_dirname(o, path, &dir) != 0) { 1578 if (io->release) io->release(io->user, &fd); 1579 return 1; 1580 } 1581 memset(&s, 0, sizeof s); 1582 s.o = o; 1583 s.script_path = path; 1584 s.script_dir = dir; 1585 s.p = (const char*)fd.data; 1586 s.end = s.p + fd.size; 1587 s.order_pos = order_pos; 1588 s.insert_pos = order_pos + 1u; 1589 if (ld_script_parse_input(&s) != 0) { 1590 rc = 1; 1591 } else if (s.added) { 1592 *changed = 1; 1593 } 1594 if (io->release) io->release(io->user, &fd); 1595 return rc; 1596 } 1597 1598 static int ld_expand_dso_scripts(LdOptions* o) { 1599 uint32_t pass; 1600 for (pass = 0; pass < 8u; ++pass) { 1601 uint32_t i; 1602 int changed = 0; 1603 for (i = 0; i < o->inputs.nlink_items; ++i) { 1604 if (ld_try_expand_dso_script(o, i, &changed) != 0) return 1; 1605 } 1606 if (!changed) return 0; 1607 } 1608 driver_errf(LD_TOOL, "too many nested linker-script inputs"); 1609 return 1; 1610 } 1611 1612 /* ---------- argv parser ---------- */ 1613 1614 /* If `arg` starts with `prefix` followed by '=', returns the tail past the 1615 * '='; otherwise returns NULL. */ 1616 static const char* arg_eq_value(const char* arg, const char* prefix) { 1617 size_t n = driver_strlen(prefix); 1618 if (!driver_strneq(arg, prefix, n)) return NULL; 1619 if (arg[n] != '=') return NULL; 1620 return arg + n + 1; 1621 } 1622 1623 /* Compare an MSVC-style flag against `arg`, case-insensitive on the 1624 * key. MSVC accepts both `/` and `-` as the lead char and is 1625 * case-insensitive in the key part — we accept `/KEY:val`, `/key:val`, 1626 * `-KEY:val`. Returns the tail past the colon, or NULL on mismatch. */ 1627 static const char* ms_flag_value(const char* arg, const char* key) { 1628 size_t klen = driver_strlen(key); 1629 size_t i; 1630 if (arg[0] != '/' && arg[0] != '-') return NULL; 1631 for (i = 0; i < klen; ++i) { 1632 char a = arg[1 + i]; 1633 char k = key[i]; 1634 if (a >= 'a' && a <= 'z') a = (char)(a - 'a' + 'A'); 1635 if (k >= 'a' && k <= 'z') k = (char)(k - 'a' + 'A'); 1636 if (a != k) return NULL; 1637 } 1638 if (arg[1 + klen] != ':') return NULL; 1639 return arg + 1 + klen + 1; 1640 } 1641 1642 /* Same shape as ms_flag_value but for bare flags (no `:value`). */ 1643 static int ms_flag_match(const char* arg, const char* key) { 1644 size_t klen = driver_strlen(key); 1645 size_t i; 1646 if (arg[0] != '/' && arg[0] != '-') return 0; 1647 for (i = 0; i < klen; ++i) { 1648 char a = arg[1 + i]; 1649 char k = key[i]; 1650 if (a >= 'a' && a <= 'z') a = (char)(a - 'a' + 'A'); 1651 if (k >= 'a' && k <= 'z') k = (char)(k - 'a' + 'A'); 1652 if (a != k) return 0; 1653 } 1654 return arg[1 + klen] == '\0'; 1655 } 1656 1657 /* Parse one MSVC-style argument. Recognized subset (others warn and 1658 * skip — match-but-no-op so legacy build scripts pass cleanly): 1659 * /OUT:path → o->output_path 1660 * /ENTRY:sym → o->entry 1661 * /SUBSYSTEM:CONSOLE|WINDOWS → PE optional-header subsystem; WINDOWS 1662 * also defaults entry to WinMainCRTStartup. 1663 * /DEFAULTLIB:name → equivalent to -l<name>; resolved 1664 * lazily in the same path as -l. 1665 * /LIBPATH:dir → equivalent to -L dir 1666 * 1667 * Returns 1 if consumed, 0 if not a recognized MS flag (caller falls 1668 * through to its existing behaviour), -1 on hard error. */ 1669 static int ld_try_ms_flag(LdOptions* o, const char* a) { 1670 const char* val; 1671 if (!o->ms_link_driver) return 0; 1672 if (a[0] != '/' && a[0] != '-') return 0; 1673 1674 if ((val = ms_flag_value(a, "OUT")) != NULL) { 1675 if (o->output_seen) { 1676 driver_errf(LD_TOOL, "/OUT specified after -o"); 1677 return -1; 1678 } 1679 o->output_path = val; 1680 o->output_seen = 1; 1681 return 1; 1682 } 1683 if ((val = ms_flag_value(a, "ENTRY")) != NULL) { 1684 o->lf.entry = val; 1685 return 1; 1686 } 1687 if ((val = ms_flag_value(a, "LIBPATH")) != NULL) { 1688 if (ld_add_lib_dir(o, val) != 0) return -1; 1689 return 1; 1690 } 1691 if ((val = ms_flag_value(a, "DEFAULTLIB")) != NULL) { 1692 /* Resolve eagerly like -l does, using whatever current link-mode 1693 * state is in effect. Windows mode triggers the .lib/.dll.a/.a 1694 * suffix list. */ 1695 char* resolved; 1696 size_t resolved_size; 1697 LibResolveKind kind; 1698 LibResolveMode mode = (o->inputs.cur_link_mode == KIT_LM_STATIC) 1699 ? LIB_RESOLVE_STATIC_ONLY 1700 : LIB_RESOLVE_DYNAMIC_PREFER; 1701 if (ld_resolve_library(o, val, mode, LIB_RESOLVE_OS_WINDOWS, &resolved, 1702 &resolved_size, &kind) != 0) { 1703 driver_errf(LD_TOOL, "/DEFAULTLIB: cannot find %.*s", 1704 KIT_SLICE_ARG(kit_slice_cstr(val))); 1705 return -1; 1706 } 1707 if (kind == LIB_RESOLVE_KIND_SHARED || kind == LIB_RESOLVE_KIND_TBD) { 1708 ld_push_dso(o, resolved, 1, resolved_size); 1709 } else { 1710 ld_push_archive(o, resolved, 1, resolved_size); 1711 } 1712 return 1; 1713 } 1714 if ((val = ms_flag_value(a, "SUBSYSTEM")) != NULL) { 1715 if (driver_link_flags_record_pe_subsystem(&o->lf, val, 1716 driver_strlen(val)) != 0) 1717 return -1; 1718 return 1; 1719 } 1720 if (ms_flag_match(a, "NOLOGO") || ms_flag_match(a, "VERBOSE") || 1721 ms_flag_match(a, "INCREMENTAL") || ms_flag_match(a, "DEBUG") || 1722 ms_flag_match(a, "DYNAMICBASE") || ms_flag_match(a, "NXCOMPAT")) { 1723 /* Common flags every Windows build script sets; silently accept. */ 1724 return 1; 1725 } 1726 1727 /* Any other `/key[:val]` shape under --ms-link-driver: warn + skip. 1728 * We treat the entire arg as consumed so it doesn't fall through to 1729 * the positional path and try to open a file. */ 1730 driver_errf(LD_TOOL, "ignoring unsupported MS-style flag: %.*s", 1731 KIT_SLICE_ARG(kit_slice_cstr(a))); 1732 return 1; 1733 } 1734 1735 static int ld_parse(int argc, char** argv, LdOptions* o) { 1736 int i; 1737 if (ld_alloc_arrays(o, argc) != 0) return 1; 1738 1739 o->target = driver_host_target(); 1740 1741 /* First pass: detect --ms-link-driver up front so the option can 1742 * appear anywhere on the command line and still affect earlier 1743 * `/...` tokens. Also capture --sysroot before resolving any -l 1744 * entries; GNU ld treats the sysroot as a global search-prefix 1745 * setting, not positional state. Also detect -lc so the hosted lib 1746 * dirs can be pre-populated before -lm / -lpthread etc. are resolved. */ 1747 { 1748 int has_lc = 0; 1749 for (i = 1; i < argc; ++i) { 1750 if (driver_streq(argv[i], "--ms-link-driver")) { 1751 o->ms_link_driver = 1; 1752 continue; 1753 } 1754 if (driver_streq(argv[i], "-nostdlib")) { 1755 o->no_default_libs = 1; 1756 o->nostdlib = 1; 1757 o->nostartfiles = 1; 1758 continue; 1759 } 1760 if (driver_streq(argv[i], "-nostartfiles")) { 1761 o->nostartfiles = 1; 1762 continue; 1763 } 1764 if (driver_streq(argv[i], "--no-default-libs") || 1765 driver_streq(argv[i], "-nodefaultlibs")) { 1766 o->no_default_libs = 1; 1767 continue; 1768 } 1769 if (driver_strneq(argv[i], "-Wl,", 4)) { 1770 const char* wl = argv[i] + 4; 1771 if (strstr(wl, "-nostdlib")) { 1772 o->no_default_libs = 1; 1773 o->nostdlib = 1; 1774 o->nostartfiles = 1; 1775 continue; 1776 } 1777 if (strstr(wl, "-nostartfiles")) { 1778 o->nostartfiles = 1; 1779 continue; 1780 } 1781 if (strstr(wl, "--no-default-libs") || 1782 strstr(wl, "-nodefaultlibs")) { 1783 o->no_default_libs = 1; 1784 continue; 1785 } 1786 continue; 1787 } 1788 if (driver_streq(argv[i], "-target") || 1789 driver_streq(argv[i], "--target")) { 1790 if (i + 1 < argc) { 1791 if (ld_set_target_triple(o, argv[i + 1]) != 0) return 1; 1792 i++; 1793 } 1794 continue; 1795 } 1796 if (driver_strneq(argv[i], "--target=", 9)) { 1797 if (ld_set_target_triple(o, argv[i] + 9) != 0) return 1; 1798 continue; 1799 } 1800 { 1801 int dr = driver_darwin_platform_try_consume( 1802 LD_TOOL, argc, argv, &i, &o->target, o->pic_explicit); 1803 if (dr < 0) return 1; 1804 if (dr > 0) continue; 1805 } 1806 if (ld_is_cc_driver_noop(argv[i], driver_strlen(argv[i]))) { 1807 continue; 1808 } 1809 if (driver_streq(argv[i], "-m")) { 1810 if (i + 1 < argc) { 1811 if (ld_set_gnu_emulation(o, argv[i + 1]) != 0) return 1; 1812 i++; 1813 } 1814 continue; 1815 } 1816 if (driver_strneq(argv[i], "-m", 2) && argv[i][2] != '\0') { 1817 if (ld_set_gnu_emulation(o, argv[i] + 2) != 0) return 1; 1818 continue; 1819 } 1820 if (driver_streq(argv[i], "--sysroot") || 1821 driver_streq(argv[i], "-syslibroot")) { 1822 if (i + 1 < argc) { 1823 o->sysroot = argv[i + 1]; 1824 i++; 1825 } 1826 continue; 1827 } 1828 if (driver_strneq(argv[i], "--sysroot=", 10)) { 1829 o->sysroot = argv[i] + 10; 1830 continue; 1831 } 1832 if (argv[i][0] != '-' && ld_is_crt_start_object(argv[i])) { 1833 o->explicit_crt_start = 1; 1834 continue; 1835 } 1836 /* Detect -lc / -l c so hosted lib dirs are available for later -l 1837 * flags regardless of where -lc appears on the command line. */ 1838 if (driver_streq(argv[i], "-lc")) { 1839 has_lc = 1; 1840 continue; 1841 } 1842 if ((driver_streq(argv[i], "-l") || driver_streq(argv[i], "--library")) && 1843 i + 1 < argc && driver_streq(argv[i + 1], "c")) { 1844 has_lc = 1; 1845 i++; 1846 continue; 1847 } 1848 } 1849 if (!o->sysroot || !o->sysroot[0]) { 1850 const char* env_sysroot = driver_getenv("KIT_SYSROOT"); 1851 if (env_sysroot && env_sysroot[0]) o->sysroot = env_sysroot; 1852 } 1853 /* GNU ld treats -L / --library-path as global library-search state, not 1854 * as a positional option that only affects later -l flags. Pre-collect 1855 * those directories now so Rust-style invocations can put self-contained 1856 * runtime libdirs after an earlier -l. */ 1857 for (i = 1; i < argc; ++i) { 1858 const char* a = argv[i]; 1859 const char* val; 1860 if (driver_strneq(a, "-L", 2)) { 1861 const char* dir = a[2] ? a + 2 : (++i < argc ? argv[i] : NULL); 1862 const char* rewritten; 1863 if (!dir) { 1864 driver_errf(LD_TOOL, "-L requires an argument"); 1865 return 1; 1866 } 1867 if (ld_sysroot_rewrite_path(o, dir, &rewritten) != 0) return 1; 1868 if (ld_add_lib_dir(o, rewritten) != 0) return 1; 1869 continue; 1870 } 1871 if ((val = arg_eq_value(a, "--library-path")) != NULL) { 1872 const char* rewritten; 1873 if (ld_sysroot_rewrite_path(o, val, &rewritten) != 0) return 1; 1874 if (ld_add_lib_dir(o, rewritten) != 0) return 1; 1875 continue; 1876 } 1877 if (driver_streq(a, "--library-path")) { 1878 const char* rewritten; 1879 if (++i >= argc) { 1880 driver_errf(LD_TOOL, "--library-path requires an argument"); 1881 return 1; 1882 } 1883 if (ld_sysroot_rewrite_path(o, argv[i], &rewritten) != 0) return 1; 1884 if (ld_add_lib_dir(o, rewritten) != 0) return 1; 1885 continue; 1886 } 1887 if (driver_strneq(a, "-F", 2)) { 1888 const char* dir = a[2] ? a + 2 : (++i < argc ? argv[i] : NULL); 1889 const char* rewritten; 1890 if (!dir) { 1891 driver_errf(LD_TOOL, "-F requires an argument"); 1892 return 1; 1893 } 1894 if (ld_sysroot_rewrite_path(o, dir, &rewritten) != 0) return 1; 1895 if (ld_add_framework_dir(o, rewritten) != 0) return 1; 1896 continue; 1897 } 1898 } 1899 o->lib_dirs_precollected = 1; 1900 if (ld_add_sysroot_libdir(o) != 0) return 1; 1901 if (ld_add_sysroot_framework_dirs(o) != 0) return 1; 1902 /* Pre-populate the hosted lib dirs so user -l flags are resolved 1903 * against the correct sysroot even when they appear before -lc. */ 1904 if (has_lc && !o->explicit_crt_start) { 1905 DriverHostedRequest req; 1906 DriverHostedDirs dirs; 1907 uint32_t j; 1908 memset(&req, 0, sizeof req); 1909 req.env = o->env; 1910 req.tool = LD_TOOL; 1911 req.target = o->target; 1912 req.sysroot = o->sysroot; 1913 if (driver_hosted_dirs_resolve(&req, &dirs) == 0) { 1914 for (j = 0; j < dirs.nlibdirs; ++j) { 1915 /* Transfer ownership of each dir string to o->owned_paths so 1916 * it is freed in ld_options_release; then point lib_dirs at it. */ 1917 const char* p; 1918 if (ld_own_path(o, dirs.libdirs[j], dirs.libdir_sizes[j], &p) == 0) { 1919 dirs.libdirs[j] = NULL; 1920 dirs.libdir_sizes[j] = 0; 1921 if (ld_add_lib_dir(o, p) != 0) { 1922 driver_hosted_dirs_fini(&dirs); 1923 return 1; 1924 } 1925 } 1926 } 1927 driver_hosted_dirs_fini(&dirs); 1928 } 1929 } 1930 } 1931 1932 for (i = 1; i < argc; ++i) { 1933 const char* a = argv[i]; 1934 const char* val; 1935 int ms_rc; 1936 1937 if (driver_streq(a, "--ms-link-driver")) { 1938 o->ms_link_driver = 1; 1939 continue; 1940 } 1941 ms_rc = ld_try_ms_flag(o, a); 1942 if (ms_rc < 0) return 1; 1943 if (ms_rc > 0) continue; 1944 1945 if (driver_strneq(a, "-Wl,", 4)) { 1946 if (ld_parse_wl(o, a + 4) != 0) return 1; 1947 continue; 1948 } 1949 1950 if (driver_streq(a, "-o")) { 1951 if (++i >= argc) { 1952 driver_errf(LD_TOOL, "-o requires an argument"); 1953 return 1; 1954 } 1955 if (o->output_seen) { 1956 driver_errf(LD_TOOL, "-o specified more than once"); 1957 return 1; 1958 } 1959 o->output_path = argv[i]; 1960 o->output_seen = 1; 1961 continue; 1962 } 1963 if ((val = arg_eq_value(a, "--output")) != NULL) { 1964 if (o->output_seen) { 1965 driver_errf(LD_TOOL, "-o specified more than once"); 1966 return 1; 1967 } 1968 o->output_path = val; 1969 o->output_seen = 1; 1970 continue; 1971 } 1972 if (driver_streq(a, "--output")) { 1973 if (++i >= argc) { 1974 driver_errf(LD_TOOL, "--output requires an argument"); 1975 return 1; 1976 } 1977 if (o->output_seen) { 1978 driver_errf(LD_TOOL, "-o specified more than once"); 1979 return 1; 1980 } 1981 o->output_path = argv[i]; 1982 o->output_seen = 1; 1983 continue; 1984 } 1985 if (driver_streq(a, "-e")) { 1986 if (++i >= argc) { 1987 driver_errf(LD_TOOL, "-e requires an argument"); 1988 return 1; 1989 } 1990 o->lf.entry = argv[i]; 1991 continue; 1992 } 1993 if ((val = arg_eq_value(a, "--entry")) != NULL) { 1994 o->lf.entry = val; 1995 continue; 1996 } 1997 if (driver_streq(a, "--entry")) { 1998 if (++i >= argc) { 1999 driver_errf(LD_TOOL, "--entry requires an argument"); 2000 return 1; 2001 } 2002 o->lf.entry = argv[i]; 2003 continue; 2004 } 2005 if ((val = arg_eq_value(a, "--subsystem")) != NULL) { 2006 if (driver_link_flags_record_pe_subsystem(&o->lf, val, 2007 driver_strlen(val)) != 0) 2008 return 1; 2009 continue; 2010 } 2011 if (driver_streq(a, "--subsystem")) { 2012 if (++i >= argc) { 2013 driver_errf(LD_TOOL, "--subsystem requires an argument"); 2014 return 1; 2015 } 2016 if (driver_link_flags_record_pe_subsystem(&o->lf, argv[i], 2017 driver_strlen(argv[i])) != 0) 2018 return 1; 2019 continue; 2020 } 2021 { 2022 int dr = driver_darwin_platform_try_consume( 2023 LD_TOOL, argc, argv, &i, &o->target, o->pic_explicit); 2024 if (dr < 0) return 1; 2025 if (dr > 0) continue; 2026 } 2027 if (driver_streq(a, "-target") || driver_streq(a, "--target")) { 2028 if (++i >= argc) { 2029 driver_errf(LD_TOOL, "%s requires an argument", a); 2030 return 1; 2031 } 2032 if (ld_set_target_triple(o, argv[i]) != 0) return 1; 2033 continue; 2034 } 2035 if (driver_strneq(a, "--target=", 9)) { 2036 if (ld_set_target_triple(o, a + 9) != 0) return 1; 2037 continue; 2038 } 2039 if (driver_streq(a, "-flavor")) { 2040 if (++i >= argc) { 2041 driver_errf(LD_TOOL, "-flavor requires an argument"); 2042 return 1; 2043 } 2044 if (!driver_streq(argv[i], "gnu")) { 2045 driver_errf(LD_TOOL, "unsupported linker flavor: %s", argv[i]); 2046 return 1; 2047 } 2048 continue; 2049 } 2050 if (ld_is_cc_driver_noop(a, driver_strlen(a))) { 2051 continue; 2052 } 2053 if (driver_streq(a, "-m")) { 2054 if (++i >= argc) { 2055 driver_errf(LD_TOOL, "-m requires an argument"); 2056 return 1; 2057 } 2058 if (ld_set_gnu_emulation(o, argv[i]) != 0) return 1; 2059 continue; 2060 } 2061 if (driver_strneq(a, "-m", 2) && a[2] != '\0') { 2062 if (ld_set_gnu_emulation(o, a + 2) != 0) return 1; 2063 continue; 2064 } 2065 2066 if (driver_streq(a, "-T")) { 2067 if (++i >= argc) { 2068 driver_errf(LD_TOOL, "-T requires an argument"); 2069 return 1; 2070 } 2071 o->script_path = argv[i]; 2072 continue; 2073 } 2074 if ((val = arg_eq_value(a, "--script")) != NULL) { 2075 o->script_path = val; 2076 continue; 2077 } 2078 if (driver_streq(a, "--script")) { 2079 if (++i >= argc) { 2080 driver_errf(LD_TOOL, "--script requires an argument"); 2081 return 1; 2082 } 2083 o->script_path = argv[i]; 2084 continue; 2085 } 2086 /* -Ttext ADDR / -Ttext=ADDR: set the static ET_EXEC image (text) base, for 2087 * freestanding images that must load at a fixed address (e.g. the qemu 2088 * `virt` RAM base 0x80000000). Matched here; the bare "-T" above is an 2089 * exact match, so it never swallows -Ttext. No effect on PIE/scripted 2090 * layouts. */ 2091 { 2092 const char* tval = NULL; 2093 if (driver_streq(a, "-Ttext")) { 2094 if (++i >= argc) { 2095 driver_errf(LD_TOOL, "-Ttext requires an argument"); 2096 return 1; 2097 } 2098 tval = argv[i]; 2099 } else if ((tval = arg_eq_value(a, "-Ttext")) != NULL) { 2100 /* -Ttext=ADDR */ 2101 } 2102 if (tval) { 2103 if (driver_link_flags_record_text_base(&o->lf, tval) != 0) return 1; 2104 continue; 2105 } 2106 } 2107 /* -Tdata / -Tbss ADDR (or =ADDR): per-section address override. Folded 2108 * into the section_starts table as `.data` / `.bss`. */ 2109 { 2110 const char* secname = NULL; 2111 const char* addr = NULL; 2112 if (driver_streq(a, "-Tdata") || driver_streq(a, "-Tbss")) { 2113 secname = driver_streq(a, "-Tdata") ? ".data" : ".bss"; 2114 if (++i >= argc) { 2115 driver_errf(LD_TOOL, "%s requires an address", a); 2116 return 1; 2117 } 2118 addr = argv[i]; 2119 } else if ((addr = arg_eq_value(a, "-Tdata")) != NULL) { 2120 secname = ".data"; 2121 } else if ((addr = arg_eq_value(a, "-Tbss")) != NULL) { 2122 secname = ".bss"; 2123 } 2124 if (secname) { 2125 if (driver_link_flags_record_section_addr(&o->lf, secname, addr) != 0) 2126 return 1; 2127 continue; 2128 } 2129 } 2130 if (driver_streq(a, "--defsym")) { 2131 if (++i >= argc) { 2132 driver_errf(LD_TOOL, "--defsym requires NAME=EXPR"); 2133 return 1; 2134 } 2135 if (driver_link_flags_record_defsym(&o->lf, argv[i], 2136 driver_strlen(argv[i])) != 0) 2137 return 1; 2138 continue; 2139 } 2140 if ((val = arg_eq_value(a, "--defsym")) != NULL) { 2141 if (driver_link_flags_record_defsym(&o->lf, val, driver_strlen(val)) != 0) 2142 return 1; 2143 continue; 2144 } 2145 if (driver_streq(a, "--section-start")) { 2146 if (++i >= argc) { 2147 driver_errf(LD_TOOL, "--section-start requires .NAME=ADDR"); 2148 return 1; 2149 } 2150 if (driver_link_flags_record_section_start( 2151 &o->lf, argv[i], driver_strlen(argv[i])) != 0) 2152 return 1; 2153 continue; 2154 } 2155 if ((val = arg_eq_value(a, "--section-start")) != NULL) { 2156 if (driver_link_flags_record_section_start(&o->lf, val, 2157 driver_strlen(val)) != 0) 2158 return 1; 2159 continue; 2160 } 2161 if (driver_streq(a, "--orphan-handling")) { 2162 if (++i >= argc) { 2163 driver_errf(LD_TOOL, "--orphan-handling requires a mode"); 2164 return 1; 2165 } 2166 if (driver_link_flags_record_orphan_handling( 2167 &o->lf, argv[i], driver_strlen(argv[i])) != 0) 2168 return 1; 2169 continue; 2170 } 2171 if ((val = arg_eq_value(a, "--orphan-handling")) != NULL) { 2172 if (driver_link_flags_record_orphan_handling(&o->lf, val, 2173 driver_strlen(val)) != 0) 2174 return 1; 2175 continue; 2176 } 2177 if (driver_streq(a, "--fatal-warnings")) { 2178 o->lf.fatal_warnings = 1; 2179 continue; 2180 } 2181 if (driver_streq(a, "--no-fatal-warnings")) { 2182 o->lf.fatal_warnings = 0; 2183 continue; 2184 } 2185 if (driver_streq(a, "--print-memory-usage")) { 2186 o->lf.print_memory_usage = 1; 2187 continue; 2188 } 2189 if (driver_streq(a, "--cref")) { 2190 if (++i >= argc) { 2191 driver_errf(LD_TOOL, "--cref requires a path"); 2192 return 1; 2193 } 2194 if (driver_link_flags_record_cref(&o->lf, argv[i], 2195 driver_strlen(argv[i])) != 0) 2196 return 1; 2197 continue; 2198 } 2199 if ((val = arg_eq_value(a, "--cref")) != NULL) { 2200 if (driver_link_flags_record_cref(&o->lf, val, driver_strlen(val)) != 0) 2201 return 1; 2202 continue; 2203 } 2204 /* -nostdlib / --no-default-libs: do not auto-resolve and link kit's 2205 * compiler runtime. A freestanding image (e.g. riscv32-none-elf) supplies 2206 * its own libkit_rt.a on the command line, and a pure-linker invocation 2207 * should not require a per-target runtime archive to exist. */ 2208 if (driver_streq(a, "-nostdlib")) { 2209 o->no_default_libs = 1; 2210 o->nostdlib = 1; 2211 o->nostartfiles = 1; 2212 continue; 2213 } 2214 if (driver_streq(a, "-nostartfiles")) { 2215 o->nostartfiles = 1; 2216 continue; 2217 } 2218 if (driver_streq(a, "--no-default-libs") || 2219 driver_streq(a, "-nodefaultlibs")) { 2220 o->no_default_libs = 1; 2221 continue; 2222 } 2223 if (driver_streq(a, "--support-dir")) { 2224 if (++i >= argc) { 2225 driver_errf(LD_TOOL, "--support-dir requires an argument"); 2226 return 1; 2227 } 2228 o->support_dir = argv[i]; 2229 continue; 2230 } 2231 if (driver_strneq(a, "--support-dir=", 14)) { 2232 o->support_dir = a + 14; 2233 continue; 2234 } 2235 /* --sysroot is authoritative in the first pass (GNU ld treats it as a 2236 * global search-prefix that must be known before any -l / "=" rewrite), so 2237 * o->sysroot is already set. Here we only consume the tokens so they are 2238 * not misread as input files; do not re-apply the value. */ 2239 if (driver_streq(a, "--sysroot") || driver_streq(a, "-syslibroot")) { 2240 if (++i >= argc) { 2241 driver_errf(LD_TOOL, "%s requires an argument", a); 2242 return 1; 2243 } 2244 continue; 2245 } 2246 if (driver_strneq(a, "--sysroot=", 10)) { 2247 continue; 2248 } 2249 2250 if (driver_strneq(a, "-L", 2)) { 2251 const char* dir = a[2] ? a + 2 : (++i < argc ? argv[i] : NULL); 2252 const char* rewritten; 2253 if (!dir) { 2254 driver_errf(LD_TOOL, "-L requires an argument"); 2255 return 1; 2256 } 2257 if (!o->lib_dirs_precollected) { 2258 if (ld_sysroot_rewrite_path(o, dir, &rewritten) != 0) return 1; 2259 if (ld_add_lib_dir(o, rewritten) != 0) return 1; 2260 } 2261 continue; 2262 } 2263 if ((val = arg_eq_value(a, "--library-path")) != NULL) { 2264 const char* rewritten; 2265 if (!o->lib_dirs_precollected) { 2266 if (ld_sysroot_rewrite_path(o, val, &rewritten) != 0) return 1; 2267 if (ld_add_lib_dir(o, rewritten) != 0) return 1; 2268 } 2269 continue; 2270 } 2271 if (driver_streq(a, "--library-path")) { 2272 const char* rewritten; 2273 if (++i >= argc) { 2274 driver_errf(LD_TOOL, "--library-path requires an argument"); 2275 return 1; 2276 } 2277 if (!o->lib_dirs_precollected) { 2278 if (ld_sysroot_rewrite_path(o, argv[i], &rewritten) != 0) return 1; 2279 if (ld_add_lib_dir(o, rewritten) != 0) return 1; 2280 } 2281 continue; 2282 } 2283 if (driver_strneq(a, "-F", 2)) { 2284 const char* dir = a[2] ? a + 2 : (++i < argc ? argv[i] : NULL); 2285 const char* rewritten; 2286 if (!dir) { 2287 driver_errf(LD_TOOL, "-F requires an argument"); 2288 return 1; 2289 } 2290 if (!o->lib_dirs_precollected) { 2291 if (ld_sysroot_rewrite_path(o, dir, &rewritten) != 0) return 1; 2292 if (ld_add_framework_dir(o, rewritten) != 0) return 1; 2293 } 2294 continue; 2295 } 2296 2297 if (driver_strneq(a, "-l", 2)) { 2298 const char* name = a[2] ? a + 2 : (++i < argc ? argv[i] : NULL); 2299 char* resolved; 2300 size_t resolved_size; 2301 LibResolveKind kind; 2302 LibResolveMode mode; 2303 LibResolveOS resolve_os; 2304 if (!name) { 2305 driver_errf(LD_TOOL, "-l requires an argument"); 2306 return 1; 2307 } 2308 if (ld_note_library_request(o, name)) continue; 2309 /* -Bstatic forces .a only; everything else (default, 2310 * -Bdynamic, --as-needed) prefers .so but falls back to .a. */ 2311 mode = (o->inputs.cur_link_mode == KIT_LM_STATIC) ? LIB_RESOLVE_STATIC_ONLY 2312 : LIB_RESOLVE_DYNAMIC_PREFER; 2313 resolve_os = (o->target.os == KIT_OS_WINDOWS) ? LIB_RESOLVE_OS_WINDOWS 2314 : LIB_RESOLVE_OS_POSIX; 2315 if (ld_resolve_library(o, name, mode, resolve_os, &resolved, 2316 &resolved_size, &kind) != 0) { 2317 driver_errf(LD_TOOL, "cannot find -l%.*s", 2318 KIT_SLICE_ARG(kit_slice_cstr(name))); 2319 return 1; 2320 } 2321 if (kind == LIB_RESOLVE_KIND_SHARED || kind == LIB_RESOLVE_KIND_TBD) { 2322 ld_push_dso(o, resolved, 1, resolved_size); 2323 } else { 2324 ld_push_archive(o, resolved, 1, resolved_size); 2325 } 2326 continue; 2327 } 2328 if ((val = arg_eq_value(a, "--library")) != NULL) { 2329 char* resolved; 2330 size_t resolved_size; 2331 LibResolveKind kind; 2332 LibResolveMode mode = (o->inputs.cur_link_mode == KIT_LM_STATIC) 2333 ? LIB_RESOLVE_STATIC_ONLY 2334 : LIB_RESOLVE_DYNAMIC_PREFER; 2335 LibResolveOS resolve_os = (o->target.os == KIT_OS_WINDOWS) 2336 ? LIB_RESOLVE_OS_WINDOWS 2337 : LIB_RESOLVE_OS_POSIX; 2338 if (ld_note_library_request(o, val)) continue; 2339 if (ld_resolve_library(o, val, mode, resolve_os, &resolved, 2340 &resolved_size, &kind) != 0) { 2341 driver_errf(LD_TOOL, "cannot find -l%.*s", 2342 KIT_SLICE_ARG(kit_slice_cstr(val))); 2343 return 1; 2344 } 2345 if (kind == LIB_RESOLVE_KIND_SHARED || kind == LIB_RESOLVE_KIND_TBD) { 2346 ld_push_dso(o, resolved, 1, resolved_size); 2347 } else { 2348 ld_push_archive(o, resolved, 1, resolved_size); 2349 } 2350 continue; 2351 } 2352 if (driver_streq(a, "--library")) { 2353 char* resolved; 2354 size_t resolved_size; 2355 LibResolveKind kind; 2356 LibResolveMode mode; 2357 LibResolveOS resolve_os; 2358 if (++i >= argc) { 2359 driver_errf(LD_TOOL, "--library requires an argument"); 2360 return 1; 2361 } 2362 if (ld_note_library_request(o, argv[i])) continue; 2363 mode = (o->inputs.cur_link_mode == KIT_LM_STATIC) ? LIB_RESOLVE_STATIC_ONLY 2364 : LIB_RESOLVE_DYNAMIC_PREFER; 2365 resolve_os = (o->target.os == KIT_OS_WINDOWS) ? LIB_RESOLVE_OS_WINDOWS 2366 : LIB_RESOLVE_OS_POSIX; 2367 if (ld_resolve_library(o, argv[i], mode, resolve_os, &resolved, 2368 &resolved_size, &kind) != 0) { 2369 driver_errf(LD_TOOL, "cannot find -l%.*s", 2370 KIT_SLICE_ARG(kit_slice_cstr(argv[i]))); 2371 return 1; 2372 } 2373 if (kind == LIB_RESOLVE_KIND_SHARED || kind == LIB_RESOLVE_KIND_TBD) { 2374 ld_push_dso(o, resolved, 1, resolved_size); 2375 } else { 2376 ld_push_archive(o, resolved, 1, resolved_size); 2377 } 2378 continue; 2379 } 2380 if (driver_streq(a, "-framework")) { 2381 if (++i >= argc) { 2382 driver_errf(LD_TOOL, "-framework requires an argument"); 2383 return 1; 2384 } 2385 if (ld_push_framework(o, argv[i]) != 0) return 1; 2386 continue; 2387 } 2388 2389 if (driver_streq(a, "-static")) { 2390 o->target.pic = KIT_PIC_NONE; 2391 o->static_link = 1; 2392 o->inputs.cur_link_mode = KIT_LM_STATIC; 2393 o->pic_explicit = 1; 2394 continue; 2395 } 2396 if (driver_streq(a, "-static-pie")) { 2397 o->target.pic = KIT_PIC_PIE; 2398 o->pie = 1; 2399 o->static_link = 1; 2400 o->inputs.cur_link_mode = KIT_LM_STATIC; 2401 o->pic_explicit = 1; 2402 continue; 2403 } 2404 if (driver_streq(a, "-pie")) { 2405 o->target.pic = KIT_PIC_PIE; 2406 o->pie = 1; 2407 o->pic_explicit = 1; 2408 continue; 2409 } 2410 if (driver_streq(a, "-dynamic-linker") || 2411 driver_streq(a, "--dynamic-linker")) { 2412 if (++i >= argc) { 2413 driver_errf(LD_TOOL, "-dynamic-linker requires an argument"); 2414 return 1; 2415 } 2416 o->lf.interp_path = argv[i]; 2417 continue; 2418 } 2419 if (driver_streq(a, "--no-dynamic-linker")) { 2420 o->lf.interp_path = ""; 2421 continue; 2422 } 2423 if ((val = arg_eq_value(a, "--dynamic-linker")) != NULL) { 2424 o->lf.interp_path = val; 2425 continue; 2426 } 2427 if (driver_streq(a, "-no-pie")) { 2428 o->target.pic = KIT_PIC_NONE; 2429 o->pie = 0; 2430 o->pic_explicit = 1; 2431 continue; 2432 } 2433 2434 if (driver_streq(a, "-shared")) { 2435 o->shared = 1; 2436 /* Shared objects must be position-independent. Force PIC unless 2437 * the caller has explicitly chosen PIE (which is also fine). */ 2438 if (o->target.pic == KIT_PIC_NONE) o->target.pic = KIT_PIC_PIC; 2439 o->pic_explicit = 1; 2440 continue; 2441 } 2442 if (driver_streq(a, "-r") || driver_streq(a, "--relocatable")) { 2443 o->relocatable = 1; 2444 continue; 2445 } 2446 if (driver_streq(a, "-soname")) { 2447 if (++i >= argc) { 2448 driver_errf(LD_TOOL, "-soname requires an argument"); 2449 return 1; 2450 } 2451 o->lf.soname = argv[i]; 2452 continue; 2453 } 2454 if ((val = arg_eq_value(a, "-soname")) != NULL) { 2455 o->lf.soname = val; 2456 continue; 2457 } 2458 if (driver_streq(a, "-rpath")) { 2459 if (++i >= argc) { 2460 driver_errf(LD_TOOL, "-rpath requires an argument"); 2461 return 1; 2462 } 2463 o->lf.rpaths[o->lf.nrpaths++] = argv[i]; 2464 continue; 2465 } 2466 if ((val = arg_eq_value(a, "-rpath")) != NULL) { 2467 o->lf.rpaths[o->lf.nrpaths++] = val; 2468 continue; 2469 } 2470 if (driver_streq(a, "-rpath-link")) { 2471 if (++i >= argc) { 2472 driver_errf(LD_TOOL, "-rpath-link requires an argument"); 2473 return 1; 2474 } 2475 o->rpath_links[o->nrpath_links++] = argv[i]; 2476 continue; 2477 } 2478 if ((val = arg_eq_value(a, "-rpath-link")) != NULL) { 2479 o->rpath_links[o->nrpath_links++] = val; 2480 continue; 2481 } 2482 if (driver_streq(a, "--enable-new-dtags")) { 2483 o->lf.new_dtags = 1; 2484 continue; 2485 } 2486 if (driver_streq(a, "--disable-new-dtags")) { 2487 o->lf.new_dtags = 0; 2488 continue; 2489 } 2490 if (driver_streq(a, "--gc-sections")) { 2491 o->lf.gc_sections = 1; 2492 continue; 2493 } 2494 if (driver_streq(a, "-dead_strip")) { 2495 o->lf.gc_sections = 1; 2496 continue; 2497 } 2498 if (driver_streq(a, "--no-gc-sections")) { 2499 o->lf.gc_sections = 0; 2500 continue; 2501 } 2502 if (driver_streq(a, "--map") || driver_streq(a, "-Map")) { 2503 if (++i >= argc) { 2504 driver_errf(LD_TOOL, "%s requires an argument", a); 2505 return 1; 2506 } 2507 if (!argv[i][0]) { 2508 driver_errf(LD_TOOL, "%s requires a non-empty path", a); 2509 return 1; 2510 } 2511 o->lf.map_path = argv[i]; 2512 continue; 2513 } 2514 if ((val = arg_eq_value(a, "--map")) != NULL) { 2515 if (!val[0]) { 2516 driver_errf(LD_TOOL, "--map requires a non-empty path"); 2517 return 1; 2518 } 2519 o->lf.map_path = val; 2520 continue; 2521 } 2522 if ((val = arg_eq_value(a, "-Map")) != NULL) { 2523 if (!val[0]) { 2524 driver_errf(LD_TOOL, "-Map requires a non-empty path"); 2525 return 1; 2526 } 2527 o->lf.map_path = val; 2528 continue; 2529 } 2530 if (driver_streq(a, "--symbols")) { 2531 if (++i >= argc) { 2532 driver_errf(LD_TOOL, "--symbols requires an argument"); 2533 return 1; 2534 } 2535 if (!argv[i][0]) { 2536 driver_errf(LD_TOOL, "--symbols requires a non-empty path"); 2537 return 1; 2538 } 2539 o->lf.symbols_path = argv[i]; 2540 continue; 2541 } 2542 if ((val = arg_eq_value(a, "--symbols")) != NULL) { 2543 if (!val[0]) { 2544 driver_errf(LD_TOOL, "--symbols requires a non-empty path"); 2545 return 1; 2546 } 2547 o->lf.symbols_path = val; 2548 continue; 2549 } 2550 if ((val = arg_eq_value(a, "--symbols-format")) != NULL) { 2551 if (driver_link_flags_record_symbols_format(&o->lf, val, 2552 driver_strlen(val)) != 0) 2553 return 1; 2554 continue; 2555 } 2556 if (driver_streq(a, "-S") || driver_streq(a, "--strip-debug")) { 2557 o->lf.strip_debug = 1; 2558 continue; 2559 } 2560 if (driver_streq(a, "-E") || driver_streq(a, "--export-dynamic")) { 2561 o->export_dynamic = 1; 2562 continue; 2563 } 2564 if (driver_streq(a, "--eh-frame-hdr")) { 2565 /* Rust/GNU drivers request this for unwind-table acceleration. Kit's 2566 * ELF writer does not currently synthesize PT_GNU_EH_FRAME, so accept it 2567 * as advisory until that feature is implemented. */ 2568 continue; 2569 } 2570 if (driver_streq(a, "--fix-cortex-a53-843419")) { 2571 /* AArch64 GNU/LLD compatibility. Kit does not currently implement this 2572 * erratum-rewrite pass, so accept the request as advisory. */ 2573 continue; 2574 } 2575 if (ld_is_pe_gnu_noop(a, driver_strlen(a))) { 2576 continue; 2577 } 2578 if (driver_streq(a, "--no-undefined")) { 2579 o->lf.allow_undefined = 0; 2580 continue; 2581 } 2582 if (driver_streq(a, "--allow-undefined") || 2583 driver_streq(a, "--allow-shlib-undefined")) { 2584 o->lf.allow_undefined = 1; 2585 continue; 2586 } 2587 if (driver_streq(a, "-z")) { 2588 if (++i >= argc) { 2589 driver_errf(LD_TOOL, "-z requires an argument"); 2590 return 1; 2591 } 2592 if (driver_link_flags_record_z(&o->lf, argv[i], driver_strlen(argv[i])) != 2593 0) 2594 return 1; 2595 continue; 2596 } 2597 if (a[0] == '-' && a[1] == 'z' && a[2] != '\0') { 2598 if (driver_link_flags_record_z(&o->lf, a + 2, driver_strlen(a + 2)) != 0) 2599 return 1; 2600 continue; 2601 } 2602 2603 if (driver_streq(a, "--whole-archive")) { 2604 o->inputs.cur_whole_archive = 1; 2605 continue; 2606 } 2607 if (driver_streq(a, "--no-whole-archive")) { 2608 o->inputs.cur_whole_archive = 0; 2609 continue; 2610 } 2611 if (driver_streq(a, "-Bstatic")) { 2612 o->inputs.cur_link_mode = KIT_LM_STATIC; 2613 continue; 2614 } 2615 if (driver_streq(a, "-Bdynamic")) { 2616 o->inputs.cur_link_mode = KIT_LM_DYNAMIC; 2617 continue; 2618 } 2619 if (driver_streq(a, "--as-needed")) { 2620 o->inputs.cur_link_mode = KIT_LM_AS_NEEDED; 2621 continue; 2622 } 2623 if (driver_streq(a, "--no-as-needed")) { 2624 o->inputs.cur_link_mode = KIT_LM_DYNAMIC; 2625 continue; 2626 } 2627 if (driver_streq(a, "--start-group")) { 2628 if (o->inputs.cur_group_id != 0) { 2629 driver_errf(LD_TOOL, "nested --start-group is not supported"); 2630 return 1; 2631 } 2632 if (o->next_group_id == UINT8_MAX) { 2633 driver_errf(LD_TOOL, "too many --start-group occurrences"); 2634 return 1; 2635 } 2636 o->next_group_id++; 2637 o->inputs.cur_group_id = o->next_group_id; 2638 continue; 2639 } 2640 if (driver_streq(a, "--end-group")) { 2641 if (o->inputs.cur_group_id == 0) { 2642 driver_errf(LD_TOOL, "--end-group without --start-group"); 2643 return 1; 2644 } 2645 o->inputs.cur_group_id = 0; 2646 continue; 2647 } 2648 2649 if ((val = arg_eq_value(a, "--build-id")) != NULL) { 2650 if (driver_link_flags_record_build_id(&o->lf, val) != 0) return 1; 2651 continue; 2652 } 2653 if (driver_streq(a, "--build-id")) { 2654 /* Bareword form defaults to sha256, matching GNU ld. */ 2655 o->lf.build_id_mode = KIT_BUILDID_SHA256; 2656 continue; 2657 } 2658 2659 if (a[0] == '-' && a[1] != '\0') { 2660 driver_errf(LD_TOOL, "unknown flag: %.*s", 2661 KIT_SLICE_ARG(kit_slice_cstr(a))); 2662 return 1; 2663 } 2664 2665 { 2666 const char* path; 2667 if (ld_sysroot_rewrite_path(o, a, &path) != 0) return 1; 2668 if (driver_has_suffix(path, ".a") || driver_has_suffix(path, ".rlib")) { 2669 ld_push_archive(o, path, 0, 0); 2670 } else if (driver_is_so_filename(path)) { 2671 ld_push_dso(o, path, 0, 0); 2672 } else { 2673 ld_push_object(o, path); 2674 } 2675 } 2676 } 2677 2678 if (!o->output_path) { 2679 driver_errf(LD_TOOL, "-o is required"); 2680 return 1; 2681 } 2682 if (o->inputs.cur_group_id != 0) { 2683 driver_errf(LD_TOOL, "missing --end-group"); 2684 return 1; 2685 } 2686 if (o->inputs.nobject_files == 0 && o->inputs.narchives == 0 && 2687 o->inputs.ndsos == 0) { 2688 driver_errf(LD_TOOL, "no input files"); 2689 ld_usage(); 2690 return 1; 2691 } 2692 if (o->wants_hosted_libc && (o->nostdlib || o->nostartfiles)) { 2693 driver_errf(LD_TOOL, 2694 "-lc hosted expansion is disabled by -nostdlib/" 2695 "-nostartfiles"); 2696 return 1; 2697 } 2698 if (o->shared && o->target.obj != KIT_OBJ_ELF) { 2699 driver_errf(LD_TOOL, 2700 "-shared output is supported only for ELF targets in v1"); 2701 return 1; 2702 } 2703 if (o->relocatable) { 2704 if (o->shared) { 2705 driver_errf(LD_TOOL, "-r and -shared are incompatible"); 2706 return 1; 2707 } 2708 if (o->wants_hosted_libc) { 2709 driver_errf(LD_TOOL, "-lc hosted expansion requires executable output"); 2710 return 1; 2711 } 2712 /* Only an explicit -pie conflicts; a default PIE target.pic is simply 2713 * overridden by -r (driver_link_pie suppresses pie when relocatable). */ 2714 if (o->pie) { 2715 driver_errf(LD_TOOL, "-r and -pie are incompatible"); 2716 return 1; 2717 } 2718 if (o->lf.interp_path) { 2719 driver_errf(LD_TOOL, "-dynamic-linker requires executable output"); 2720 return 1; 2721 } 2722 if (o->lf.soname || o->lf.nrpaths || o->nrpath_links) { 2723 driver_errf(LD_TOOL, "-soname/-rpath/-rpath-link require -shared"); 2724 return 1; 2725 } 2726 if (o->inputs.ndsos) { 2727 driver_errf(LD_TOOL, "-r does not support shared-object inputs"); 2728 return 1; 2729 } 2730 if (o->script_path) { 2731 driver_errf(LD_TOOL, "-r does not support linker scripts yet"); 2732 return 1; 2733 } 2734 if (o->lf.map_path || o->lf.symbols_path) { 2735 driver_errf(LD_TOOL, "--map/--symbols require executable output"); 2736 return 1; 2737 } 2738 } 2739 return 0; 2740 } 2741 2742 /* ---------- options teardown ---------- */ 2743 2744 static void ld_options_release(LdOptions* o) { 2745 size_t bound = o->argv_bound; 2746 uint32_t i; 2747 for (i = 0; i < o->nowned_paths; ++i) { 2748 if (o->owned_paths[i]) 2749 driver_free(o->env, o->owned_paths[i], o->owned_path_sizes[i]); 2750 } 2751 /* The shared flag model owns its FLAG strings (defsym/section/map/...), the 2752 * build-id bytes, and the rpath/defsym/section-start vectors. The shared 2753 * input set owns the resolved archive/dso paths and its parallel arrays. */ 2754 driver_link_flags_fini(&o->lf); 2755 driver_link_inputs_fini(&o->inputs); 2756 driver_cflags_fini(&o->cf, o->env); 2757 driver_hosted_plan_fini(o->env, &o->hosted); 2758 /* owned_paths/owned_path_sizes grow independently of argv_bound. */ 2759 driver_free(o->env, o->owned_paths, 2760 o->cap_owned_paths * sizeof(*o->owned_paths)); 2761 driver_free(o->env, o->owned_path_sizes, 2762 o->cap_owned_paths * sizeof(*o->owned_path_sizes)); 2763 driver_free(o->env, o->rpath_links, bound * sizeof(*o->rpath_links)); 2764 } 2765 2766 /* ---------- input loading ---------- */ 2767 2768 typedef struct LoadedFile { 2769 const KitFileIO* io; 2770 KitFileData data; 2771 int loaded; 2772 } LoadedFile; 2773 2774 static int load_file(const KitFileIO* io, const char* path, LoadedFile* out) { 2775 out->io = io; 2776 out->loaded = 0; 2777 out->data.data = NULL; 2778 out->data.size = 0; 2779 out->data.token = NULL; 2780 if (io->read_all(io->user, path, &out->data) != KIT_OK) return 1; 2781 out->loaded = 1; 2782 return 0; 2783 } 2784 2785 static void release_file(LoadedFile* lf) { 2786 if (lf->loaded && lf->io && lf->io->release) { 2787 lf->io->release(lf->io->user, &lf->data); 2788 } 2789 lf->loaded = 0; 2790 } 2791 2792 static void release_all(LoadedFile* arr, uint32_t n) { 2793 uint32_t i; 2794 if (!arr) return; 2795 for (i = 0; i < n; ++i) release_file(&arr[i]); 2796 } 2797 2798 static KitStatus ld_write_link_report(const LdOptions* o, const KitFileIO* io, 2799 KitLinkSession* link, const char* path, 2800 int symbols) { 2801 KitWriter* w = NULL; 2802 KitStatus st; 2803 if (!path) return KIT_OK; 2804 if (io->open_writer(io->user, path, &w) != KIT_OK) { 2805 driver_errf(LD_TOOL, "failed to open %s output: %.*s", 2806 symbols ? "symbols" : "map", 2807 KIT_SLICE_ARG(kit_slice_cstr(path))); 2808 return KIT_IO; 2809 } 2810 st = symbols ? kit_link_session_write_symbols(link, o->lf.symbols_format, w) 2811 : kit_link_session_write_map(link, w); 2812 if (st == KIT_OK) st = kit_writer_status(w); 2813 kit_writer_close(w); 2814 if (st != KIT_OK) { 2815 driver_errf(LD_TOOL, "failed to write %s: %.*s", 2816 symbols ? "symbols" : "map", 2817 KIT_SLICE_ARG(kit_slice_cstr(path))); 2818 } 2819 return st; 2820 } 2821 2822 /* --cref FILE: cross-reference table side file. */ 2823 static KitStatus ld_write_cref(const LdOptions* o, const KitFileIO* io, 2824 KitLinkSession* link) { 2825 KitWriter* w = NULL; 2826 KitStatus st; 2827 if (!o->lf.cref_path) return KIT_OK; 2828 if (io->open_writer(io->user, o->lf.cref_path, &w) != KIT_OK) { 2829 driver_errf(LD_TOOL, "failed to open cref output: %.*s", 2830 KIT_SLICE_ARG(kit_slice_cstr(o->lf.cref_path))); 2831 return KIT_IO; 2832 } 2833 st = kit_link_session_write_cref(link, w); 2834 if (st == KIT_OK) st = kit_writer_status(w); 2835 kit_writer_close(w); 2836 if (st != KIT_OK) 2837 driver_errf(LD_TOOL, "failed to write cref: %.*s", 2838 KIT_SLICE_ARG(kit_slice_cstr(o->lf.cref_path))); 2839 return st; 2840 } 2841 2842 /* --print-memory-usage: GNU-ld-style per-region summary to stdout. */ 2843 static KitStatus ld_print_memory_usage(LdOptions* o, KitLinkSession* link) { 2844 KitWriter* w; 2845 KitStatus st; 2846 if (!o->lf.print_memory_usage) return KIT_OK; 2847 w = driver_stdout_writer(o->env); 2848 if (!w) { 2849 driver_errf(LD_TOOL, "failed to print memory usage"); 2850 return KIT_IO; 2851 } 2852 st = kit_link_session_write_memory_usage(link, w); 2853 if (st == KIT_OK) st = kit_writer_status(w); 2854 kit_writer_close(w); 2855 if (st != KIT_OK) driver_errf(LD_TOOL, "failed to print memory usage"); 2856 return st; 2857 } 2858 2859 /* Resolve and apply the hosted libc profile: hosted lib-search dirs (so user 2860 * -l flags resolve against the sysroot), the before/after/final crt inputs in 2861 * link order, and the interpreter. The shared helper folds all of this (plus 2862 * the system includes/defines that ld discards) into one call; the runtime 2863 * archive is later inserted before the final group via 2864 * driver_link_inputs_insert_runtime_archives. The wants-hosted / -shared guard 2865 * stays here. */ 2866 static int ld_apply_hosted(LdOptions* o) { 2867 int shared_hosted = o->shared && driver_target_shared_uses_hosted(o->target); 2868 if (!o->wants_hosted_libc || (o->shared && !shared_hosted)) return 0; 2869 return driver_link_inputs_apply_hosted(&o->inputs, &o->hosted, &o->cf, &o->lf, 2870 o->target, o->sysroot, o->static_link, 2871 o->shared, o->nostartfiles, 2872 /*link_action=*/1); 2873 } 2874 2875 /* ---------- link execution ---------- */ 2876 2877 /* Run the link. Returns 0 on success, nonzero on error. The caller owns 2878 * `o` and any allocations within; this function only owns transient 2879 * loaded-file buffers and the writer/compiler it constructs. */ 2880 static int ld_run_link(LdOptions* o) { 2881 KitContext ctx = driver_env_to_context(o->env); 2882 const KitFileIO* io = ctx.file_io; 2883 KitTarget* target = NULL; 2884 KitCompiler* compiler = NULL; 2885 KitWriter* writer = NULL; 2886 LoadedFile* obj_lf = NULL; 2887 LoadedFile* arch_lf = NULL; 2888 LoadedFile* dso_lf = NULL; 2889 LoadedFile script_lf = {0}; 2890 KitSlice* obj_in = NULL; 2891 KitLinkArchiveInput* arch_in = NULL; 2892 KitSlice* dso_in = NULL; 2893 KitLinkInputOrder* order = NULL; 2894 KitLinkScript* script = NULL; 2895 KitLinkSession* link = NULL; 2896 DriverRuntimeSupport runtime = {0}; 2897 DriverRuntimeArchive rt_archive = {0}; 2898 uint32_t i; 2899 uint32_t norder = 0; 2900 uint32_t initial_nobject_files; 2901 int runtime_resolved = 0; 2902 int rc = 1; 2903 2904 if (!io || !io->read_all || !io->open_writer) { 2905 driver_errf(LD_TOOL, "host file I/O unavailable"); 2906 return 1; 2907 } 2908 2909 /* Load the caller's object files first so the final target is known before 2910 * deciding which hosted CRT/libc profile and compiler-runtime archive to 2911 * add. The arrays are sized to the argv bound because hosted expansion may 2912 * append start files after target detection. */ 2913 initial_nobject_files = o->inputs.nobject_files; 2914 if (o->argv_bound) { 2915 obj_lf = driver_alloc_zeroed(o->env, o->argv_bound * sizeof(*obj_lf)); 2916 obj_in = driver_alloc_zeroed(o->env, o->argv_bound * sizeof(*obj_in)); 2917 if (!obj_lf || !obj_in) { 2918 driver_errf(LD_TOOL, "out of memory"); 2919 goto out; 2920 } 2921 } 2922 for (i = 0; i < initial_nobject_files; ++i) { 2923 const char* path = o->inputs.object_files[i]; 2924 if (load_file(io, path, &obj_lf[i]) != 0) { 2925 driver_errf(LD_TOOL, "failed to read: %.*s", 2926 KIT_SLICE_ARG(kit_slice_cstr(path))); 2927 goto out; 2928 } 2929 obj_in[i].data = obj_lf[i].data.data; 2930 obj_in[i].len = obj_lf[i].data.size; 2931 } 2932 2933 /* Auto-detect target from the object inputs, falling back to the host target. 2934 * The PIC default is a property of the *target*, not the host: hosted targets 2935 * default to PIE, freestanding ones to no-PIE (driver_default_pic). The 2936 * host's default PIC must never leak onto a detected cross target; only an 2937 * EXPLICIT -static/-pie/-no-pie/-shared wins. 2938 * 2939 * Detection takes the arch from the first object, but the OS from any object: 2940 * a freestanding (`*-none-elf`, EI_OSABI=STANDALONE) object means a 2941 * freestanding link even if a foreign object (e.g. a clang-assembled startup 2942 * stub, which stamps EI_OSABI=SysV and so decodes as Linux) appears first. */ 2943 if (!o->target_explicit && initial_nobject_files > 0) { 2944 KitTargetSpec detected; 2945 if (kit_detect_target(obj_lf[0].data.data, obj_lf[0].data.size, 2946 &detected) == KIT_OK) { 2947 uint8_t pic = o->target.pic; 2948 uint32_t oi; 2949 for (oi = 1; oi < initial_nobject_files; ++oi) { 2950 KitTargetSpec t; 2951 if (kit_detect_target(obj_lf[oi].data.data, obj_lf[oi].data.size, &t) == 2952 KIT_OK) { 2953 if (t.os == KIT_OS_FREESTANDING) detected.os = KIT_OS_FREESTANDING; 2954 /* Reconcile the float ABI across inputs. A foreign startup stub (e.g. 2955 * a clang-assembled .S) may not carry the float-ABI e_flags that the 2956 * kit-compiled objects do, so prefer any object's hardware ABI 2957 * (single/double) over a soft/unset reading. This picks the runtime 2958 * variant (rv32 ilp32 vs ilp32f) the real code was compiled for even 2959 * when obj[0] is the stub. */ 2960 if (detected.float_abi != KIT_FLOAT_ABI_SINGLE && 2961 detected.float_abi != KIT_FLOAT_ABI_DOUBLE && 2962 (t.float_abi == KIT_FLOAT_ABI_SINGLE || 2963 t.float_abi == KIT_FLOAT_ABI_DOUBLE)) 2964 detected.float_abi = t.float_abi; 2965 } 2966 } 2967 o->target = detected; 2968 if (o->pic_explicit) 2969 o->target.pic = pic; 2970 else 2971 o->target.pic = driver_default_pic(o->target.obj, o->target.os); 2972 } 2973 } 2974 2975 if (!o->relocatable && o->target.os == KIT_OS_FREESTANDING && 2976 o->inputs.ndsos) { 2977 driver_errf(LD_TOOL, 2978 "freestanding executable links do not accept DSO inputs"); 2979 goto out; 2980 } 2981 2982 /* Strict freestanding policy: every input object must agree with the link 2983 * target's arch and object format. A `*-none-*` link silently mis-linking a 2984 * foreign-arch object (the default detection trusts obj[0]'s arch) is a hard 2985 * error here. */ 2986 if (!o->relocatable && o->target.os == KIT_OS_FREESTANDING) { 2987 uint32_t oi; 2988 for (oi = 0; oi < initial_nobject_files; ++oi) { 2989 KitTargetSpec t; 2990 if (kit_detect_target(obj_lf[oi].data.data, obj_lf[oi].data.size, &t) != 2991 KIT_OK) 2992 continue; 2993 if (t.arch != o->target.arch || t.obj != o->target.obj) { 2994 driver_errf(LD_TOOL, 2995 "freestanding link: input '%s' arch/format does not match " 2996 "the link target", 2997 o->inputs.object_files[oi]); 2998 goto out; 2999 } 3000 } 3001 } 3002 3003 if (ld_apply_hosted(o) != 0) goto out; 3004 3005 /* Hosted dynamic link: default to PIE, matching what `kit cc` does. 3006 * Without PIE the link_dyn path (PLT/GOT/.rela.plt) is not entered and 3007 * any CALL26/PLT32 reloc against an imported symbol faults at apply time. 3008 * Only override when the user has not made an explicit PIC choice. 3009 * Non-PIE (ET_EXEC) dynamic linking is not yet supported; reject early. */ 3010 if (o->wants_hosted_libc && !o->static_link && !o->shared && 3011 !o->relocatable) { 3012 if (o->pic_explicit && !o->pie) { 3013 driver_errf(LD_TOOL, 3014 "-lc with -no-pie is not supported; use -pie (default) " 3015 "or -static for a static link"); 3016 goto out; 3017 } 3018 if (!o->pic_explicit) o->pie = 1; 3019 } 3020 3021 /* Auto-link kit's compiler runtime for any target that has a variant unless 3022 * the caller has already supplied compiler builtins (Rust's 3023 * libcompiler_builtins*.rlib, libgcc.a, clang_rt.builtins, ...). This keeps 3024 * `kit ld object.o` useful while letting `kit ld` behave like a system 3025 * linker under external compiler drivers. A target with no variant is 3026 * implicitly -nostdlib and supplies its own libkit_rt.a on the command line, 3027 * so skip resolution rather than erroring. -nostdlib forces the skip for any 3028 * target. 3029 */ 3030 if (!o->relocatable && !o->no_default_libs && !o->has_compiler_runtime && 3031 driver_runtime_has_variant(o->target)) { 3032 if (driver_runtime_resolve(o->env, o->support_dir, o->driver_path, 3033 &runtime) != 0) { 3034 driver_errf(LD_TOOL, "support dir not found"); 3035 goto out; 3036 } 3037 runtime_resolved = 1; 3038 if (driver_runtime_prepare_archive(o->env, LD_TOOL, &runtime, o->target, 0, 3039 &rt_archive) != 0) 3040 goto out; 3041 /* Insert before the hosted plan's `final` (crt-end) group — the shared 3042 * helper also does the Windows two-position insert that the old single 3043 * append lacked. ld's runtime is never whole-archive, matching cc/build. */ 3044 driver_link_inputs_insert_runtime_archives( 3045 &o->inputs, &rt_archive, o->target, o->hosted.nfinal, o->hosted.nafter); 3046 } 3047 3048 if (ld_expand_dso_scripts(o) != 0) goto out; 3049 3050 for (i = initial_nobject_files; i < o->inputs.nobject_files; ++i) { 3051 const char* path = o->inputs.object_files[i]; 3052 if (load_file(io, path, &obj_lf[i]) != 0) { 3053 driver_errf(LD_TOOL, "failed to read: %.*s", 3054 KIT_SLICE_ARG(kit_slice_cstr(path))); 3055 goto out; 3056 } 3057 obj_in[i].data = obj_lf[i].data.data; 3058 obj_in[i].len = obj_lf[i].data.size; 3059 } 3060 3061 if (o->inputs.narchives) { 3062 arch_lf = 3063 driver_alloc_zeroed(o->env, o->inputs.narchives * sizeof(*arch_lf)); 3064 arch_in = 3065 driver_alloc_zeroed(o->env, o->inputs.narchives * sizeof(*arch_in)); 3066 if (!arch_lf || !arch_in) { 3067 driver_errf(LD_TOOL, "out of memory"); 3068 goto out; 3069 } 3070 } 3071 if (o->inputs.ndsos) { 3072 dso_lf = driver_alloc_zeroed(o->env, o->inputs.ndsos * sizeof(*dso_lf)); 3073 dso_in = driver_alloc_zeroed(o->env, o->inputs.ndsos * sizeof(*dso_in)); 3074 if (!dso_lf || !dso_in) { 3075 driver_errf(LD_TOOL, "out of memory"); 3076 goto out; 3077 } 3078 } 3079 3080 /* Load archives. */ 3081 for (i = 0; i < o->inputs.narchives; ++i) { 3082 const DriverArchiveInput* a = &o->inputs.archives[i]; 3083 if (load_file(io, a->path, &arch_lf[i]) != 0) { 3084 driver_errf(LD_TOOL, "failed to read: %.*s", 3085 KIT_SLICE_ARG(kit_slice_cstr(a->path))); 3086 goto out; 3087 } 3088 arch_in[i].name = kit_slice_cstr(a->path); 3089 arch_in[i].bytes.data = arch_lf[i].data.data; 3090 arch_in[i].bytes.len = arch_lf[i].data.size; 3091 arch_in[i].whole_archive = a->whole_archive; 3092 arch_in[i].link_mode = a->link_mode; 3093 arch_in[i].group_id = a->group_id; 3094 } 3095 /* Load shared objects. */ 3096 for (i = 0; i < o->inputs.ndsos; ++i) { 3097 const DriverDsoInput* d = &o->inputs.dsos[i]; 3098 if (load_file(io, d->path, &dso_lf[i]) != 0) { 3099 driver_errf(LD_TOOL, "failed to read: %.*s", 3100 KIT_SLICE_ARG(kit_slice_cstr(d->path))); 3101 goto out; 3102 } 3103 dso_in[i].data = dso_lf[i].data.data; 3104 dso_in[i].len = dso_lf[i].data.size; 3105 } 3106 3107 /* Load and parse the linker script (if any). The structured script is 3108 * arena-owned by the compiler; we free it explicitly before the 3109 * compiler is destroyed. */ 3110 if (o->script_path) { 3111 if (load_file(io, o->script_path, &script_lf) != 0) { 3112 driver_errf(LD_TOOL, "failed to read: %.*s", 3113 KIT_SLICE_ARG(kit_slice_cstr(o->script_path))); 3114 goto out; 3115 } 3116 } 3117 3118 { 3119 KitTargetOptions topts; 3120 memset(&topts, 0, sizeof topts); 3121 topts.spec = o->target; 3122 /* A linker target auto-detected from RISC-V ELF inputs already carries 3123 * the psABI in spec.float_abi. kit_target_new normally derives that 3124 * field from -march/-mabi, so reproduce the detected profile here rather 3125 * than letting the rv32 default (ilp32 soft-float) overwrite ilp32f/d. 3126 * The ISA matters for rv32 hardware ABIs because its conservative default 3127 * deliberately omits F/D; rv64's default already includes both. */ 3128 if (o->target.arch == KIT_ARCH_RV32) { 3129 if (o->target.float_abi == KIT_FLOAT_ABI_SINGLE) { 3130 topts.isa = kit_slice_cstr("rv32imafc_zicsr_zifencei"); 3131 topts.abi = kit_slice_cstr("ilp32f"); 3132 } else if (o->target.float_abi == KIT_FLOAT_ABI_DOUBLE) { 3133 topts.isa = kit_slice_cstr("rv32imafdc_zicsr_zifencei"); 3134 topts.abi = kit_slice_cstr("ilp32d"); 3135 } else if (o->target.float_abi == KIT_FLOAT_ABI_SOFT) { 3136 topts.abi = kit_slice_cstr("ilp32"); 3137 } 3138 } else if (o->target.arch == KIT_ARCH_RV64) { 3139 if (o->target.float_abi == KIT_FLOAT_ABI_SINGLE) 3140 topts.abi = kit_slice_cstr("lp64f"); 3141 else if (o->target.float_abi == KIT_FLOAT_ABI_DOUBLE) 3142 topts.abi = kit_slice_cstr("lp64d"); 3143 else if (o->target.float_abi == KIT_FLOAT_ABI_SOFT) 3144 topts.abi = kit_slice_cstr("lp64"); 3145 } 3146 if (kit_target_new(&ctx, &topts, &target) != KIT_OK || 3147 driver_compiler_new(target, &ctx, &compiler) != KIT_OK) { 3148 driver_errf(LD_TOOL, "failed to initialize compiler"); 3149 goto out; 3150 } 3151 } 3152 3153 if (script_lf.loaded) { 3154 KitSlice script_text = {.s = (const char*)script_lf.data.data, 3155 .len = script_lf.data.size}; 3156 if (kit_link_script_parse(&ctx, script_text, &script) != KIT_OK) { 3157 /* The parser reports a diagnostic via env.diag. */ 3158 goto out; 3159 } 3160 } 3161 3162 /* Translate the recorded link-item order into the engine's KitLinkInputOrder 3163 * list. ld records no compiled-source items, so the source args are NULL. */ 3164 if (o->inputs.nlink_items) { 3165 order = 3166 driver_alloc_zeroed(o->env, o->inputs.nlink_items * sizeof(*order)); 3167 if (!order) { 3168 driver_errf(LD_TOOL, "out of memory"); 3169 goto out; 3170 } 3171 } 3172 norder = driver_link_inputs_build_order(&o->inputs, NULL, NULL, 0, order); 3173 3174 if (o->lf.soname || o->lf.nrpaths || o->nrpath_links) { 3175 if (!o->shared) { 3176 driver_errf(LD_TOOL, "-soname/-rpath/-rpath-link require -shared"); 3177 goto out; 3178 } 3179 } 3180 3181 { 3182 KitLinkSessionOptions lopts; 3183 KitStatus st; 3184 KitSlice* rpath_slices = NULL; 3185 uint8_t output_kind = o->relocatable ? KIT_LINK_OUTPUT_RELOCATABLE 3186 : o->shared ? KIT_LINK_OUTPUT_SHARED 3187 : KIT_LINK_OUTPUT_EXE; 3188 /* The shared flag model fills entry/text-base/defsym/section-start/orphan/ 3189 * fatal-warnings/build-id/gc/strip/pe-subsystem/interp/soname/rpath. It also 3190 * derives lopts.pie via driver_link_pie, but ld overrides that below. */ 3191 if (driver_link_flags_fill_options(&o->lf, o->target, o->pie, o->shared, 3192 o->relocatable, output_kind, script, 3193 &lopts, &rpath_slices) != 0) 3194 goto out; 3195 /* GNU ld and lld default to a non-PIE ET_EXEC; PIE is opt-in via -pie. The 3196 * linker imposes no hosted-PIE default the way a compiler driver does (kit 3197 * cc still defaults hosted executables to PIE through the link API) — a 3198 * freestanding or static link has no dynamic loader to apply a PIE image's 3199 * relocations or choose its base, so a PIE default produces a binary that 3200 * faults under a direct/qemu loader (its writable segments sit below 3201 * mmap_min_addr at the vaddr-0 PIE base). -shared/-r never PIE. Callers that 3202 * want a hosted PIE executable pass -pie explicitly (as the musl dynamic 3203 * lane and real compiler drivers do); the hosted-libc dynamic lane forces 3204 * o->pie = 1 above. So override the shared driver_link_pie decision (which 3205 * would default hosted target.pic == KIT_PIC_PIE targets to PIE) back to 3206 * ld's policy. */ 3207 lopts.pie = o->pie && !o->shared && !o->relocatable; 3208 /* Strict freestanding policy: a `*-none-*` (FREESTANDING) static non-PIE 3209 * executable must reject dynamic-link artifacts and cross-input 3210 * target/format mismatches. Only the EXE lane imposes it; -r/-shared do 3211 * not. --allow-undefined still relaxes undef references but not these 3212 * structural rejections. Set after fill_options, which derives lopts.pie. */ 3213 if (lopts.output_kind == KIT_LINK_OUTPUT_EXE && !lopts.pie && 3214 o->target.os == KIT_OS_FREESTANDING) 3215 lopts.freestanding_strict = true; 3216 (void)o->export_dynamic; 3217 3218 st = kit_link_session_new(compiler, &lopts, &link); 3219 for (i = 0; i < norder && st == KIT_OK; ++i) { 3220 const KitLinkInputOrder* ord = &order[i]; 3221 switch ((KitLinkInputOrderKind)ord->kind) { 3222 case KIT_LINK_INPUT_OBJ: 3223 case KIT_LINK_INPUT_OBJ_BYTES: 3224 st = kit_link_session_add_obj_bytes( 3225 link, kit_slice_cstr(o->inputs.object_files[ord->index]), 3226 &obj_in[ord->index]); 3227 break; 3228 case KIT_LINK_INPUT_ARCHIVE: 3229 st = kit_link_session_add_archive_bytes(link, &arch_in[ord->index]); 3230 break; 3231 case KIT_LINK_INPUT_DSO: 3232 st = kit_link_session_add_dso_bytes( 3233 link, kit_slice_cstr(o->inputs.dsos[ord->index].path), 3234 &dso_in[ord->index]); 3235 break; 3236 } 3237 } 3238 /* Parse and validate the complete input set before an output writer is 3239 * opened. Apart from preserving the primary named-input diagnostic, this 3240 * means a malformed object/archive/DSO or a link-resolution failure cannot 3241 * create even a temporary output artifact. */ 3242 if (st == KIT_OK) st = kit_link_session_resolve(link); 3243 if (st == KIT_OK && 3244 io->open_writer(io->user, o->output_path, &writer) != KIT_OK) { 3245 driver_errf(LD_TOOL, "failed to open output: %.*s", 3246 KIT_SLICE_ARG(kit_slice_cstr(o->output_path))); 3247 st = KIT_IO; 3248 } 3249 if (st == KIT_OK) st = kit_link_session_emit(link, writer); 3250 if (st == KIT_OK) st = ld_write_link_report(o, io, link, o->lf.map_path, 0); 3251 if (st == KIT_OK) 3252 st = ld_write_link_report(o, io, link, o->lf.symbols_path, 1); 3253 if (st == KIT_OK) st = ld_write_cref(o, io, link); 3254 if (st == KIT_OK) st = ld_print_memory_usage(o, link); 3255 rc = st == KIT_OK ? 0 : 1; 3256 driver_link_flags_free_rpath_slices(&o->lf, rpath_slices); 3257 } 3258 3259 out: 3260 if (writer) { 3261 if (rc != 0) driver_writer_abort(writer); 3262 kit_writer_close(writer); 3263 } 3264 kit_link_session_free(link); 3265 /* Match compiler/linker drivers: successful link outputs get executable 3266 * file modes while still respecting the process umask. Done after closing 3267 * the writer so the bits are stable on disk. */ 3268 if (rc == 0 && o->output_path && !o->relocatable) { 3269 if (driver_mark_executable_output(o->output_path) != 0) { 3270 driver_errf(LD_TOOL, "failed to set executable mode: %.*s", 3271 KIT_SLICE_ARG(kit_slice_cstr(o->output_path))); 3272 rc = 1; 3273 } 3274 } 3275 if (script) kit_link_script_free(&ctx, script); 3276 if (compiler) driver_compiler_free(compiler); 3277 kit_target_free(target); 3278 driver_runtime_archive_fini(o->env, &rt_archive); 3279 if (runtime_resolved) driver_runtime_support_fini(o->env, &runtime); 3280 release_file(&script_lf); 3281 release_all(arch_lf, o->inputs.narchives); 3282 release_all(obj_lf, o->inputs.nobject_files); 3283 release_all(dso_lf, o->inputs.ndsos); 3284 if (arch_in) 3285 driver_free(o->env, arch_in, o->inputs.narchives * sizeof(*arch_in)); 3286 if (arch_lf) 3287 driver_free(o->env, arch_lf, o->inputs.narchives * sizeof(*arch_lf)); 3288 if (obj_in) driver_free(o->env, obj_in, o->argv_bound * sizeof(*obj_in)); 3289 if (obj_lf) driver_free(o->env, obj_lf, o->argv_bound * sizeof(*obj_lf)); 3290 if (dso_in) driver_free(o->env, dso_in, o->inputs.ndsos * sizeof(*dso_in)); 3291 if (dso_lf) driver_free(o->env, dso_lf, o->inputs.ndsos * sizeof(*dso_lf)); 3292 if (order) 3293 driver_free(o->env, order, o->inputs.nlink_items * sizeof(*order)); 3294 return rc; 3295 } 3296 3297 int driver_ld(int argc, char** argv) { 3298 DriverEnv env; 3299 LdOptions lo = {0}; 3300 int rc; 3301 3302 if (argc < 2 || driver_argv_wants_help(argc, argv, 1)) { 3303 driver_help_ld(); 3304 return 0; 3305 } 3306 3307 driver_env_init(&env); 3308 lo.env = &env; 3309 lo.driver_path = argv[0]; 3310 3311 if (ld_parse(argc, argv, &lo) != 0) { 3312 ld_options_release(&lo); 3313 driver_env_fini(&env); 3314 return 2; 3315 } 3316 3317 rc = ld_run_link(&lo); 3318 3319 ld_options_release(&lo); 3320 driver_env_fini(&env); 3321 return rc; 3322 }