diff options
| -rw-r--r-- | lld/include/lld/ReaderWriter/ELFLinkingContext.h | 1 | ||||
| -rw-r--r-- | lld/include/lld/ReaderWriter/LinkerScript.h | 10 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h | 4 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/DynamicLibraryWriter.h | 4 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/ELFFile.h | 8 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/ExecutableWriter.h | 6 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableAtoms.h | 4 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h | 4 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/OutputELFWriter.h | 49 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/LinkerScript.cpp | 22 | ||||
| -rw-r--r-- | lld/test/elf/linkerscript/Inputs/simple.o.yaml | 52 | ||||
| -rw-r--r-- | lld/test/elf/linkerscript/symbol-definition.test | 54 |
12 files changed, 191 insertions, 27 deletions
diff --git a/lld/include/lld/ReaderWriter/ELFLinkingContext.h b/lld/include/lld/ReaderWriter/ELFLinkingContext.h index c8f85dc5d00..d1cd3d9f3d6 100644 --- a/lld/include/lld/ReaderWriter/ELFLinkingContext.h +++ b/lld/include/lld/ReaderWriter/ELFLinkingContext.h @@ -306,6 +306,7 @@ public: void setUndefinesResolver(std::unique_ptr<File> resolver); script::Sema &linkerScriptSema() { return _linkerScriptSema; } + const script::Sema &linkerScriptSema() const { return _linkerScriptSema; } private: ELFLinkingContext() = delete; diff --git a/lld/include/lld/ReaderWriter/LinkerScript.h b/lld/include/lld/ReaderWriter/LinkerScript.h index 6eab12d9bbf..ae8d18d830c 100644 --- a/lld/include/lld/ReaderWriter/LinkerScript.h +++ b/lld/include/lld/ReaderWriter/LinkerScript.h @@ -21,6 +21,7 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringSet.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/MemoryBuffer.h" @@ -1264,6 +1265,14 @@ public: /// update our symbol table with new symbols calculated in this expression. std::error_code evalExpr(const SymbolAssignment *assgn, uint64_t &curPos); + /// Retrieve the set of symbols defined in linker script expressions. + const llvm::StringSet<> &getScriptDefinedSymbols() const; + + /// Queries the linker script symbol table for the value of a given symbol. + /// This function must be called after linker script expressions evaluation + /// has been performed (by calling evalExpr() for all expressions). + uint64_t getLinkerScriptExprValue(StringRef name) const; + void dump() const; private: @@ -1370,6 +1379,7 @@ private: mutable std::unordered_map<SectionKey, int, SectionKeyHash, SectionKeyEq> _cacheSectionOrder, _cacheExpressionOrder; llvm::DenseSet<int> _deliveredExprs; + mutable llvm::StringSet<> _definedSymbols; Expression::SymbolTableTy _symbolTable; }; diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h b/lld/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h index 7f1d37e3d5b..b53a8fee76b 100644 --- a/lld/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h +++ b/lld/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h @@ -37,7 +37,7 @@ protected: unique_bump_ptr<SymbolTable<ELFT>> createSymbolTable() override; void processUndefinedSymbol(StringRef symName, - CRuntimeFile<ELFT> &file) const override; + RuntimeFile<ELFT> &file) const override; private: ARMLinkingContext &_context; ARMTargetLayout<ELFT> &_armLayout; @@ -83,7 +83,7 @@ unique_bump_ptr<SymbolTable<ELFT>> template <class ELFT> void ARMExecutableWriter<ELFT>::processUndefinedSymbol( - StringRef symName, CRuntimeFile<ELFT> &file) const { + StringRef symName, RuntimeFile<ELFT> &file) const { if (symName == _gotSymbol) { file.addAbsoluteAtom(_gotSymbol); } else if (symName.startswith("__exidx")) { diff --git a/lld/lib/ReaderWriter/ELF/DynamicLibraryWriter.h b/lld/lib/ReaderWriter/ELF/DynamicLibraryWriter.h index 62fa6a767fa..3ca4aac129b 100644 --- a/lld/lib/ReaderWriter/ELF/DynamicLibraryWriter.h +++ b/lld/lib/ReaderWriter/ELF/DynamicLibraryWriter.h @@ -27,7 +27,7 @@ class DynamicLibraryWriter : public OutputELFWriter<ELFT> { public: DynamicLibraryWriter(ELFLinkingContext &context, TargetLayout<ELFT> &layout) : OutputELFWriter<ELFT>(context, layout), - _runtimeFile(new CRuntimeFile<ELFT>(context)) {} + _runtimeFile(new RuntimeFile<ELFT>(context, "C runtime")) {} protected: virtual void buildDynamicSymbolTable(const File &file); @@ -36,7 +36,7 @@ protected: virtual void finalizeDefaultAtomValues(); protected: - std::unique_ptr<CRuntimeFile<ELFT> > _runtimeFile; + std::unique_ptr<RuntimeFile<ELFT> > _runtimeFile; }; //===----------------------------------------------------------------------===// diff --git a/lld/lib/ReaderWriter/ELF/ELFFile.h b/lld/lib/ReaderWriter/ELF/ELFFile.h index fb7c0213247..bd4fa832261 100644 --- a/lld/lib/ReaderWriter/ELF/ELFFile.h +++ b/lld/lib/ReaderWriter/ELF/ELFFile.h @@ -430,14 +430,14 @@ protected: }; /// \brief All atoms are owned by a File. To add linker specific atoms -/// the atoms need to be inserted to a file called (CRuntimeFile) which +/// the atoms need to be inserted to a file called (RuntimeFile) which /// are basically additional symbols required by libc and other runtime /// libraries part of executing a program. This class provides support /// for adding absolute symbols and undefined symbols -template <class ELFT> class CRuntimeFile : public ELFFile<ELFT> { +template <class ELFT> class RuntimeFile : public ELFFile<ELFT> { public: typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym; - CRuntimeFile(ELFLinkingContext &context, StringRef name = "C runtime") + RuntimeFile(ELFLinkingContext &context, StringRef name) : ELFFile<ELFT>(name, context) {} /// \brief add a global absolute atom @@ -470,7 +470,7 @@ public: return *newAtom; } - // cannot add atoms to C Runtime file + // cannot add atoms to Runtime file virtual void addAtom(const Atom &) { llvm_unreachable("cannot add atoms to Runtime files"); } diff --git a/lld/lib/ReaderWriter/ELF/ExecutableWriter.h b/lld/lib/ReaderWriter/ELF/ExecutableWriter.h index 92a8ea9ff57..477e3920aba 100644 --- a/lld/lib/ReaderWriter/ELF/ExecutableWriter.h +++ b/lld/lib/ReaderWriter/ELF/ExecutableWriter.h @@ -27,7 +27,7 @@ class ExecutableWriter : public OutputELFWriter<ELFT> { public: ExecutableWriter(ELFLinkingContext &context, TargetLayout<ELFT> &layout) : OutputELFWriter<ELFT>(context, layout), - _runtimeFile(new CRuntimeFile<ELFT>(context)) {} + _runtimeFile(new RuntimeFile<ELFT>(context, "C runtime")) {} protected: virtual void buildDynamicSymbolTable(const File &file); @@ -41,7 +41,7 @@ protected: } unique_bump_ptr<InterpSection<ELFT>> _interpSection; - std::unique_ptr<CRuntimeFile<ELFT> > _runtimeFile; + std::unique_ptr<RuntimeFile<ELFT> > _runtimeFile; }; //===----------------------------------------------------------------------===// @@ -80,6 +80,7 @@ void ExecutableWriter<ELFT>::buildDynamicSymbolTable(const File &file) { /// absolute symbols template<class ELFT> void ExecutableWriter<ELFT>::addDefaultAtoms() { + OutputELFWriter<ELFT>::addDefaultAtoms(); _runtimeFile->addUndefinedAtom(this->_context.entrySymbolName()); _runtimeFile->addAbsoluteAtom("__bss_start"); _runtimeFile->addAbsoluteAtom("__bss_end"); @@ -124,6 +125,7 @@ template <class ELFT> void ExecutableWriter<ELFT>::createDefaultSections() { /// Finalize the value of all the absolute symbols that we /// created template <class ELFT> void ExecutableWriter<ELFT>::finalizeDefaultAtomValues() { + OutputELFWriter<ELFT>::finalizeDefaultAtomValues(); auto bssStartAtomIter = this->_layout.findAbsoluteAtom("__bss_start"); auto bssEndAtomIter = this->_layout.findAbsoluteAtom("__bss_end"); auto underScoreEndAtomIter = this->_layout.findAbsoluteAtom("_end"); diff --git a/lld/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableAtoms.h b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableAtoms.h index 47a0996fcfd..a2505aa460c 100644 --- a/lld/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableAtoms.h +++ b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonExecutableAtoms.h @@ -18,10 +18,10 @@ typedef llvm::object::ELFType<llvm::support::little, 2, false> HexagonELFType; class HexagonLinkingContext; template <class HexagonELFType> class HexagonRuntimeFile - : public CRuntimeFile<HexagonELFType> { + : public RuntimeFile<HexagonELFType> { public: HexagonRuntimeFile(HexagonLinkingContext &context) - : CRuntimeFile<HexagonELFType>(context, "Hexagon runtime file") {} + : RuntimeFile<HexagonELFType>(context, "Hexagon runtime file") {} }; } // elf } // lld diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h index 023c7a8ec8c..49affe6589f 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h @@ -87,10 +87,10 @@ private: /// \brief Mips Runtime file. template <class ELFType> -class MipsRuntimeFile final : public CRuntimeFile<ELFType> { +class MipsRuntimeFile final : public RuntimeFile<ELFType> { public: MipsRuntimeFile(MipsLinkingContext &ctx) - : CRuntimeFile<ELFType>(ctx, "Mips runtime file") {} + : RuntimeFile<ELFType>(ctx, "Mips runtime file") {} }; /// \brief Auxiliary class holds relocation's names table. diff --git a/lld/lib/ReaderWriter/ELF/OutputELFWriter.h b/lld/lib/ReaderWriter/ELF/OutputELFWriter.h index b44da49402f..e26bb685c1e 100644 --- a/lld/lib/ReaderWriter/ELF/OutputELFWriter.h +++ b/lld/lib/ReaderWriter/ELF/OutputELFWriter.h @@ -33,14 +33,14 @@ template <class ELFT> class TargetLayout; namespace { template<class ELFT> -class SymbolFile : public CRuntimeFile<ELFT> { +class SymbolFile : public RuntimeFile<ELFT> { public: SymbolFile(ELFLinkingContext &context) - : CRuntimeFile<ELFT>(context, "Dynamic absolute symbols"), + : RuntimeFile<ELFT>(context, "Dynamic absolute symbols"), _atomsAdded(false) {} Atom *addAbsoluteAtom(StringRef symbolName) override { - auto *a = CRuntimeFile<ELFT>::addAbsoluteAtom(symbolName); + auto *a = RuntimeFile<ELFT>::addAbsoluteAtom(symbolName); if (a) _atomsAdded = true; return a; } @@ -57,7 +57,7 @@ private: template<class ELFT> class DynamicSymbolFile : public SimpleArchiveLibraryFile { - typedef std::function<void(StringRef, CRuntimeFile<ELFT> &)> Resolver; + typedef std::function<void(StringRef, RuntimeFile<ELFT> &)> Resolver; public: DynamicSymbolFile(ELFLinkingContext &context, Resolver resolver) : SimpleArchiveLibraryFile("Dynamically added runtime symbols"), @@ -99,7 +99,7 @@ public: typedef Elf_Sym_Impl<ELFT> Elf_Sym; typedef Elf_Dyn_Impl<ELFT> Elf_Dyn; - OutputELFWriter(const ELFLinkingContext &context, TargetLayout<ELFT> &layout); + OutputELFWriter(ELFLinkingContext &context, TargetLayout<ELFT> &layout); protected: // build the sections that need to be created @@ -141,13 +141,13 @@ protected: virtual void assignSectionsWithNoSegments(); // Add default atoms that need to be present in the output file - virtual void addDefaultAtoms() = 0; + virtual void addDefaultAtoms(); // Add any runtime files and their atoms to the output bool createImplicitFiles(std::vector<std::unique_ptr<File>> &) override; // Finalize the default atom values - virtual void finalizeDefaultAtomValues() = 0; + virtual void finalizeDefaultAtomValues(); // This is called by the write section to apply relocations uint64_t addressOfAtom(const Atom *atom) override { @@ -180,11 +180,11 @@ protected: /// \brief Process undefined symbols that left after resolution step. virtual void processUndefinedSymbol(StringRef symName, - CRuntimeFile<ELFT> &file) const {} + RuntimeFile<ELFT> &file) const {} llvm::BumpPtrAllocator _alloc; - const ELFLinkingContext &_context; + ELFLinkingContext &_context; TargetHandler<ELFT> &_targetHandler; typedef llvm::DenseMap<const Atom *, uint64_t> AtomToAddress; @@ -205,6 +205,7 @@ protected: unique_bump_ptr<HashSection<ELFT>> _hashTable; llvm::StringSet<> _soNeeded; /// @} + std::unique_ptr<RuntimeFile<ELFT>> _scriptFile; private: static StringRef maybeGetSOName(Node *node); @@ -214,10 +215,11 @@ private: // OutputELFWriter //===----------------------------------------------------------------------===// template <class ELFT> -OutputELFWriter<ELFT>::OutputELFWriter(const ELFLinkingContext &context, +OutputELFWriter<ELFT>::OutputELFWriter(ELFLinkingContext &context, TargetLayout<ELFT> &layout) : _context(context), _targetHandler(context.getTargetHandler<ELFT>()), - _layout(layout) {} + _layout(layout), + _scriptFile(new RuntimeFile<ELFT>(context, "Linker script runtime")) {} template <class ELFT> void OutputELFWriter<ELFT>::buildChunks(const File &file) { @@ -363,20 +365,41 @@ void OutputELFWriter<ELFT>::assignSectionsWithNoSegments() { _shdrtab->updateSection(section); } +template <class ELFT> void OutputELFWriter<ELFT>::addDefaultAtoms() { + const llvm::StringSet<> &symbols = + _context.linkerScriptSema().getScriptDefinedSymbols(); + for (auto &sym : symbols) + _scriptFile->addAbsoluteAtom(sym.getKey()); +} + template <class ELFT> bool OutputELFWriter<ELFT>::createImplicitFiles( - std::vector<std::unique_ptr<File>> &) { + std::vector<std::unique_ptr<File>> &result) { // Add the virtual archive to resolve undefined symbols. // The file will be added later in the linking context. - auto callback = [this](StringRef sym, CRuntimeFile<ELFT> &file) { + auto callback = [this](StringRef sym, RuntimeFile<ELFT> &file) { processUndefinedSymbol(sym, file); }; auto &ctx = const_cast<ELFLinkingContext &>(_context); ctx.setUndefinesResolver( llvm::make_unique<DynamicSymbolFile<ELFT>>(ctx, std::move(callback))); + // Add script defined symbols + result.push_back(std::move(_scriptFile)); return true; } +template <class ELFT> +void OutputELFWriter<ELFT>::finalizeDefaultAtomValues() { + const llvm::StringSet<> &symbols = + _context.linkerScriptSema().getScriptDefinedSymbols(); + for (auto &sym : symbols) { + uint64_t res = + _context.linkerScriptSema().getLinkerScriptExprValue(sym.getKey()); + auto a = _layout.findAbsoluteAtom(sym.getKey()); + (*a)->_virtualAddr = res; + } +} + template <class ELFT> void OutputELFWriter<ELFT>::createDefaultSections() { _elfHeader.reset(new (_alloc) ELFHeader<ELFT>(_context)); _programHeader.reset(new (_alloc) ProgramHeader<ELFT>(_context)); diff --git a/lld/lib/ReaderWriter/LinkerScript.cpp b/lld/lib/ReaderWriter/LinkerScript.cpp index 34a7d4a79c7..56194cae5e7 100644 --- a/lld/lib/ReaderWriter/LinkerScript.cpp +++ b/lld/lib/ReaderWriter/LinkerScript.cpp @@ -2232,6 +2232,28 @@ std::error_code Sema::evalExpr(const SymbolAssignment *assgn, return std::error_code(); } +const llvm::StringSet<> &Sema::getScriptDefinedSymbols() const { + // Do we have cached results? + if (!_definedSymbols.empty()) + return _definedSymbols; + + // Populate our defined set and return it + for (auto cmd : _layoutCommands) + if (auto sa = dyn_cast<SymbolAssignment>(cmd)) { + StringRef symbol = sa->symbol(); + if (!symbol.empty() && symbol != ".") + _definedSymbols.insert(symbol); + } + + return _definedSymbols; +} + +uint64_t Sema::getLinkerScriptExprValue(StringRef name) const { + auto it = _symbolTable.find(name); + assert (it != _symbolTable.end() && "Invalid symbol name!"); + return it->second; +} + void Sema::dump() const { raw_ostream &os = llvm::outs(); os << "Linker script semantics dump\n"; diff --git a/lld/test/elf/linkerscript/Inputs/simple.o.yaml b/lld/test/elf/linkerscript/Inputs/simple.o.yaml new file mode 100644 index 00000000000..91d4e1b5778 --- /dev/null +++ b/lld/test/elf/linkerscript/Inputs/simple.o.yaml @@ -0,0 +1,52 @@ +--- +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: 0x0000000000000004 + Content: B80100000048C7C70100000048C7C60000000048C7C20E0000000F05C3E8DEFFFFFFB83C0000000F05C3 + - Name: .rela.text + Type: SHT_RELA + Link: .symtab + AddressAlign: 0x0000000000000008 + Info: .text + Relocations: + - Offset: 0x000000000000000F + Symbol: .data + Type: R_X86_64_32S + - Name: .data + Type: SHT_PROGBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000004 + Content: 48656C6C6F2C20576F726C64210A00 + - Name: .bss + Type: SHT_NOBITS + Flags: [ SHF_WRITE, SHF_ALLOC ] + AddressAlign: 0x0000000000000004 + Content: '' +Symbols: + Local: + - Name: main + Section: .text + - Name: msg + Section: .data + - Name: .text + Type: STT_SECTION + Section: .text + - Name: .data + Type: STT_SECTION + Section: .data + - Name: .bss + Type: STT_SECTION + Section: .bss + Global: + - Name: _start + Section: .text + Value: 0x000000000000001D +... diff --git a/lld/test/elf/linkerscript/symbol-definition.test b/lld/test/elf/linkerscript/symbol-definition.test new file mode 100644 index 00000000000..fc595bbe1f1 --- /dev/null +++ b/lld/test/elf/linkerscript/symbol-definition.test @@ -0,0 +1,54 @@ +/* +We test whether we can define symbols in a linker script and have them exported +to the output file symbol table. + +This test uses a single X86-64 input object, simple.o, created with the +following X86-64 assembly code: + +*** simple.S: + +(command line clang -c simple.S -o simple.o) + + .text + main: + mov $1, %eax + movq $1, %rdi + movq $msg, %rsi + movq $14, %rdx + syscall + ret + + .globl _start + _start: + call main + mov $60, %eax + syscall + ret + + .data + msg: .asciz "Hello, World!\n" + + +We use the following linker script for this test: +*/ + +ENTRY(_start) + +SECTIONS +{ + . = 0x500000; + .text : { *(.text) } + MYSTRING = .; + .data : { *(.data) } +} + +/* +RUN: mkdir -p %T +RUN: yaml2obj -format=elf %p/Inputs/simple.o.yaml -o=%T/simple.o + +RUN: lld -flavor gnu -target x86_64 -T %s %T/simple.o -static -o %t1 +RUN: llvm-readobj -symbols %t1 | FileCheck -check-prefix CHECKSYMS %s + +CHECKSYMS: Name: MYSTRING +CHECKSYMS-NEXT: Value: 0x501000 +*/ |

