Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -20,6 +20,8 @@ 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; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -117,6 +117,12 @@ 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(); Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -32,6 +32,12 @@ def export_dynamic : Flag<["--", "-"], "export-dynamic">, HelpText<"Put symbols in the dynamic symbol table">; +def fini : Separate<["-"], "fini">, MetaVarName<"">, + HelpText<"Specify a finalizer function">; + +def init : Separate<["-"], "init">, MetaVarName<"">, + HelpText<"Specify an initializer function">; + def l : Joined<["-"], "l">, MetaVarName<"">, HelpText<"Root name of library to use">; @@ -74,6 +80,8 @@ def alias_discard_all: Flag<["-"], "x">, Alias; def alias_discard_locals: Flag<["-"], "X">, Alias; def alias_entry : Separate<["-"], "e">, Alias; +def alias_fini : Joined<["-"], "fini=">, Alias; +def alias_init : Joined<["-"], "init=">, Alias; def alias_l : Joined<["--"], "library=">, Alias; def alias_soname : Separate<["-"], "h">, Alias; Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -319,7 +319,8 @@ public: DynamicSection(SymbolTable &SymTab, HashTableSection &HashSec, - RelocationSection &RelaDynSec); + RelocationSection &RelaDynSec, + const OutputSection &BssSec); void finalize() override; void writeTo(uint8_t *Buf) override; @@ -328,7 +329,10 @@ SymbolTableSection &DynSymSec; StringTableSection &DynStrSec; RelocationSection &RelaDynSec; + const OutputSection &BssSec; SymbolTable &SymTab; + const ELFSymbolBody *InitSymbolBody = nullptr; + const ELFSymbolBody *FiniSymbolBody = nullptr; }; } } Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -170,13 +170,14 @@ template DynamicSection::DynamicSection(SymbolTable &SymTab, HashTableSection &HashSec, - RelocationSection &RelaDynSec) + RelocationSection &RelaDynSec, + const OutputSection &BssSec) : OutputSectionBase(".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; @@ -217,6 +218,18 @@ DynStrSec.add(File->getSoName()); NumEntries += SharedFiles.size(); + auto LookupForBody = [&](StringRef Name) { + ELFSymbolBody *Body = nullptr; + if (Symbol *Sym = SymTab.getSymbols().lookup(Name)) + Body = dyn_cast>(Sym->Body); + return Body; + }; + + if ((InitSymbolBody = LookupForBody(Config->Init))) + ++NumEntries; // DT_INIT + if ((FiniSymbolBody = LookupForBody(Config->Fini))) + ++NumEntries; // DT_FINI + ++NumEntries; // DT_NULL Header.sh_size = NumEntries * Header.sh_entsize; @@ -264,6 +277,11 @@ for (const std::unique_ptr &File : SharedFiles) WriteVal(DT_NEEDED, DynStrSec.getFileOff(File->getSoName())); + if (InitSymbolBody) + WritePtr(DT_INIT, getSymVA(*InitSymbolBody, BssSec)); + if (FiniSymbolBody) + WritePtr(DT_FINI, getSymVA(*FiniSymbolBody, BssSec)); + WriteVal(DT_NULL, 0); } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -99,7 +99,7 @@ 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(); Index: test/elf2/init-fini.s =================================================================== --- /dev/null +++ test/elf2/init-fini.s @@ -0,0 +1,31 @@ +// 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 not add the dynamic table entry if the symbol is undefined +// RUN: lld -flavor gnu2 -shared %t -o %t2 -init=_undefined -fini=_undefined +// RUN: llvm-readobj -dynamic-table %t2 | FileCheck --check-prefix=NOENTRY %s +// NOENTRY-NOT: INIT +// NOENTRY-NOT: FINI + +.global _start,_init,_fini,_foo,_bar; +_start: +_init = 0x11010 +_fini = 0x11020 +_foo = 0x11030 +_bar = 0x11040