[lld] r189719 - [lld][ELF] Add Init/Fini support
Shankar Easwaran
shankare at codeaurora.org
Fri Aug 30 22:27:44 PDT 2013
Author: shankare
Date: Sat Aug 31 00:27:44 2013
New Revision: 189719
URL: http://llvm.org/viewvc/llvm-project?rev=189719&view=rev
Log:
[lld][ELF] Add Init/Fini support
This creates .init_array/.fini_array section for X86_64 ELF
targets and executes init/fini functions specified by the
-init/-fini options respectively.
Added:
lld/trunk/test/elf/X86_64/Inputs/initfini-option.c
lld/trunk/test/elf/X86_64/Inputs/initfini-option.o
lld/trunk/test/elf/X86_64/initfini-option.test
Modified:
lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h
lld/trunk/lib/Driver/GnuLdDriver.cpp
lld/trunk/lib/Driver/LDOptions.td
lld/trunk/lib/ReaderWriter/ELF/Atoms.h
lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp
lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h
Modified: lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h?rev=189719&r1=189718&r2=189719&view=diff
==============================================================================
--- lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h (original)
+++ lld/trunk/include/lld/ReaderWriter/ELFLinkingContext.h Sat Aug 31 00:27:44 2013
@@ -159,6 +159,22 @@ public:
/// Get the entry symbol name
virtual StringRef entrySymbolName() const;
+ /// add to the list of initializer functions
+ void addInitFunction(StringRef name) { _initFunctions.push_back(name); }
+
+ /// add to the list of finalizer functions
+ void addFiniFunction(StringRef name) { _finiFunctions.push_back(name); }
+
+ /// Return the list of initializer symbols that are specified in the
+ /// linker command line, using the -init option.
+ range<const StringRef *> initFunctions() const {
+ return _initFunctions;
+ }
+
+ /// Return the list of finalizer symbols that are specified in the
+ /// linker command line, using the -fini option.
+ range<const StringRef *> finiFunctions() const { return _finiFunctions; }
+
private:
ELFLinkingContext() LLVM_DELETED_FUNCTION;
@@ -189,6 +205,8 @@ protected:
std::unique_ptr<Writer> _writer;
std::unique_ptr<Reader> _linkerScriptReader;
StringRef _dynamicLinkerPath;
+ StringRefVector _initFunctions;
+ StringRefVector _finiFunctions;
};
} // end namespace lld
Modified: lld/trunk/lib/Driver/GnuLdDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/GnuLdDriver.cpp?rev=189719&r1=189718&r2=189719&view=diff
==============================================================================
--- lld/trunk/lib/Driver/GnuLdDriver.cpp (original)
+++ lld/trunk/lib/Driver/GnuLdDriver.cpp Sat Aug 31 00:27:44 2013
@@ -230,6 +230,14 @@ bool GnuLdDriver::parse(int argc, const
ctx->addInitialUndefinedSymbol(inputArg->getValue());
break;
+ case OPT_init:
+ ctx->addInitFunction(inputArg->getValue());
+ break;
+
+ case OPT_fini:
+ ctx->addFiniFunction(inputArg->getValue());
+ break;
+
case OPT_emit_yaml:
if (!_outputOptionSet)
ctx->setOutputPath("-");
Modified: lld/trunk/lib/Driver/LDOptions.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/LDOptions.td?rev=189719&r1=189718&r2=189719&view=diff
==============================================================================
--- lld/trunk/lib/Driver/LDOptions.td (original)
+++ lld/trunk/lib/Driver/LDOptions.td Sat Aug 31 00:27:44 2013
@@ -18,6 +18,13 @@ multiclass smDash<string opt1, string op
Alias<!cast<Option>(opt1)>;
}
+// Support -<option>,-<option>=
+multiclass dashEq<string opt1, string opt2, string help> {
+ def "" : Separate<["-"], opt1>, HelpText<help>;
+ def opt2_eq : Separate<["-"], opt2#"=">,
+ Alias<!cast<Option>(opt1)>;
+}
+
defm e : smDash<"e", "entry",
"Name of entry point symbol">;
@@ -102,6 +109,12 @@ def no_as_needed : Flag<["--"], "no-as-n
HelpText<"This option restores the default behavior"
" of adding DT_NEEDED entries">;
+defm init: dashEq<"init", "init",
+ "Specify an initializer function">;
+
+defm fini: dashEq<"fini", "fini",
+ "Specify a finalizer function">;
+
// extensions
def emit_yaml : Flag<["-"], "emit-yaml">,
HelpText<"Write YAML instead of ELF">;
Modified: lld/trunk/lib/ReaderWriter/ELF/Atoms.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/Atoms.h?rev=189719&r1=189718&r2=189719&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/Atoms.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/Atoms.h Sat Aug 31 00:27:44 2013
@@ -879,6 +879,39 @@ public:
virtual ArrayRef<uint8_t> rawContent() const { return ArrayRef<uint8_t>(); }
};
+class InitFiniAtom : public SimpleDefinedAtom {
+ StringRef _section;
+
+public:
+ InitFiniAtom(const File &f, StringRef secName)
+ : SimpleDefinedAtom(f), _section(secName) {
+ }
+
+ virtual Scope scope() const { return scopeGlobal; }
+
+ virtual SectionChoice sectionChoice() const { return sectionCustomRequired; }
+
+ virtual StringRef customSectionName() const { return _section; }
+
+ virtual ContentType contentType() const { return typeStub; }
+
+ virtual uint64_t size() const { return rawContent().size(); }
+
+ virtual ContentPermissions permissions() const { return permRW_; }
+
+ virtual ArrayRef<uint8_t> rawContent() const = 0;
+
+ virtual Alignment alignment() const { return size(); }
+
+#ifndef NDEBUG
+ virtual StringRef name() const { return _name; }
+
+ std::string _name;
+#else
+ virtual StringRef name() const { return ""; }
+#endif
+};
+
} // end namespace elf
} // end namespace lld
Modified: lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp?rev=189719&r1=189718&r2=189719&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.cpp Sat Aug 31 00:27:44 2013
@@ -29,6 +29,7 @@ using namespace llvm::ELF;
// .got values
const uint8_t x86_64GotAtomContent[8] = { 0 };
+const uint8_t x86_64InitFiniAtomContent[8] = { 0 };
// .plt value (entry 0)
const uint8_t x86_64Plt0AtomContent[16] = {
@@ -393,8 +394,69 @@ public:
const_cast<Reference &>(ref).setTarget(getSharedGOT(sla));
}
};
+
+// X86_64InitFini Atom
+class X86_64InitAtom : public InitFiniAtom {
+public:
+ X86_64InitAtom(const File &f, StringRef function)
+ : InitFiniAtom(f, ".init_array") {
+#ifndef NDEBUG
+ _name = "__init_fn";
+ _name += function;
+#endif
+ }
+ virtual ArrayRef<uint8_t> rawContent() const {
+ return ArrayRef<uint8_t>(x86_64InitFiniAtomContent, 8);
+ }
+};
+
+class X86_64FiniAtom : public InitFiniAtom {
+public:
+ X86_64FiniAtom(const File &f, StringRef function)
+ : InitFiniAtom(f, ".fini_array") {
+#ifndef NDEBUG
+ _name = "__fini_fn_";
+ _name += function;
+#endif
+ }
+ virtual ArrayRef<uint8_t> rawContent() const {
+ return ArrayRef<uint8_t>(x86_64InitFiniAtomContent, 8);
+ }
+};
+
+class X86_64InitFiniFile : public SimpleFile {
+public:
+ X86_64InitFiniFile(const ELFLinkingContext &context):
+ SimpleFile(context, "command line option -init/-fini")
+ {}
+
+ void addInitFunction(StringRef name) {
+ Atom *initFunctionAtom = new (_allocator) SimpleUndefinedAtom(*this, name);
+ X86_64InitAtom *initAtom =
+ (new (_allocator) X86_64InitAtom(*this, name));
+ initAtom->addReference(llvm::ELF::R_X86_64_64, 0, initFunctionAtom, 0);
+ initAtom->setOrdinal(_ordinal++);
+ addAtom(*initFunctionAtom);
+ addAtom(*initAtom);
+ }
+
+ void addFiniFunction(StringRef name) {
+ Atom *finiFunctionAtom = new (_allocator) SimpleUndefinedAtom(*this, name);
+ X86_64FiniAtom *finiAtom =
+ (new (_allocator) X86_64FiniAtom(*this, name));
+ finiAtom->addReference(llvm::ELF::R_X86_64_64, 0, finiFunctionAtom, 0);
+ finiAtom->setOrdinal(_ordinal++);
+ addAtom(*finiFunctionAtom);
+ addAtom(*finiAtom);
+ }
+
+private:
+ llvm::BumpPtrAllocator _allocator;
+};
+
} // end anon namespace
+
void elf::X86_64LinkingContext::addPasses(PassManager &pm) const {
switch (_outputFileType) {
case llvm::ELF::ET_EXEC:
@@ -414,6 +476,20 @@ void elf::X86_64LinkingContext::addPasse
ELFLinkingContext::addPasses(pm);
}
+std::vector<std::unique_ptr<File>>
+ elf::X86_64LinkingContext::createInternalFiles(){
+ std::vector<std::unique_ptr<File> > result =
+ ELFLinkingContext::createInternalFiles();
+ std::unique_ptr<X86_64InitFiniFile>
+ initFiniFile(new X86_64InitFiniFile(*this));
+ for (auto ai:initFunctions())
+ initFiniFile->addInitFunction(ai);
+ for (auto ai:finiFunctions())
+ initFiniFile->addFiniFunction(ai);
+ result.push_back(std::move(initFiniFile));
+ return result;
+}
+
#define LLD_CASE(name) .Case(#name, llvm::ELF::name)
ErrorOr<Reference::Kind>
@@ -497,3 +573,4 @@ elf::X86_64LinkingContext::stringFromRel
return make_error_code(yaml_reader_error::illegal_value);
}
+
Modified: lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h?rev=189719&r1=189718&r2=189719&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/X86_64/X86_64LinkingContext.h Sat Aug 31 00:27:44 2013
@@ -75,6 +75,9 @@ public:
}
}
+ /// \brief Create Internal files for Init/Fini
+ std::vector<std::unique_ptr<File>> createInternalFiles();
+
virtual ErrorOr<Reference::Kind> relocKindFromString(StringRef str) const;
virtual ErrorOr<std::string> stringFromRelocKind(Reference::Kind kind) const;
};
Added: lld/trunk/test/elf/X86_64/Inputs/initfini-option.c
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/X86_64/Inputs/initfini-option.c?rev=189719&view=auto
==============================================================================
--- lld/trunk/test/elf/X86_64/Inputs/initfini-option.c (added)
+++ lld/trunk/test/elf/X86_64/Inputs/initfini-option.c Sat Aug 31 00:27:44 2013
@@ -0,0 +1,13 @@
+#include <stdio.h>
+
+void init() {
+ printf("%s\n", __FUNCTION__);
+}
+
+void fini() {
+ printf("%s\n", __FUNCTION__);
+}
+
+int main() {
+}
+
Added: lld/trunk/test/elf/X86_64/Inputs/initfini-option.o
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/X86_64/Inputs/initfini-option.o?rev=189719&view=auto
==============================================================================
Binary files lld/trunk/test/elf/X86_64/Inputs/initfini-option.o (added) and lld/trunk/test/elf/X86_64/Inputs/initfini-option.o Sat Aug 31 00:27:44 2013 differ
Added: lld/trunk/test/elf/X86_64/initfini-option.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/X86_64/initfini-option.test?rev=189719&view=auto
==============================================================================
--- lld/trunk/test/elf/X86_64/initfini-option.test (added)
+++ lld/trunk/test/elf/X86_64/initfini-option.test Sat Aug 31 00:27:44 2013
@@ -0,0 +1,21 @@
+# This tests the functionality that lld is able to create
+# init_array/fini_array sections in the output ELF. This
+# corresponds to the the .init_array/.fini_array sections
+# in the output ELF.
+
+RUN: lld -flavor gnu -target x86_64-linux %p/Inputs/initfini-option.o \
+RUN: -init init -fini fini --noinhibit-exec -emit-yaml -o %t
+RUN: FileCheck %s < %t
+
+CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+CHECK: section-name: .init_array
+CHECK: references:
+CHECK: - kind: R_X86_64_64
+CHECK: offset: 0
+CHECK: target: init
+CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00 ]
+CHECK: section-name: .fini_array
+CHECK: references:
+CHECK: - kind: R_X86_64_64
+CHECK: offset: 0
+CHECK: target: fini
More information about the llvm-commits
mailing list