diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:48:50 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2016-07-23 20:48:50 +0000 |
commit | 1c98619801a5705c688e683be3ef9d70169a0686 (patch) | |
tree | 8422105cd1a94c368315f2db16b9ac746cf7c000 /lib/ReaderWriter/ELF/OutputELFWriter.cpp | |
parent | f4f3ce4613680903220815690ad79fc7ba0a2e26 (diff) |
Notes
Diffstat (limited to 'lib/ReaderWriter/ELF/OutputELFWriter.cpp')
-rw-r--r-- | lib/ReaderWriter/ELF/OutputELFWriter.cpp | 514 |
1 files changed, 0 insertions, 514 deletions
diff --git a/lib/ReaderWriter/ELF/OutputELFWriter.cpp b/lib/ReaderWriter/ELF/OutputELFWriter.cpp deleted file mode 100644 index 4f8b0eac655f..000000000000 --- a/lib/ReaderWriter/ELF/OutputELFWriter.cpp +++ /dev/null @@ -1,514 +0,0 @@ -//===- lib/ReaderWriter/ELF/OutputELFWriter.cpp --------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "OutputELFWriter.h" -#include "lld/Core/SharedLibraryFile.h" -#include "lld/Core/Simple.h" -#include "lld/ReaderWriter/ELFLinkingContext.h" -#include "llvm/Support/Path.h" - -namespace lld { -namespace elf { - -namespace { - -template <class ELFT> class SymbolFile : public RuntimeFile<ELFT> { -public: - SymbolFile(ELFLinkingContext &ctx) - : RuntimeFile<ELFT>(ctx, "Dynamic absolute symbols") {} - - void addUndefinedAtom(StringRef) override { - llvm_unreachable("Cannot add undefined atoms to resolve undefined symbols"); - } - - bool hasAtoms() const { return this->absolute().size(); } -}; - -template <class ELFT> -class DynamicSymbolFile : public SimpleArchiveLibraryFile { - typedef std::function<void(StringRef, RuntimeFile<ELFT> &)> Resolver; - -public: - DynamicSymbolFile(ELFLinkingContext &ctx, Resolver resolver) - : SimpleArchiveLibraryFile("Dynamically added runtime symbols"), - _ctx(ctx), _resolver(resolver) {} - - File *find(StringRef sym, bool dataSymbolOnly) override { - if (!_file) - _file.reset(new (_alloc) SymbolFile<ELFT>(_ctx)); - - assert(!_file->hasAtoms() && "The file shouldn't have atoms yet"); - _resolver(sym, *_file); - - if (!_file->hasAtoms()) - return nullptr; - - // If atoms were added - return the file but also store it for later - // destruction. - File *result = _file.get(); - _returnedFiles.push_back(std::move(_file)); - return result; - } - -private: - ELFLinkingContext &_ctx; - Resolver _resolver; - - // The allocator should go before bump pointers because of - // reversed destruction order. - llvm::BumpPtrAllocator _alloc; - unique_bump_ptr<SymbolFile<ELFT>> _file; - std::vector<unique_bump_ptr<SymbolFile<ELFT>>> _returnedFiles; -}; - -} // end anon namespace - -template <class ELFT> -OutputELFWriter<ELFT>::OutputELFWriter(ELFLinkingContext &ctx, - TargetLayout<ELFT> &layout) - : _ctx(ctx), _targetHandler(ctx.getTargetHandler()), _layout(layout) {} - -template <class ELFT> -void OutputELFWriter<ELFT>::buildChunks(const File &file) { - ScopedTask task(getDefaultDomain(), "buildChunks"); - for (const DefinedAtom *definedAtom : file.defined()) { - DefinedAtom::ContentType contentType = definedAtom->contentType(); - // Dont add COMDAT group atoms and GNU linkonce atoms, as they are used for - // symbol resolution. - // TODO: handle partial linking. - if (contentType == DefinedAtom::typeGroupComdat || - contentType == DefinedAtom::typeGnuLinkOnce) - continue; - _layout.addAtom(definedAtom); - } - for (const AbsoluteAtom *absoluteAtom : file.absolute()) - _layout.addAtom(absoluteAtom); -} - -template <class ELFT> -void OutputELFWriter<ELFT>::buildStaticSymbolTable(const File &file) { - ScopedTask task(getDefaultDomain(), "buildStaticSymbolTable"); - for (auto sec : _layout.sections()) - if (auto section = dyn_cast<AtomSection<ELFT>>(sec)) - for (const auto &atom : section->atoms()) - _symtab->addSymbol(atom->_atom, section->ordinal(), atom->_virtualAddr); - for (auto &atom : _layout.absoluteAtoms()) - _symtab->addSymbol(atom->_atom, ELF::SHN_ABS, atom->_virtualAddr); - for (const UndefinedAtom *a : file.undefined()) - _symtab->addSymbol(a, ELF::SHN_UNDEF); -} - -// Returns the DSO name for a given input file if it's a shared library -// file and not marked as --as-needed. -template <class ELFT> -StringRef OutputELFWriter<ELFT>::maybeGetSOName(Node *node) { - if (auto *fnode = dyn_cast<FileNode>(node)) - if (!fnode->asNeeded()) - if (auto *file = dyn_cast<SharedLibraryFile>(fnode->getFile())) - return file->getDSOName(); - return ""; -} - -template <class ELFT> -void OutputELFWriter<ELFT>::buildDynamicSymbolTable(const File &file) { - ScopedTask task(getDefaultDomain(), "buildDynamicSymbolTable"); - for (const auto &sla : file.sharedLibrary()) { - if (isDynSymEntryRequired(sla)) { - _dynamicSymbolTable->addSymbol(sla, ELF::SHN_UNDEF); - _soNeeded.insert(sla->loadName()); - continue; - } - if (isNeededTagRequired(sla)) - _soNeeded.insert(sla->loadName()); - } - for (const std::unique_ptr<Node> &node : _ctx.getNodes()) { - StringRef soname = maybeGetSOName(node.get()); - if (!soname.empty()) - _soNeeded.insert(soname); - } - // Never mark the dynamic linker as DT_NEEDED - _soNeeded.erase(sys::path::filename(_ctx.getInterpreter())); - for (const auto &loadName : _soNeeded) - _dynamicTable->addEntry(DT_NEEDED, - _dynamicStringTable->addString(loadName.getKey())); - const auto &rpathList = _ctx.getRpathList(); - if (!rpathList.empty()) { - auto rpath = - new (_alloc) std::string(join(rpathList.begin(), rpathList.end(), ":")); - _dynamicTable->addEntry(_ctx.getEnableNewDtags() ? DT_RUNPATH : DT_RPATH, - _dynamicStringTable->addString(*rpath)); - } - StringRef soname = _ctx.sharedObjectName(); - if (!soname.empty() && _ctx.getOutputELFType() == llvm::ELF::ET_DYN) - _dynamicTable->addEntry(DT_SONAME, _dynamicStringTable->addString(soname)); - - // Add DT_FLAGS/DT_FLAGS_1 entries if necessary. - uint32_t dtflags = 0, dt1flags = 0; - if (_ctx.getDTFlag(ELFLinkingContext::DTFlag::DT_NOW)) { - dtflags |= DF_BIND_NOW; - dt1flags |= DF_1_NOW; - } - if (_ctx.getDTFlag(ELFLinkingContext::DTFlag::DT_ORIGIN)) { - dtflags |= DF_ORIGIN; - dt1flags |= DF_1_ORIGIN; - } - if (dtflags != 0) - _dynamicTable->addEntry(DT_FLAGS, dtflags); - if (dt1flags != 0) - _dynamicTable->addEntry(DT_FLAGS_1, dt1flags); - - // The dynamic symbol table need to be sorted earlier because the hash - // table needs to be built using the dynamic symbol table. It would be - // late to sort the symbols due to that in finalize. In the dynamic symbol - // table finalize, we call the symbol table finalize and we don't want to - // sort again - _dynamicSymbolTable->sortSymbols(); - - // Add the dynamic symbols into the hash table - _dynamicSymbolTable->addSymbolsToHashTable(); -} - -template <class ELFT> -void OutputELFWriter<ELFT>::buildAtomToAddressMap(const File &file) { - ScopedTask task(getDefaultDomain(), "buildAtomToAddressMap"); - int64_t totalAbsAtoms = _layout.absoluteAtoms().size(); - int64_t totalUndefinedAtoms = file.undefined().size(); - int64_t totalDefinedAtoms = 0; - for (auto sec : _layout.sections()) - if (auto section = dyn_cast<AtomSection<ELFT>>(sec)) { - totalDefinedAtoms += section->atoms().size(); - for (const auto &atom : section->atoms()) - _atomToAddressMap[atom->_atom] = atom->_virtualAddr; - } - // build the atomToAddressMap that contains absolute symbols too - for (auto &atom : _layout.absoluteAtoms()) - _atomToAddressMap[atom->_atom] = atom->_virtualAddr; - - // Set the total number of atoms in the symbol table, so that appropriate - // resizing of the string table can be done. - // There's no such thing as symbol table if we're stripping all the symbols - if (!_ctx.stripSymbols()) - _symtab->setNumEntries(totalDefinedAtoms + totalAbsAtoms + - totalUndefinedAtoms); -} - -template <class ELFT> void OutputELFWriter<ELFT>::buildSectionHeaderTable() { - ScopedTask task(getDefaultDomain(), "buildSectionHeaderTable"); - for (auto outputSection : _layout.outputSections()) { - if (outputSection->kind() != Chunk<ELFT>::Kind::ELFSection && - outputSection->kind() != Chunk<ELFT>::Kind::AtomSection) - continue; - if (outputSection->hasSegment()) - _shdrtab->appendSection(outputSection); - } -} - -template <class ELFT> -void OutputELFWriter<ELFT>::assignSectionsWithNoSegments() { - ScopedTask task(getDefaultDomain(), "assignSectionsWithNoSegments"); - for (auto outputSection : _layout.outputSections()) { - if (outputSection->kind() != Chunk<ELFT>::Kind::ELFSection && - outputSection->kind() != Chunk<ELFT>::Kind::AtomSection) - continue; - if (!outputSection->hasSegment()) - _shdrtab->appendSection(outputSection); - } - _layout.assignFileOffsetsForMiscSections(); - for (auto sec : _layout.sections()) - if (auto section = dyn_cast<Section<ELFT>>(sec)) - if (!TargetLayout<ELFT>::hasOutputSegment(section)) - _shdrtab->updateSection(section); -} - -template <class ELFT> -void OutputELFWriter<ELFT>::createImplicitFiles( - 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, RuntimeFile<ELFT> &file) { - processUndefinedSymbol(sym, file); - }; - _ctx.setUndefinesResolver( - llvm::make_unique<DynamicSymbolFile<ELFT>>(_ctx, std::move(callback))); - // Add script defined symbols - auto file = - llvm::make_unique<RuntimeFile<ELFT>>(_ctx, "Linker script runtime"); - for (auto &sym : this->_ctx.linkerScriptSema().getScriptDefinedSymbols()) - file->addAbsoluteAtom(sym.getKey()); - result.push_back(std::move(file)); -} - -template <class ELFT> void OutputELFWriter<ELFT>::finalizeDefaultAtomValues() { - const llvm::StringSet<> &symbols = - _ctx.linkerScriptSema().getScriptDefinedSymbols(); - for (auto &sym : symbols) { - uint64_t res = - _ctx.linkerScriptSema().getLinkerScriptExprValue(sym.getKey()); - AtomLayout *a = _layout.findAbsoluteAtom(sym.getKey()); - assert(a); - a->_virtualAddr = res; - } - // If there is a section named XXX, and XXX is a valid C identifier, - // and there are undefined or weak __start_XXX/__stop_XXX symbols, - // set the symbols values to the begin/end of the XXX section - // correspondingly. - for (const auto &name : _ctx.cidentSectionNames()) - updateScopeAtomValues((Twine("__start_") + name.getKey()).str(), - (Twine("__stop_") + name.getKey()).str(), - name.getKey()); -} - -template <class ELFT> void OutputELFWriter<ELFT>::createDefaultSections() { - _elfHeader.reset(new (_alloc) ELFHeader<ELFT>(_ctx)); - _programHeader.reset(new (_alloc) ProgramHeader<ELFT>(_ctx)); - _layout.setHeader(_elfHeader.get()); - _layout.setProgramHeader(_programHeader.get()); - - // Don't create .symtab and .strtab sections if we're going to - // strip all the symbols. - if (!_ctx.stripSymbols()) { - _symtab = this->createSymbolTable(); - _strtab.reset(new (_alloc) StringTable<ELFT>( - _ctx, ".strtab", TargetLayout<ELFT>::ORDER_STRING_TABLE)); - _layout.addSection(_symtab.get()); - _layout.addSection(_strtab.get()); - _symtab->setStringSection(_strtab.get()); - } - - _shstrtab.reset(new (_alloc) StringTable<ELFT>( - _ctx, ".shstrtab", TargetLayout<ELFT>::ORDER_SECTION_STRINGS)); - _shdrtab.reset(new (_alloc) SectionHeader<ELFT>( - _ctx, TargetLayout<ELFT>::ORDER_SECTION_HEADERS)); - _layout.addSection(_shstrtab.get()); - _shdrtab->setStringSection(_shstrtab.get()); - _layout.addSection(_shdrtab.get()); - - for (auto sec : _layout.sections()) { - // TODO: use findOutputSection - auto section = dyn_cast<Section<ELFT>>(sec); - if (!section || section->outputSectionName() != ".eh_frame") - continue; - _ehFrameHeader.reset(new (_alloc) EHFrameHeader<ELFT>( - _ctx, ".eh_frame_hdr", _layout, TargetLayout<ELFT>::ORDER_EH_FRAMEHDR)); - _layout.addSection(_ehFrameHeader.get()); - break; - } - - if (_ctx.isDynamic()) { - _dynamicTable = createDynamicTable(); - _dynamicStringTable.reset(new (_alloc) StringTable<ELFT>( - _ctx, ".dynstr", TargetLayout<ELFT>::ORDER_DYNAMIC_STRINGS, true)); - _dynamicSymbolTable = createDynamicSymbolTable(); - _hashTable.reset(new (_alloc) HashSection<ELFT>( - _ctx, ".hash", TargetLayout<ELFT>::ORDER_HASH)); - // Set the hash table in the dynamic symbol table so that the entries in the - // hash table can be created - _dynamicSymbolTable->setHashTable(_hashTable.get()); - _hashTable->setSymbolTable(_dynamicSymbolTable.get()); - _layout.addSection(_dynamicTable.get()); - _layout.addSection(_dynamicStringTable.get()); - _layout.addSection(_dynamicSymbolTable.get()); - _layout.addSection(_hashTable.get()); - _dynamicSymbolTable->setStringSection(_dynamicStringTable.get()); - _dynamicTable->setSymbolTable(_dynamicSymbolTable.get()); - _dynamicTable->setHashTable(_hashTable.get()); - if (_layout.hasDynamicRelocationTable()) - _layout.getDynamicRelocationTable()->setSymbolTable( - _dynamicSymbolTable.get()); - if (_layout.hasPLTRelocationTable()) - _layout.getPLTRelocationTable()->setSymbolTable( - _dynamicSymbolTable.get()); - } -} - -template <class ELFT> -unique_bump_ptr<SymbolTable<ELFT>> OutputELFWriter<ELFT>::createSymbolTable() { - return unique_bump_ptr<SymbolTable<ELFT>>(new (_alloc) SymbolTable<ELFT>( - this->_ctx, ".symtab", TargetLayout<ELFT>::ORDER_SYMBOL_TABLE)); -} - -/// \brief create dynamic table -template <class ELFT> -unique_bump_ptr<DynamicTable<ELFT>> -OutputELFWriter<ELFT>::createDynamicTable() { - return unique_bump_ptr<DynamicTable<ELFT>>(new (_alloc) DynamicTable<ELFT>( - this->_ctx, _layout, ".dynamic", TargetLayout<ELFT>::ORDER_DYNAMIC)); -} - -/// \brief create dynamic symbol table -template <class ELFT> -unique_bump_ptr<DynamicSymbolTable<ELFT>> -OutputELFWriter<ELFT>::createDynamicSymbolTable() { - return unique_bump_ptr<DynamicSymbolTable<ELFT>>( - new (_alloc) - DynamicSymbolTable<ELFT>(this->_ctx, _layout, ".dynsym", - TargetLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS)); -} - -template <class ELFT> -std::error_code OutputELFWriter<ELFT>::buildOutput(const File &file) { - ScopedTask buildTask(getDefaultDomain(), "ELF Writer buildOutput"); - buildChunks(file); - - // Create the default sections like the symbol table, string table, and the - // section string table - createDefaultSections(); - - // Set the Layout - _layout.assignSectionsToSegments(); - - // Create the dynamic table entries - if (_ctx.isDynamic()) { - _dynamicTable->createDefaultEntries(); - buildDynamicSymbolTable(file); - } - - // Call the preFlight callbacks to modify the sections and the atoms - // contained in them, in anyway the targets may want - _layout.doPreFlight(); - - _layout.assignVirtualAddress(); - - // Finalize the default value of symbols that the linker adds - finalizeDefaultAtomValues(); - - // Build the Atom To Address map for applying relocations - buildAtomToAddressMap(file); - - // Create symbol table and section string table - // Do it only if -s is not specified. - if (!_ctx.stripSymbols()) - buildStaticSymbolTable(file); - - // Finalize the layout by calling the finalize() functions - _layout.finalize(); - - // build Section Header table - buildSectionHeaderTable(); - - // assign Offsets and virtual addresses - // for sections with no segments - assignSectionsWithNoSegments(); - - if (_ctx.isDynamic()) - _dynamicTable->updateDynamicTable(); - - return std::error_code(); -} - -template <class ELFT> std::error_code OutputELFWriter<ELFT>::setELFHeader() { - _elfHeader->e_type(_ctx.getOutputELFType()); - _elfHeader->e_machine(_ctx.getOutputMachine()); - _elfHeader->e_ident(ELF::EI_VERSION, 1); - _elfHeader->e_ident(ELF::EI_OSABI, 0); - _elfHeader->e_version(1); - _elfHeader->e_phoff(_programHeader->fileOffset()); - _elfHeader->e_shoff(_shdrtab->fileOffset()); - _elfHeader->e_phentsize(_programHeader->entsize()); - _elfHeader->e_phnum(_programHeader->numHeaders()); - _elfHeader->e_shentsize(_shdrtab->entsize()); - _elfHeader->e_shnum(_shdrtab->numHeaders()); - _elfHeader->e_shstrndx(_shstrtab->ordinal()); - if (const auto *al = _layout.findAtomLayoutByName(_ctx.entrySymbolName())) - _elfHeader->e_entry(al->_virtualAddr); - else - _elfHeader->e_entry(0); - - return std::error_code(); -} - -template <class ELFT> uint64_t OutputELFWriter<ELFT>::outputFileSize() const { - return _shdrtab->fileOffset() + _shdrtab->fileSize(); -} - -template <class ELFT> -std::error_code OutputELFWriter<ELFT>::writeOutput(const File &file, - StringRef path) { - - ScopedTask createOutputTask(getDefaultDomain(), "ELF Writer Create Output"); - ErrorOr<std::unique_ptr<FileOutputBuffer>> bufferOrErr = - FileOutputBuffer::create(path, outputFileSize(), - FileOutputBuffer::F_executable); - if (std::error_code ec = bufferOrErr.getError()) - return ec; - std::unique_ptr<FileOutputBuffer> &buffer = *bufferOrErr; - createOutputTask.end(); - - ScopedTask writeTask(getDefaultDomain(), "ELF Writer write to memory"); - - // HACK: We have to write out the header and program header here even though - // they are a member of a segment because only sections are written in the - // following loop. - - // Finalize ELF Header / Program Headers. - _elfHeader->finalize(); - _programHeader->finalize(); - - _elfHeader->write(this, _layout, *buffer); - _programHeader->write(this, _layout, *buffer); - - auto sections = _layout.sections(); - parallel_for_each( - sections.begin(), sections.end(), - [&](Chunk<ELFT> *section) { section->write(this, _layout, *buffer); }); - writeTask.end(); - - ScopedTask commitTask(getDefaultDomain(), "ELF Writer commit to disk"); - return buffer->commit(); -} - -template <class ELFT> -std::error_code OutputELFWriter<ELFT>::writeFile(const File &file, - StringRef path) { - if (std::error_code ec = buildOutput(file)) - return ec; - if (std::error_code ec = setELFHeader()) - return ec; - return writeOutput(file, path); -} - -template <class ELFT> -void OutputELFWriter<ELFT>::processUndefinedSymbol( - StringRef symName, RuntimeFile<ELFT> &file) const { - if (symName.startswith("__start_")) { - if (_ctx.cidentSectionNames().count(symName.drop_front(8))) - file.addAbsoluteAtom(symName); - } else if (symName.startswith("__stop_")) { - if (_ctx.cidentSectionNames().count(symName.drop_front(7))) - file.addAbsoluteAtom(symName); - } -} - -template <class ELFT> -void OutputELFWriter<ELFT>::updateScopeAtomValues(StringRef sym, - StringRef sec) { - updateScopeAtomValues(("__" + sym + "_start").str().c_str(), - ("__" + sym + "_end").str().c_str(), sec); -} - -template <class ELFT> -void OutputELFWriter<ELFT>::updateScopeAtomValues(StringRef start, - StringRef end, - StringRef sec) { - AtomLayout *s = _layout.findAbsoluteAtom(start); - AtomLayout *e = _layout.findAbsoluteAtom(end); - const OutputSection<ELFT> *section = _layout.findOutputSection(sec); - if (s) - s->_virtualAddr = section ? section->virtualAddr() : 0; - if (e) - e->_virtualAddr = section ? section->virtualAddr() + section->memSize() : 0; -} - -template class OutputELFWriter<ELF32LE>; -template class OutputELFWriter<ELF32BE>; -template class OutputELFWriter<ELF64LE>; -template class OutputELFWriter<ELF64BE>; - -} // namespace elf -} // namespace lld |