commit 86578e086af87817f5e12c08978143bfc10f1946
parent e98db5738ea91cf5fe5953d9f5a9937a56377a59
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Mon, 1 Jun 2026 17:22:42 -0700
link: treat DSO exports as defined so archives don't shadow shared libs
scan_presence_before classified a DSO export (cfree records it as an
OBJ_SEC_NONE global) as undefined via obj_sym_is_logical_undef, so when a
later static archive also defined the name, the archive member was pulled to
redefine a symbol the shared library already provides. Linking a -pie
executable against a real libc thus let libcfree_rt.a's freestanding
atoi/strtol shadow the libc's versions, breaking the dynamic 12_stdlib_convert
case in test-libc-musl-rv64 / test-libc-glibc-rv64.
Count a DSO's exported (non-SK_UNDEF) symbols as defined so a static-archive
member is not pulled to shadow them, matching standard ld behavior.
Diffstat:
1 file changed, 12 insertions(+), 0 deletions(-)
diff --git a/src/link/link_resolve.c b/src/link/link_resolve.c
@@ -885,12 +885,24 @@ static void scan_presence_before(Linker* l, u32 max_order, SymHash* defined,
for (ii = 0; ii < LinkInputs_count(&l->inputs); ++ii) {
LinkInput* in = LinkInputs_at(&l->inputs, ii);
ObjBuilder* ob = in->obj;
+ int is_dso = (in->kind == LINK_INPUT_DSO_BYTES);
if (!ob || in->order > max_order) continue;
it = obj_symiter_new(ob);
while (obj_symiter_next(it, &e)) {
const ObjSym* s = e.sym;
if (s->name == 0) continue;
if (s->bind == SB_LOCAL) continue;
+ if (is_dso) {
+ /* A DSO's exported symbols satisfy undefined references, so a later
+ * static-archive member must NOT be pulled to redefine them. cfree
+ * records DSO exports as OBJ_SEC_NONE globals (the importer's view),
+ * which obj_sym_is_logical_undef would otherwise misclassify as
+ * undefined — leaving e.g. a real libc's atoi looking unsatisfied and
+ * letting the freestanding rt's atoi shadow it. The DSO's own undefs
+ * (SK_UNDEF) are not exports and stay out of `defined`. */
+ if (s->kind != SK_UNDEF) symhash_set(defined, s->name, 1u);
+ continue;
+ }
if (obj_sym_is_logical_undef(s)) {
/* Match the spurious-UNDEF prune in link_resolve (line 109) and
* obj_sweep_dead at .o emit (obj.c:513): an unreferenced