Skip to content

Commit

Permalink
Report all undefined symbols correctly
Browse files Browse the repository at this point in the history
Previously, we failed to report an undefined error if we have two
undefined symbols, a strong and a weak one, for the same symbol.

It is an undefined symbol error if an undefined symbol is resolved
to a weak undefined symbol.

Fixes #967
  • Loading branch information
rui314 committed Jan 18, 2023
1 parent 00af084 commit 8936194
Show file tree
Hide file tree
Showing 18 changed files with 119 additions and 85 deletions.
6 changes: 4 additions & 2 deletions elf/arch-alpha.cc
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,10 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];
u8 *loc = base + rel.r_offset;

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down Expand Up @@ -217,8 +218,9 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down
6 changes: 4 additions & 2 deletions elf/arch-arm32.cc
Original file line number Diff line number Diff line change
Expand Up @@ -506,9 +506,10 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];
u8 *loc = base + rel.r_offset;

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down Expand Up @@ -555,8 +556,9 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down
6 changes: 4 additions & 2 deletions elf/arch-arm64.cc
Original file line number Diff line number Diff line change
Expand Up @@ -413,9 +413,10 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];
u8 *loc = base + rel.r_offset;

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down Expand Up @@ -469,9 +470,10 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];
u8 *loc = (u8 *)(contents.data() + rel.r_offset);

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down
6 changes: 4 additions & 2 deletions elf/arch-i386.cc
Original file line number Diff line number Diff line change
Expand Up @@ -393,9 +393,10 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];
u8 *loc = base + rel.r_offset;

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down Expand Up @@ -476,9 +477,10 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];
u8 *loc = (u8 *)(contents.data() + rel.r_offset);

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down
6 changes: 4 additions & 2 deletions elf/arch-m68k.cc
Original file line number Diff line number Diff line change
Expand Up @@ -225,9 +225,10 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];
u8 *loc = base + rel.r_offset;

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down Expand Up @@ -266,8 +267,9 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down
6 changes: 4 additions & 2 deletions elf/arch-ppc32.cc
Original file line number Diff line number Diff line change
Expand Up @@ -297,9 +297,10 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];
u8 *loc = base + rel.r_offset;

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down Expand Up @@ -339,8 +340,9 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down
6 changes: 4 additions & 2 deletions elf/arch-ppc64v1.cc
Original file line number Diff line number Diff line change
Expand Up @@ -290,9 +290,10 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];
u8 *loc = base + rel.r_offset;

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down Expand Up @@ -348,8 +349,9 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down
6 changes: 4 additions & 2 deletions elf/arch-ppc64v2.cc
Original file line number Diff line number Diff line change
Expand Up @@ -284,9 +284,10 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];
u8 *loc = base + rel.r_offset;

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down Expand Up @@ -342,8 +343,9 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down
6 changes: 4 additions & 2 deletions elf/arch-riscv.cc
Original file line number Diff line number Diff line change
Expand Up @@ -548,9 +548,10 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];
u8 *loc = base + rel.r_offset;

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down Expand Up @@ -660,8 +661,9 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down
6 changes: 4 additions & 2 deletions elf/arch-s390x.cc
Original file line number Diff line number Diff line change
Expand Up @@ -339,9 +339,10 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];
u8 *loc = base + rel.r_offset;

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down Expand Up @@ -399,8 +400,9 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down
6 changes: 4 additions & 2 deletions elf/arch-sh4.cc
Original file line number Diff line number Diff line change
Expand Up @@ -275,9 +275,10 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];
u8 *loc = base + rel.r_offset;

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down Expand Up @@ -316,8 +317,9 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down
6 changes: 4 additions & 2 deletions elf/arch-sparc64.cc
Original file line number Diff line number Diff line change
Expand Up @@ -429,9 +429,10 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];
u8 *loc = base + rel.r_offset;

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down Expand Up @@ -491,8 +492,9 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down
6 changes: 4 additions & 2 deletions elf/arch-x86-64.cc
Original file line number Diff line number Diff line change
Expand Up @@ -538,9 +538,10 @@ void InputSection<E>::apply_reloc_nonalloc(Context<E> &ctx, u8 *base) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];
u8 *loc = base + rel.r_offset;

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down Expand Up @@ -635,9 +636,10 @@ void InputSection<E>::scan_relocations(Context<E> &ctx) {
continue;

Symbol<E> &sym = *file.symbols[rel.r_sym];
const ElfSym<E> &esym = file.elf_syms[rel.r_sym];
u8 *loc = (u8 *)(contents.data() + rel.r_offset);

if (!sym.file) {
if (!is_resolved(sym, esym)) {
record_undef_error(ctx, rel);
continue;
}
Expand Down
35 changes: 5 additions & 30 deletions elf/input-files.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1020,18 +1020,6 @@ void ObjectFile<E>::claim_unresolved_symbols(Context<E> &ctx) {
if (!this->is_alive)
return;

auto report_undef = [&](Symbol<E> &sym) {
std::stringstream ss;
if (std::string_view source = this->get_source_name(); !source.empty())
ss << ">>> referenced by " << source << "\n";
else
ss << ">>> referenced by " << *this << "\n";

typename decltype(ctx.undef_errors)::accessor acc;
ctx.undef_errors.insert(acc, {sym.name(), {}});
acc->second.push_back(ss.str());
};

for (i64 i = this->first_global; i < this->elf_syms.size(); i++) {
const ElfSym<E> &esym = this->elf_syms[i];
Symbol<E> &sym = *this->symbols[i];
Expand All @@ -1040,17 +1028,9 @@ void ObjectFile<E>::claim_unresolved_symbols(Context<E> &ctx) {

std::scoped_lock lock(sym.mu);

// If a protected/hidden undefined symbol is resolved to an
// imported symbol, it's handled as if no symbols were found.
if (sym.file && sym.file->is_dso &&
(sym.visibility == STV_PROTECTED || sym.visibility == STV_HIDDEN)) {
report_undef(sym);
continue;
}

if (sym.file &&
(!sym.esym().is_undef() || sym.file->priority <= this->priority))
continue;
if (sym.file)
if (!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".
Expand Down Expand Up @@ -1094,9 +1074,6 @@ void ObjectFile<E>::claim_unresolved_symbols(Context<E> &ctx) {
continue;
}

if (ctx.arg.unresolved_symbols == UNRESOLVED_WARN)
report_undef(sym);

// 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 @@ -1107,15 +1084,13 @@ 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 && sym.visibility != STV_HIDDEN &&
(!ctx.arg.z_defs || ctx.arg.unresolved_symbols != UNRESOLVED_ERROR)) {
if (ctx.arg.shared && sym.visibility != STV_HIDDEN && !ctx.arg.z_defs) {
claim(true);
continue;
}

// Convert remaining undefined symbols to absolute symbols with value 0.
if (ctx.arg.unresolved_symbols != UNRESOLVED_ERROR || ctx.arg.noinhibit_exec)
claim(false);
claim(false);
}
}

Expand Down
24 changes: 24 additions & 0 deletions elf/mold.h
Original file line number Diff line number Diff line change
Expand Up @@ -2830,4 +2830,28 @@ inline bool relax_tlsdesc(Context<E> &ctx, Symbol<E> &sym) {
return ctx.arg.relax && !ctx.arg.shared && !sym.is_imported;
}

// Returns true if esym has already been resolved.
template <typename E>
bool is_resolved(Symbol<E> &sym, const ElfSym<E> &esym) {
assert(sym.file);

// A non-weak undefined symbol must be promoted to an imported
// symbol or resolved to an defined symbol. Otherwise, it's an
// undefined symbol error.
//
// Every ELF file has an absolute local symbol as its first symbol.
// Referring to that symbol is always valid.
bool is_undef = esym.is_undef() && !esym.is_weak() && sym.sym_idx;
if (!sym.is_imported && is_undef && sym.esym().is_undef())
return false;

// If a protected/hidden undefined symbol is resolved to other .so,
// it's handled as if no symbols were found.
if (sym.file->is_dso &&
(sym.visibility == STV_PROTECTED || sym.visibility == STV_HIDDEN))
return false;

return true;
}

} // namespace mold::elf
Loading

0 comments on commit 8936194

Please sign in to comment.