diff options
author | Igor Kudrin <ikudrin.dev@gmail.com> | 2015-10-05 10:29:46 +0000 |
---|---|---|
committer | Igor Kudrin <ikudrin.dev@gmail.com> | 2015-10-05 10:29:46 +0000 |
commit | b1f2b51a896e561397aa4ef2620b37ed02c03a58 (patch) | |
tree | 67a956eeee946c230793ce83f92e6fbae68a87cc | |
parent | 9ed154f9213acaa34fd79aa4a274e9162bf3bf77 (diff) | |
download | llvm-b1f2b51a896e561397aa4ef2620b37ed02c03a58.zip llvm-b1f2b51a896e561397aa4ef2620b37ed02c03a58.tar.gz llvm-b1f2b51a896e561397aa4ef2620b37ed02c03a58.tar.bz2 |
[ELF2] Add DT_INIT and DT_FINI dynamic table entries
The entries are added if there are "_init" or "_fini" entries in
the symbol table respectively. According to the behavior of ld,
entries are inserted even for undefined symbols.
Symbol names can be overridden by using -init and -fini command
line switches. If used, these switches neither add new symbol table
entries nor require those symbols to be resolved.
Differential Revision: http://reviews.llvm.org/D13385
llvm-svn: 249297
-rw-r--r-- | lld/ELF/Config.h | 2 | ||||
-rw-r--r-- | lld/ELF/Driver.cpp | 6 | ||||
-rw-r--r-- | lld/ELF/Options.td | 8 | ||||
-rw-r--r-- | lld/ELF/OutputSections.cpp | 20 | ||||
-rw-r--r-- | lld/ELF/OutputSections.h | 6 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 2 | ||||
-rw-r--r-- | lld/test/elf2/init-fini.s | 43 |
7 files changed, 83 insertions, 4 deletions
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index e774583..d9c3a4b 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -20,6 +20,8 @@ namespace elf2 { struct Configuration { llvm::StringRef DynamicLinker; llvm::StringRef Entry; + llvm::StringRef Fini = "_fini"; + llvm::StringRef Init = "_init"; llvm::StringRef OutputFile = "a.out"; llvm::StringRef SoName; llvm::StringRef Sysroot; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 078382c..7921764 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -117,6 +117,12 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { if (auto *Arg = Args.getLastArg(OPT_entry)) Config->Entry = Arg->getValue(); + if (auto *Arg = Args.getLastArg(OPT_fini)) + Config->Fini = Arg->getValue(); + + if (auto *Arg = Args.getLastArg(OPT_init)) + Config->Init = Arg->getValue(); + if (auto *Arg = Args.getLastArg(OPT_soname)) Config->SoName = Arg->getValue(); diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index a9b0cf8..abdd439 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -32,6 +32,12 @@ def entry : Separate<["--", "-"], "entry">, MetaVarName<"<entry>">, def export_dynamic : Flag<["--", "-"], "export-dynamic">, HelpText<"Put symbols in the dynamic symbol table">; +def fini : Separate<["-"], "fini">, MetaVarName<"<symbol>">, + HelpText<"Specify a finalizer function">; + +def init : Separate<["-"], "init">, MetaVarName<"<symdol>">, + HelpText<"Specify an initializer function">; + def l : Joined<["-"], "l">, MetaVarName<"<libName>">, HelpText<"Root name of library to use">; @@ -77,6 +83,8 @@ def alias_L__library_path : Joined<["--"], "library-path=">, Alias<L>; def alias_discard_all_x: Flag<["-"], "x">, Alias<discard_all>; def alias_discard_locals_X: Flag<["-"], "X">, Alias<discard_locals>; def alias_entry_e : Separate<["-"], "e">, Alias<entry>; +def alias_fini_fini : Joined<["-"], "fini=">, Alias<fini>; +def alias_init_init : Joined<["-"], "init=">, Alias<init>; def alias_l__library : Joined<["--"], "library=">, Alias<l>; def alias_rpath_rpath : Joined<["-"], "rpath=">, Alias<rpath>; def alias_soname_h : Separate<["-"], "h">, Alias<soname>; diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index 7e7ad49..c9a353b 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -170,13 +170,14 @@ template <class ELFT> void HashTableSection<ELFT>::addSymbol(SymbolBody *S) { template <class ELFT> DynamicSection<ELFT>::DynamicSection(SymbolTable &SymTab, HashTableSection<ELFT> &HashSec, - RelocationSection<ELFT> &RelaDynSec) + RelocationSection<ELFT> &RelaDynSec, + const OutputSection<ELFT> &BssSec) : OutputSectionBase<ELFT::Is64Bits>(".dynamic", llvm::ELF::SHT_DYNAMIC, llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE), HashSec(HashSec), DynSymSec(HashSec.getDynSymSec()), DynStrSec(DynSymSec.getStrTabSec()), RelaDynSec(RelaDynSec), - SymTab(SymTab) { + BssSec(BssSec), SymTab(SymTab) { typename Base::HeaderT &Header = this->Header; Header.sh_addralign = ELFT::Is64Bits ? 8 : 4; Header.sh_entsize = ELFT::Is64Bits ? 16 : 8; @@ -224,6 +225,16 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() { DynStrSec.add(File->getSoName()); NumEntries += SharedFiles.size(); + if (Symbol *S = SymTab.getSymbols().lookup(Config->Init)) + InitSym = dyn_cast<ELFSymbolBody<ELFT>>(S->Body); + if (Symbol *S = SymTab.getSymbols().lookup(Config->Fini)) + FiniSym = dyn_cast<ELFSymbolBody<ELFT>>(S->Body); + + if (InitSym) + ++NumEntries; // DT_INIT + if (FiniSym) + ++NumEntries; // DT_FINI + ++NumEntries; // DT_NULL Header.sh_size = NumEntries * Header.sh_entsize; @@ -280,6 +291,11 @@ template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) { for (const std::unique_ptr<SharedFileBase> &File : SharedFiles) WriteVal(DT_NEEDED, DynStrSec.getFileOff(File->getSoName())); + if (InitSym) + WritePtr(DT_INIT, getSymVA(*InitSym, BssSec)); + if (FiniSym) + WritePtr(DT_FINI, getSymVA(*FiniSym, BssSec)); + WriteVal(DT_NULL, 0); } diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h index e36ac9e..5e21196 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -320,7 +320,8 @@ class DynamicSection final : public OutputSectionBase<ELFT::Is64Bits> { public: DynamicSection(SymbolTable &SymTab, HashTableSection<ELFT> &HashSec, - RelocationSection<ELFT> &RelaDynSec); + RelocationSection<ELFT> &RelaDynSec, + const OutputSection<ELFT> &BssSec); void finalize() override; void writeTo(uint8_t *Buf) override; @@ -333,7 +334,10 @@ private: SymbolTableSection<ELFT> &DynSymSec; StringTableSection<ELFT::Is64Bits> &DynStrSec; RelocationSection<ELFT> &RelaDynSec; + const OutputSection<ELFT> &BssSec; SymbolTable &SymTab; + const ELFSymbolBody<ELFT> *InitSym = nullptr; + const ELFSymbolBody<ELFT> *FiniSym = nullptr; }; } } diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index c7dbafe..4fadfd2 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -85,7 +85,7 @@ public: Writer(SymbolTable *T) : SymTabSec(*T, StrTabSec, BssSec), DynSymSec(*T, DynStrSec, BssSec), RelaDynSec(DynSymSec, GotSec, T->shouldUseRela()), PltSec(GotSec), - HashSec(DynSymSec), DynamicSec(*T, HashSec, RelaDynSec), + HashSec(DynSymSec), DynamicSec(*T, HashSec, RelaDynSec, BssSec), BssSec(PltSec, GotSec, BssSec, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE) {} void run(); diff --git a/lld/test/elf2/init-fini.s b/lld/test/elf2/init-fini.s new file mode 100644 index 0000000..cd1649e --- /dev/null +++ b/lld/test/elf2/init-fini.s @@ -0,0 +1,43 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t + +// Should use "_init" and "_fini" by default when fills dynamic table +// RUN: lld -flavor gnu2 -shared %t -o %t2 +// RUN: llvm-readobj -dynamic-table %t2 | FileCheck --check-prefix=BYDEF %s +// BYDEF: INIT 0x11010 +// BYDEF: FINI 0x11020 + +// -init and -fini override symbols to use +// RUN: lld -flavor gnu2 -shared %t -o %t2 -init _foo -fini _bar +// RUN: llvm-readobj -dynamic-table %t2 | FileCheck --check-prefix=OVR %s +// OVR: INIT 0x11030 +// OVR: FINI 0x11040 + +// Check aliases as well +// RUN: lld -flavor gnu2 -shared %t -o %t2 -init=_foo -fini=_bar +// RUN: llvm-readobj -dynamic-table %t2 | FileCheck --check-prefix=OVR %s + +// Should add a dynamic table entry even if a given symbol stay undefined +// RUN: lld -flavor gnu2 -shared %t -o %t2 -init=_undef -fini=_undef +// RUN: llvm-readobj -dynamic-table %t2 | FileCheck --check-prefix=UNDEF %s +// UNDEF: INIT 0x0 +// UNDEF: FINI 0x0 + +// Should not add new entries to the symbol table +// and should not require given symbols to be resolved +// RUN: lld -flavor gnu2 -shared %t -o %t2 -init=_unknown -fini=_unknown +// RUN: llvm-readobj -symbols -dynamic-table %t2 | FileCheck --check-prefix=NOENTRY %s +// NOENTRY: Symbols [ +// NOENTRY-NOT: Name: _unknown +// NOENTRY: ] +// NOENTRY: DynamicSection [ +// NOENTRY-NOT: INIT +// NOENTRY-NOT: FINI +// NOENTRY: ] + +.global _start,_init,_fini,_foo,_bar,_undef; +_start: +_init = 0x11010 +_fini = 0x11020 +_foo = 0x11030 +_bar = 0x11040 |