Skip to content

Commit 6b0ecea

Browse files
rui314claude
andcommitted
Don't drop DSO undef references when versym is VER_NDX_LOCAL
Commit 6b8293b changed the early `ver` computation in SharedFile::parse so that undef symbols use the raw versym instead of being forced to VER_NDX_GLOBAL. Some BFD ld versions (notably binutils 2.35 on Debian 11) emit VER_NDX_LOCAL (0) as the versym for unversioned undefined dynamic symbols, so the subsequent `if (ver == VER_NDX_LOCAL) continue;` check silently dropped those undef references. With the DSO's reference invisible to mold, the matching object-file definition was never marked as exported, and at runtime the dynamic loader failed with "undefined symbol". Restore the old behavior: defined symbols with VER_NDX_LOCAL are still skipped (they aren't really exposed for dynamic linking), but undef references are always processed. Also fix the verdef/verneed merge in the same path. vd_ndx and vna_other share a single versym index space (a producing linker assigns them from one counter), so a single vector covers both. read_verdef and read_verneed are folded into one read_version_strings that populates that shared-index vector directly, replacing the buggy `append` concatenation. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 6b8293b commit 6b0ecea

2 files changed

Lines changed: 59 additions & 66 deletions

File tree

src/input-files.cc

Lines changed: 58 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1260,8 +1260,7 @@ void SharedFile<E>::parse(Context<E> &ctx) {
12601260

12611261
this->symbol_strtab = this->get_string(ctx, symtab_sec->sh_link);
12621262
soname = get_soname(ctx);
1263-
version_strings = read_verdef(ctx);
1264-
append(version_strings, read_verneed(ctx));
1263+
version_strings = read_version_strings(ctx);
12651264

12661265
// Read a symbol table.
12671266
std::span<ElfSym<E>> esyms = this->template get_data<ElfSym<E>>(ctx, *symtab_sec);
@@ -1271,20 +1270,21 @@ void SharedFile<E>::parse(Context<E> &ctx) {
12711270
vers = this->template get_data<U16<E>>(ctx, *sec);
12721271

12731272
for (i64 i = symtab_sec->sh_info; i < esyms.size(); i++) {
1274-
u16 ver;
1275-
if (vers.empty())
1276-
ver = VER_NDX_GLOBAL;
1277-
else
1278-
ver = vers[i] & ~VERSYM_HIDDEN;
1279-
1280-
if (ver == VER_NDX_LOCAL)
1273+
u16 ver = vers.empty() ? VER_NDX_GLOBAL : (vers[i] & ~VERSYM_HIDDEN);
1274+
1275+
// A defined symbol with VER_NDX_LOCAL is bound locally and isn't
1276+
// really exposed for dynamic linking; skip it. We never skip
1277+
// undefined references — the dynamic loader doesn't distinguish
1278+
// local vs global on the undef side, and dropping them would hide
1279+
// the DSO's reference from us.
1280+
if (ver == VER_NDX_LOCAL && !esyms[i].is_undef())
12811281
continue;
12821282

12831283
this->elf_syms2.push_back(esyms[i]);
1284-
// Defined symbols index into verdef; undefined symbols index into
1285-
// verneed. We record VER_NDX_GLOBAL for undefined symbols here
1286-
// because resolve_symbols only consults versyms[] for defined
1287-
// symbols (see SharedFile::resolve_symbols).
1284+
1285+
// resolve_symbols only consults versyms[] for defined symbols
1286+
// (see SharedFile::resolve_symbols), so VER_NDX_GLOBAL is fine
1287+
// for undefined entries.
12881288
this->versyms.push_back(esyms[i].is_undef() ? (u16)VER_NDX_GLOBAL : ver);
12891289

12901290
std::string_view name = this->symbol_strtab.data() + esyms[i].st_name;
@@ -1384,67 +1384,61 @@ std::string_view SharedFile<E>::get_dt_audit(Context<E> &ctx) {
13841384
// If an undefiend symbol `foo` is resolved to a symbol defined by the
13851385
// shared object, it's marked so that it'll be resolved to (`foo`, the
13861386
// default version of the library) at load-time.
1387+
//
1388+
// Reads .gnu.version_d and .gnu.version_r and returns a vector of
1389+
// version names indexed by versym value. The versym index space is
1390+
// shared between the two sections (vd_ndx for defined symbols and
1391+
// vna_other for undefined ones), so a single vector covers both.
13871392
template <typename E>
1388-
std::vector<std::string_view> SharedFile<E>::read_verdef(Context<E> &ctx) {
1389-
ElfShdr<E> *verdef_sec = this->find_section(SHT_GNU_VERDEF);
1390-
if (!verdef_sec)
1391-
return {};
1392-
1393-
std::string_view verdef = this->get_string(ctx, *verdef_sec);
1394-
std::string_view strtab = this->get_string(ctx, verdef_sec->sh_link);
1395-
1393+
std::vector<std::string_view>
1394+
SharedFile<E>::read_version_strings(Context<E> &ctx) {
13961395
std::vector<std::string_view> vec;
1397-
u8 *ptr = (u8 *)verdef.data();
13981396

1399-
for (;;) {
1400-
ElfVerdef<E> *ver = (ElfVerdef<E> *)ptr;
1401-
if (ver->vd_ndx == VER_NDX_UNSPECIFIED)
1402-
Fatal(ctx) << *this << ": symbol version too large";
1397+
if (ElfShdr<E> *sec = this->find_section(SHT_GNU_VERDEF)) {
1398+
std::string_view verdef = this->get_string(ctx, *sec);
1399+
std::string_view strtab = this->get_string(ctx, sec->sh_link);
1400+
u8 *ptr = (u8 *)verdef.data();
14031401

1404-
if (vec.size() <= ver->vd_ndx)
1405-
vec.resize(ver->vd_ndx + 1);
1402+
for (;;) {
1403+
ElfVerdef<E> *ver = (ElfVerdef<E> *)ptr;
1404+
if (ver->vd_ndx == VER_NDX_UNSPECIFIED)
1405+
Fatal(ctx) << *this << ": symbol version too large";
14061406

1407-
ElfVerdaux<E> *aux = (ElfVerdaux<E> *)(ptr + ver->vd_aux);
1408-
vec[ver->vd_ndx] = strtab.data() + aux->vda_name;
1409-
if (!ver->vd_next)
1410-
break;
1411-
ptr += ver->vd_next;
1412-
}
1413-
return vec;
1414-
}
1407+
if (vec.size() <= ver->vd_ndx)
1408+
vec.resize(ver->vd_ndx + 1);
14151409

1416-
// Reads .gnu.version_r and returns a vector of version names indexed
1417-
// by vna_other. .gnu.version_r records the versions a shared object
1418-
// needs from the libraries it depends on; the versym of an undefined
1419-
// dynamic symbol indexes into these entries.
1420-
template <typename E>
1421-
std::vector<std::string_view> SharedFile<E>::read_verneed(Context<E> &ctx) {
1422-
ElfShdr<E> *verneed_sec = this->find_section(SHT_GNU_VERNEED);
1423-
if (!verneed_sec)
1424-
return {};
1410+
ElfVerdaux<E> *aux = (ElfVerdaux<E> *)(ptr + ver->vd_aux);
1411+
vec[ver->vd_ndx] = strtab.data() + aux->vda_name;
1412+
if (!ver->vd_next)
1413+
break;
1414+
ptr += ver->vd_next;
1415+
}
1416+
}
14251417

1426-
std::vector<std::string_view> vec;
1427-
std::string_view verneed = this->get_string(ctx, *verneed_sec);
1428-
std::string_view strtab = this->get_string(ctx, verneed_sec->sh_link);
1429-
1430-
u8 *ptr = (u8 *)verneed.data();
1431-
for (;;) {
1432-
ElfVerneed<E> *vn = (ElfVerneed<E> *)ptr;
1433-
u8 *aux_ptr = ptr + vn->vn_aux;
1434-
for (i64 i = 0; i < vn->vn_cnt; i++) {
1435-
ElfVernaux<E> *aux = (ElfVernaux<E> *)aux_ptr;
1436-
u16 idx = aux->vna_other & ~VERSYM_HIDDEN;
1437-
if (vec.size() <= idx)
1438-
vec.resize(idx + 1);
1439-
vec[idx] = strtab.data() + aux->vna_name;
1440-
if (!aux->vna_next)
1418+
if (ElfShdr<E> *sec = this->find_section(SHT_GNU_VERNEED)) {
1419+
std::string_view verneed = this->get_string(ctx, *sec);
1420+
std::string_view strtab = this->get_string(ctx, sec->sh_link);
1421+
u8 *ptr = (u8 *)verneed.data();
1422+
1423+
for (;;) {
1424+
ElfVerneed<E> *vn = (ElfVerneed<E> *)ptr;
1425+
u8 *aux_ptr = ptr + vn->vn_aux;
1426+
for (i64 i = 0; i < vn->vn_cnt; i++) {
1427+
ElfVernaux<E> *aux = (ElfVernaux<E> *)aux_ptr;
1428+
u16 idx = aux->vna_other & ~VERSYM_HIDDEN;
1429+
if (vec.size() <= idx)
1430+
vec.resize(idx + 1);
1431+
vec[idx] = strtab.data() + aux->vna_name;
1432+
if (!aux->vna_next)
1433+
break;
1434+
aux_ptr += aux->vna_next;
1435+
}
1436+
if (!vn->vn_next)
14411437
break;
1442-
aux_ptr += aux->vna_next;
1438+
ptr += vn->vn_next;
14431439
}
1444-
if (!vn->vn_next)
1445-
break;
1446-
ptr += vn->vn_next;
14471440
}
1441+
14481442
return vec;
14491443
}
14501444

src/mold.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1850,8 +1850,7 @@ class SharedFile : public InputFile<E> {
18501850
std::string get_soname(Context<E> &ctx);
18511851
void maybe_override_symbol(Symbol<E> &sym, const ElfSym<E> &esym);
18521852
std::vector<std::string_view> read_dt_needed(Context<E> &ctx);
1853-
std::vector<std::string_view> read_verdef(Context<E> &ctx);
1854-
std::vector<std::string_view> read_verneed(Context<E> &ctx);
1853+
std::vector<std::string_view> read_version_strings(Context<E> &ctx);
18551854

18561855
std::vector<u16> versyms;
18571856
const ElfShdr<E> *symtab_sec;

0 commit comments

Comments
 (0)