[ELF] Implement --export-dynamic/-E

When creating a dynamic executable and receiving the -E flag, the linker should
export all globally visible symbols in its dynamic symbol table.

This commit also moves the logic that exports symbols in the dynamic symbol
table from OutputELFWriter to the ExecutableWriter class. It is not correct to
leave this at OutputELFWriter because DynamicLibraryWriter, another subclass of
OutputELFWriter, already exports all symbols, meaning we can potentially end up
with duplicated symbols in the dynamic symbol table when creating shared libs.

Reviewers: shankarke

http://reviews.llvm.org/D5585

llvm-svn: 219334
This commit is contained in:
Rafael Auler 2014-10-08 18:54:26 +00:00
parent e4320f5e6a
commit ce1af1a201
6 changed files with 133 additions and 9 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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