Skip to content

Commit

Permalink
[ELF] Export undef symbols if both -z defs and `-warn-undefined-sym…
Browse files Browse the repository at this point in the history
…bols` are given

When we are creating a DSO, unresolved undefined symbols are promoted to
dynamic symbols by default so that they will get another chance to be
resolved at runtime.

You can suppress this behavior by passing `-z defs`. If that option is
given, remaining undefs are reported as errors instead of being silently
promoted.

It looks like `-warn-undefined-symbols` negates the effect of `-z defs`.
So, if both options are given, remaining undefs are promoted to dynamic
symbols. mold previously silently make such symbols absolute symbols with
value 0.

Fixed #152
  • Loading branch information
rui314 committed Dec 24, 2021
1 parent 5601cf4 commit 04ccd4d
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 30 deletions.
58 changes: 30 additions & 28 deletions elf/object-file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -992,6 +992,22 @@ void ObjectFile<E>::claim_unresolved_symbols(Context<E> &ctx) {

std::lock_guard lock(sym.mu);

if (sym.file &&
(!sym.esym().is_undef() || sym.file->priority <= this->priority))
continue;

// If a symbol name is in the form of "foo@version", search for
// symbol "foo" and check if the symbol has version "version".
std::string_view key = symbol_strtab.data() + esym.st_name;
if (i64 pos = key.find('@'); pos != key.npos) {
Symbol<E> *sym2 = intern(ctx, key.substr(0, pos));
if (sym2->file && sym2->file->is_dso &&
sym2->get_version() == key.substr(pos + 1)) {
this->symbols[i] = sym2;
continue;
}
}

auto claim = [&]() {
sym.file = this;
sym.input_section = nullptr;
Expand All @@ -1002,23 +1018,11 @@ void ObjectFile<E>::claim_unresolved_symbols(Context<E> &ctx) {
sym.is_exported = false;
};

if (!sym.file ||
(sym.esym().is_undef() && this->priority < sym.file->priority)) {
std::string_view key = symbol_strtab.data() + esym.st_name;

// If a symbol name is in the form of "foo@version", search for
// symbol "foo" and check if the symbol has version "version".
if (i64 pos = key.find('@'); pos != key.npos) {
Symbol<E> *sym2 = intern(ctx, key.substr(0, pos));
if (sym2->file && sym2->file->is_dso &&
sym2->get_version() == key.substr(pos + 1)) {
this->symbols[i] = sym2;
continue;
}
}
if (ctx.arg.unresolved_symbols == UnresolvedKind::WARN)
Warn(ctx) << "undefined symbol: " << *this << ": " << sym;

// Convert remaining undefined symbols to dynamic symbols.
//
// Convert remaining undefined symbols to dynamic symbols.
if (ctx.arg.shared) {
// Traditionally, remaining undefined symbols cause a link failure
// only when we are creating an executable. Undefined symbols in
// shared objects are promoted to dynamic symbols, so that they'll
Expand All @@ -1029,28 +1033,26 @@ void ObjectFile<E>::claim_unresolved_symbols(Context<E> &ctx) {
// promoted to dynamic symbols for compatibility with other linkers.
// Some major programs, notably Firefox, depend on the behavior
// (they use this loophole to export symbols from libxul.so).
if (ctx.arg.shared && (!ctx.arg.z_defs || esym.is_undef_weak())) {
if (!ctx.arg.z_defs || esym.is_undef_weak() ||
ctx.arg.unresolved_symbols != UnresolvedKind::ERROR) {
claim();
sym.ver_idx = 0;
sym.is_imported = !ctx.arg.is_static;
sym.is_imported = true;

if (sym.traced)
SyncOut(ctx) << "trace-symbol: " << *this << ": unresolved"
<< (esym.is_weak() ? " weak" : "")
<< " symbol " << sym;
continue;
}
}

// Convert remaining undefined symbols to absolute symbols with value 0.
if (ctx.arg.unresolved_symbols != UnresolvedKind::ERROR ||
esym.is_undef_weak()) {
claim();
sym.ver_idx = ctx.arg.default_version;
sym.is_imported = false;

if (ctx.arg.unresolved_symbols == UnresolvedKind::WARN)
Warn(ctx) << "undefined symbol: " << *this << ": " << sym;
}
// Convert remaining undefined symbols to absolute symbols with value 0.
if (ctx.arg.unresolved_symbols != UnresolvedKind::ERROR ||
esym.is_undef_weak()) {
claim();
sym.ver_idx = ctx.arg.default_version;
sym.is_imported = false;
}
}
}
Expand Down
11 changes: 9 additions & 2 deletions test/elf/defs.sh → test/elf/z-defs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,17 @@ EOF
clang -fuse-ld=$mold -shared -o $t/b.so $t/a.o
clang -fuse-ld=$mold -shared -o $t/b.so $t/a.o -Wl,-z,nodefs

! clang -fuse-ld=$mold -shared -o $t/b.so $t/a.o -Wl,-z,defs 2> $t/log || false
! clang -fuse-ld=$mold -shared -o $t/b.so $t/a.o -Wl,-z,defs \
2> $t/log || false
grep -q 'undefined symbol:.* foo' $t/log

! clang -fuse-ld=$mold -shared -o $t/b.so $t/a.o -Wl,-no-undefined 2> $t/log || false
! clang -fuse-ld=$mold -shared -o $t/b.so $t/a.o -Wl,-no-undefined \
2> $t/log || false
grep -q 'undefined symbol:.* foo' $t/log

clang -fuse-ld=$mold -shared -o $t/c.so $t/a.o -Wl,-z,defs \
-Wl,--warn-unresolved-symbols 2> $t/log
grep -q 'undefined symbol: .* foo$' $t/log
readelf --dyn-syms $t/c.so | grep -q ' foo$'

echo OK

0 comments on commit 04ccd4d

Please sign in to comment.