kit

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

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 }