[lld] r217363 - [ELF] Export strong defined symbol if it coalesces away a weak symbol
Simon Atanasyan
simon at atanasyan.com
Mon Sep 8 02:43:38 PDT 2014
Author: atanasyan
Date: Mon Sep 8 04:43:38 2014
New Revision: 217363
URL: http://llvm.org/viewvc/llvm-project?rev=217363&view=rev
Log:
[ELF] Export strong defined symbol if it coalesces away a weak symbol
defined in a shared library.
Now LLD does not export a strong defined symbol if it coalesces away a
weak symbol defined in a shared library. This bug affects all ELF
architectures and leads to segfault:
% cat foo.c
extern int __attribute__((weak)) flag;
int foo() { return flag; }
% cat main.c
int flag = 1;
int foo();
int main() { return foo() == 1 ? 0 : -1; }
% clang -c -fPIC foo.c main.c
% lld -flavor gnu -target x86_64 -shared -o libfoo.so ... foo.o
% lld -flavor gnu -target x86_64 -o a.out ... main.o libfoo.so
% ./a.out
Segmentation fault
The problem is caused by the fact that we lose all information about
coalesced symbols after the `Resolver::resolve()` method is finished.
The patch solves the problem by overriding the
`LinkingContext::notifySymbolTableCoalesce()` method and saving names
of coalesced symbols. Later in the `buildDynamicSymbolTable()` routine
we use this information to export these symbols.
Added:
lld/trunk/test/elf/X86_64/dynsym-weak.test
Modified:
lld/trunk/include/lld/Core/LinkingContext.h
lld/trunk/include/lld/Core/SymbolTable.h
lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h
lld/trunk/lib/Core/SymbolTable.cpp
lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp
lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h
Modified: lld/trunk/include/lld/Core/LinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Core/LinkingContext.h?rev=217363&r1=217362&r2=217363&view=diff
==============================================================================
--- lld/trunk/include/lld/Core/LinkingContext.h (original)
+++ lld/trunk/include/lld/Core/LinkingContext.h Mon Sep 8 04:43:38 2014
@@ -234,9 +234,7 @@ public:
/// but that can be changed by the LinkingContext. This is also an
/// opportunity for flavor specific processing.
virtual void notifySymbolTableCoalesce(const Atom *existingAtom,
- const Atom *newAtom,
- bool &useNew) const {
- }
+ const Atom *newAtom, bool &useNew) {}
/// This method adds undefined symbols specified by the -u option to the to
/// the list of undefined symbols known to the linker. This option essentially
Modified: lld/trunk/include/lld/Core/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Core/SymbolTable.h?rev=217363&r1=217362&r2=217363&view=diff
==============================================================================
--- lld/trunk/include/lld/Core/SymbolTable.h (original)
+++ lld/trunk/include/lld/Core/SymbolTable.h Mon Sep 8 04:43:38 2014
@@ -36,7 +36,7 @@ class UndefinedAtom;
/// if an atom has been coalesced away.
class SymbolTable {
public:
- explicit SymbolTable(const LinkingContext &);
+ explicit SymbolTable(LinkingContext &);
/// @brief add atom to symbol table
bool add(const DefinedAtom &);
@@ -108,7 +108,7 @@ private:
bool addByName(const Atom &);
bool addByContent(const DefinedAtom &);
- const LinkingContext &_context;
+ LinkingContext &_context;
AtomToAtom _replacedAtoms;
NameToAtom _nameTable;
NameToAtom _groupTable;
Modified: lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h?rev=217363&r1=217362&r2=217363&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h (original)
+++ lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h Mon Sep 8 04:43:38 2014
@@ -19,6 +19,7 @@
#include "lld/ReaderWriter/Reader.h"
#include "lld/ReaderWriter/Writer.h"
+#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/ELF.h"
@@ -69,6 +70,9 @@ public:
bool mergeCommonStrings() const { return _mergeCommonStrings; }
virtual uint64_t getBaseAddress() const { return _baseAddress; }
+ void notifySymbolTableCoalesce(const Atom *existingAtom, const Atom *newAtom,
+ bool &useNew) override;
+
/// This controls if undefined atoms need to be created for undefines that are
/// present in a SharedLibrary. If this option is set, undefined atoms are
/// created for every undefined symbol that are present in the dynamic table
@@ -258,6 +262,10 @@ public:
void setCreateSeparateROSegment() { _mergeRODataToTextSegment = false; }
+ bool hasCoalescedWeakPair(StringRef name) const {
+ return _weakCoalescedSymbols.count(name) != 0;
+ }
+
private:
ELFLinkingContext() LLVM_DELETED_FUNCTION;
@@ -292,6 +300,7 @@ protected:
StringRefVector _rpathList;
StringRefVector _rpathLinkList;
std::map<std::string, uint64_t> _absoluteSymbols;
+ llvm::StringSet<> _weakCoalescedSymbols;
};
} // end namespace lld
Modified: lld/trunk/lib/Core/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/SymbolTable.cpp?rev=217363&r1=217362&r2=217363&view=diff
==============================================================================
--- lld/trunk/lib/Core/SymbolTable.cpp (original)
+++ lld/trunk/lib/Core/SymbolTable.cpp Mon Sep 8 04:43:38 2014
@@ -30,7 +30,7 @@
#include <vector>
namespace lld {
-SymbolTable::SymbolTable(const LinkingContext &context) : _context(context) {}
+SymbolTable::SymbolTable(LinkingContext &context) : _context(context) {}
bool SymbolTable::add(const UndefinedAtom &atom) { return addByName(atom); }
Modified: lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp?rev=217363&r1=217362&r2=217363&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/ELFLinkingContext.cpp Mon Sep 8 04:43:38 2014
@@ -241,4 +241,29 @@ std::unique_ptr<File> ELFLinkingContext:
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) {
+ // First suppose that the `existingAtom` is defined
+ // and the `newAtom` is undefined.
+ auto *da = dyn_cast<DefinedAtom>(existingAtom);
+ auto *ua = dyn_cast<UndefinedAtom>(newAtom);
+ if (!da && !ua) {
+ // Then try to reverse the assumption.
+ da = dyn_cast<DefinedAtom>(newAtom);
+ 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.
+ // Save its name.
+ _weakCoalescedSymbols.insert(ua->name());
+}
+
} // end namespace lld
Modified: lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h?rev=217363&r1=217362&r2=217363&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h Mon Sep 8 04:43:38 2014
@@ -182,7 +182,8 @@ void OutputELFWriter<ELFT>::buildDynamic
if (auto section = dyn_cast<AtomSection<ELFT>>(sec))
for (const auto &atom : section->atoms()) {
const DefinedAtom *da = dyn_cast<const DefinedAtom>(atom->_atom);
- if (da && da->dynamicExport() == DefinedAtom::dynamicExportAlways)
+ if (da && (da->dynamicExport() == DefinedAtom::dynamicExportAlways ||
+ _context.hasCoalescedWeakPair(da->name())))
_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(),
atom->_virtualAddr, atom);
}
Added: lld/trunk/test/elf/X86_64/dynsym-weak.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/X86_64/dynsym-weak.test?rev=217363&view=auto
==============================================================================
--- lld/trunk/test/elf/X86_64/dynsym-weak.test (added)
+++ lld/trunk/test/elf/X86_64/dynsym-weak.test Mon Sep 8 04:43:38 2014
@@ -0,0 +1,118 @@
+# Check that a symbol declared as a week in a shared library gets a dynamic
+# symbol table record in an executable file if this executabe file declares the
+# symbol as strong.
+
+# RUN: yaml2obj -format=elf -docnum 1 %s > %t.foo.o
+# RUN: lld -flavor gnu -target x86_64 -shared -o %t.so %t.foo.o
+# RUN: yaml2obj -format=elf -docnum 2 %s > %t.main.o
+#
+# Link executable file with strong symbol. Weak symbol is in the shared lib.
+# RUN: lld -flavor gnu -target x86_64 -e main -o %t1.exe %t.main.o %t.so
+# RUN: llvm-readobj -dyn-symbols %t1.exe | FileCheck -check-prefix=EXE %s
+#
+# Link executable file. Strong and weak symbol come from different object files.
+# RUN: lld -flavor gnu -target x86_64 -e main -o %t2.exe %t.main.o %t.foo.o
+# RUN: llvm-readobj -dyn-symbols %t2.exe | FileCheck -check-prefix=OBJ %s
+#
+# Link shared library. Weak symbol is in the another shared lib.
+# RUN: lld -flavor gnu -target x86_64 -shared -o %t.res.so %t.main.o %t.so
+# RUN: llvm-readobj -dyn-symbols %t.res.so | FileCheck -check-prefix=SO %s
+
+# EXE: Symbol {
+# EXE: Name: flag@ ({{[0-9]+}})
+# EXE-NEXT: Value: 0x{{[0-9A-F]+}}
+# EXE-NEXT: Size: 4
+# EXE-NEXT: Binding: Global (0x1)
+# EXE-NEXT: Type: Object (0x1)
+# EXE-NEXT: Other: 0
+# EXE-NEXT: Section: .data (0x{{[0-9A-F]+}})
+# EXE-NEXT: }
+
+# OBJ-NOT: Name: flag@ ({{[0-9]+}})
+
+# SO: Symbol {
+# SO: Name: flag@ ({{[0-9]+}})
+# SO-NEXT: Value: 0x{{[0-9A-F]+}}
+# SO-NEXT: Size: 4
+# SO-NEXT: Binding: Global (0x1)
+# SO-NEXT: Type: Object (0x1)
+# SO-NEXT: Other: 0
+# SO-NEXT: Section: .data (0x{{[0-9A-F]+}})
+# SO-NEXT: }
+
+# foo.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x08
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x08
+ Info: .text
+ Relocations:
+ - Offset: 0x00
+ Symbol: flag
+ Type: R_X86_64_GOTPCREL
+ Addend: -4
+
+Symbols:
+ Global:
+ - Name: foo
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x08
+ Weak:
+ - Name: flag
+
+# main.o
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_X86_64
+
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x04
+ Size: 0x08
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x08
+ Info: .text
+ Relocations:
+ - Offset: 0x00
+ Symbol: foo
+ Type: R_X86_64_PLT32
+ Addend: -4
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x04
+ Size: 0x04
+
+Symbols:
+ Global:
+ - Name: flag
+ Type: STT_OBJECT
+ Section: .data
+ Size: 0x04
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x08
+ - Name: foo
+...
More information about the llvm-commits
mailing list