link_inputs.c (19282B)
1 #include "link_inputs.h" 2 3 #include <kit/compile.h> 4 #include <kit/core.h> 5 6 #include "lib_resolve.h" 7 8 int driver_link_inputs_init(DriverLinkInputSet* set, DriverEnv* env, 9 const char* tool, size_t bound) { 10 set->env = env; 11 set->tool = tool; 12 set->bound = bound; 13 set->object_files = 14 driver_alloc_zeroed(env, bound * sizeof(*set->object_files)); 15 set->archives = driver_alloc_zeroed(env, bound * sizeof(*set->archives)); 16 set->dsos = driver_alloc_zeroed(env, bound * sizeof(*set->dsos)); 17 set->lib_search_paths = 18 driver_alloc_zeroed(env, bound * sizeof(*set->lib_search_paths)); 19 set->framework_search_paths = 20 driver_alloc_zeroed(env, bound * sizeof(*set->framework_search_paths)); 21 set->pending_libs = 22 driver_alloc_zeroed(env, bound * sizeof(*set->pending_libs)); 23 set->pending_frameworks = 24 driver_alloc_zeroed(env, bound * sizeof(*set->pending_frameworks)); 25 set->link_items = driver_alloc_zeroed(env, bound * sizeof(*set->link_items)); 26 if (!set->object_files || !set->archives || !set->dsos || 27 !set->lib_search_paths || !set->framework_search_paths || 28 !set->pending_libs || !set->pending_frameworks || !set->link_items) { 29 driver_errf(tool, "out of memory"); 30 return 1; 31 } 32 set->cur_link_mode = KIT_LM_DEFAULT; 33 return 0; 34 } 35 36 void driver_link_inputs_fini(DriverLinkInputSet* set) { 37 DriverEnv* env = set->env; 38 size_t bound = set->bound; 39 uint32_t i; 40 for (i = 0; i < set->narchives; ++i) 41 if (set->archives[i].owned) 42 driver_free(env, (void*)set->archives[i].path, 43 set->archives[i].owned_size); 44 for (i = 0; i < set->ndsos; ++i) 45 if (set->dsos[i].owned) 46 driver_free(env, (void*)set->dsos[i].path, set->dsos[i].owned_size); 47 if (set->owned_sysroot_lib_dir) 48 driver_free(env, set->owned_sysroot_lib_dir, 49 set->owned_sysroot_lib_dir_size); 50 for (i = 0; i < set->nowned_sysroot_framework_dirs; ++i) 51 if (set->owned_sysroot_framework_dirs[i]) 52 driver_free(env, set->owned_sysroot_framework_dirs[i], 53 set->owned_sysroot_framework_dir_sizes[i]); 54 if (set->object_files) 55 driver_free(env, set->object_files, bound * sizeof(*set->object_files)); 56 if (set->archives) 57 driver_free(env, set->archives, bound * sizeof(*set->archives)); 58 if (set->dsos) driver_free(env, set->dsos, bound * sizeof(*set->dsos)); 59 if (set->lib_search_paths) 60 driver_free(env, set->lib_search_paths, 61 bound * sizeof(*set->lib_search_paths)); 62 if (set->framework_search_paths) 63 driver_free(env, set->framework_search_paths, 64 bound * sizeof(*set->framework_search_paths)); 65 if (set->pending_libs) 66 driver_free(env, set->pending_libs, bound * sizeof(*set->pending_libs)); 67 if (set->pending_frameworks) 68 driver_free(env, set->pending_frameworks, 69 bound * sizeof(*set->pending_frameworks)); 70 if (set->link_items) 71 driver_free(env, set->link_items, bound * sizeof(*set->link_items)); 72 } 73 74 int driver_is_dso_path(const char* s) { 75 return kit_input_kind_for_path(NULL, s) == KIT_INPUT_DSO; 76 } 77 78 void driver_link_inputs_push(DriverLinkInputSet* set, uint8_t kind, 79 uint32_t index) { 80 DriverLinkItem* it = &set->link_items[set->nlink_items++]; 81 it->kind = kind; 82 it->index = index; 83 } 84 85 void driver_link_inputs_insert(DriverLinkInputSet* set, uint32_t pos, 86 uint8_t kind, uint32_t index) { 87 uint32_t i; 88 if (pos > set->nlink_items) pos = set->nlink_items; 89 for (i = set->nlink_items; i > pos; --i) 90 set->link_items[i] = set->link_items[i - 1u]; 91 set->link_items[pos].kind = kind; 92 set->link_items[pos].index = index; 93 set->nlink_items++; 94 } 95 96 int driver_link_inputs_append_hosted(DriverLinkInputSet* set, 97 const DriverHostedInput* in, 98 uint32_t insert_pos, int insert) { 99 uint32_t index; 100 uint8_t kind; 101 switch ((DriverHostedInputKind)in->kind) { 102 case DRIVER_HOSTED_INPUT_OBJECT: 103 index = set->nobject_files++; 104 set->object_files[index] = in->path; 105 kind = DRIVER_LINK_OBJECT; 106 break; 107 case DRIVER_HOSTED_INPUT_ARCHIVE: { 108 DriverArchiveInput* ar = &set->archives[set->narchives++]; 109 ar->path = in->path; 110 ar->whole_archive = 0; 111 ar->link_mode = KIT_LM_DEFAULT; 112 ar->group_id = 0; 113 index = set->narchives - 1u; 114 kind = DRIVER_LINK_ARCHIVE; 115 break; 116 } 117 case DRIVER_HOSTED_INPUT_DSO: { 118 DriverDsoInput* d = &set->dsos[set->ndsos++]; 119 d->path = in->path; 120 index = set->ndsos - 1u; 121 kind = DRIVER_LINK_DSO; 122 break; 123 } 124 default: 125 driver_errf(set->tool, "internal error: unknown hosted input kind"); 126 return 1; 127 } 128 if (insert) 129 driver_link_inputs_insert(set, insert_pos, kind, index); 130 else 131 driver_link_inputs_push(set, kind, index); 132 return 0; 133 } 134 135 void driver_link_inputs_insert_runtime_archive(DriverLinkInputSet* set, 136 DriverRuntimeArchive* rt, 137 uint32_t insert_pos) { 138 DriverArchiveInput* ar = &set->archives[set->narchives++]; 139 ar->path = rt->path; 140 ar->owned = 1; 141 ar->owned_size = rt->path_size; 142 ar->whole_archive = rt->whole_archive; 143 ar->link_mode = rt->link_mode; 144 ar->group_id = rt->group_id; 145 rt->path = NULL; 146 rt->path_size = 0; 147 driver_link_inputs_insert(set, insert_pos, DRIVER_LINK_ARCHIVE, 148 set->narchives - 1u); 149 } 150 151 void driver_link_inputs_insert_runtime_archives(DriverLinkInputSet* set, 152 DriverRuntimeArchive* rt, 153 KitTargetSpec target, 154 uint32_t nfinal, 155 uint32_t nafter) { 156 /* On Windows the rt archive is inserted at TWO positions to handle two 157 * competing requirements: 158 * 159 * (a) Before the hosted 'after' group: libucrt.a's _setjmp is a COFF 160 * WEAK_EXTERNAL aliasing __intrinsic_setjmp from the private api-set 161 * api-ms-win-crt-private-l1-1-0.dll. When libucrt.a's inner loop 162 * pulls that WEAK_EXTERNAL member it immediately satisfies 163 * __intrinsic_setjmp from the same archive, binding the PE to the 164 * private DLL (0xC0000139 on Prism). rt's strong _setjmp/_setjmpex 165 * must be in 'defined' before libucrt.a is scanned to prevent the 166 * WEAK_EXTERNAL member from ever being pulled. 167 * 168 * (b) After the hosted 'after' group (before crtend only): libucrt.a 169 * pulls libc functions (printf, malloc, …) that contain large stack 170 * frames compiled by GCC, which call ___chkstk_ms. Those undefs 171 * appear only after libucrt.a's own inner loop runs — after all 172 * earlier archives have already finished. A second rt entry here 173 * catches those late ___chkstk_ms undefs and satisfies them with 174 * rt's own chkstk implementation. 175 * 176 * Because archive scanning is lazy, no symbol is ever defined twice: 177 * the second rt entry skips every member the first already pulled. 178 * 179 * On other hosts rt stays at the end (before crtend only) — DSO-provided 180 * libc symbols shadow rt's freestanding fallbacks cleanly. */ 181 if (target.os == KIT_OS_WINDOWS) { 182 char* rt_path2 = NULL; 183 size_t rt_path2_size = 0; 184 uint32_t before_pos, after_pos; 185 186 /* before_pos: just before the 'after' group */ 187 before_pos = set->nlink_items; 188 { 189 uint32_t nadj = nfinal + nafter; 190 if (nadj <= before_pos) before_pos -= nadj; 191 } 192 /* after_pos: before crtend.o only (original position) */ 193 after_pos = set->nlink_items; 194 if (nfinal <= after_pos) after_pos -= nfinal; 195 196 /* Duplicate path for the second entry before ownership is transferred. 197 * Both inserts use lazy pull (no whole_archive). */ 198 if (rt->path && rt->path_size > 0) { 199 rt_path2 = (char*)driver_alloc(set->env, rt->path_size + 1u); 200 if (rt_path2) { 201 rt_path2_size = rt->path_size; 202 driver_memcpy(rt_path2, rt->path, rt->path_size); 203 rt_path2[rt->path_size] = '\0'; 204 } 205 } 206 207 /* Insert later position first so it doesn't shift before_pos. */ 208 if (rt_path2) { 209 DriverArchiveInput* ar2 = &set->archives[set->narchives++]; 210 ar2->path = rt_path2; 211 ar2->owned = 1; 212 ar2->owned_size = rt_path2_size; 213 ar2->whole_archive = 0; 214 ar2->link_mode = rt->link_mode; 215 ar2->group_id = rt->group_id; 216 driver_link_inputs_insert(set, after_pos, DRIVER_LINK_ARCHIVE, 217 set->narchives - 1u); 218 } 219 /* Insert earlier position (original path; ownership transferred). */ 220 driver_link_inputs_insert_runtime_archive(set, rt, before_pos); 221 } else { 222 uint32_t insert_pos = set->nlink_items; 223 if (nfinal <= insert_pos) insert_pos -= nfinal; 224 driver_link_inputs_insert_runtime_archive(set, rt, insert_pos); 225 } 226 } 227 228 uint32_t driver_link_inputs_build_order(const DriverLinkInputSet* set, 229 const uint32_t* source_obj_index, 230 const uint8_t* source_order_keep, 231 uint32_t nsource_files, 232 KitLinkInputOrder* order) { 233 uint32_t i; 234 uint32_t norder = 0; 235 for (i = 0; i < set->nlink_items; ++i) { 236 const DriverLinkItem* item = &set->link_items[i]; 237 KitLinkInputOrder* ord; 238 switch ((DriverLinkKind)item->kind) { 239 case DRIVER_LINK_SOURCE: 240 if (!source_order_keep[item->index]) continue; 241 ord = &order[norder++]; 242 ord->kind = KIT_LINK_INPUT_OBJ; 243 ord->index = source_obj_index[item->index]; 244 break; 245 case DRIVER_LINK_SOURCE_MEMORY: { 246 /* cc-only (in-memory stdin source) — indexes the shared source arrays 247 * past the file-backed sources. build never records this kind. */ 248 uint32_t si = nsource_files + item->index; 249 if (!source_order_keep[si]) continue; 250 ord = &order[norder++]; 251 ord->kind = KIT_LINK_INPUT_OBJ; 252 ord->index = source_obj_index[si]; 253 break; 254 } 255 case DRIVER_LINK_OBJECT: 256 ord = &order[norder++]; 257 ord->kind = KIT_LINK_INPUT_OBJ_BYTES; 258 ord->index = item->index; 259 break; 260 case DRIVER_LINK_ARCHIVE: 261 ord = &order[norder++]; 262 ord->kind = KIT_LINK_INPUT_ARCHIVE; 263 ord->index = item->index; 264 break; 265 case DRIVER_LINK_DSO: 266 ord = &order[norder++]; 267 ord->kind = KIT_LINK_INPUT_DSO; 268 ord->index = item->index; 269 break; 270 case DRIVER_LINK_LIB: { 271 const DriverPendingLib* pl = &set->pending_libs[item->index]; 272 ord = &order[norder++]; 273 if (pl->resolved_kind == DRIVER_LINK_DSO) { 274 ord->kind = KIT_LINK_INPUT_DSO; 275 ord->index = pl->resolved_index; 276 } else { 277 ord->kind = KIT_LINK_INPUT_ARCHIVE; 278 ord->index = pl->resolved_index; 279 } 280 break; 281 } 282 case DRIVER_LINK_FRAMEWORK: { 283 const DriverPendingFramework* pf = 284 &set->pending_frameworks[item->index]; 285 ord = &order[norder++]; 286 ord->kind = KIT_LINK_INPUT_DSO; 287 ord->index = pf->resolved_index; 288 break; 289 } 290 } 291 } 292 return norder; 293 } 294 295 int driver_link_inputs_resolve_pending(DriverLinkInputSet* set, 296 KitTargetSpec target, int static_link) { 297 uint32_t i; 298 for (i = 0; i < set->npending_libs; ++i) { 299 DriverPendingLib* pl = &set->pending_libs[i]; 300 char* p; 301 size_t sz; 302 LibResolveKind kind; 303 LibResolveMode mode = (static_link || pl->link_mode == KIT_LM_STATIC) 304 ? LIB_RESOLVE_STATIC_ONLY 305 : LIB_RESOLVE_DYNAMIC_PREFER; 306 LibResolveOS resolve_os = (target.os == KIT_OS_WINDOWS) 307 ? LIB_RESOLVE_OS_WINDOWS 308 : LIB_RESOLVE_OS_POSIX; 309 if (driver_lib_resolve_for_os(set->env, pl->name, mode, resolve_os, 310 set->lib_search_paths, set->nlib_search_paths, 311 &p, &sz, &kind) != 0) { 312 driver_errf(set->tool, "library not found: -l%.*s", 313 KIT_SLICE_ARG(kit_slice_cstr(pl->name))); 314 return 1; 315 } 316 if (kind == LIB_RESOLVE_KIND_SHARED || kind == LIB_RESOLVE_KIND_TBD) { 317 DriverDsoInput* d = &set->dsos[set->ndsos++]; 318 d->path = p; 319 d->owned = 1; 320 d->owned_size = sz; 321 pl->resolved_kind = DRIVER_LINK_DSO; 322 pl->resolved_index = set->ndsos - 1u; 323 } else { 324 DriverArchiveInput* ar = &set->archives[set->narchives++]; 325 ar->path = p; 326 ar->owned = 1; 327 ar->owned_size = sz; 328 ar->whole_archive = pl->whole_archive; 329 ar->link_mode = pl->link_mode; 330 ar->group_id = pl->group_id; 331 pl->resolved_kind = DRIVER_LINK_ARCHIVE; 332 pl->resolved_index = set->narchives - 1u; 333 } 334 } 335 for (i = 0; i < set->npending_frameworks; ++i) { 336 DriverPendingFramework* pf = &set->pending_frameworks[i]; 337 char* p; 338 size_t sz; 339 LibResolveKind kind; 340 if (driver_framework_resolve(set->env, pf->name, 341 set->framework_search_paths, 342 set->nframework_search_paths, &p, &sz, 343 &kind) != 0) { 344 driver_errf(set->tool, "framework not found: -framework %.*s", 345 KIT_SLICE_ARG(kit_slice_cstr(pf->name))); 346 return 1; 347 } 348 (void)kind; 349 { 350 DriverDsoInput* d = &set->dsos[set->ndsos++]; 351 d->path = p; 352 d->owned = 1; 353 d->owned_size = sz; 354 pf->resolved_index = set->ndsos - 1u; 355 } 356 } 357 return 0; 358 } 359 360 /* The llvm-mingw UCRT sysroot ships import archives (libkernel32.a, libucrt.a, 361 * the UCRT API-set archives) under <sysroot>/lib; the user `-L` list is 362 * searched first, then this appended default. Sysroot resolution order: 363 * 1. -isysroot / --sysroot on the command line (already in *sysroot); 364 * 2. KIT_SYSROOT env var (e.g. .../x86_64-w64-mingw32). 365 * The appended path aliases the sysroot string for its lifetime; *sysroot is 366 * either argv-borrowed or env-borrowed, both stable across the driver run, so 367 * the lib_search_paths slot remains valid. */ 368 int driver_link_inputs_append_windows_lib_dirs(DriverLinkInputSet* set, 369 const char** sysroot, 370 KitTargetSpec target) { 371 const char* sr = *sysroot; 372 char* joined; 373 size_t srlen, need_slash, bytes, off = 0; 374 if (!driver_target_needs_sysroot_libdir(target)) return 0; 375 if (!sr || !sr[0]) { 376 sr = driver_getenv("KIT_SYSROOT"); 377 if (!sr || !sr[0]) return 0; 378 *sysroot = sr; 379 } 380 srlen = driver_strlen(sr); 381 need_slash = (srlen > 0 && sr[srlen - 1] != '/') ? 1u : 0u; 382 /* "<sysroot>" + "/"? + "lib" + NUL */ 383 bytes = srlen + need_slash + 3u + 1u; 384 joined = driver_alloc(set->env, bytes); 385 if (!joined) { 386 driver_errf(set->tool, "out of memory"); 387 return 1; 388 } 389 driver_memcpy(joined + off, sr, srlen); 390 off += srlen; 391 if (need_slash) joined[off++] = '/'; 392 driver_memcpy(joined + off, "lib", 3); 393 off += 3; 394 joined[off] = '\0'; 395 if (set->owned_sysroot_lib_dir) 396 driver_free(set->env, set->owned_sysroot_lib_dir, 397 set->owned_sysroot_lib_dir_size); 398 set->owned_sysroot_lib_dir = joined; 399 set->owned_sysroot_lib_dir_size = bytes; 400 set->lib_search_paths[set->nlib_search_paths++] = joined; 401 return 0; 402 } 403 404 int driver_target_uses_framework_dirs(KitTargetSpec target) { 405 const KitOsImpl* o = kit_os_lookup(target.os); 406 return target.obj == KIT_OBJ_MACHO && o && o->hosted && 407 o->hosted->uses_framework_dirs; 408 } 409 410 static int driver_link_inputs_add_owned_framework_dir(DriverLinkInputSet* set, 411 const char* sysroot, 412 const char* sub) { 413 char* joined; 414 size_t size; 415 if (set->nowned_sysroot_framework_dirs >= 2u) return 0; 416 joined = driver_path_join(set->env, sysroot, sub, &size); 417 if (!joined) { 418 driver_errf(set->tool, "out of memory"); 419 return 1; 420 } 421 set->owned_sysroot_framework_dirs[set->nowned_sysroot_framework_dirs] = 422 joined; 423 set->owned_sysroot_framework_dir_sizes[set->nowned_sysroot_framework_dirs] = 424 size; 425 set->nowned_sysroot_framework_dirs++; 426 set->framework_search_paths[set->nframework_search_paths++] = joined; 427 return 0; 428 } 429 430 int driver_link_inputs_append_sysroot_framework_dirs(DriverLinkInputSet* set, 431 const char** sysroot, 432 KitTargetSpec target) { 433 const char* sr = *sysroot; 434 if (!driver_target_uses_framework_dirs(target)) return 0; 435 if (!sr || !sr[0]) { 436 sr = driver_getenv("KIT_SYSROOT"); 437 if (!sr || !sr[0]) return 0; 438 *sysroot = sr; 439 } 440 if (driver_link_inputs_add_owned_framework_dir( 441 set, sr, "System/Library/Frameworks") != 0) 442 return 1; 443 if (driver_link_inputs_add_owned_framework_dir( 444 set, sr, "System/Library/PrivateFrameworks") != 0) 445 return 1; 446 return 0; 447 } 448 449 int driver_link_inputs_apply_hosted(DriverLinkInputSet* set, 450 DriverHostedPlan* plan, DriverCflags* cf, 451 DriverLinkFlags* link, KitTargetSpec target, 452 const char* sysroot, int static_link, 453 int shared_link, int no_startfiles, 454 int link_action) { 455 DriverHostedRequest req = {0}; 456 uint32_t i; 457 uint32_t insert_pos = 0; 458 req.env = set->env; 459 req.tool = set->tool; 460 req.target = target; 461 req.sysroot = sysroot; 462 req.static_link = static_link; 463 req.shared_link = shared_link; 464 req.link_inputs = link_action; 465 if (driver_hosted_resolve(&req, plan) != 0) return 1; 466 for (i = 0; i < plan->nsystem_includes; ++i) 467 cf->system_include_dirs[cf->nsystem_include_dirs++] = 468 plan->system_includes[i]; 469 for (i = 0; i < plan->ndefines; ++i) 470 cf->defines[cf->ndefines++] = plan->defines[i]; 471 /* Hosted lib search dirs let user -l flags (-lm, -lpthread, ...) resolve. The 472 * strings are owned by `plan` and outlive lib_search_paths. Insert before any 473 * user -L dirs so sysroot libs take precedence. */ 474 for (i = 0; i < plan->nlib_search_dirs; ++i) 475 set->lib_search_paths[set->nlib_search_paths++] = plan->lib_search_dirs[i]; 476 if (!link_action) return 0; 477 for (i = 0; i < plan->nbefore; ++i) { 478 if (no_startfiles) break; 479 if (driver_link_inputs_append_hosted(set, &plan->before[i], insert_pos, 480 1) != 0) 481 return 1; 482 insert_pos++; 483 } 484 for (i = 0; i < plan->nafter; ++i) 485 if (driver_link_inputs_append_hosted(set, &plan->after[i], 0, 0) != 0) 486 return 1; 487 for (i = 0; i < plan->nfinal; ++i) { 488 if (no_startfiles) break; 489 if (driver_link_inputs_append_hosted(set, &plan->final[i], 0, 0) != 0) 490 return 1; 491 } 492 if (!link->interp_path && plan->interp_path) 493 link->interp_path = plan->interp_path; 494 return 0; 495 }