commit 73252b15fee3804dec7b25c929f612252cf0a678
parent 2efb3802d3b9f032447fcc69b8c3142bc305a466
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Wed, 17 Jun 2026 08:16:36 -0700
Merge ld-link-share: ld consumes shared DriverLinkFlags + DriverLinkInputSet
ld.c stops duplicating the linker-flag and link-input models that cc/build
already share (driver/lib/link_flags.c, link_inputs.c): −470 lines, behavior
byte-identical (12/12 differential vs pre-refactor + hosted -lc link runs),
and gains the shared Windows two-position runtime-archive insert. ld keeps its
foreign-linker-compat surface (GNU -m/INPUT/GROUP, Apple -arch, MS link driver)
and its documented non-PIE default.
Diffstat:
| M | driver/cmd/ld.c | | | 1230 | ++++++++++++++++++++++++------------------------------------------------------- |
1 file changed, 378 insertions(+), 852 deletions(-)
diff --git a/driver/cmd/ld.c b/driver/cmd/ld.c
@@ -7,6 +7,8 @@
#include "driver.h"
#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
@@ -56,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;
@@ -86,10 +67,7 @@ typedef struct LdOptions {
const char* output_path; /* -o */
int output_seen;
- const char* entry; /* -e */
const char* script_path; /* -T */
- int text_base_set; /* -Ttext seen */
- uint64_t text_base; /* -Ttext ADDR: static ET_EXEC image base */
int no_default_libs; /* -nostdlib / -nodefaultlibs / --no-default-libs */
int nostdlib; /* -nostdlib: no CRT startup or default libraries */
int nostartfiles; /* -nostartfiles: caller supplies CRT startup */
@@ -97,85 +75,48 @@ typedef struct LdOptions {
int target_explicit; /* -target / --target seen */
const char* support_dir; /* --support-dir */
const char* sysroot; /* --sysroot / KIT_SYSROOT */
- uint16_t pe_subsystem; /* KitPeSubsystem */
- /* PT_INTERP path. NULL means "let libkit pick the target default
- * (e.g. /lib/ld-musl-aarch64.so.1)". Set by -dynamic-linker /
- * --dynamic-linker. */
- const char* interp_path;
int pie; /* -pie was requested */
- const char** object_files;
- uint32_t nobject_files;
-
- LdArchive* archives;
- uint32_t narchives;
+ /* Shared linker-flag model: entry, pe_subsystem, interp/soname/rpath, the
+ * -Wl, comma flags (defsym/section-start/build-id/map/symbols/cref/...), and
+ * the owned FLAG-string pool that backs them. Populated via the
+ * driver_link_flags_record_* family and consumed by
+ * driver_link_flags_fill_options. */
+ DriverLinkFlags lf;
- /* 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;
+ /* 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;
- 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 */
int relocatable; /* -r / --relocatable */
- const char* soname; /* -soname NAME */
- const char** rpaths; /* -rpath DIR (repeatable) */
- uint32_t nrpaths;
const char** rpath_links; /* -rpath-link DIR (advisory) */
uint32_t nrpath_links;
- int new_dtags; /* 1=DT_RUNPATH (default), 0=DT_RPATH */
int export_dynamic; /* -E / --export-dynamic */
- int gc_sections; /* --gc-sections / --no-gc-sections */
- int strip_debug; /* -S / --strip-debug */
- int allow_undefined; /* explicit unresolved-symbol escape hatch */
- const char* map_path; /* --map / -Map */
- const char* symbols_path;
- uint8_t symbols_format; /* KitLinkSymbolsFormat */
- const char* cref_path; /* --cref FILE */
- int print_memory_usage; /* --print-memory-usage */
- uint8_t orphan_handling; /* KitLinkOrphanHandling */
- int fatal_warnings; /* --fatal-warnings */
- /* --defsym NAME=EXPR (owned name/alias strings). */
- KitLinkDefsym* defsyms;
- uint32_t ndefsyms;
- uint32_t cap_defsyms;
- /* --section-start / -Tdata / -Tbss section address overrides. */
- KitLinkSectionStart* section_starts;
- uint32_t nsection_starts;
- uint32_t cap_section_starts;
int static_link; /* -static: hosted libc should pick static profile */
int wants_hosted_libc; /* libc request: expand crt + libc via hosted resolver */
int windows_ucrt_target; /* *-windows-gnullvm: MinGW UCRT hosted profile */
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;
- /* --build-id state */
- uint8_t build_id_mode; /* KitBuildIdMode */
- uint8_t* build_id_bytes; /* USER mode: parsed hex, owned */
- uint32_t build_id_len;
- size_t build_id_alloc; /* allocation size for free */
-
- /* 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. */
@@ -291,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->rpaths = driver_alloc_zeroed(o->env, bound * sizeof(*o->rpaths));
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->rpaths || !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;
}
- o->new_dtags = 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);
@@ -372,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 void ld_insert_object(LdOptions* o, const char* path, uint32_t pos) {
+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 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) {
@@ -580,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;
}
@@ -695,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;
@@ -727,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) {
@@ -864,182 +767,6 @@ static int ld_is_cc_driver_noop(const char* tok, size_t n) {
ld_tok_prefix(tok, n, "--unwindlib=");
}
-static int ld_apply_z_option(LdOptions* o, const char* z, size_t n) {
- if (ld_tok_eq(z, n, "defs")) {
- o->allow_undefined = 0;
- return 0;
- }
- if (ld_tok_eq(z, n, "nodefs")) {
- o->allow_undefined = 1;
- return 0;
- }
- if (ld_tok_eq(z, n, "noexecstack") || ld_tok_eq(z, n, "relro") ||
- ld_tok_eq(z, n, "now") || ld_tok_eq(z, n, "text")) {
- return 0;
- }
- driver_errf(LD_TOOL, "unsupported -z option: %.*s", (int)n, z);
- return 1;
-}
-
-static int ld_record_symbols_format(LdOptions* o, const char* val, size_t n) {
- if (n == 2 && driver_strneq(val, "nm", 2)) {
- o->symbols_format = KIT_LINK_SYMBOLS_NM;
- return 0;
- }
- driver_errf(LD_TOOL, "unsupported --symbols-format: %.*s", (int)n, val);
- return 1;
-}
-
-/* --defsym NAME=EXPR. `val`/`n` is the span after `--defsym `. */
-static int ld_record_defsym(LdOptions* o, const char* val, size_t n) {
- size_t eq = 0;
- const char* name_owned;
- const char* rhs;
- size_t rhs_len;
- KitLinkDefsym* d;
- while (eq < n && val[eq] != '=') ++eq;
- if (eq == 0 || eq >= n) {
- driver_errf(LD_TOOL, "--defsym requires NAME=EXPR: %.*s", (int)n, val);
- return 1;
- }
- rhs = val + eq + 1u;
- rhs_len = n - eq - 1u;
- if (rhs_len == 0) {
- driver_errf(LD_TOOL, "--defsym requires a value: %.*s", (int)n, val);
- return 1;
- }
- if (o->ndefsyms >= o->cap_defsyms) {
- uint32_t nc = o->cap_defsyms ? o->cap_defsyms * 2u : 4u;
- KitLinkDefsym* nd = driver_alloc_zeroed(o->env, nc * sizeof(*nd));
- if (!nd) {
- driver_errf(LD_TOOL, "out of memory");
- return 1;
- }
- if (o->defsyms) {
- driver_memcpy(nd, o->defsyms, o->ndefsyms * sizeof(*nd));
- driver_free(o->env, o->defsyms, o->cap_defsyms * sizeof(*nd));
- }
- o->defsyms = nd;
- o->cap_defsyms = nc;
- }
- if (ld_span_to_owned_cstr(o, val, eq, &name_owned) != 0) return 1;
- d = &o->defsyms[o->ndefsyms];
- memset(d, 0, sizeof(*d));
- d->name = kit_slice_cstr(name_owned);
- if (rhs[0] >= '0' && rhs[0] <= '9') {
- const char* num;
- uint64_t v;
- if (ld_span_to_owned_cstr(o, rhs, rhs_len, &num) != 0) return 1;
- if (driver_parse_u64(num, &v) != 0) {
- driver_errf(LD_TOOL, "--defsym: invalid value: %.*s", (int)rhs_len, rhs);
- return 1;
- }
- d->value = v;
- } else {
- const char* alias;
- if (ld_span_to_owned_cstr(o, rhs, rhs_len, &alias) != 0) return 1;
- d->alias = kit_slice_cstr(alias);
- }
- o->ndefsyms++;
- return 0;
-}
-
-/* Store a NAME -> ADDR override where `name_owned` is ALREADY owned by
- * o->owned_paths (so this neither dups nor frees it). Parses `addr` and grows
- * the section_starts vector. */
-static int ld_store_section_start(LdOptions* o, const char* name_owned,
- const char* addr) {
- uint64_t v;
- KitLinkSectionStart* ss;
- if (!name_owned || !*name_owned || !addr || !*addr) {
- driver_errf(LD_TOOL, "--section-start requires .NAME=ADDR");
- return 1;
- }
- if (driver_parse_u64(addr, &v) != 0) {
- driver_errf(LD_TOOL, "--section-start: invalid address: %s", addr);
- return 1;
- }
- if (o->nsection_starts >= o->cap_section_starts) {
- uint32_t nc = o->cap_section_starts ? o->cap_section_starts * 2u : 4u;
- KitLinkSectionStart* ns = driver_alloc_zeroed(o->env, nc * sizeof(*ns));
- if (!ns) {
- driver_errf(LD_TOOL, "out of memory");
- return 1;
- }
- if (o->section_starts) {
- driver_memcpy(ns, o->section_starts, o->nsection_starts * sizeof(*ns));
- driver_free(o->env, o->section_starts,
- o->cap_section_starts * sizeof(*ns));
- }
- o->section_starts = ns;
- o->cap_section_starts = nc;
- }
- ss = &o->section_starts[o->nsection_starts];
- memset(ss, 0, sizeof(*ss));
- ss->name = kit_slice_cstr(name_owned);
- ss->addr = v;
- o->nsection_starts++;
- return 0;
-}
-
-/* --section-start: store a NAME -> ADDR override (NAME may be ".data"/".bss"
- * synthesized from -Tdata/-Tbss, or a not-yet-owned argv span). Owns `secname`
- * once, then stores it. */
-static int ld_record_section_addr(LdOptions* o, const char* secname,
- const char* addr) {
- const char* name_owned;
- if (!secname || !*secname) {
- driver_errf(LD_TOOL, "--section-start requires .NAME=ADDR");
- return 1;
- }
- if (ld_span_to_owned_cstr(o, secname, driver_strlen(secname), &name_owned) !=
- 0)
- return 1;
- return ld_store_section_start(o, name_owned, addr);
-}
-
-static int ld_record_section_start(LdOptions* o, const char* val, size_t n) {
- size_t eq = n;
- size_t i;
- const char* name_owned;
- const char* addr_owned;
- for (i = 0; i < n; ++i)
- if (val[i] == '=') eq = i;
- if (eq == n || eq == 0) {
- driver_errf(LD_TOOL, "--section-start requires .NAME=ADDR: %.*s", (int)n,
- val);
- return 1;
- }
- /* Own the name span ONCE here and store it directly — going through
- * ld_record_section_addr would re-dup it, costing a third owned slot per
- * --section-start (the overflow this fixes). */
- if (ld_span_to_owned_cstr(o, val, eq, &name_owned) != 0) return 1;
- if (ld_span_to_owned_cstr(o, val + eq + 1u, n - eq - 1u, &addr_owned) != 0)
- return 1;
- return ld_store_section_start(o, name_owned, addr_owned);
-}
-
-static int ld_record_orphan_handling(LdOptions* o, const char* val, size_t n) {
- if (n == 5 && driver_strneq(val, "place", 5)) {
- o->orphan_handling = KIT_LINK_ORPHAN_PLACE;
- return 0;
- }
- if (n == 4 && driver_strneq(val, "warn", 4)) {
- o->orphan_handling = KIT_LINK_ORPHAN_WARN;
- return 0;
- }
- if (n == 5 && driver_strneq(val, "error", 5)) {
- o->orphan_handling = KIT_LINK_ORPHAN_ERROR;
- return 0;
- }
- if (n == 7 && driver_strneq(val, "discard", 7)) {
- o->orphan_handling = KIT_LINK_ORPHAN_DISCARD;
- return 0;
- }
- driver_errf(LD_TOOL, "unsupported --orphan-handling: %.*s", (int)n, val);
- return 1;
-}
-
static int ld_parse_wl(LdOptions* o, const char* arg) {
const char* p = arg;
int expect_rpath = 0;
@@ -1066,9 +793,10 @@ static int ld_parse_wl(LdOptions* o, const char* arg) {
expect_section_start || expect_cref || expect_orphan ||
expect_framework || expect_framework_dir) {
if (expect_defsym) {
- if (ld_record_defsym(o, tok, n) != 0) return 1;
+ if (driver_link_flags_record_defsym(&o->lf, tok, n) != 0) return 1;
} else if (expect_section_start) {
- if (ld_record_section_start(o, tok, n) != 0) return 1;
+ if (driver_link_flags_record_section_start(&o->lf, tok, n) != 0)
+ return 1;
} else if (expect_framework) {
const char* owned;
if (ld_span_to_owned_cstr(o, tok, n, &owned) != 0) return 1;
@@ -1078,49 +806,32 @@ static int ld_parse_wl(LdOptions* o, const char* arg) {
if (ld_span_to_owned_cstr(o, tok, n, &owned) != 0) return 1;
if (ld_add_framework_dir(o, owned) != 0) return 1;
} else if (expect_cref) {
- const char* owned;
- if (n == 0) {
- driver_errf(LD_TOOL, "--cref requires a non-empty path");
- return 1;
- }
- if (ld_span_to_owned_cstr(o, tok, n, &owned) != 0) return 1;
- o->cref_path = owned;
+ if (driver_link_flags_record_cref(&o->lf, tok, n) != 0) return 1;
} else if (expect_orphan) {
- if (ld_record_orphan_handling(o, tok, n) != 0) return 1;
+ if (driver_link_flags_record_orphan_handling(&o->lf, tok, n) != 0)
+ return 1;
} else if (expect_rpath) {
const char* owned;
if (ld_span_to_owned_cstr(o, tok, n, &owned) != 0) return 1;
- o->rpaths[o->nrpaths++] = owned;
+ o->lf.rpaths[o->lf.nrpaths++] = owned;
} else if (expect_soname) {
const char* owned;
if (ld_span_to_owned_cstr(o, tok, n, &owned) != 0) return 1;
- o->soname = owned;
+ o->lf.soname = owned;
} else if (expect_interp) {
const char* owned;
if (ld_span_to_owned_cstr(o, tok, n, &owned) != 0) return 1;
- o->interp_path = owned;
+ o->lf.interp_path = owned;
} else if (expect_z) {
- if (ld_apply_z_option(o, tok, n) != 0) return 1;
+ if (driver_link_flags_record_z(&o->lf, tok, n) != 0) return 1;
} else if (expect_emulation) {
const char* owned;
if (ld_span_to_owned_cstr(o, tok, n, &owned) != 0) return 1;
if (ld_set_gnu_emulation(o, owned) != 0) return 1;
} else if (expect_map) {
- const char* owned;
- if (n == 0) {
- driver_errf(LD_TOOL, "--map requires a non-empty path");
- return 1;
- }
- if (ld_span_to_owned_cstr(o, tok, n, &owned) != 0) return 1;
- o->map_path = owned;
+ if (driver_link_flags_record_map(&o->lf, tok, n) != 0) return 1;
} else if (expect_symbols) {
- const char* owned;
- if (n == 0) {
- driver_errf(LD_TOOL, "--symbols requires a non-empty path");
- return 1;
- }
- if (ld_span_to_owned_cstr(o, tok, n, &owned) != 0) return 1;
- o->symbols_path = owned;
+ if (driver_link_flags_record_symbols(&o->lf, tok, n) != 0) return 1;
}
expect_rpath = expect_soname = expect_interp = expect_z =
expect_emulation = expect_map = expect_symbols = expect_defsym =
@@ -1131,20 +842,20 @@ static int ld_parse_wl(LdOptions* o, const char* arg) {
if (ld_tok_eq(tok, n, "-dead_strip") ||
ld_tok_eq(tok, n, "--gc-sections")) {
- o->gc_sections = 1;
+ o->lf.gc_sections = 1;
continue;
}
if (ld_tok_eq(tok, n, "--no-gc-sections")) {
- o->gc_sections = 0;
+ o->lf.gc_sections = 0;
continue;
}
if (ld_tok_eq(tok, n, "--no-undefined")) {
- o->allow_undefined = 0;
+ o->lf.allow_undefined = 0;
continue;
}
if (ld_tok_eq(tok, n, "--allow-undefined") ||
ld_tok_eq(tok, n, "--allow-shlib-undefined")) {
- o->allow_undefined = 1;
+ o->lf.allow_undefined = 1;
continue;
}
if (ld_tok_eq(tok, n, "--map") || ld_tok_eq(tok, n, "-Map")) {
@@ -1152,23 +863,15 @@ static int ld_parse_wl(LdOptions* o, const char* arg) {
continue;
}
if (ld_tok_prefix(tok, n, "--map=")) {
- const char* owned;
- if (n == 6) {
- driver_errf(LD_TOOL, "--map requires a non-empty path");
- return 1;
- }
- if (ld_span_to_owned_cstr(o, tok + 6, n - 6u, &owned) != 0) return 1;
- o->map_path = owned;
+ if (driver_link_flags_record_map(&o->lf, tok + 6, n - 6u) != 0) return 1;
continue;
}
if (ld_tok_prefix(tok, n, "-Map=")) {
- const char* owned;
if (n == 5) {
driver_errf(LD_TOOL, "-Map requires a non-empty path");
return 1;
}
- if (ld_span_to_owned_cstr(o, tok + 5, n - 5u, &owned) != 0) return 1;
- o->map_path = owned;
+ if (driver_link_flags_record_map(&o->lf, tok + 5, n - 5u) != 0) return 1;
continue;
}
if (ld_tok_eq(tok, n, "--symbols")) {
@@ -1176,41 +879,38 @@ static int ld_parse_wl(LdOptions* o, const char* arg) {
continue;
}
if (ld_tok_prefix(tok, n, "--symbols=")) {
- const char* owned;
- if (n == 10) {
- driver_errf(LD_TOOL, "--symbols requires a non-empty path");
+ if (driver_link_flags_record_symbols(&o->lf, tok + 10, n - 10u) != 0)
return 1;
- }
- if (ld_span_to_owned_cstr(o, tok + 10, n - 10u, &owned) != 0) return 1;
- o->symbols_path = owned;
continue;
}
if (ld_tok_prefix(tok, n, "--symbols-format=")) {
- if (ld_record_symbols_format(o, tok + 17, n - 17u) != 0) return 1;
+ if (driver_link_flags_record_symbols_format(&o->lf, tok + 17, n - 17u) !=
+ 0)
+ return 1;
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")) {
@@ -1218,7 +918,7 @@ static int ld_parse_wl(LdOptions* o, const char* arg) {
continue;
}
if (n > 2 && tok[0] == '-' && tok[1] == 'z') {
- if (ld_apply_z_option(o, tok + 2, n - 2) != 0) return 1;
+ if (driver_link_flags_record_z(&o->lf, tok + 2, n - 2) != 0) return 1;
continue;
}
if (ld_tok_eq(tok, n, "--eh-frame-hdr") ||
@@ -1246,7 +946,7 @@ static int ld_parse_wl(LdOptions* o, const char* arg) {
continue;
}
if (ld_tok_eq(tok, n, "-S") || ld_tok_eq(tok, n, "--strip-debug")) {
- o->strip_debug = 1;
+ o->lf.strip_debug = 1;
continue;
}
if (ld_tok_eq(tok, n, "-E") || ld_tok_eq(tok, n, "--export-dynamic")) {
@@ -1254,11 +954,11 @@ static int ld_parse_wl(LdOptions* o, const char* arg) {
continue;
}
if (ld_tok_eq(tok, n, "--enable-new-dtags")) {
- o->new_dtags = 1;
+ o->lf.new_dtags = 1;
continue;
}
if (ld_tok_eq(tok, n, "--disable-new-dtags")) {
- o->new_dtags = 0;
+ o->lf.new_dtags = 0;
continue;
}
if (ld_tok_eq(tok, n, "-rpath")) {
@@ -1282,7 +982,7 @@ static int ld_parse_wl(LdOptions* o, const char* arg) {
if (ld_tok_prefix(tok, n, "-rpath=")) {
const char* owned;
if (ld_span_to_owned_cstr(o, tok + 7, n - 7u, &owned) != 0) return 1;
- o->rpaths[o->nrpaths++] = owned;
+ o->lf.rpaths[o->lf.nrpaths++] = owned;
continue;
}
if (ld_tok_eq(tok, n, "-soname")) {
@@ -1292,7 +992,7 @@ static int ld_parse_wl(LdOptions* o, const char* arg) {
if (ld_tok_prefix(tok, n, "-soname=")) {
const char* owned;
if (ld_span_to_owned_cstr(o, tok + 8, n - 8u, &owned) != 0) return 1;
- o->soname = owned;
+ o->lf.soname = owned;
continue;
}
if (ld_tok_eq(tok, n, "-dynamic-linker") ||
@@ -1303,7 +1003,7 @@ static int ld_parse_wl(LdOptions* o, const char* arg) {
if (ld_tok_prefix(tok, n, "-dynamic-linker=")) {
const char* owned;
if (ld_span_to_owned_cstr(o, tok + 16, n - 16u, &owned) != 0) return 1;
- o->interp_path = owned;
+ o->lf.interp_path = owned;
continue;
}
/* -Tdata / -Tbss section base overrides. */
@@ -1319,23 +1019,30 @@ static int ld_parse_wl(LdOptions* o, const char* arg) {
while (atok[an] && atok[an] != ',') ++an;
p = atok + an + (atok[an] == ',' ? 1u : 0u);
if (ld_span_to_owned_cstr(o, atok, an, &addr_owned) != 0) return 1;
- if (ld_record_section_addr(o, secname, addr_owned) != 0) return 1;
+ if (driver_link_flags_record_section_addr(&o->lf, secname, addr_owned) !=
+ 0)
+ return 1;
continue;
}
if (ld_tok_prefix(tok, n, "-Tdata=")) {
const char* addr_owned;
if (ld_span_to_owned_cstr(o, tok + 7, n - 7u, &addr_owned) != 0) return 1;
- if (ld_record_section_addr(o, ".data", addr_owned) != 0) return 1;
+ if (driver_link_flags_record_section_addr(&o->lf, ".data", addr_owned) !=
+ 0)
+ return 1;
continue;
}
if (ld_tok_prefix(tok, n, "-Tbss=")) {
const char* addr_owned;
if (ld_span_to_owned_cstr(o, tok + 6, n - 6u, &addr_owned) != 0) return 1;
- if (ld_record_section_addr(o, ".bss", addr_owned) != 0) return 1;
+ if (driver_link_flags_record_section_addr(&o->lf, ".bss", addr_owned) !=
+ 0)
+ return 1;
continue;
}
if (ld_tok_prefix(tok, n, "--defsym=")) {
- if (ld_record_defsym(o, tok + 9, n - 9u) != 0) return 1;
+ if (driver_link_flags_record_defsym(&o->lf, tok + 9, n - 9u) != 0)
+ return 1;
continue;
}
if (ld_tok_eq(tok, n, "--defsym")) {
@@ -1343,7 +1050,8 @@ static int ld_parse_wl(LdOptions* o, const char* arg) {
continue;
}
if (ld_tok_prefix(tok, n, "--section-start=")) {
- if (ld_record_section_start(o, tok + 16, n - 16u) != 0) return 1;
+ if (driver_link_flags_record_section_start(&o->lf, tok + 16, n - 16u) != 0)
+ return 1;
continue;
}
if (ld_tok_eq(tok, n, "--section-start")) {
@@ -1351,9 +1059,7 @@ static int ld_parse_wl(LdOptions* o, const char* arg) {
continue;
}
if (ld_tok_prefix(tok, n, "--cref=")) {
- const char* owned;
- if (ld_span_to_owned_cstr(o, tok + 7, n - 7u, &owned) != 0) return 1;
- o->cref_path = owned;
+ if (driver_link_flags_record_cref(&o->lf, tok + 7, n - 7u) != 0) return 1;
continue;
}
if (ld_tok_eq(tok, n, "--cref")) {
@@ -1361,7 +1067,9 @@ static int ld_parse_wl(LdOptions* o, const char* arg) {
continue;
}
if (ld_tok_prefix(tok, n, "--orphan-handling=")) {
- if (ld_record_orphan_handling(o, tok + 18, n - 18u) != 0) return 1;
+ if (driver_link_flags_record_orphan_handling(&o->lf, tok + 18, n - 18u) !=
+ 0)
+ return 1;
continue;
}
if (ld_tok_eq(tok, n, "--orphan-handling")) {
@@ -1369,15 +1077,15 @@ static int ld_parse_wl(LdOptions* o, const char* arg) {
continue;
}
if (ld_tok_eq(tok, n, "--fatal-warnings")) {
- o->fatal_warnings = 1;
+ o->lf.fatal_warnings = 1;
continue;
}
if (ld_tok_eq(tok, n, "--no-fatal-warnings")) {
- o->fatal_warnings = 0;
+ o->lf.fatal_warnings = 0;
continue;
}
if (ld_tok_eq(tok, n, "--print-memory-usage")) {
- o->print_memory_usage = 1;
+ o->lf.print_memory_usage = 1;
continue;
}
@@ -1583,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;
@@ -1610,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;
}
@@ -1631,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")) {
@@ -1642,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;
@@ -1654,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:
@@ -1679,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)
@@ -1818,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) {
@@ -1864,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;
@@ -1873,64 +1585,6 @@ static int ld_expand_dso_scripts(LdOptions* o) {
return 1;
}
-/* ---------- --build-id parsing ---------- */
-
-/* Parse `--build-id=...` argument into options. Accepts "none", "sha256",
- * "uuid", or "0x<even-hex>". Returns 0 on success, 1 on bad value. */
-static int ld_parse_build_id(LdOptions* o, const char* val) {
- if (driver_streq(val, "none")) {
- o->build_id_mode = KIT_BUILDID_NONE;
- return 0;
- }
- if (driver_streq(val, "sha256")) {
- o->build_id_mode = KIT_BUILDID_SHA256;
- return 0;
- }
- if (driver_streq(val, "uuid")) {
- o->build_id_mode = KIT_BUILDID_UUID;
- return 0;
- }
-
- /* "0x<hex>" — must be even number of hex digits, at least one byte. */
- if (val[0] == '0' && (val[1] == 'x' || val[1] == 'X')) {
- const char* hex = val + 2;
- size_t hex_len = driver_strlen(hex);
- size_t nbytes;
- size_t i;
- uint8_t* buf;
- if (hex_len == 0 || (hex_len & 1u)) {
- driver_errf(LD_TOOL,
- "--build-id=0xHEX requires an even number of hex digits");
- return 1;
- }
- nbytes = hex_len / 2;
- buf = driver_alloc(o->env, nbytes);
- if (!buf) {
- driver_errf(LD_TOOL, "out of memory");
- return 1;
- }
- for (i = 0; i < nbytes; ++i) {
- int hi = driver_hex_nibble(hex[2 * i]);
- int lo = driver_hex_nibble(hex[2 * i + 1]);
- if (hi < 0 || lo < 0) {
- driver_errf(LD_TOOL, "--build-id: invalid hex digit");
- driver_free(o->env, buf, nbytes);
- return 1;
- }
- buf[i] = (uint8_t)((hi << 4) | lo);
- }
- o->build_id_mode = KIT_BUILDID_USER;
- o->build_id_bytes = buf;
- o->build_id_len = (uint32_t)nbytes;
- o->build_id_alloc = nbytes;
- return 0;
- }
-
- driver_errf(LD_TOOL, "--build-id: unknown value: %.*s",
- KIT_SLICE_ARG(kit_slice_cstr(val)));
- return 1;
-}
-
/* ---------- argv parser ---------- */
/* If `arg` starts with `prefix` followed by '=', returns the tail past the
@@ -1976,34 +1630,6 @@ static int ms_flag_match(const char* arg, const char* key) {
return arg[1 + klen] == '\0';
}
-static int ld_subsystem_value_eq(const char* val, const char* want) {
- size_t i;
- for (i = 0; want[i]; ++i) {
- char a = val[i];
- char b = want[i];
- if (a >= 'a' && a <= 'z') a = (char)(a - 'a' + 'A');
- if (b >= 'a' && b <= 'z') b = (char)(b - 'a' + 'A');
- if (a != b) return 0;
- }
- return val[i] == '\0' || val[i] == ',';
-}
-
-static int ld_parse_pe_subsystem(LdOptions* o, const char* val) {
- if (ld_subsystem_value_eq(val, "CONSOLE") ||
- ld_subsystem_value_eq(val, "CUI")) {
- o->pe_subsystem = KIT_PE_SUBSYSTEM_WINDOWS_CUI;
- return 0;
- }
- if (ld_subsystem_value_eq(val, "WINDOWS") ||
- ld_subsystem_value_eq(val, "GUI")) {
- o->pe_subsystem = KIT_PE_SUBSYSTEM_WINDOWS_GUI;
- return 0;
- }
- driver_errf(LD_TOOL, "unsupported subsystem: %.*s",
- KIT_SLICE_ARG(kit_slice_cstr(val)));
- return 1;
-}
-
/* Parse one MSVC-style argument. Recognized subset (others warn and
* skip — match-but-no-op so legacy build scripts pass cleanly):
* /OUT:path → o->output_path
@@ -2031,7 +1657,7 @@ static int ld_try_ms_flag(LdOptions* o, const char* a) {
return 1;
}
if ((val = ms_flag_value(a, "ENTRY")) != NULL) {
- o->entry = val;
+ o->lf.entry = val;
return 1;
}
if ((val = ms_flag_value(a, "LIBPATH")) != NULL) {
@@ -2045,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,
@@ -2062,7 +1688,9 @@ static int ld_try_ms_flag(LdOptions* o, const char* a) {
return 1;
}
if ((val = ms_flag_value(a, "SUBSYSTEM")) != NULL) {
- if (ld_parse_pe_subsystem(o, val) != 0) return -1;
+ if (driver_link_flags_record_pe_subsystem(&o->lf, val,
+ driver_strlen(val)) != 0)
+ return -1;
return 1;
}
if (ms_flag_match(a, "NOLOGO") || ms_flag_match(a, "VERBOSE") ||
@@ -2335,11 +1963,11 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
driver_errf(LD_TOOL, "-e requires an argument");
return 1;
}
- o->entry = argv[i];
+ o->lf.entry = argv[i];
continue;
}
if ((val = arg_eq_value(a, "--entry")) != NULL) {
- o->entry = val;
+ o->lf.entry = val;
continue;
}
if (driver_streq(a, "--entry")) {
@@ -2347,11 +1975,13 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
driver_errf(LD_TOOL, "--entry requires an argument");
return 1;
}
- o->entry = argv[i];
+ o->lf.entry = argv[i];
continue;
}
if ((val = arg_eq_value(a, "--subsystem")) != NULL) {
- if (ld_parse_pe_subsystem(o, val) != 0) return 1;
+ if (driver_link_flags_record_pe_subsystem(&o->lf, val,
+ driver_strlen(val)) != 0)
+ return 1;
continue;
}
if (driver_streq(a, "--subsystem")) {
@@ -2359,7 +1989,9 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
driver_errf(LD_TOOL, "--subsystem requires an argument");
return 1;
}
- if (ld_parse_pe_subsystem(o, argv[i]) != 0) return 1;
+ if (driver_link_flags_record_pe_subsystem(&o->lf, argv[i],
+ driver_strlen(argv[i])) != 0)
+ return 1;
continue;
}
{
@@ -2444,13 +2076,7 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
/* -Ttext=ADDR */
}
if (tval) {
- uint64_t v;
- if (driver_parse_u64(tval, &v) != 0) {
- driver_errf(LD_TOOL, "-Ttext: invalid address: %s", tval);
- return 1;
- }
- o->text_base = v;
- o->text_base_set = 1;
+ if (driver_link_flags_record_text_base(&o->lf, tval) != 0) return 1;
continue;
}
}
@@ -2472,7 +2098,8 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
secname = ".bss";
}
if (secname) {
- if (ld_record_section_addr(o, secname, addr) != 0) return 1;
+ if (driver_link_flags_record_section_addr(&o->lf, secname, addr) != 0)
+ return 1;
continue;
}
}
@@ -2481,11 +2108,14 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
driver_errf(LD_TOOL, "--defsym requires NAME=EXPR");
return 1;
}
- if (ld_record_defsym(o, argv[i], driver_strlen(argv[i])) != 0) return 1;
+ if (driver_link_flags_record_defsym(&o->lf, argv[i],
+ driver_strlen(argv[i])) != 0)
+ return 1;
continue;
}
if ((val = arg_eq_value(a, "--defsym")) != NULL) {
- if (ld_record_defsym(o, val, driver_strlen(val)) != 0) return 1;
+ if (driver_link_flags_record_defsym(&o->lf, val, driver_strlen(val)) != 0)
+ return 1;
continue;
}
if (driver_streq(a, "--section-start")) {
@@ -2493,12 +2123,15 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
driver_errf(LD_TOOL, "--section-start requires .NAME=ADDR");
return 1;
}
- if (ld_record_section_start(o, argv[i], driver_strlen(argv[i])) != 0)
+ if (driver_link_flags_record_section_start(
+ &o->lf, argv[i], driver_strlen(argv[i])) != 0)
return 1;
continue;
}
if ((val = arg_eq_value(a, "--section-start")) != NULL) {
- if (ld_record_section_start(o, val, driver_strlen(val)) != 0) return 1;
+ if (driver_link_flags_record_section_start(&o->lf, val,
+ driver_strlen(val)) != 0)
+ return 1;
continue;
}
if (driver_streq(a, "--orphan-handling")) {
@@ -2506,24 +2139,27 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
driver_errf(LD_TOOL, "--orphan-handling requires a mode");
return 1;
}
- if (ld_record_orphan_handling(o, argv[i], driver_strlen(argv[i])) != 0)
+ if (driver_link_flags_record_orphan_handling(
+ &o->lf, argv[i], driver_strlen(argv[i])) != 0)
return 1;
continue;
}
if ((val = arg_eq_value(a, "--orphan-handling")) != NULL) {
- if (ld_record_orphan_handling(o, val, driver_strlen(val)) != 0) return 1;
+ if (driver_link_flags_record_orphan_handling(&o->lf, val,
+ driver_strlen(val)) != 0)
+ return 1;
continue;
}
if (driver_streq(a, "--fatal-warnings")) {
- o->fatal_warnings = 1;
+ o->lf.fatal_warnings = 1;
continue;
}
if (driver_streq(a, "--no-fatal-warnings")) {
- o->fatal_warnings = 0;
+ o->lf.fatal_warnings = 0;
continue;
}
if (driver_streq(a, "--print-memory-usage")) {
- o->print_memory_usage = 1;
+ o->lf.print_memory_usage = 1;
continue;
}
if (driver_streq(a, "--cref")) {
@@ -2531,20 +2167,14 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
driver_errf(LD_TOOL, "--cref requires a path");
return 1;
}
- {
- const char* owned;
- if (ld_span_to_owned_cstr(o, argv[i], driver_strlen(argv[i]), &owned) !=
- 0)
- return 1;
- o->cref_path = owned;
- }
+ if (driver_link_flags_record_cref(&o->lf, argv[i],
+ driver_strlen(argv[i])) != 0)
+ return 1;
continue;
}
if ((val = arg_eq_value(a, "--cref")) != NULL) {
- const char* owned;
- if (ld_span_to_owned_cstr(o, val, driver_strlen(val), &owned) != 0)
+ if (driver_link_flags_record_cref(&o->lf, val, driver_strlen(val)) != 0)
return 1;
- o->cref_path = owned;
continue;
}
/* -nostdlib / --no-default-libs: do not auto-resolve and link kit's
@@ -2654,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;
@@ -2675,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)
@@ -2706,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;
@@ -2735,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;
}
@@ -2743,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;
}
@@ -2759,15 +2389,15 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
driver_errf(LD_TOOL, "-dynamic-linker requires an argument");
return 1;
}
- o->interp_path = argv[i];
+ o->lf.interp_path = argv[i];
continue;
}
if (driver_streq(a, "--no-dynamic-linker")) {
- o->interp_path = "";
+ o->lf.interp_path = "";
continue;
}
if ((val = arg_eq_value(a, "--dynamic-linker")) != NULL) {
- o->interp_path = val;
+ o->lf.interp_path = val;
continue;
}
if (driver_streq(a, "-no-pie")) {
@@ -2794,11 +2424,11 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
driver_errf(LD_TOOL, "-soname requires an argument");
return 1;
}
- o->soname = argv[i];
+ o->lf.soname = argv[i];
continue;
}
if ((val = arg_eq_value(a, "-soname")) != NULL) {
- o->soname = val;
+ o->lf.soname = val;
continue;
}
if (driver_streq(a, "-rpath")) {
@@ -2806,11 +2436,11 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
driver_errf(LD_TOOL, "-rpath requires an argument");
return 1;
}
- o->rpaths[o->nrpaths++] = argv[i];
+ o->lf.rpaths[o->lf.nrpaths++] = argv[i];
continue;
}
if ((val = arg_eq_value(a, "-rpath")) != NULL) {
- o->rpaths[o->nrpaths++] = val;
+ o->lf.rpaths[o->lf.nrpaths++] = val;
continue;
}
if (driver_streq(a, "-rpath-link")) {
@@ -2826,23 +2456,23 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
continue;
}
if (driver_streq(a, "--enable-new-dtags")) {
- o->new_dtags = 1;
+ o->lf.new_dtags = 1;
continue;
}
if (driver_streq(a, "--disable-new-dtags")) {
- o->new_dtags = 0;
+ o->lf.new_dtags = 0;
continue;
}
if (driver_streq(a, "--gc-sections")) {
- o->gc_sections = 1;
+ o->lf.gc_sections = 1;
continue;
}
if (driver_streq(a, "-dead_strip")) {
- o->gc_sections = 1;
+ o->lf.gc_sections = 1;
continue;
}
if (driver_streq(a, "--no-gc-sections")) {
- o->gc_sections = 0;
+ o->lf.gc_sections = 0;
continue;
}
if (driver_streq(a, "--map") || driver_streq(a, "-Map")) {
@@ -2854,7 +2484,7 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
driver_errf(LD_TOOL, "%s requires a non-empty path", a);
return 1;
}
- o->map_path = argv[i];
+ o->lf.map_path = argv[i];
continue;
}
if ((val = arg_eq_value(a, "--map")) != NULL) {
@@ -2862,7 +2492,7 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
driver_errf(LD_TOOL, "--map requires a non-empty path");
return 1;
}
- o->map_path = val;
+ o->lf.map_path = val;
continue;
}
if ((val = arg_eq_value(a, "-Map")) != NULL) {
@@ -2870,7 +2500,7 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
driver_errf(LD_TOOL, "-Map requires a non-empty path");
return 1;
}
- o->map_path = val;
+ o->lf.map_path = val;
continue;
}
if (driver_streq(a, "--symbols")) {
@@ -2882,7 +2512,7 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
driver_errf(LD_TOOL, "--symbols requires a non-empty path");
return 1;
}
- o->symbols_path = argv[i];
+ o->lf.symbols_path = argv[i];
continue;
}
if ((val = arg_eq_value(a, "--symbols")) != NULL) {
@@ -2890,15 +2520,17 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
driver_errf(LD_TOOL, "--symbols requires a non-empty path");
return 1;
}
- o->symbols_path = val;
+ o->lf.symbols_path = val;
continue;
}
if ((val = arg_eq_value(a, "--symbols-format")) != NULL) {
- if (ld_record_symbols_format(o, val, driver_strlen(val)) != 0) return 1;
+ if (driver_link_flags_record_symbols_format(&o->lf, val,
+ driver_strlen(val)) != 0)
+ return 1;
continue;
}
if (driver_streq(a, "-S") || driver_streq(a, "--strip-debug")) {
- o->strip_debug = 1;
+ o->lf.strip_debug = 1;
continue;
}
if (driver_streq(a, "-E") || driver_streq(a, "--export-dynamic")) {
@@ -2920,12 +2552,12 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
continue;
}
if (driver_streq(a, "--no-undefined")) {
- o->allow_undefined = 0;
+ o->lf.allow_undefined = 0;
continue;
}
if (driver_streq(a, "--allow-undefined") ||
driver_streq(a, "--allow-shlib-undefined")) {
- o->allow_undefined = 1;
+ o->lf.allow_undefined = 1;
continue;
}
if (driver_streq(a, "-z")) {
@@ -2933,40 +2565,43 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
driver_errf(LD_TOOL, "-z requires an argument");
return 1;
}
- if (ld_apply_z_option(o, argv[i], driver_strlen(argv[i])) != 0) return 1;
+ if (driver_link_flags_record_z(&o->lf, argv[i], driver_strlen(argv[i])) !=
+ 0)
+ return 1;
continue;
}
if (a[0] == '-' && a[1] == 'z' && a[2] != '\0') {
- if (ld_apply_z_option(o, a + 2, driver_strlen(a + 2)) != 0) return 1;
+ if (driver_link_flags_record_z(&o->lf, a + 2, driver_strlen(a + 2)) != 0)
+ return 1;
continue;
}
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;
}
@@ -2975,25 +2610,25 @@ 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;
}
if ((val = arg_eq_value(a, "--build-id")) != NULL) {
- if (ld_parse_build_id(o, val) != 0) return 1;
+ if (driver_link_flags_record_build_id(&o->lf, val) != 0) return 1;
continue;
}
if (driver_streq(a, "--build-id")) {
/* Bareword form defaults to sha256, matching GNU ld. */
- o->build_id_mode = KIT_BUILDID_SHA256;
+ o->lf.build_id_mode = KIT_BUILDID_SHA256;
continue;
}
@@ -3020,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;
@@ -3055,15 +2691,15 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
driver_errf(LD_TOOL, "-r and -pie are incompatible");
return 1;
}
- if (o->interp_path) {
+ if (o->lf.interp_path) {
driver_errf(LD_TOOL, "-dynamic-linker requires executable output");
return 1;
}
- if (o->soname || o->nrpaths || o->nrpath_links) {
+ if (o->lf.soname || o->lf.nrpaths || o->nrpath_links) {
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;
}
@@ -3071,7 +2707,7 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
driver_errf(LD_TOOL, "-r does not support linker scripts yet");
return 1;
}
- if (o->map_path || o->symbols_path) {
+ if (o->lf.map_path || o->lf.symbols_path) {
driver_errf(LD_TOOL, "--map/--symbols require executable output");
return 1;
}
@@ -3084,44 +2720,23 @@ 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]);
}
- if (o->build_id_bytes) {
- driver_free(o->env, o->build_id_bytes, o->build_id_alloc);
- }
+ /* The shared flag model owns its FLAG strings (defsym/section/map/...), the
+ * 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));
driver_free(o->env, o->owned_path_sizes,
o->cap_owned_paths * sizeof(*o->owned_path_sizes));
- driver_free(o->env, o->rpaths, bound * sizeof(*o->rpaths));
driver_free(o->env, o->rpath_links, bound * sizeof(*o->rpath_links));
- if (o->defsyms)
- driver_free(o->env, o->defsyms, o->cap_defsyms * sizeof(*o->defsyms));
- if (o->section_starts)
- driver_free(o->env, o->section_starts,
- o->cap_section_starts * sizeof(*o->section_starts));
}
/* ---------- input loading ---------- */
@@ -3168,7 +2783,7 @@ static KitStatus ld_write_link_report(const LdOptions* o, const KitFileIO* io,
KIT_SLICE_ARG(kit_slice_cstr(path)));
return KIT_IO;
}
- st = symbols ? kit_link_session_write_symbols(link, o->symbols_format, w)
+ st = symbols ? kit_link_session_write_symbols(link, o->lf.symbols_format, w)
: kit_link_session_write_map(link, w);
if (st == KIT_OK) st = kit_writer_status(w);
kit_writer_close(w);
@@ -3185,10 +2800,10 @@ static KitStatus ld_write_cref(const LdOptions* o, const KitFileIO* io,
KitLinkSession* link) {
KitWriter* w = NULL;
KitStatus st;
- if (!o->cref_path) return KIT_OK;
- if (io->open_writer(io->user, o->cref_path, &w) != KIT_OK) {
+ if (!o->lf.cref_path) return KIT_OK;
+ if (io->open_writer(io->user, o->lf.cref_path, &w) != KIT_OK) {
driver_errf(LD_TOOL, "failed to open cref output: %.*s",
- KIT_SLICE_ARG(kit_slice_cstr(o->cref_path)));
+ KIT_SLICE_ARG(kit_slice_cstr(o->lf.cref_path)));
return KIT_IO;
}
st = kit_link_session_write_cref(link, w);
@@ -3196,7 +2811,7 @@ static KitStatus ld_write_cref(const LdOptions* o, const KitFileIO* io,
kit_writer_close(w);
if (st != KIT_OK)
driver_errf(LD_TOOL, "failed to write cref: %.*s",
- KIT_SLICE_ARG(kit_slice_cstr(o->cref_path)));
+ KIT_SLICE_ARG(kit_slice_cstr(o->lf.cref_path)));
return st;
}
@@ -3204,7 +2819,7 @@ static KitStatus ld_write_cref(const LdOptions* o, const KitFileIO* io,
static KitStatus ld_print_memory_usage(LdOptions* o, KitLinkSession* link) {
KitWriter* w;
KitStatus st;
- if (!o->print_memory_usage) return KIT_OK;
+ if (!o->lf.print_memory_usage) return KIT_OK;
w = driver_stdout_writer(o->env);
if (!w) {
driver_errf(LD_TOOL, "failed to print memory usage");
@@ -3217,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->interp_path && o->hosted.interp_path)
- o->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 ---------- */
@@ -3314,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;
@@ -3332,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));
@@ -3342,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)));
@@ -3394,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;
@@ -3415,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
@@ -3459,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)));
@@ -3477,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;
@@ -3495,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)));
@@ -3510,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)));
@@ -3558,7 +3115,19 @@ static int ld_run_link(LdOptions* o) {
goto out;
}
- if (o->soname || o->nrpaths || o->nrpath_links) {
+ /* 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");
goto out;
@@ -3569,114 +3138,67 @@ static int ld_run_link(LdOptions* o) {
KitLinkSessionOptions lopts;
KitStatus st;
KitSlice* rpath_slices = NULL;
- /* Lift the argv-derived -rpath dirs into slices for the linker. */
- if (o->nrpaths) {
- rpath_slices =
- driver_alloc_zeroed(o->env, o->nrpaths * sizeof(*rpath_slices));
- if (!rpath_slices) {
- driver_errf(LD_TOOL, "out of memory");
- goto out;
- }
- for (i = 0; i < o->nrpaths; ++i)
- rpath_slices[i] = kit_slice_cstr(o->rpaths[i]);
- }
- memset(&lopts, 0, sizeof(lopts));
- lopts.output_kind = o->relocatable ? KIT_LINK_OUTPUT_RELOCATABLE
- : o->shared ? KIT_LINK_OUTPUT_SHARED
- : KIT_LINK_OUTPUT_EXE;
- lopts.entry = kit_slice_cstr(o->entry);
- lopts.text_base_set = o->text_base_set;
- lopts.text_base = o->text_base;
- lopts.defsyms = o->defsyms;
- lopts.ndefsyms = o->ndefsyms;
- lopts.section_starts = o->section_starts;
- lopts.nsection_starts = o->nsection_starts;
- lopts.orphan_handling = o->orphan_handling;
- lopts.fatal_warnings = o->fatal_warnings ? true : false;
- lopts.linker_script = script;
- lopts.build_id_mode = o->build_id_mode;
- lopts.build_id_bytes = o->build_id_bytes;
- lopts.build_id_len = o->build_id_len;
- lopts.gc_sections = o->gc_sections;
- lopts.strip_debug = o->strip_debug;
- /* GNU ld and lld default to a non-PIE ET_EXEC; PIE is opt-in via -pie.
- * The linker imposes no hosted-PIE default the way a compiler driver
- * does (kit cc still defaults hosted executables to PIE through the link
- * API) — a freestanding or static link has no dynamic loader to apply a
- * PIE image's relocations or choose its base, so a PIE default produces a
- * binary that faults under a direct/qemu loader (its writable segments
- * sit below mmap_min_addr at the vaddr-0 PIE base). -shared/-r never PIE.
- * Callers that want a hosted PIE executable pass -pie explicitly (as the
- * musl dynamic lane and real compiler drivers do). */
+ uint8_t output_kind = o->relocatable ? KIT_LINK_OUTPUT_RELOCATABLE
+ : o->shared ? KIT_LINK_OUTPUT_SHARED
+ : KIT_LINK_OUTPUT_EXE;
+ /* The shared flag model fills entry/text-base/defsym/section-start/orphan/
+ * fatal-warnings/build-id/gc/strip/pe-subsystem/interp/soname/rpath. It also
+ * derives lopts.pie via driver_link_pie, but ld overrides that below. */
+ if (driver_link_flags_fill_options(&o->lf, o->target, o->pie, o->shared,
+ o->relocatable, output_kind, script,
+ &lopts, &rpath_slices) != 0)
+ goto out;
+ /* GNU ld and lld default to a non-PIE ET_EXEC; PIE is opt-in via -pie. The
+ * linker imposes no hosted-PIE default the way a compiler driver does (kit
+ * cc still defaults hosted executables to PIE through the link API) — a
+ * freestanding or static link has no dynamic loader to apply a PIE image's
+ * relocations or choose its base, so a PIE default produces a binary that
+ * faults under a direct/qemu loader (its writable segments sit below
+ * mmap_min_addr at the vaddr-0 PIE base). -shared/-r never PIE. Callers that
+ * want a hosted PIE executable pass -pie explicitly (as the musl dynamic
+ * lane and real compiler drivers do); the hosted-libc dynamic lane forces
+ * o->pie = 1 above. So override the shared driver_link_pie decision (which
+ * would default hosted target.pic == KIT_PIC_PIE targets to PIE) back to
+ * ld's policy. */
lopts.pie = o->pie && !o->shared && !o->relocatable;
- lopts.pe_subsystem = o->pe_subsystem;
- lopts.interp_path = kit_slice_cstr(o->interp_path);
- lopts.soname = kit_slice_cstr(o->soname);
- /* Per --enable-new-dtags / --disable-new-dtags: when new_dtags is
- * set (the default), -rpath entries land in DT_RUNPATH; otherwise
- * in DT_RPATH. -rpath-link is link-time-only and is forwarded as
- * runpaths so the library has a record of the search paths used
- * (advisory; ELF runtime ignores DT_RUNPATH entries it didn't
- * write itself, so this matches GNU-ld behaviour where rpath-link
- * does not appear in DT_*PATH). */
- if (o->new_dtags) {
- lopts.runpaths = rpath_slices;
- lopts.nrunpaths = o->nrpaths;
- } else {
- lopts.rpaths = rpath_slices;
- lopts.nrpaths = o->nrpaths;
- }
- /* Executable links are strict by default; --allow-undefined is the
- * explicit escape hatch for freestanding bring-up and diagnostics. */
- lopts.allow_undefined = o->allow_undefined ? 1 : 0;
/* Strict freestanding policy: a `*-none-*` (FREESTANDING) static non-PIE
* executable must reject dynamic-link artifacts and cross-input
* target/format mismatches. Only the EXE lane imposes it; -r/-shared do
* not. --allow-undefined still relaxes undef references but not these
- * structural rejections. */
+ * structural rejections. Set after fill_options, which derives lopts.pie. */
if (lopts.output_kind == KIT_LINK_OUTPUT_EXE && !lopts.pie &&
o->target.os == KIT_OS_FREESTANDING)
lopts.freestanding_strict = true;
(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->map_path, 0);
+ if (st == KIT_OK) st = ld_write_link_report(o, io, link, o->lf.map_path, 0);
if (st == KIT_OK)
- st = ld_write_link_report(o, io, link, o->symbols_path, 1);
+ st = ld_write_link_report(o, io, link, o->lf.symbols_path, 1);
if (st == KIT_OK) st = ld_write_cref(o, io, link);
if (st == KIT_OK) st = ld_print_memory_usage(o, link);
rc = st == KIT_OK ? 0 : 1;
+ driver_link_flags_free_rpath_slices(&o->lf, rpath_slices);
}
out:
@@ -3698,15 +3220,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;
}