[ELF] Fix linking when a regular object defines a symbol that is used in a DSO

Patch from Rafael Auler!

When a shared lib has an undefined symbol that is defined in a regular object
(the program), the final executable must export this symbol in the dynamic
symbol table. However, in the current logic, lld only puts the symbol in the
dynamic symbol table if the symbol is weak. This patch fixes lld to put the
symbol in the dynamic symbol table regardless if it is weak or not.

This caused a problem in FreeBSD10, whose programs link against a crt1.o
that defines the symbol __progname, which is, in turn, undefined in libc.so.7
and will only be resolved in runtime.

http://reviews.llvm.org/D5424

llvm-svn: 218259
This commit is contained in:
Rui Ueyama 2014-09-22 17:52:50 +00:00
parent a3d8879be7
commit 508a007ae6
4 changed files with 16 additions and 13 deletions

View File

@ -262,8 +262,8 @@ public:
void setCreateSeparateROSegment() { _mergeRODataToTextSegment = false; }
bool hasCoalescedWeakPair(StringRef name) const {
return _weakCoalescedSymbols.count(name) != 0;
bool hasCoalescedSharedLibPair(StringRef name) const {
return _sharedLibCoalescedSymbols.count(name) != 0;
}
private:
@ -300,7 +300,7 @@ protected:
StringRefVector _rpathList;
StringRefVector _rpathLinkList;
std::map<std::string, uint64_t> _absoluteSymbols;
llvm::StringSet<> _weakCoalescedSymbols;
llvm::StringSet<> _sharedLibCoalescedSymbols;
};
} // end namespace lld

View File

@ -241,11 +241,6 @@ std::unique_ptr<File> ELFLinkingContext::createUndefinedSymbolFile() const {
return std::move(undefinedSymFile);
}
static bool isSharedWeakAtom(const UndefinedAtom *ua) {
return ua->canBeNull() != UndefinedAtom::canBeNullNever &&
isa<SharedLibraryFile>(ua->file());
}
void ELFLinkingContext::notifySymbolTableCoalesce(const Atom *existingAtom,
const Atom *newAtom,
bool &useNew) {
@ -259,11 +254,12 @@ void ELFLinkingContext::notifySymbolTableCoalesce(const Atom *existingAtom,
ua = dyn_cast<UndefinedAtom>(existingAtom);
}
if (da && ua && da->scope() == Atom::scopeGlobal && isSharedWeakAtom(ua))
// If strong defined atom coalesces away weak atom declared
// in the shared object the strong atom needs to be dynamicaly exported.
if (da && ua && da->scope() == Atom::scopeGlobal &&
isa<SharedLibraryFile>(ua->file()))
// If strong defined atom coalesces away an atom declared
// in the shared object the strong atom needs to be dynamically exported.
// Save its name.
_weakCoalescedSymbols.insert(ua->name());
_sharedLibCoalescedSymbols.insert(ua->name());
}
} // end namespace lld

View File

@ -183,7 +183,7 @@ void OutputELFWriter<ELFT>::buildDynamicSymbolTable(const File &file) {
for (const auto &atom : section->atoms()) {
const DefinedAtom *da = dyn_cast<const DefinedAtom>(atom->_atom);
if (da && (da->dynamicExport() == DefinedAtom::dynamicExportAlways ||
_context.hasCoalescedWeakPair(da->name())))
_context.hasCoalescedSharedLibPair(da->name())))
_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(),
atom->_virtualAddr, atom);
}

View File

@ -0,0 +1,7 @@
# Tests that a reference from a DSO to a regular object
# forces the final executable to export the symbol.
RUN: lld -flavor gnu -target x86_64 %p/Inputs/defobj.o -L%p/Inputs -lundef2 -o %t1
RUN: llvm-readobj -dyn-symbols %t1 | FileCheck -check-prefix CHECKSYMS %s
CHECKSYMS: myexportedsymbol