Index: include/lld/ReaderWriter/ELFLinkingContext.h =================================================================== --- include/lld/ReaderWriter/ELFLinkingContext.h +++ include/lld/ReaderWriter/ELFLinkingContext.h @@ -301,6 +301,7 @@ const llvm::StringSet<> &wrapCalls() const { return _wrapCalls; } script::Sema &linkerScriptSema() { return _linkerScriptSema; } + const script::Sema &linkerScriptSema() const { return _linkerScriptSema; } private: ELFLinkingContext() = delete; Index: include/lld/ReaderWriter/LinkerScript.h =================================================================== --- include/lld/ReaderWriter/LinkerScript.h +++ 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" @@ -1173,6 +1174,14 @@ /// 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: @@ -1279,6 +1288,7 @@ mutable std::unordered_map _cacheSectionOrder, _cacheExpressionOrder; llvm::DenseSet _deliveredExprs; + mutable llvm::StringSet<> _definedSymbols; Expression::SymbolTableTy _symbolTable; }; Index: lib/ReaderWriter/ELF/DynamicLibraryWriter.h =================================================================== --- lib/ReaderWriter/ELF/DynamicLibraryWriter.h +++ lib/ReaderWriter/ELF/DynamicLibraryWriter.h @@ -27,7 +27,7 @@ public: DynamicLibraryWriter(ELFLinkingContext &context, TargetLayout &layout) : OutputELFWriter(context, layout), - _runtimeFile(new CRuntimeFile(context)) {} + _runtimeFile(new RuntimeFile(context, "C runtime")) {} protected: virtual void buildDynamicSymbolTable(const File &file); @@ -36,7 +36,7 @@ virtual void finalizeDefaultAtomValues(); protected: - std::unique_ptr > _runtimeFile; + std::unique_ptr > _runtimeFile; }; //===----------------------------------------------------------------------===// Index: lib/ReaderWriter/ELF/ELFFile.h =================================================================== --- lib/ReaderWriter/ELF/ELFFile.h +++ lib/ReaderWriter/ELF/ELFFile.h @@ -430,14 +430,14 @@ }; /// \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 CRuntimeFile : public ELFFile { +template class RuntimeFile : public ELFFile { public: typedef llvm::object::Elf_Sym_Impl Elf_Sym; - CRuntimeFile(ELFLinkingContext &context, StringRef name = "C runtime") + RuntimeFile(ELFLinkingContext &context, StringRef name) : ELFFile(name, context) {} /// \brief add a global absolute atom @@ -470,7 +470,7 @@ 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"); } Index: lib/ReaderWriter/ELF/ExecutableWriter.h =================================================================== --- lib/ReaderWriter/ELF/ExecutableWriter.h +++ lib/ReaderWriter/ELF/ExecutableWriter.h @@ -27,7 +27,7 @@ public: ExecutableWriter(ELFLinkingContext &context, TargetLayout &layout) : OutputELFWriter(context, layout), - _runtimeFile(new CRuntimeFile(context)) {} + _runtimeFile(new RuntimeFile(context, "C runtime")) {} protected: virtual void buildDynamicSymbolTable(const File &file); @@ -41,7 +41,7 @@ } unique_bump_ptr> _interpSection; - std::unique_ptr > _runtimeFile; + std::unique_ptr > _runtimeFile; }; //===----------------------------------------------------------------------===// @@ -80,6 +80,7 @@ /// absolute symbols template void ExecutableWriter::addDefaultAtoms() { + OutputELFWriter::addDefaultAtoms(); _runtimeFile->addUndefinedAtom(this->_context.entrySymbolName()); _runtimeFile->addAbsoluteAtom("__bss_start"); _runtimeFile->addAbsoluteAtom("__bss_end"); @@ -124,6 +125,7 @@ /// Finalize the value of all the absolute symbols that we /// created template void ExecutableWriter::finalizeDefaultAtomValues() { + OutputELFWriter::finalizeDefaultAtomValues(); auto bssStartAtomIter = this->_layout.findAbsoluteAtom("__bss_start"); auto bssEndAtomIter = this->_layout.findAbsoluteAtom("__bss_end"); auto underScoreEndAtomIter = this->_layout.findAbsoluteAtom("_end"); Index: lib/ReaderWriter/ELF/Hexagon/HexagonExecutableAtoms.h =================================================================== --- lib/ReaderWriter/ELF/Hexagon/HexagonExecutableAtoms.h +++ lib/ReaderWriter/ELF/Hexagon/HexagonExecutableAtoms.h @@ -18,10 +18,10 @@ class HexagonLinkingContext; template class HexagonRuntimeFile - : public CRuntimeFile { + : public RuntimeFile { public: HexagonRuntimeFile(HexagonLinkingContext &context) - : CRuntimeFile(context, "Hexagon runtime file") {} + : RuntimeFile(context, "Hexagon runtime file") {} }; } // elf } // lld Index: lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h =================================================================== --- lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h +++ lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h @@ -87,10 +87,10 @@ /// \brief Mips Runtime file. template -class MipsRuntimeFile final : public CRuntimeFile { +class MipsRuntimeFile final : public RuntimeFile { public: MipsRuntimeFile(MipsLinkingContext &ctx) - : CRuntimeFile(ctx, "Mips runtime file") {} + : RuntimeFile(ctx, "Mips runtime file") {} }; /// \brief Auxiliary class holds relocation's names table. Index: lib/ReaderWriter/ELF/OutputELFWriter.h =================================================================== --- lib/ReaderWriter/ELF/OutputELFWriter.h +++ lib/ReaderWriter/ELF/OutputELFWriter.h @@ -42,7 +42,7 @@ typedef Elf_Sym_Impl Elf_Sym; typedef Elf_Dyn_Impl Elf_Dyn; - OutputELFWriter(const ELFLinkingContext &context, TargetLayout &layout); + OutputELFWriter(ELFLinkingContext &context, TargetLayout &layout); protected: // build the sections that need to be created @@ -84,13 +84,13 @@ 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> &) 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 { @@ -123,7 +123,7 @@ llvm::BumpPtrAllocator _alloc; - const ELFLinkingContext &_context; + ELFLinkingContext &_context; TargetHandler &_targetHandler; typedef llvm::DenseMap AtomToAddress; @@ -144,6 +144,7 @@ unique_bump_ptr> _hashTable; llvm::StringSet<> _soNeeded; /// @} + std::unique_ptr> _scriptFile; private: static StringRef maybeGetSOName(Node *node); @@ -153,10 +154,11 @@ // OutputELFWriter //===----------------------------------------------------------------------===// template -OutputELFWriter::OutputELFWriter(const ELFLinkingContext &context, +OutputELFWriter::OutputELFWriter(ELFLinkingContext &context, TargetLayout &layout) : _context(context), _targetHandler(context.getTargetHandler()), - _layout(layout) {} + _layout(layout), + _scriptFile(new RuntimeFile(context, "Linker script runtime")) {} template void OutputELFWriter::buildChunks(const File &file) { @@ -302,12 +304,32 @@ _shdrtab->updateSection(section); } +template void OutputELFWriter::addDefaultAtoms() { + const llvm::StringSet<> &symbols = + _context.linkerScriptSema().getScriptDefinedSymbols(); + for (auto &sym : symbols) + _scriptFile->addAbsoluteAtom(sym.getKey()); +} + template bool OutputELFWriter::createImplicitFiles( - std::vector> &) { + std::vector> &result) { + result.push_back(std::move(_scriptFile)); return true; } +template +void OutputELFWriter::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 void OutputELFWriter::createDefaultSections() { _elfHeader.reset(new (_alloc) ELFHeader(_context)); _programHeader.reset(new (_alloc) ProgramHeader(_context)); Index: lib/ReaderWriter/LinkerScript.cpp =================================================================== --- lib/ReaderWriter/LinkerScript.cpp +++ lib/ReaderWriter/LinkerScript.cpp @@ -2062,6 +2062,28 @@ 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(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"; Index: test/elf/linkerscript/Inputs/simple.o.yaml =================================================================== --- /dev/null +++ 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 +... Index: test/elf/linkerscript/symbol-definition.test =================================================================== --- /dev/null +++ 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 +*/