forked from OSchip/llvm-project
[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
This commit is contained in:
parent
9ed154f921
commit
b1f2b51a89
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue