summaryrefslogtreecommitdiffstats
path: root/lld
diff options
context:
space:
mode:
Diffstat (limited to 'lld')
-rw-r--r--lld/include/lld/ReaderWriter/ELFLinkingContext.h4
-rw-r--r--lld/lib/Driver/GnuLdDriver.cpp4
-rw-r--r--lld/lib/Driver/GnuLdOptions.td6
-rw-r--r--lld/lib/ReaderWriter/ELF/ExecutableWriter.h20
-rw-r--r--lld/lib/ReaderWriter/ELF/OutputELFWriter.h9
-rw-r--r--lld/test/elf/export-dynamic.test99
6 files changed, 133 insertions, 9 deletions
diff --git a/lld/include/lld/ReaderWriter/ELFLinkingContext.h b/lld/include/lld/ReaderWriter/ELFLinkingContext.h
index 4c350775675..1ace8b93a07 100644
--- a/lld/include/lld/ReaderWriter/ELFLinkingContext.h
+++ b/lld/include/lld/ReaderWriter/ELFLinkingContext.h
@@ -152,11 +152,14 @@ public:
void setTriple(llvm::Triple trip) { _triple = trip; }
void setNoInhibitExec(bool v) { _noInhibitExec = v; }
+ void setExportDynamic(bool v) { _exportDynamic = v; }
void setIsStaticExecutable(bool v) { _isStaticExecutable = v; }
void setMergeCommonStrings(bool v) { _mergeCommonStrings = v; }
void setUseShlibUndefines(bool use) { _useShlibUndefines = use; }
void setOutputELFType(uint32_t type) { _outputELFType = type; }
+ bool shouldExportDynamic() const { return _exportDynamic; }
+
void createInternalFiles(std::vector<std::unique_ptr<File>> &) const override;
/// \brief Set the dynamic linker path
@@ -283,6 +286,7 @@ protected:
uint64_t _baseAddress;
bool _isStaticExecutable;
bool _noInhibitExec;
+ bool _exportDynamic;
bool _mergeCommonStrings;
bool _runLayoutPass;
bool _useShlibUndefines;
diff --git a/lld/lib/Driver/GnuLdDriver.cpp b/lld/lib/Driver/GnuLdDriver.cpp
index 683bf318ef5..ded0b70e0cd 100644
--- a/lld/lib/Driver/GnuLdDriver.cpp
+++ b/lld/lib/Driver/GnuLdDriver.cpp
@@ -372,6 +372,10 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
ctx->setAllowRemainingUndefines(true);
break;
+ case OPT_export_dynamic:
+ ctx->setExportDynamic(true);
+ break;
+
case OPT_merge_strings:
ctx->setMergeCommonStrings(true);
break;
diff --git a/lld/lib/Driver/GnuLdOptions.td b/lld/lib/Driver/GnuLdOptions.td
index 08adcc4b6ab..590ce9509aa 100644
--- a/lld/lib/Driver/GnuLdOptions.td
+++ b/lld/lib/Driver/GnuLdOptions.td
@@ -139,6 +139,12 @@ defm rpath : dashEq<"rpath", "rpath",
def rpath_link : Separate<["-"], "rpath-link">,
HelpText<"Specifies the first set of directories to search">,
Group<grp_dynlibexec>;
+def export_dynamic : Flag<["--"], "export-dynamic">,
+ HelpText<"Add all symbols to the dynamic symbol table"
+ " when creating executables">,
+ Group<grp_main>;
+def alias_export_dynamic: Flag<["-"], "E">,
+ Alias<export_dynamic>;
//===----------------------------------------------------------------------===//
/// Dynamic Library Options
diff --git a/lld/lib/ReaderWriter/ELF/ExecutableWriter.h b/lld/lib/ReaderWriter/ELF/ExecutableWriter.h
index af780b687e0..a65e8f58729 100644
--- a/lld/lib/ReaderWriter/ELF/ExecutableWriter.h
+++ b/lld/lib/ReaderWriter/ELF/ExecutableWriter.h
@@ -30,6 +30,7 @@ public:
_runtimeFile(new CRuntimeFile<ELFT>(context)) {}
protected:
+ virtual void buildDynamicSymbolTable(const File &file);
virtual void addDefaultAtoms();
virtual bool createImplicitFiles(std::vector<std::unique_ptr<File> > &);
virtual void finalizeDefaultAtomValues();
@@ -41,6 +42,25 @@ protected:
//===----------------------------------------------------------------------===//
// ExecutableWriter
//===----------------------------------------------------------------------===//
+template<class ELFT>
+void ExecutableWriter<ELFT>::buildDynamicSymbolTable(const File &file) {
+ for (auto sec : this->_layout.sections())
+ 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)
+ continue;
+ if (da->dynamicExport() != DefinedAtom::dynamicExportAlways &&
+ !this->_context.isDynamicallyExportedSymbol(da->name()) &&
+ !(this->_context.shouldExportDynamic() &&
+ da->scope() == Atom::Scope::scopeGlobal))
+ continue;
+ this->_dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(),
+ atom->_virtualAddr, atom);
+ }
+
+ OutputELFWriter<ELFT>::buildDynamicSymbolTable(file);
+}
/// \brief Add absolute symbols by default. These are linker added
/// absolute symbols
diff --git a/lld/lib/ReaderWriter/ELF/OutputELFWriter.h b/lld/lib/ReaderWriter/ELF/OutputELFWriter.h
index e7a81cc9180..30b1e573a66 100644
--- a/lld/lib/ReaderWriter/ELF/OutputELFWriter.h
+++ b/lld/lib/ReaderWriter/ELF/OutputELFWriter.h
@@ -179,15 +179,6 @@ void OutputELFWriter<ELFT>::buildStaticSymbolTable(const File &file) {
template <class ELFT>
void OutputELFWriter<ELFT>::buildDynamicSymbolTable(const File &file) {
ScopedTask task(getDefaultDomain(), "buildDynamicSymbolTable");
- for (auto sec : this->_layout.sections())
- 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 ||
- _context.isDynamicallyExportedSymbol(da->name())))
- _dynamicSymbolTable->addSymbol(atom->_atom, section->ordinal(),
- atom->_virtualAddr, atom);
- }
for (const auto &sla : file.sharedLibrary()) {
if (isDynSymEntryRequired(sla))
_dynamicSymbolTable->addSymbol(sla, ELF::SHN_UNDEF);
diff --git a/lld/test/elf/export-dynamic.test b/lld/test/elf/export-dynamic.test
new file mode 100644
index 00000000000..6456668dd25
--- /dev/null
+++ b/lld/test/elf/export-dynamic.test
@@ -0,0 +1,99 @@
+# Tests the --export-dynamic (-E) flag. When creating a dynamic executable and
+# receiving this flag, the linker should export all globally visible symbols in
+# its dynamic symbol table.
+
+#RUN: yaml2obj -format=elf %s -o=%t.o
+#RUN: lld -flavor gnu -target x86_64 -E %t.o -e=main -o %t1
+#RUN: llvm-readobj -dt %t1 | FileCheck -check-prefix CHECKSYMS %s
+
+#CHECKSYMS: myfunc1@
+#CHECKSYMS: main@
+#CHECKSYMS: myvar1@
+
+# The object file below was generated with the following code:
+#
+# (command line clang -c prog.c -o prog.o)
+#
+# int myvar1 = 22;
+#
+# static int mysecretvar = 11;
+#
+# int myfunc1() {
+# return 23;
+# }
+#
+# static int mysecretfunc() {
+# return 42;
+# }
+#
+# int main() {
+# return mysecretfunc() + mysecretvar;
+# }
+---
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ OSABI: ELFOSABI_GNU
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .text
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000010
+ Content: 554889E5B8170000005DC30F1F440000554889E54883EC10C745FC00000000E81C000000030425000000004883C4105DC36666666666662E0F1F840000000000554889E5B82A0000005DC3
+ - Name: .rela.text
+ Type: SHT_RELA
+ Link: .symtab
+ AddressAlign: 0x0000000000000008
+ Info: .text
+ Relocations:
+ - Offset: 0x0000000000000027
+ Symbol: .data
+ Type: R_X86_64_32S
+ Addend: 4
+ - Name: .data
+ Type: SHT_PROGBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: 160000000B000000
+ - Name: .bss
+ Type: SHT_NOBITS
+ Flags: [ SHF_WRITE, SHF_ALLOC ]
+ AddressAlign: 0x0000000000000004
+ Content: ''
+Symbols:
+ Local:
+ - Name: mysecretfunc
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000040
+ Size: 0x000000000000000B
+ - Name: mysecretvar
+ Type: STT_OBJECT
+ Section: .data
+ Value: 0x0000000000000004
+ Size: 0x0000000000000004
+ - Name: .text
+ Type: STT_SECTION
+ Section: .text
+ - Name: .data
+ Type: STT_SECTION
+ Section: .data
+ - Name: .bss
+ Type: STT_SECTION
+ Section: .bss
+ Global:
+ - Name: main
+ Type: STT_FUNC
+ Section: .text
+ Value: 0x0000000000000010
+ Size: 0x0000000000000021
+ - Name: myfunc1
+ Type: STT_FUNC
+ Section: .text
+ Size: 0x000000000000000B
+ - Name: myvar1
+ Type: STT_OBJECT
+ Section: .data
+ Size: 0x0000000000000004
OpenPOWER on IntegriCloud