commit ba66f6d185d5821bdbd424aa95957d9af2fdfdca
parent 5e1e8ee566de76b632288cc242977c11e301a917
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Wed, 17 Jun 2026 08:04:48 -0700
ld: embed DriverLinkInputSet (drop private input model)
Diffstat:
| M | driver/cmd/ld.c | | | 560 | ++++++++++++++++++++++++++++++------------------------------------------------- |
1 file changed, 214 insertions(+), 346 deletions(-)
diff --git a/driver/cmd/ld.c b/driver/cmd/ld.c
@@ -8,6 +8,7 @@
#include "hosted.h"
#include "lib_resolve.h"
#include "link_flags.h"
+#include "link_inputs.h"
#include "runtime.h"
/* `kit ld` — link object/archive inputs into an executable, shared
@@ -57,27 +58,6 @@
#define LD_TOOL "ld"
-/* Per-archive metadata mirroring the relevant subset of
- * KitLinkArchiveInput plus driver-side ownership info. */
-typedef struct LdArchive {
- const char* path; /* path used for both open and KitSliceInput.name */
- int owned; /* 1 if `path` was alloc'd by lib_resolve */
- size_t owned_size; /* allocation size (for driver_free) */
- uint8_t whole_archive; /* nonzero == --whole-archive */
- uint8_t link_mode; /* KitLinkMode (-Bstatic/-Bdynamic/--as-needed) */
- uint8_t group_id; /* cyclic resolution group id; 0 = single-pass */
-} LdArchive;
-
-/* Per-DSO ownership info. The DSO bytes are loaded straight off disk
- * via env->file_io into the KitSlice passed to libkit; only
- * the path itself may need to be free'd if it came from -l<name>
- * resolution. */
-typedef struct LdDso {
- const char* path; /* path used for both open and KitSliceInput.name */
- int owned; /* 1 if `path` was alloc'd by lib_resolve */
- size_t owned_size; /* allocation size (for driver_free) */
-} LdDso;
-
typedef struct LdOptions {
DriverEnv* env;
const char* driver_path;
@@ -104,31 +84,19 @@ typedef struct LdOptions {
* driver_link_flags_fill_options. */
DriverLinkFlags lf;
- const char** object_files;
- uint32_t nobject_files;
-
- LdArchive* archives;
- uint32_t narchives;
+ /* Shared link-input model: object/archive/dso arrays, the ordered link-item
+ * list, the -L/-F search paths, and the positional archive flag state
+ * (cur_whole_archive/cur_link_mode/cur_group_id). ld resolves -l/-framework
+ * eagerly into archives/dsos rather than via the pending-lib model, to
+ * preserve GNU GROUP / positional link ordering. */
+ DriverLinkInputSet inputs;
- /* Shared-object inputs (positional .so / .so.N or `-l<name>` under
- * -Bdynamic). The runtime loader resolves these by SONAME at link
- * time → DT_NEEDED entries. */
- LdDso* dsos;
- uint32_t ndsos;
- KitLinkInputOrder* order;
- uint32_t norder;
-
- const char** lib_dirs; /* -L */
- uint32_t nlib_dirs;
- const char** framework_dirs; /* -F */
- uint32_t nframework_dirs;
int lib_dirs_precollected; /* first pass collected argv -L / --library-path */
- char** owned_paths; /* sysroot-expanded argv/search paths */
+ char** owned_paths; /* INPUT-path strings: sysroot-rewritten -L/-F dirs and
+ * hosted libdir strings (the FLAG strings live in lf). */
size_t* owned_path_sizes;
uint32_t nowned_paths;
- size_t cap_owned_paths; /* grows independently of argv_bound: a single -Wl
- * token (e.g. --section-start/--defsym) can mint
- * several owned strings, so this is not argv-bounded */
+ size_t cap_owned_paths; /* grows independently of argv_bound */
/* Shared-library output state. */
int shared; /* -shared */
@@ -142,12 +110,13 @@ typedef struct LdOptions {
int explicit_crt_start; /* caller supplied crt1/Scrt1/rcrt1-style start */
int has_compiler_runtime; /* caller supplied compiler builtins/runtime */
DriverHostedPlan hosted;
+ /* Sink for the hosted profile's system includes/defines required by the
+ * shared driver_link_inputs_apply_hosted contract. ld never compiles, so
+ * these are populated but unused (only the plan's lib dirs + crt inputs +
+ * interp matter to the linker). */
+ DriverCflags cf;
- /* Mutable parse state for positional archive flags / groups. */
- uint8_t cur_whole_archive; /* pending --whole-archive flag */
- uint8_t cur_link_mode; /* KitLinkMode for following inputs */
- uint8_t cur_group_id; /* 0 outside any --start-group */
- uint8_t next_group_id; /* increments on --start-group */
+ uint8_t next_group_id; /* increments on --start-group / GROUP() */
/* Opt-in: treat `/...` arguments as MSVC link.exe flags. Off by
* default so legacy paths like `/usr/lib/foo.o` remain inputs. */
@@ -263,48 +232,32 @@ void driver_help_ld(void) {
static int ld_alloc_arrays(LdOptions* o, int argc) {
size_t bound = (size_t)argc + 32u;
o->argv_bound = bound;
- o->object_files =
- driver_alloc_zeroed(o->env, bound * sizeof(*o->object_files));
- o->archives = driver_alloc_zeroed(o->env, bound * sizeof(*o->archives));
- o->dsos = driver_alloc_zeroed(o->env, bound * sizeof(*o->dsos));
- o->order = driver_alloc_zeroed(o->env, bound * sizeof(*o->order));
- o->lib_dirs = driver_alloc_zeroed(o->env, bound * sizeof(*o->lib_dirs));
- o->framework_dirs =
- driver_alloc_zeroed(o->env, bound * sizeof(*o->framework_dirs));
o->owned_paths = driver_alloc_zeroed(o->env, bound * sizeof(*o->owned_paths));
o->owned_path_sizes =
driver_alloc_zeroed(o->env, bound * sizeof(*o->owned_path_sizes));
o->cap_owned_paths = bound;
o->rpath_links = driver_alloc_zeroed(o->env, bound * sizeof(*o->rpath_links));
- if (!o->object_files || !o->archives || !o->dsos || !o->order ||
- !o->lib_dirs || !o->framework_dirs || !o->owned_paths ||
- !o->owned_path_sizes || !o->rpath_links) {
+ if (!o->owned_paths || !o->owned_path_sizes || !o->rpath_links) {
driver_errf(LD_TOOL, "out of memory");
return 1;
}
if (driver_link_flags_init(&o->lf, o->env, LD_TOOL, (uint32_t)bound) != 0)
return 1;
+ if (driver_link_inputs_init(&o->inputs, o->env, LD_TOOL, bound) != 0)
+ return 1;
+ /* Sized for the hosted profile's includes/defines only (ld parses no -D/-I);
+ * see the cf comment in LdOptions. */
+ if (driver_cflags_init(&o->cf, o->env,
+ (int)(DRIVER_HOSTED_MAX_DEFINES +
+ DRIVER_HOSTED_MAX_INCLUDES)) != 0) {
+ driver_errf(LD_TOOL, "out of memory");
+ return 1;
+ }
return 0;
}
/* ---------- positional archive bookkeeping ---------- */
-static void ld_push_order(LdOptions* o, uint8_t kind, uint32_t index) {
- KitLinkInputOrder* slot = &o->order[o->norder++];
- slot->kind = kind;
- slot->index = index;
-}
-
-static void ld_insert_order(LdOptions* o, uint32_t pos, uint8_t kind,
- uint32_t index) {
- uint32_t i;
- if (pos > o->norder) pos = o->norder;
- for (i = o->norder; i > pos; --i) o->order[i] = o->order[i - 1u];
- o->order[pos].kind = kind;
- o->order[pos].index = index;
- o->norder++;
-}
-
static int ld_str_prefix(const char* s, const char* prefix) {
size_t n = driver_strlen(prefix);
return driver_strneq(s, prefix, n);
@@ -344,106 +297,80 @@ static void ld_note_object_path(LdOptions* o, const char* path) {
if (ld_is_crt_start_object(path)) o->explicit_crt_start = 1;
}
-static void ld_push_object(LdOptions* o, const char* path) {
- ld_note_object_path(o, path);
- o->object_files[o->nobject_files++] = path;
- ld_push_order(o, KIT_LINK_INPUT_OBJ_BYTES, o->nobject_files - 1u);
+/* Fill the next free archive slot in the shared input set (without ordering)
+ * and return its index, noting compiler-runtime archives along the way. */
+static uint32_t ld_add_archive_slot(LdOptions* o, const char* path, int owned,
+ size_t owned_size, uint8_t whole_archive,
+ uint8_t link_mode, uint8_t group_id) {
+ DriverArchiveInput* a = &o->inputs.archives[o->inputs.narchives++];
+ if (ld_is_compiler_runtime_archive(path)) o->has_compiler_runtime = 1;
+ a->path = path;
+ a->owned = owned;
+ a->owned_size = owned_size;
+ a->whole_archive = whole_archive;
+ a->link_mode = link_mode;
+ a->group_id = group_id;
+ return o->inputs.narchives - 1u;
+}
+
+static uint32_t ld_add_dso_slot(LdOptions* o, const char* path, int owned,
+ size_t owned_size) {
+ DriverDsoInput* d = &o->inputs.dsos[o->inputs.ndsos++];
+ d->path = path;
+ d->owned = owned;
+ d->owned_size = owned_size;
+ return o->inputs.ndsos - 1u;
}
-static void ld_insert_object(LdOptions* o, const char* path, uint32_t pos) {
+static uint32_t ld_add_object_slot(LdOptions* o, const char* path) {
ld_note_object_path(o, path);
- o->object_files[o->nobject_files++] = path;
- ld_insert_order(o, pos, KIT_LINK_INPUT_OBJ_BYTES, o->nobject_files - 1u);
+ o->inputs.object_files[o->inputs.nobject_files++] = path;
+ return o->inputs.nobject_files - 1u;
}
-static void ld_push_archive(LdOptions* o, const char* path, int owned,
- size_t owned_size) {
- LdArchive* a = &o->archives[o->narchives++];
- if (ld_is_compiler_runtime_archive(path)) o->has_compiler_runtime = 1;
- a->path = path;
- a->owned = owned;
- a->owned_size = owned_size;
- a->whole_archive = o->cur_whole_archive;
- a->link_mode = o->cur_link_mode;
- a->group_id = o->cur_group_id;
- ld_push_order(o, KIT_LINK_INPUT_ARCHIVE, o->narchives - 1u);
+static void ld_push_object(LdOptions* o, const char* path) {
+ uint32_t idx = ld_add_object_slot(o, path);
+ driver_link_inputs_push(&o->inputs, DRIVER_LINK_OBJECT, idx);
}
-static void ld_push_runtime_archive(LdOptions* o, DriverRuntimeArchive* rt) {
- LdArchive* a = &o->archives[o->narchives++];
- a->path = rt->path;
- a->owned = 1;
- a->owned_size = rt->path_size;
- a->whole_archive = rt->whole_archive;
- a->link_mode = rt->link_mode;
- a->group_id = rt->group_id;
- rt->path = NULL;
- rt->path_size = 0;
- ld_push_order(o, KIT_LINK_INPUT_ARCHIVE, o->narchives - 1u);
+static void ld_push_archive(LdOptions* o, const char* path, int owned,
+ size_t owned_size) {
+ uint32_t idx = ld_add_archive_slot(
+ o, path, owned, owned_size, o->inputs.cur_whole_archive,
+ o->inputs.cur_link_mode, o->inputs.cur_group_id);
+ driver_link_inputs_push(&o->inputs, DRIVER_LINK_ARCHIVE, idx);
}
static void ld_push_dso(LdOptions* o, const char* path, int owned,
size_t owned_size) {
- LdDso* d = &o->dsos[o->ndsos++];
- d->path = path;
- d->owned = owned;
- d->owned_size = owned_size;
- ld_push_order(o, KIT_LINK_INPUT_DSO, o->ndsos - 1u);
+ uint32_t idx = ld_add_dso_slot(o, path, owned, owned_size);
+ driver_link_inputs_push(&o->inputs, DRIVER_LINK_DSO, idx);
}
static int ld_order_capacity(LdOptions* o, uint32_t nmore) {
- if (o->norder + nmore <= o->argv_bound) return 0;
+ if (o->inputs.nlink_items + nmore <= o->argv_bound) return 0;
driver_errf(LD_TOOL, "too many linker inputs");
return 1;
}
static int ld_archive_capacity(LdOptions* o) {
- if (o->narchives < o->argv_bound) return 0;
+ if (o->inputs.narchives < o->argv_bound) return 0;
driver_errf(LD_TOOL, "too many archive inputs");
return 1;
}
static int ld_dso_capacity(LdOptions* o) {
- if (o->ndsos < o->argv_bound) return 0;
+ if (o->inputs.ndsos < o->argv_bound) return 0;
driver_errf(LD_TOOL, "too many shared-object inputs");
return 1;
}
static int ld_object_capacity(LdOptions* o) {
- if (o->nobject_files < o->argv_bound) return 0;
+ if (o->inputs.nobject_files < o->argv_bound) return 0;
driver_errf(LD_TOOL, "too many object inputs");
return 1;
}
-static uint32_t ld_add_archive_slot(LdOptions* o, const char* path, int owned,
- size_t owned_size, uint8_t whole_archive,
- uint8_t link_mode, uint8_t group_id) {
- LdArchive* a = &o->archives[o->narchives++];
- if (ld_is_compiler_runtime_archive(path)) o->has_compiler_runtime = 1;
- a->path = path;
- a->owned = owned;
- a->owned_size = owned_size;
- a->whole_archive = whole_archive;
- a->link_mode = link_mode;
- a->group_id = group_id;
- return o->narchives - 1u;
-}
-
-static uint32_t ld_add_dso_slot(LdOptions* o, const char* path, int owned,
- size_t owned_size) {
- LdDso* d = &o->dsos[o->ndsos++];
- d->path = path;
- d->owned = owned;
- d->owned_size = owned_size;
- return o->ndsos - 1u;
-}
-
-static uint32_t ld_add_object_slot(LdOptions* o, const char* path) {
- ld_note_object_path(o, path);
- o->object_files[o->nobject_files++] = path;
- return o->nobject_files - 1u;
-}
-
/* Filename ends in `.so` (with no further extension) or in `.so.N`
* for some run of digits and dots. */
static int driver_is_so_filename(const char* path) {
@@ -552,20 +479,20 @@ static int ld_own_path(LdOptions* o, char* path, size_t size,
}
static int ld_add_lib_dir(LdOptions* o, const char* dir) {
- if (o->nlib_dirs >= o->argv_bound) {
+ if (o->inputs.nlib_search_paths >= o->argv_bound) {
driver_errf(LD_TOOL, "too many library search paths");
return 1;
}
- o->lib_dirs[o->nlib_dirs++] = dir;
+ o->inputs.lib_search_paths[o->inputs.nlib_search_paths++] = dir;
return 0;
}
static int ld_add_framework_dir(LdOptions* o, const char* dir) {
- if (o->nframework_dirs >= o->argv_bound) {
+ if (o->inputs.nframework_search_paths >= o->argv_bound) {
driver_errf(LD_TOOL, "too many framework search paths");
return 1;
}
- o->framework_dirs[o->nframework_dirs++] = dir;
+ o->inputs.framework_search_paths[o->inputs.nframework_search_paths++] = dir;
return 0;
}
@@ -667,9 +594,10 @@ static int ld_resolve_exact_library(LdOptions* o, const char* leaf,
LibResolveKind* out_kind) {
uint32_t i;
if (!leaf || !leaf[0]) return 1;
- for (i = 0; i < o->nlib_dirs; ++i) {
+ for (i = 0; i < o->inputs.nlib_search_paths; ++i) {
size_t size = 0;
- char* cand = driver_path_join(o->env, o->lib_dirs[i], leaf, &size);
+ char* cand =
+ driver_path_join(o->env, o->inputs.lib_search_paths[i], leaf, &size);
if (!cand) return 1;
if (driver_path_exists(cand)) {
*out_path = cand;
@@ -699,23 +627,26 @@ static int ld_resolve_library(LdOptions* o, const char* name,
const char* alias;
if (name && name[0] == ':')
return ld_resolve_exact_library(o, name + 1, out_path, out_size, out_kind);
- if (driver_lib_resolve_for_os(o->env, name, mode, resolve_os, o->lib_dirs,
- o->nlib_dirs, out_path, out_size,
+ if (driver_lib_resolve_for_os(o->env, name, mode, resolve_os,
+ o->inputs.lib_search_paths,
+ o->inputs.nlib_search_paths, out_path, out_size,
out_kind) == 0)
return 0;
if (resolve_os != LIB_RESOLVE_OS_WINDOWS) return 1;
alias = ld_windows_runtime_alias(o, name);
if (!alias) return 1;
- return driver_lib_resolve_for_os(o->env, alias, mode, resolve_os, o->lib_dirs,
- o->nlib_dirs, out_path, out_size, out_kind);
+ return driver_lib_resolve_for_os(o->env, alias, mode, resolve_os,
+ o->inputs.lib_search_paths,
+ o->inputs.nlib_search_paths, out_path,
+ out_size, out_kind);
}
static int ld_resolve_framework(LdOptions* o, const char* name,
char** out_path, size_t* out_size) {
LibResolveKind kind;
- return driver_framework_resolve(o->env, name, o->framework_dirs,
- o->nframework_dirs, out_path, out_size,
- &kind);
+ return driver_framework_resolve(o->env, name, o->inputs.framework_search_paths,
+ o->inputs.nframework_search_paths, out_path,
+ out_size, &kind);
}
static int ld_push_framework(LdOptions* o, const char* name) {
@@ -959,27 +890,27 @@ static int ld_parse_wl(LdOptions* o, const char* arg) {
continue;
}
if (ld_tok_eq(tok, n, "-Bstatic")) {
- o->cur_link_mode = KIT_LM_STATIC;
+ o->inputs.cur_link_mode = KIT_LM_STATIC;
continue;
}
if (ld_tok_eq(tok, n, "-Bdynamic")) {
- o->cur_link_mode = KIT_LM_DYNAMIC;
+ o->inputs.cur_link_mode = KIT_LM_DYNAMIC;
continue;
}
if (ld_tok_eq(tok, n, "--as-needed")) {
- o->cur_link_mode = KIT_LM_AS_NEEDED;
+ o->inputs.cur_link_mode = KIT_LM_AS_NEEDED;
continue;
}
if (ld_tok_eq(tok, n, "--no-as-needed")) {
- o->cur_link_mode = KIT_LM_DYNAMIC;
+ o->inputs.cur_link_mode = KIT_LM_DYNAMIC;
continue;
}
if (ld_tok_eq(tok, n, "--whole-archive")) {
- o->cur_whole_archive = 1;
+ o->inputs.cur_whole_archive = 1;
continue;
}
if (ld_tok_eq(tok, n, "--no-whole-archive")) {
- o->cur_whole_archive = 0;
+ o->inputs.cur_whole_archive = 0;
continue;
}
if (ld_tok_eq(tok, n, "-z")) {
@@ -1360,9 +1291,10 @@ static int ld_script_resolve_file(LdInputScript* s, const char* name,
driver_free(o->env, cand, size);
}
- for (i = 0; i < o->nlib_dirs; ++i) {
+ for (i = 0; i < o->inputs.nlib_search_paths; ++i) {
size_t size = 0;
- char* cand = driver_path_join(o->env, o->lib_dirs[i], name, &size);
+ char* cand =
+ driver_path_join(o->env, o->inputs.lib_search_paths[i], name, &size);
if (!cand) {
driver_errf(LD_TOOL, "out of memory");
return 1;
@@ -1387,16 +1319,19 @@ static int ld_script_resolve_file(LdInputScript* s, const char* name,
return 1;
}
+/* The GNU INPUT()/GROUP() expander replaces the DSO-script link item at
+ * `order_pos` with the script's first input, then inserts the rest just after
+ * it — preserving the script's position in the overall link order. */
static int ld_script_add_order(LdInputScript* s, uint8_t kind, uint32_t index) {
if (!s->added) {
- s->o->order[s->order_pos].kind = kind;
- s->o->order[s->order_pos].index = index;
+ s->o->inputs.link_items[s->order_pos].kind = kind;
+ s->o->inputs.link_items[s->order_pos].index = index;
s->insert_pos = s->order_pos + 1u;
s->added = 1;
return 0;
}
if (ld_order_capacity(s->o, 1) != 0) return 1;
- ld_insert_order(s->o, s->insert_pos, kind, index);
+ driver_link_inputs_insert(&s->o->inputs, s->insert_pos, kind, index);
s->insert_pos++;
return 0;
}
@@ -1408,10 +1343,10 @@ static int ld_script_add_path(LdInputScript* s, const char* path, int owned,
if (driver_has_suffix(path, ".a") || driver_has_suffix(path, ".rlib")) {
uint32_t idx;
if (ld_archive_capacity(o) != 0) goto fail;
- idx = ld_add_archive_slot(o, path, owned, owned_size, o->cur_whole_archive,
- as_needed ? KIT_LM_AS_NEEDED : o->cur_link_mode,
- group_id);
- return ld_script_add_order(s, KIT_LINK_INPUT_ARCHIVE, idx);
+ idx = ld_add_archive_slot(
+ o, path, owned, owned_size, o->inputs.cur_whole_archive,
+ as_needed ? KIT_LM_AS_NEEDED : o->inputs.cur_link_mode, group_id);
+ return ld_script_add_order(s, DRIVER_LINK_ARCHIVE, idx);
}
if (driver_is_so_filename(path) || driver_has_suffix(path, ".dylib") ||
driver_has_suffix(path, ".tbd")) {
@@ -1419,7 +1354,7 @@ static int ld_script_add_path(LdInputScript* s, const char* path, int owned,
if (as_needed) goto skip;
if (ld_dso_capacity(o) != 0) goto fail;
idx = ld_add_dso_slot(o, path, owned, owned_size);
- return ld_script_add_order(s, KIT_LINK_INPUT_DSO, idx);
+ return ld_script_add_order(s, DRIVER_LINK_DSO, idx);
}
{
uint32_t idx;
@@ -1431,7 +1366,7 @@ static int ld_script_add_path(LdInputScript* s, const char* path, int owned,
}
if (ld_object_capacity(o) != 0) return 1;
idx = ld_add_object_slot(o, keep);
- return ld_script_add_order(s, KIT_LINK_INPUT_OBJ_BYTES, idx);
+ return ld_script_add_order(s, DRIVER_LINK_OBJECT, idx);
}
skip:
@@ -1456,7 +1391,7 @@ static int ld_script_add_token(LdInputScript* s, const char* tok, size_t n,
char* resolved = NULL;
size_t resolved_size = 0;
LibResolveKind kind;
- LibResolveMode mode = (o->cur_link_mode == KIT_LM_STATIC)
+ LibResolveMode mode = (o->inputs.cur_link_mode == KIT_LM_STATIC)
? LIB_RESOLVE_STATIC_ONLY
: LIB_RESOLVE_DYNAMIC_PREFER;
LibResolveOS resolve_os = (o->target.os == KIT_OS_WINDOWS)
@@ -1595,15 +1530,15 @@ static int ld_script_parse_input(LdInputScript* s) {
static int ld_try_expand_dso_script(LdOptions* o, uint32_t order_pos,
int* changed) {
const KitFileIO* io = &o->env->file_io;
- const KitLinkInputOrder* ord = &o->order[order_pos];
+ const DriverLinkItem* ord = &o->inputs.link_items[order_pos];
const char* path;
KitFileData fd;
LdInputScript s;
const char* dir = NULL;
int rc = 0;
- if (ord->kind != KIT_LINK_INPUT_DSO) return 0;
- if (ord->index >= o->ndsos) return 0;
- path = o->dsos[ord->index].path;
+ if (ord->kind != DRIVER_LINK_DSO) return 0;
+ if (ord->index >= o->inputs.ndsos) return 0;
+ path = o->inputs.dsos[ord->index].path;
if (!path || !io->read_all) return 0;
memset(&fd, 0, sizeof fd);
if (io->read_all(io->user, path, &fd) != KIT_OK) {
@@ -1641,7 +1576,7 @@ static int ld_expand_dso_scripts(LdOptions* o) {
for (pass = 0; pass < 8u; ++pass) {
uint32_t i;
int changed = 0;
- for (i = 0; i < o->norder; ++i) {
+ for (i = 0; i < o->inputs.nlink_items; ++i) {
if (ld_try_expand_dso_script(o, i, &changed) != 0) return 1;
}
if (!changed) return 0;
@@ -1736,7 +1671,7 @@ static int ld_try_ms_flag(LdOptions* o, const char* a) {
char* resolved;
size_t resolved_size;
LibResolveKind kind;
- LibResolveMode mode = (o->cur_link_mode == KIT_LM_STATIC)
+ LibResolveMode mode = (o->inputs.cur_link_mode == KIT_LM_STATIC)
? LIB_RESOLVE_STATIC_ONLY
: LIB_RESOLVE_DYNAMIC_PREFER;
if (ld_resolve_library(o, val, mode, LIB_RESOLVE_OS_WINDOWS, &resolved,
@@ -2349,7 +2284,7 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
if (ld_note_library_request(o, name)) continue;
/* -Bstatic forces .a only; everything else (default,
* -Bdynamic, --as-needed) prefers .so but falls back to .a. */
- mode = (o->cur_link_mode == KIT_LM_STATIC) ? LIB_RESOLVE_STATIC_ONLY
+ mode = (o->inputs.cur_link_mode == KIT_LM_STATIC) ? LIB_RESOLVE_STATIC_ONLY
: LIB_RESOLVE_DYNAMIC_PREFER;
resolve_os = (o->target.os == KIT_OS_WINDOWS) ? LIB_RESOLVE_OS_WINDOWS
: LIB_RESOLVE_OS_POSIX;
@@ -2370,7 +2305,7 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
char* resolved;
size_t resolved_size;
LibResolveKind kind;
- LibResolveMode mode = (o->cur_link_mode == KIT_LM_STATIC)
+ LibResolveMode mode = (o->inputs.cur_link_mode == KIT_LM_STATIC)
? LIB_RESOLVE_STATIC_ONLY
: LIB_RESOLVE_DYNAMIC_PREFER;
LibResolveOS resolve_os = (o->target.os == KIT_OS_WINDOWS)
@@ -2401,7 +2336,7 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
return 1;
}
if (ld_note_library_request(o, argv[i])) continue;
- mode = (o->cur_link_mode == KIT_LM_STATIC) ? LIB_RESOLVE_STATIC_ONLY
+ mode = (o->inputs.cur_link_mode == KIT_LM_STATIC) ? LIB_RESOLVE_STATIC_ONLY
: LIB_RESOLVE_DYNAMIC_PREFER;
resolve_os = (o->target.os == KIT_OS_WINDOWS) ? LIB_RESOLVE_OS_WINDOWS
: LIB_RESOLVE_OS_POSIX;
@@ -2430,7 +2365,7 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
if (driver_streq(a, "-static")) {
o->target.pic = KIT_PIC_NONE;
o->static_link = 1;
- o->cur_link_mode = KIT_LM_STATIC;
+ o->inputs.cur_link_mode = KIT_LM_STATIC;
o->pic_explicit = 1;
continue;
}
@@ -2438,7 +2373,7 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
o->target.pic = KIT_PIC_PIE;
o->pie = 1;
o->static_link = 1;
- o->cur_link_mode = KIT_LM_STATIC;
+ o->inputs.cur_link_mode = KIT_LM_STATIC;
o->pic_explicit = 1;
continue;
}
@@ -2642,31 +2577,31 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
}
if (driver_streq(a, "--whole-archive")) {
- o->cur_whole_archive = 1;
+ o->inputs.cur_whole_archive = 1;
continue;
}
if (driver_streq(a, "--no-whole-archive")) {
- o->cur_whole_archive = 0;
+ o->inputs.cur_whole_archive = 0;
continue;
}
if (driver_streq(a, "-Bstatic")) {
- o->cur_link_mode = KIT_LM_STATIC;
+ o->inputs.cur_link_mode = KIT_LM_STATIC;
continue;
}
if (driver_streq(a, "-Bdynamic")) {
- o->cur_link_mode = KIT_LM_DYNAMIC;
+ o->inputs.cur_link_mode = KIT_LM_DYNAMIC;
continue;
}
if (driver_streq(a, "--as-needed")) {
- o->cur_link_mode = KIT_LM_AS_NEEDED;
+ o->inputs.cur_link_mode = KIT_LM_AS_NEEDED;
continue;
}
if (driver_streq(a, "--no-as-needed")) {
- o->cur_link_mode = KIT_LM_DYNAMIC;
+ o->inputs.cur_link_mode = KIT_LM_DYNAMIC;
continue;
}
if (driver_streq(a, "--start-group")) {
- if (o->cur_group_id != 0) {
+ if (o->inputs.cur_group_id != 0) {
driver_errf(LD_TOOL, "nested --start-group is not supported");
return 1;
}
@@ -2675,15 +2610,15 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
return 1;
}
o->next_group_id++;
- o->cur_group_id = o->next_group_id;
+ o->inputs.cur_group_id = o->next_group_id;
continue;
}
if (driver_streq(a, "--end-group")) {
- if (o->cur_group_id == 0) {
+ if (o->inputs.cur_group_id == 0) {
driver_errf(LD_TOOL, "--end-group without --start-group");
return 1;
}
- o->cur_group_id = 0;
+ o->inputs.cur_group_id = 0;
continue;
}
@@ -2720,11 +2655,12 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
driver_errf(LD_TOOL, "-o is required");
return 1;
}
- if (o->cur_group_id != 0) {
+ if (o->inputs.cur_group_id != 0) {
driver_errf(LD_TOOL, "missing --end-group");
return 1;
}
- if (o->nobject_files == 0 && o->narchives == 0 && o->ndsos == 0) {
+ if (o->inputs.nobject_files == 0 && o->inputs.narchives == 0 &&
+ o->inputs.ndsos == 0) {
driver_errf(LD_TOOL, "no input files");
ld_usage();
return 1;
@@ -2763,7 +2699,7 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
driver_errf(LD_TOOL, "-soname/-rpath/-rpath-link require -shared");
return 1;
}
- if (o->ndsos) {
+ if (o->inputs.ndsos) {
driver_errf(LD_TOOL, "-r does not support shared-object inputs");
return 1;
}
@@ -2784,32 +2720,17 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
static void ld_options_release(LdOptions* o) {
size_t bound = o->argv_bound;
uint32_t i;
- for (i = 0; i < o->narchives; ++i) {
- LdArchive* a = &o->archives[i];
- if (a->owned && a->path) {
- driver_free(o->env, (void*)a->path, a->owned_size);
- }
- }
- for (i = 0; i < o->ndsos; ++i) {
- LdDso* d = &o->dsos[i];
- if (d->owned && d->path) {
- driver_free(o->env, (void*)d->path, d->owned_size);
- }
- }
for (i = 0; i < o->nowned_paths; ++i) {
if (o->owned_paths[i])
driver_free(o->env, o->owned_paths[i], o->owned_path_sizes[i]);
}
/* The shared flag model owns its FLAG strings (defsym/section/map/...), the
- * build-id bytes, and the rpath/defsym/section-start vectors. */
+ * build-id bytes, and the rpath/defsym/section-start vectors. The shared
+ * input set owns the resolved archive/dso paths and its parallel arrays. */
driver_link_flags_fini(&o->lf);
+ driver_link_inputs_fini(&o->inputs);
+ driver_cflags_fini(&o->cf, o->env);
driver_hosted_plan_fini(o->env, &o->hosted);
- driver_free(o->env, o->object_files, bound * sizeof(*o->object_files));
- driver_free(o->env, o->archives, bound * sizeof(*o->archives));
- driver_free(o->env, o->dsos, bound * sizeof(*o->dsos));
- driver_free(o->env, o->order, bound * sizeof(*o->order));
- driver_free(o->env, o->lib_dirs, bound * sizeof(*o->lib_dirs));
- driver_free(o->env, o->framework_dirs, bound * sizeof(*o->framework_dirs));
/* owned_paths/owned_path_sizes grow independently of argv_bound. */
driver_free(o->env, o->owned_paths,
o->cap_owned_paths * sizeof(*o->owned_paths));
@@ -2911,83 +2832,18 @@ static KitStatus ld_print_memory_usage(LdOptions* o, KitLinkSession* link) {
return st;
}
-static int ld_append_hosted_input(LdOptions* o, const DriverHostedInput* in,
- uint32_t insert_pos, int insert) {
- switch ((DriverHostedInputKind)in->kind) {
- case DRIVER_HOSTED_INPUT_OBJECT:
- if (insert)
- ld_insert_object(o, in->path, insert_pos);
- else
- ld_push_object(o, in->path);
- return 0;
- case DRIVER_HOSTED_INPUT_ARCHIVE: {
- LdArchive* a = &o->archives[o->narchives++];
- a->path = in->path;
- a->owned = 0;
- a->owned_size = 0;
- a->whole_archive = 0;
- a->link_mode = KIT_LM_DEFAULT;
- a->group_id = 0;
- if (insert)
- ld_insert_order(o, insert_pos, KIT_LINK_INPUT_ARCHIVE,
- o->narchives - 1u);
- else
- ld_push_order(o, KIT_LINK_INPUT_ARCHIVE, o->narchives - 1u);
- return 0;
- }
- case DRIVER_HOSTED_INPUT_DSO: {
- LdDso* d = &o->dsos[o->ndsos++];
- d->path = in->path;
- d->owned = 0;
- d->owned_size = 0;
- if (insert)
- ld_insert_order(o, insert_pos, KIT_LINK_INPUT_DSO, o->ndsos - 1u);
- else
- ld_push_order(o, KIT_LINK_INPUT_DSO, o->ndsos - 1u);
- return 0;
- }
- default:
- driver_errf(LD_TOOL, "internal error: unknown hosted input kind");
- return 1;
- }
-}
-
-static int ld_apply_hosted_before_after(LdOptions* o) {
- DriverHostedRequest req;
- uint32_t i;
- uint32_t insert_pos = 0;
+/* Resolve and apply the hosted libc profile: hosted lib-search dirs (so user
+ * -l flags resolve against the sysroot), the before/after/final crt inputs in
+ * link order, and the interpreter. The shared helper folds all of this (plus
+ * the system includes/defines that ld discards) into one call; the runtime
+ * archive is later inserted before the final group via
+ * driver_link_inputs_insert_runtime_archives. The wants-hosted / -shared guard
+ * stays here. */
+static int ld_apply_hosted(LdOptions* o) {
if (!o->wants_hosted_libc || o->shared) return 0;
- memset(&req, 0, sizeof req);
- req.env = o->env;
- req.tool = LD_TOOL;
- req.target = o->target;
- req.sysroot = o->sysroot;
- req.static_link = o->static_link;
- req.link_inputs = 1;
- if (driver_hosted_resolve(&req, &o->hosted) != 0) return 1;
- /* Add hosted lib search dirs so user -l flags resolve against the sysroot. */
- for (i = 0; i < o->hosted.nlib_search_dirs; ++i)
- if (ld_add_lib_dir(o, o->hosted.lib_search_dirs[i]) != 0) return 1;
- for (i = 0; i < o->hosted.nbefore; ++i) {
- if (ld_append_hosted_input(o, &o->hosted.before[i], insert_pos, 1) != 0)
- return 1;
- insert_pos++;
- }
- for (i = 0; i < o->hosted.nafter; ++i) {
- if (ld_append_hosted_input(o, &o->hosted.after[i], 0, 0) != 0) return 1;
- }
- if (!o->lf.interp_path && o->hosted.interp_path)
- o->lf.interp_path = o->hosted.interp_path;
- return 0;
-}
-
-static int ld_apply_hosted_final(LdOptions* o) {
- uint32_t i;
- if (!o->hosted.profile_name) return 0;
- for (i = 0; i < o->hosted.nfinal; ++i) {
- if (ld_append_hosted_input(o, &o->hosted.final[i], 0, 0) != 0) return 1;
- }
- return 0;
+ return driver_link_inputs_apply_hosted(&o->inputs, &o->hosted, &o->cf, &o->lf,
+ o->target, o->sysroot, o->static_link,
+ o->nostartfiles, /*link_action=*/1);
}
/* ---------- link execution ---------- */
@@ -3008,11 +2864,13 @@ static int ld_run_link(LdOptions* o) {
KitSlice* obj_in = NULL;
KitLinkArchiveInput* arch_in = NULL;
KitSlice* dso_in = NULL;
+ KitLinkInputOrder* order = NULL;
KitLinkScript* script = NULL;
KitLinkSession* link = NULL;
DriverRuntimeSupport runtime = {0};
DriverRuntimeArchive rt_archive = {0};
uint32_t i;
+ uint32_t norder = 0;
uint32_t initial_nobject_files;
int runtime_resolved = 0;
int rc = 1;
@@ -3026,7 +2884,7 @@ static int ld_run_link(LdOptions* o) {
* deciding which hosted CRT/libc profile and compiler-runtime archive to
* add. The arrays are sized to the argv bound because hosted expansion may
* append start files after target detection. */
- initial_nobject_files = o->nobject_files;
+ initial_nobject_files = o->inputs.nobject_files;
if (o->argv_bound) {
obj_lf = driver_alloc_zeroed(o->env, o->argv_bound * sizeof(*obj_lf));
obj_in = driver_alloc_zeroed(o->env, o->argv_bound * sizeof(*obj_in));
@@ -3036,7 +2894,7 @@ static int ld_run_link(LdOptions* o) {
}
}
for (i = 0; i < initial_nobject_files; ++i) {
- const char* path = o->object_files[i];
+ const char* path = o->inputs.object_files[i];
if (load_file(io, path, &obj_lf[i]) != 0) {
driver_errf(LD_TOOL, "failed to read: %.*s",
KIT_SLICE_ARG(kit_slice_cstr(path)));
@@ -3088,7 +2946,8 @@ static int ld_run_link(LdOptions* o) {
}
}
- if (!o->relocatable && o->target.os == KIT_OS_FREESTANDING && o->ndsos) {
+ if (!o->relocatable && o->target.os == KIT_OS_FREESTANDING &&
+ o->inputs.ndsos) {
driver_errf(LD_TOOL,
"freestanding executable links do not accept DSO inputs");
goto out;
@@ -3109,13 +2968,13 @@ static int ld_run_link(LdOptions* o) {
driver_errf(LD_TOOL,
"freestanding link: input '%s' arch/format does not match "
"the link target",
- o->object_files[oi]);
+ o->inputs.object_files[oi]);
goto out;
}
}
}
- if (ld_apply_hosted_before_after(o) != 0) goto out;
+ if (ld_apply_hosted(o) != 0) goto out;
/* Hosted dynamic link: default to PIE, matching what `kit cc` does.
* Without PIE the link_dyn path (PLT/GOT/.rela.plt) is not entered and
@@ -3153,15 +3012,17 @@ static int ld_run_link(LdOptions* o) {
if (driver_runtime_prepare_archive(o->env, LD_TOOL, &runtime, o->target, 0,
&rt_archive) != 0)
goto out;
- ld_push_runtime_archive(o, &rt_archive);
+ /* Insert before the hosted plan's `final` (crt-end) group — the shared
+ * helper also does the Windows two-position insert that the old single
+ * append lacked. ld's runtime is never whole-archive, matching cc/build. */
+ driver_link_inputs_insert_runtime_archives(
+ &o->inputs, &rt_archive, o->target, o->hosted.nfinal, o->hosted.nafter);
}
- if (ld_apply_hosted_final(o) != 0) goto out;
-
if (ld_expand_dso_scripts(o) != 0) goto out;
- for (i = initial_nobject_files; i < o->nobject_files; ++i) {
- const char* path = o->object_files[i];
+ for (i = initial_nobject_files; i < o->inputs.nobject_files; ++i) {
+ const char* path = o->inputs.object_files[i];
if (load_file(io, path, &obj_lf[i]) != 0) {
driver_errf(LD_TOOL, "failed to read: %.*s",
KIT_SLICE_ARG(kit_slice_cstr(path)));
@@ -3171,17 +3032,19 @@ static int ld_run_link(LdOptions* o) {
obj_in[i].len = obj_lf[i].data.size;
}
- if (o->narchives) {
- arch_lf = driver_alloc_zeroed(o->env, o->narchives * sizeof(*arch_lf));
- arch_in = driver_alloc_zeroed(o->env, o->narchives * sizeof(*arch_in));
+ if (o->inputs.narchives) {
+ arch_lf =
+ driver_alloc_zeroed(o->env, o->inputs.narchives * sizeof(*arch_lf));
+ arch_in =
+ driver_alloc_zeroed(o->env, o->inputs.narchives * sizeof(*arch_in));
if (!arch_lf || !arch_in) {
driver_errf(LD_TOOL, "out of memory");
goto out;
}
}
- if (o->ndsos) {
- dso_lf = driver_alloc_zeroed(o->env, o->ndsos * sizeof(*dso_lf));
- dso_in = driver_alloc_zeroed(o->env, o->ndsos * sizeof(*dso_in));
+ if (o->inputs.ndsos) {
+ dso_lf = driver_alloc_zeroed(o->env, o->inputs.ndsos * sizeof(*dso_lf));
+ dso_in = driver_alloc_zeroed(o->env, o->inputs.ndsos * sizeof(*dso_in));
if (!dso_lf || !dso_in) {
driver_errf(LD_TOOL, "out of memory");
goto out;
@@ -3189,8 +3052,8 @@ static int ld_run_link(LdOptions* o) {
}
/* Load archives. */
- for (i = 0; i < o->narchives; ++i) {
- const LdArchive* a = &o->archives[i];
+ for (i = 0; i < o->inputs.narchives; ++i) {
+ const DriverArchiveInput* a = &o->inputs.archives[i];
if (load_file(io, a->path, &arch_lf[i]) != 0) {
driver_errf(LD_TOOL, "failed to read: %.*s",
KIT_SLICE_ARG(kit_slice_cstr(a->path)));
@@ -3204,8 +3067,8 @@ static int ld_run_link(LdOptions* o) {
arch_in[i].group_id = a->group_id;
}
/* Load shared objects. */
- for (i = 0; i < o->ndsos; ++i) {
- const LdDso* d = &o->dsos[i];
+ for (i = 0; i < o->inputs.ndsos; ++i) {
+ const DriverDsoInput* d = &o->inputs.dsos[i];
if (load_file(io, d->path, &dso_lf[i]) != 0) {
driver_errf(LD_TOOL, "failed to read: %.*s",
KIT_SLICE_ARG(kit_slice_cstr(d->path)));
@@ -3252,6 +3115,18 @@ static int ld_run_link(LdOptions* o) {
goto out;
}
+ /* Translate the recorded link-item order into the engine's KitLinkInputOrder
+ * list. ld records no compiled-source items, so the source args are NULL. */
+ if (o->inputs.nlink_items) {
+ order =
+ driver_alloc_zeroed(o->env, o->inputs.nlink_items * sizeof(*order));
+ if (!order) {
+ driver_errf(LD_TOOL, "out of memory");
+ goto out;
+ }
+ }
+ norder = driver_link_inputs_build_order(&o->inputs, NULL, NULL, 0, order);
+
if (o->lf.soname || o->lf.nrpaths || o->nrpath_links) {
if (!o->shared) {
driver_errf(LD_TOOL, "-soname/-rpath/-rpath-link require -shared");
@@ -3287,35 +3162,24 @@ static int ld_run_link(LdOptions* o) {
(void)o->export_dynamic;
st = kit_link_session_new(compiler, &lopts, &link);
- if (o->order && o->norder) {
- for (i = 0; i < o->norder && st == KIT_OK; ++i) {
- const KitLinkInputOrder* ord = &o->order[i];
- switch ((KitLinkInputOrderKind)ord->kind) {
- case KIT_LINK_INPUT_OBJ:
- case KIT_LINK_INPUT_OBJ_BYTES:
- st = kit_link_session_add_obj_bytes(
- link, kit_slice_cstr(o->object_files[ord->index]),
- &obj_in[ord->index]);
- break;
- case KIT_LINK_INPUT_ARCHIVE:
- st = kit_link_session_add_archive_bytes(link, &arch_in[ord->index]);
- break;
- case KIT_LINK_INPUT_DSO:
- st = kit_link_session_add_dso_bytes(
- link, kit_slice_cstr(o->dsos[ord->index].path),
- &dso_in[ord->index]);
- break;
- }
+ for (i = 0; i < norder && st == KIT_OK; ++i) {
+ const KitLinkInputOrder* ord = &order[i];
+ switch ((KitLinkInputOrderKind)ord->kind) {
+ case KIT_LINK_INPUT_OBJ:
+ case KIT_LINK_INPUT_OBJ_BYTES:
+ st = kit_link_session_add_obj_bytes(
+ link, kit_slice_cstr(o->inputs.object_files[ord->index]),
+ &obj_in[ord->index]);
+ break;
+ case KIT_LINK_INPUT_ARCHIVE:
+ st = kit_link_session_add_archive_bytes(link, &arch_in[ord->index]);
+ break;
+ case KIT_LINK_INPUT_DSO:
+ st = kit_link_session_add_dso_bytes(
+ link, kit_slice_cstr(o->inputs.dsos[ord->index].path),
+ &dso_in[ord->index]);
+ break;
}
- } else {
- for (i = 0; i < o->nobject_files && st == KIT_OK; ++i)
- st = kit_link_session_add_obj_bytes(
- link, kit_slice_cstr(o->object_files[i]), &obj_in[i]);
- for (i = 0; i < o->narchives && st == KIT_OK; ++i)
- st = kit_link_session_add_archive_bytes(link, &arch_in[i]);
- for (i = 0; i < o->ndsos && st == KIT_OK; ++i)
- st = kit_link_session_add_dso_bytes(
- link, kit_slice_cstr(o->dsos[i].path), &dso_in[i]);
}
if (st == KIT_OK) st = kit_link_session_emit(link, writer);
if (st == KIT_OK) st = ld_write_link_report(o, io, link, o->lf.map_path, 0);
@@ -3346,15 +3210,19 @@ out:
driver_runtime_archive_fini(o->env, &rt_archive);
if (runtime_resolved) driver_runtime_support_fini(o->env, &runtime);
release_file(&script_lf);
- release_all(arch_lf, o->narchives);
- release_all(obj_lf, o->nobject_files);
- release_all(dso_lf, o->ndsos);
- if (arch_in) driver_free(o->env, arch_in, o->narchives * sizeof(*arch_in));
- if (arch_lf) driver_free(o->env, arch_lf, o->narchives * sizeof(*arch_lf));
+ release_all(arch_lf, o->inputs.narchives);
+ release_all(obj_lf, o->inputs.nobject_files);
+ release_all(dso_lf, o->inputs.ndsos);
+ if (arch_in)
+ driver_free(o->env, arch_in, o->inputs.narchives * sizeof(*arch_in));
+ if (arch_lf)
+ driver_free(o->env, arch_lf, o->inputs.narchives * sizeof(*arch_lf));
if (obj_in) driver_free(o->env, obj_in, o->argv_bound * sizeof(*obj_in));
if (obj_lf) driver_free(o->env, obj_lf, o->argv_bound * sizeof(*obj_lf));
- if (dso_in) driver_free(o->env, dso_in, o->ndsos * sizeof(*dso_in));
- if (dso_lf) driver_free(o->env, dso_lf, o->ndsos * sizeof(*dso_lf));
+ if (dso_in) driver_free(o->env, dso_in, o->inputs.ndsos * sizeof(*dso_in));
+ if (dso_lf) driver_free(o->env, dso_lf, o->inputs.ndsos * sizeof(*dso_lf));
+ if (order)
+ driver_free(o->env, order, o->inputs.nlink_items * sizeof(*order));
return rc;
}