diff options
Diffstat (limited to 'lld/lib/ReaderWriter/ELF/SectionChunks.cpp')
-rw-r--r-- | lld/lib/ReaderWriter/ELF/SectionChunks.cpp | 996 |
1 files changed, 0 insertions, 996 deletions
diff --git a/lld/lib/ReaderWriter/ELF/SectionChunks.cpp b/lld/lib/ReaderWriter/ELF/SectionChunks.cpp deleted file mode 100644 index 520fbe24af3..00000000000 --- a/lld/lib/ReaderWriter/ELF/SectionChunks.cpp +++ /dev/null @@ -1,996 +0,0 @@ -//===- lib/ReaderWriter/ELF/SectionChunks.h -------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "SectionChunks.h" -#include "TargetLayout.h" -#include "lld/Core/Parallel.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/Support/Dwarf.h" - -namespace lld { -namespace elf { - -template <class ELFT> -Section<ELFT>::Section(const ELFLinkingContext &ctx, StringRef sectionName, - StringRef chunkName, typename Chunk<ELFT>::Kind k) - : Chunk<ELFT>(chunkName, k, ctx), _inputSectionName(sectionName), - _outputSectionName(sectionName) {} - -template <class ELFT> int Section<ELFT>::getContentType() const { - if (_flags & llvm::ELF::SHF_EXECINSTR) - return Chunk<ELFT>::ContentType::Code; - else if (_flags & llvm::ELF::SHF_WRITE) - return Chunk<ELFT>::ContentType::Data; - else if (_flags & llvm::ELF::SHF_ALLOC) - return Chunk<ELFT>::ContentType::Code; - else - return Chunk<ELFT>::ContentType::Unknown; -} - -template <class ELFT> -AtomSection<ELFT>::AtomSection(const ELFLinkingContext &ctx, - StringRef sectionName, int32_t contentType, - int32_t permissions, int32_t order) - : Section<ELFT>(ctx, sectionName, "AtomSection", - Chunk<ELFT>::Kind::AtomSection), - _contentType(contentType), _contentPermissions(permissions) { - this->setOrder(order); - - switch (contentType) { - case DefinedAtom::typeCode: - case DefinedAtom::typeDataFast: - case DefinedAtom::typeData: - case DefinedAtom::typeConstant: - case DefinedAtom::typeGOT: - case DefinedAtom::typeStub: - case DefinedAtom::typeResolver: - case DefinedAtom::typeThreadData: - this->_type = SHT_PROGBITS; - break; - - case DefinedAtom::typeThreadZeroFill: - case DefinedAtom::typeZeroFillFast: - case DefinedAtom::typeZeroFill: - this->_type = SHT_NOBITS; - break; - - case DefinedAtom::typeRONote: - case DefinedAtom::typeRWNote: - this->_type = SHT_NOTE; - break; - - case DefinedAtom::typeNoAlloc: - this->_type = SHT_PROGBITS; - this->_isLoadedInMemory = false; - break; - } - - switch (permissions) { - case DefinedAtom::permR__: - this->_flags = SHF_ALLOC; - break; - case DefinedAtom::permR_X: - this->_flags = SHF_ALLOC | SHF_EXECINSTR; - break; - case DefinedAtom::permRW_: - case DefinedAtom::permRW_L: - this->_flags = SHF_ALLOC | SHF_WRITE; - if (_contentType == DefinedAtom::typeThreadData || - _contentType == DefinedAtom::typeThreadZeroFill) - this->_flags |= SHF_TLS; - break; - case DefinedAtom::permRWX: - this->_flags = SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR; - break; - case DefinedAtom::perm___: - this->_flags = 0; - break; - } -} - -template <class ELFT> -void AtomSection<ELFT>::assignVirtualAddress(uint64_t addr) { - parallel_for_each(_atoms.begin(), _atoms.end(), [&](AtomLayout *ai) { - ai->_virtualAddr = addr + ai->_fileOffset; - }); -} - -template <class ELFT> -void AtomSection<ELFT>::assignFileOffsets(uint64_t offset) { - parallel_for_each(_atoms.begin(), _atoms.end(), [&](AtomLayout *ai) { - ai->_fileOffset = offset + ai->_fileOffset; - }); -} - -template <class ELFT> -const AtomLayout * -AtomSection<ELFT>::findAtomLayoutByName(StringRef name) const { - for (auto ai : _atoms) - if (ai->_atom->name() == name) - return ai; - return nullptr; -} - -template <class ELFT> -std::string AtomSection<ELFT>::formatError(const std::string &errorStr, - const AtomLayout &atom, - const Reference &ref) const { - StringRef kindValStr; - if (!this->_ctx.registry().referenceKindToString( - ref.kindNamespace(), ref.kindArch(), ref.kindValue(), kindValStr)) { - kindValStr = "unknown"; - } - - return - (Twine(errorStr) + " in file " + atom._atom->file().path() + - ": reference from " + atom._atom->name() + "+" + - Twine(ref.offsetInAtom()) + " to " + ref.target()->name() + "+" + - Twine(ref.addend()) + " of type " + Twine(ref.kindValue()) + " (" + - kindValStr + ")\n") - .str(); -} - -/// Align the offset to the required modulus defined by the atom alignment -template <class ELFT> -uint64_t AtomSection<ELFT>::alignOffset(uint64_t offset, - DefinedAtom::Alignment &atomAlign) { - uint64_t requiredModulus = atomAlign.modulus; - uint64_t alignment = atomAlign.value; - uint64_t currentModulus = (offset % alignment); - uint64_t retOffset = offset; - if (currentModulus != requiredModulus) { - if (requiredModulus > currentModulus) - retOffset += requiredModulus - currentModulus; - else - retOffset += alignment + requiredModulus - currentModulus; - } - return retOffset; -} - -// \brief Append an atom to a Section. The atom gets pushed into a vector -// contains the atom, the atom file offset, the atom virtual address -// the atom file offset is aligned appropriately as set by the Reader -template <class ELFT> -const AtomLayout *AtomSection<ELFT>::appendAtom(const Atom *atom) { - const DefinedAtom *definedAtom = cast<DefinedAtom>(atom); - - DefinedAtom::Alignment atomAlign = definedAtom->alignment(); - uint64_t alignment = atomAlign.value; - // Align the atom to the required modulus/ align the file offset and the - // memory offset separately this is required so that BSS symbols are handled - // properly as the BSS symbols only occupy memory size and not file size - uint64_t fOffset = alignOffset(this->fileSize(), atomAlign); - uint64_t mOffset = alignOffset(this->memSize(), atomAlign); - switch (definedAtom->contentType()) { - case DefinedAtom::typeCode: - case DefinedAtom::typeConstant: - case DefinedAtom::typeData: - case DefinedAtom::typeDataFast: - case DefinedAtom::typeZeroFillFast: - case DefinedAtom::typeGOT: - case DefinedAtom::typeStub: - case DefinedAtom::typeResolver: - case DefinedAtom::typeThreadData: - case DefinedAtom::typeRONote: - case DefinedAtom::typeRWNote: - _atoms.push_back(new (_alloc) AtomLayout(atom, fOffset, 0)); - this->_fsize = fOffset + definedAtom->size(); - this->_msize = mOffset + definedAtom->size(); - DEBUG_WITH_TYPE("Section", llvm::dbgs() - << "[" << this->name() << " " << this << "] " - << "Adding atom: " << atom->name() << "@" - << fOffset << "\n"); - break; - case DefinedAtom::typeNoAlloc: - _atoms.push_back(new (_alloc) AtomLayout(atom, fOffset, 0)); - this->_fsize = fOffset + definedAtom->size(); - DEBUG_WITH_TYPE("Section", llvm::dbgs() - << "[" << this->name() << " " << this << "] " - << "Adding atom: " << atom->name() << "@" - << fOffset << "\n"); - break; - case DefinedAtom::typeThreadZeroFill: - case DefinedAtom::typeZeroFill: - _atoms.push_back(new (_alloc) AtomLayout(atom, mOffset, 0)); - this->_msize = mOffset + definedAtom->size(); - break; - default: - llvm::dbgs() << definedAtom->contentType() << "\n"; - llvm_unreachable("Uexpected content type."); - } - // Set the section alignment to the largest alignment - // std::max doesn't support uint64_t - if (this->_alignment < alignment) - this->_alignment = alignment; - - if (_atoms.size()) - return _atoms.back(); - return nullptr; -} - -/// \brief convert the segment type to a String for diagnostics -/// and printing purposes -template <class ELFT> StringRef Section<ELFT>::segmentKindToStr() const { - switch (_segmentType) { - case llvm::ELF::PT_DYNAMIC: - return "DYNAMIC"; - case llvm::ELF::PT_INTERP: - return "INTERP"; - case llvm::ELF::PT_LOAD: - return "LOAD"; - case llvm::ELF::PT_GNU_EH_FRAME: - return "EH_FRAME"; - case llvm::ELF::PT_GNU_RELRO: - return "GNU_RELRO"; - case llvm::ELF::PT_NOTE: - return "NOTE"; - case llvm::ELF::PT_NULL: - return "NULL"; - case llvm::ELF::PT_TLS: - return "TLS"; - default: - return "UNKNOWN"; - } -} - -/// \brief Write the section and the atom contents to the buffer -template <class ELFT> -void AtomSection<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) { - uint8_t *chunkBuffer = buffer.getBufferStart(); - bool success = true; - - // parallel_for_each() doesn't have deterministic order. To guarantee - // deterministic error output, collect errors in this vector and sort it - // by atom file offset before printing all errors. - std::vector<std::pair<size_t, std::string>> errors; - parallel_for_each(_atoms.begin(), _atoms.end(), [&](AtomLayout *ai) { - DEBUG_WITH_TYPE("Section", llvm::dbgs() - << "Writing atom: " << ai->_atom->name() - << " | " << ai->_fileOffset << "\n"); - const DefinedAtom *definedAtom = cast<DefinedAtom>(ai->_atom); - if (!definedAtom->occupiesDiskSpace()) - return; - // Copy raw content of atom to file buffer. - ArrayRef<uint8_t> content = definedAtom->rawContent(); - uint64_t contentSize = content.size(); - if (contentSize == 0) - return; - uint8_t *atomContent = chunkBuffer + ai->_fileOffset; - std::memcpy(atomContent, content.data(), contentSize); - const TargetRelocationHandler &relHandler = - this->_ctx.getTargetHandler().getRelocationHandler(); - for (const auto ref : *definedAtom) { - if (std::error_code ec = - relHandler.applyRelocation(*writer, buffer, *ai, *ref)) { - std::lock_guard<std::mutex> lock(_outputMutex); - errors.push_back(std::make_pair(ai->_fileOffset, - formatError(ec.message(), *ai, *ref))); - success = false; - } - } - }); - if (!success) { - std::sort(errors.begin(), errors.end()); - for (auto &&error : errors) - llvm::errs() << error.second; - llvm::report_fatal_error("relocating output"); - } -} - -template <class ELFT> -void OutputSection<ELFT>::appendSection(Section<ELFT> *section) { - if (section->alignment() > _alignment) - _alignment = section->alignment(); - assert(!_link && "Section already has a link!"); - _link = section->getLink(); - _shInfo = section->getInfo(); - _entSize = section->getEntSize(); - _type = section->getType(); - if (_flags < section->getFlags()) - _flags = section->getFlags(); - section->setOutputSection(this, (_sections.size() == 0)); - _kind = section->kind(); - _sections.push_back(section); -} - -template <class ELFT> -StringTable<ELFT>::StringTable(const ELFLinkingContext &ctx, const char *str, - int32_t order, bool dynamic) - : Section<ELFT>(ctx, str, "StringTable") { - // the string table has a NULL entry for which - // add an empty string - _strings.push_back(""); - this->_fsize = 1; - this->_alignment = 1; - this->setOrder(order); - this->_type = SHT_STRTAB; - if (dynamic) { - this->_flags = SHF_ALLOC; - this->_msize = this->_fsize; - } -} - -template <class ELFT> uint64_t StringTable<ELFT>::addString(StringRef symname) { - if (symname.empty()) - return 0; - StringMapTIter stringIter = _stringMap.find(symname); - if (stringIter == _stringMap.end()) { - _strings.push_back(symname); - uint64_t offset = this->_fsize; - this->_fsize += symname.size() + 1; - if (this->_flags & SHF_ALLOC) - this->_msize = this->_fsize; - _stringMap[symname] = offset; - return offset; - } - return stringIter->second; -} - -template <class ELFT> -void StringTable<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &, - llvm::FileOutputBuffer &buffer) { - uint8_t *chunkBuffer = buffer.getBufferStart(); - uint8_t *dest = chunkBuffer + this->fileOffset(); - for (auto si : _strings) { - memcpy(dest, si.data(), si.size()); - dest += si.size(); - memcpy(dest, "", 1); - dest += 1; - } -} - -/// ELF Symbol Table -template <class ELFT> -SymbolTable<ELFT>::SymbolTable(const ELFLinkingContext &ctx, const char *str, - int32_t order) - : Section<ELFT>(ctx, str, "SymbolTable") { - this->setOrder(order); - Elf_Sym symbol; - std::memset(&symbol, 0, sizeof(Elf_Sym)); - _symbolTable.push_back(SymbolEntry(nullptr, symbol, nullptr)); - this->_entSize = sizeof(Elf_Sym); - this->_fsize = sizeof(Elf_Sym); - this->_alignment = sizeof(Elf_Addr); - this->_type = SHT_SYMTAB; -} - -template <class ELFT> -void SymbolTable<ELFT>::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da, - int64_t addr) { - unsigned char binding = 0, type = 0; - sym.st_size = da->size(); - DefinedAtom::ContentType ct; - switch (ct = da->contentType()) { - case DefinedAtom::typeCode: - case DefinedAtom::typeStub: - sym.st_value = addr; - type = llvm::ELF::STT_FUNC; - break; - case DefinedAtom::typeResolver: - sym.st_value = addr; - type = llvm::ELF::STT_GNU_IFUNC; - break; - case DefinedAtom::typeDataFast: - case DefinedAtom::typeData: - case DefinedAtom::typeConstant: - sym.st_value = addr; - type = llvm::ELF::STT_OBJECT; - break; - case DefinedAtom::typeGOT: - sym.st_value = addr; - type = llvm::ELF::STT_NOTYPE; - break; - case DefinedAtom::typeZeroFill: - case DefinedAtom::typeZeroFillFast: - type = llvm::ELF::STT_OBJECT; - sym.st_value = addr; - break; - case DefinedAtom::typeThreadData: - case DefinedAtom::typeThreadZeroFill: - type = llvm::ELF::STT_TLS; - sym.st_value = addr; - break; - default: - type = llvm::ELF::STT_NOTYPE; - } - if (da->customSectionName() == da->name()) - type = llvm::ELF::STT_SECTION; - - if (da->scope() == DefinedAtom::scopeTranslationUnit) - binding = llvm::ELF::STB_LOCAL; - else - binding = llvm::ELF::STB_GLOBAL; - - sym.setBindingAndType(binding, type); -} - -template <class ELFT> -void SymbolTable<ELFT>::addAbsoluteAtom(Elf_Sym &sym, const AbsoluteAtom *aa, - int64_t addr) { - unsigned char binding = 0, type = 0; - type = llvm::ELF::STT_OBJECT; - sym.st_shndx = llvm::ELF::SHN_ABS; - switch (aa->scope()) { - case AbsoluteAtom::scopeLinkageUnit: - sym.setVisibility(llvm::ELF::STV_HIDDEN); - binding = llvm::ELF::STB_LOCAL; - break; - case AbsoluteAtom::scopeTranslationUnit: - binding = llvm::ELF::STB_LOCAL; - break; - case AbsoluteAtom::scopeGlobal: - binding = llvm::ELF::STB_GLOBAL; - break; - } - sym.st_value = addr; - sym.setBindingAndType(binding, type); -} - -template <class ELFT> -void SymbolTable<ELFT>::addSharedLibAtom(Elf_Sym &sym, - const SharedLibraryAtom *aa) { - unsigned char binding = 0, type = 0; - if (aa->type() == SharedLibraryAtom::Type::Data) { - type = llvm::ELF::STT_OBJECT; - sym.st_size = aa->size(); - } else - type = llvm::ELF::STT_FUNC; - sym.st_shndx = llvm::ELF::SHN_UNDEF; - binding = llvm::ELF::STB_GLOBAL; - sym.setBindingAndType(binding, type); -} - -template <class ELFT> -void SymbolTable<ELFT>::addUndefinedAtom(Elf_Sym &sym, - const UndefinedAtom *ua) { - unsigned char binding = 0, type = 0; - sym.st_value = 0; - type = llvm::ELF::STT_NOTYPE; - if (ua->canBeNull()) - binding = llvm::ELF::STB_WEAK; - else - binding = llvm::ELF::STB_GLOBAL; - sym.setBindingAndType(binding, type); -} - -/// Add a symbol to the symbol Table, definedAtoms which get added to the symbol -/// section don't have their virtual addresses set at the time of adding the -/// symbol to the symbol table(Example: dynamic symbols), the addresses needs -/// to be updated in the table before writing the dynamic symbol table -/// information -template <class ELFT> -void SymbolTable<ELFT>::addSymbol(const Atom *atom, int32_t sectionIndex, - uint64_t addr, const AtomLayout *atomLayout) { - Elf_Sym symbol; - - if (atom->name().empty()) - return; - - symbol.st_name = _stringSection->addString(atom->name()); - symbol.st_size = 0; - symbol.st_shndx = sectionIndex; - symbol.st_value = 0; - symbol.st_other = 0; - symbol.setVisibility(llvm::ELF::STV_DEFAULT); - - // Add all the atoms - if (const DefinedAtom *da = dyn_cast<const DefinedAtom>(atom)) - addDefinedAtom(symbol, da, addr); - else if (const AbsoluteAtom *aa = dyn_cast<const AbsoluteAtom>(atom)) - addAbsoluteAtom(symbol, aa, addr); - else if (isa<const SharedLibraryAtom>(atom)) - addSharedLibAtom(symbol, dyn_cast<SharedLibraryAtom>(atom)); - else - addUndefinedAtom(symbol, dyn_cast<UndefinedAtom>(atom)); - - // If --discard-all is on, don't add to the symbol table - // symbols with local binding. - if (this->_ctx.discardLocals() && symbol.getBinding() == llvm::ELF::STB_LOCAL) - return; - - // Temporary locals are all the symbols which name starts with .L. - // This is defined by the ELF standard. - if (this->_ctx.discardTempLocals() && atom->name().startswith(".L")) - return; - - _symbolTable.push_back(SymbolEntry(atom, symbol, atomLayout)); - this->_fsize += sizeof(Elf_Sym); - if (this->_flags & SHF_ALLOC) - this->_msize = this->_fsize; -} - -template <class ELFT> void SymbolTable<ELFT>::finalize(bool sort) { - // sh_info should be one greater than last symbol with STB_LOCAL binding - // we sort the symbol table to keep all local symbols at the beginning - if (sort) - sortSymbols(); - - uint16_t shInfo = 0; - for (const auto &i : _symbolTable) { - if (i._symbol.getBinding() != llvm::ELF::STB_LOCAL) - break; - shInfo++; - } - this->_info = shInfo; - this->_link = _stringSection->ordinal(); - if (this->_outputSection) { - this->_outputSection->setInfo(this->_info); - this->_outputSection->setLink(this->_link); - } -} - -template <class ELFT> -void SymbolTable<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &, - llvm::FileOutputBuffer &buffer) { - uint8_t *chunkBuffer = buffer.getBufferStart(); - uint8_t *dest = chunkBuffer + this->fileOffset(); - for (const auto &sti : _symbolTable) { - memcpy(dest, &sti._symbol, sizeof(Elf_Sym)); - dest += sizeof(Elf_Sym); - } -} - -template <class ELFT> -DynamicSymbolTable<ELFT>::DynamicSymbolTable(const ELFLinkingContext &ctx, - TargetLayout<ELFT> &layout, - const char *str, int32_t order) - : SymbolTable<ELFT>(ctx, str, order), _layout(layout) { - this->_type = SHT_DYNSYM; - this->_flags = SHF_ALLOC; - this->_msize = this->_fsize; -} - -template <class ELFT> void DynamicSymbolTable<ELFT>::addSymbolsToHashTable() { - int index = 0; - for (auto &ste : this->_symbolTable) { - if (!ste._atom) - _hashTable->addSymbol("", index); - else - _hashTable->addSymbol(ste._atom->name(), index); - ++index; - } -} - -template <class ELFT> void DynamicSymbolTable<ELFT>::finalize() { - // Defined symbols which have been added into the dynamic symbol table - // don't have their addresses known until addresses have been assigned - // so let's update the symbol values after they have got assigned - for (auto &ste : this->_symbolTable) { - const AtomLayout *atomLayout = ste._atomLayout; - if (!atomLayout) - continue; - ste._symbol.st_value = atomLayout->_virtualAddr; - } - - // Don't sort the symbols - SymbolTable<ELFT>::finalize(false); -} - -template <class ELFT> -RelocationTable<ELFT>::RelocationTable(const ELFLinkingContext &ctx, - StringRef str, int32_t order) - : Section<ELFT>(ctx, str, "RelocationTable") { - this->setOrder(order); - this->_flags = SHF_ALLOC; - // Set the alignment properly depending on the target architecture - this->_alignment = ELFT::Is64Bits ? 8 : 4; - if (ctx.isRelaOutputFormat()) { - this->_entSize = sizeof(Elf_Rela); - this->_type = SHT_RELA; - } else { - this->_entSize = sizeof(Elf_Rel); - this->_type = SHT_REL; - } -} - -template <class ELFT> -uint32_t RelocationTable<ELFT>::addRelocation(const DefinedAtom &da, - const Reference &r) { - _relocs.emplace_back(&da, &r); - this->_fsize = _relocs.size() * this->_entSize; - this->_msize = this->_fsize; - return _relocs.size() - 1; -} - -template <class ELFT> -bool RelocationTable<ELFT>::getRelocationIndex(const Reference &r, - uint32_t &res) { - auto rel = std::find_if( - _relocs.begin(), _relocs.end(), - [&](const std::pair<const DefinedAtom *, const Reference *> &p) { - if (p.second == &r) - return true; - return false; - }); - if (rel == _relocs.end()) - return false; - res = std::distance(_relocs.begin(), rel); - return true; -} - -template <class ELFT> -bool RelocationTable<ELFT>::canModifyReadonlySection() const { - for (const auto &rel : _relocs) { - const DefinedAtom *atom = rel.first; - if ((atom->permissions() & DefinedAtom::permRW_) != DefinedAtom::permRW_) - return true; - } - return false; -} - -template <class ELFT> void RelocationTable<ELFT>::finalize() { - this->_link = _symbolTable ? _symbolTable->ordinal() : 0; - if (this->_outputSection) - this->_outputSection->setLink(this->_link); -} - -template <class ELFT> -void RelocationTable<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) { - uint8_t *chunkBuffer = buffer.getBufferStart(); - uint8_t *dest = chunkBuffer + this->fileOffset(); - for (const auto &rel : _relocs) { - if (this->_ctx.isRelaOutputFormat()) { - auto &r = *reinterpret_cast<Elf_Rela *>(dest); - writeRela(writer, r, *rel.first, *rel.second); - DEBUG_WITH_TYPE("ELFRelocationTable", - llvm::dbgs() - << rel.second->kindValue() << " relocation at " - << rel.first->name() << "@" << r.r_offset << " to " - << rel.second->target()->name() << "@" << r.r_addend - << "\n";); - } else { - auto &r = *reinterpret_cast<Elf_Rel *>(dest); - writeRel(writer, r, *rel.first, *rel.second); - DEBUG_WITH_TYPE("ELFRelocationTable", - llvm::dbgs() << rel.second->kindValue() - << " relocation at " << rel.first->name() - << "@" << r.r_offset << " to " - << rel.second->target()->name() << "\n";); - } - dest += this->_entSize; - } -} - -template <class ELFT> -void RelocationTable<ELFT>::writeRela(ELFWriter *writer, Elf_Rela &r, - const DefinedAtom &atom, - const Reference &ref) { - r.setSymbolAndType(getSymbolIndex(ref.target()), ref.kindValue(), false); - r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom(); - // The addend is used only by relative relocations - if (this->_ctx.isRelativeReloc(ref)) - r.r_addend = writer->addressOfAtom(ref.target()) + ref.addend(); - else - r.r_addend = 0; -} - -template <class ELFT> -void RelocationTable<ELFT>::writeRel(ELFWriter *writer, Elf_Rel &r, - const DefinedAtom &atom, - const Reference &ref) { - r.setSymbolAndType(getSymbolIndex(ref.target()), ref.kindValue(), false); - r.r_offset = writer->addressOfAtom(&atom) + ref.offsetInAtom(); -} - -template <class ELFT> -uint32_t RelocationTable<ELFT>::getSymbolIndex(const Atom *a) { - return _symbolTable ? _symbolTable->getSymbolTableIndex(a) - : (uint32_t)STN_UNDEF; -} - -template <class ELFT> -DynamicTable<ELFT>::DynamicTable(const ELFLinkingContext &ctx, - TargetLayout<ELFT> &layout, StringRef str, - int32_t order) - : Section<ELFT>(ctx, str, "DynamicSection"), _layout(layout) { - this->setOrder(order); - this->_entSize = sizeof(Elf_Dyn); - this->_alignment = ELFT::Is64Bits ? 8 : 4; - // Reserve space for the DT_NULL entry. - this->_fsize = sizeof(Elf_Dyn); - this->_msize = sizeof(Elf_Dyn); - this->_type = SHT_DYNAMIC; - this->_flags = SHF_ALLOC; -} - -template <class ELFT> -std::size_t DynamicTable<ELFT>::addEntry(int64_t tag, uint64_t val) { - Elf_Dyn dyn; - dyn.d_tag = tag; - dyn.d_un.d_val = val; - _entries.push_back(dyn); - this->_fsize = (_entries.size() * sizeof(Elf_Dyn)) + sizeof(Elf_Dyn); - this->_msize = this->_fsize; - return _entries.size() - 1; -} - -template <class ELFT> -void DynamicTable<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) { - uint8_t *chunkBuffer = buffer.getBufferStart(); - uint8_t *dest = chunkBuffer + this->fileOffset(); - // Add the null entry. - Elf_Dyn d; - d.d_tag = 0; - d.d_un.d_val = 0; - _entries.push_back(d); - std::memcpy(dest, _entries.data(), this->_fsize); -} - -template <class ELFT> void DynamicTable<ELFT>::createDefaultEntries() { - bool isRela = this->_ctx.isRelaOutputFormat(); - _dt_hash = addEntry(DT_HASH, 0); - _dt_strtab = addEntry(DT_STRTAB, 0); - _dt_symtab = addEntry(DT_SYMTAB, 0); - _dt_strsz = addEntry(DT_STRSZ, 0); - _dt_syment = addEntry(DT_SYMENT, 0); - if (_layout.hasDynamicRelocationTable()) { - _dt_rela = addEntry(isRela ? DT_RELA : DT_REL, 0); - _dt_relasz = addEntry(isRela ? DT_RELASZ : DT_RELSZ, 0); - _dt_relaent = addEntry(isRela ? DT_RELAENT : DT_RELENT, 0); - if (_layout.getDynamicRelocationTable()->canModifyReadonlySection()) - _dt_textrel = addEntry(DT_TEXTREL, 0); - } - if (_layout.hasPLTRelocationTable()) { - _dt_pltrelsz = addEntry(DT_PLTRELSZ, 0); - _dt_pltgot = addEntry(getGotPltTag(), 0); - _dt_pltrel = addEntry(DT_PLTREL, isRela ? DT_RELA : DT_REL); - _dt_jmprel = addEntry(DT_JMPREL, 0); - } -} - -template <class ELFT> void DynamicTable<ELFT>::doPreFlight() { - auto initArray = _layout.findOutputSection(".init_array"); - auto finiArray = _layout.findOutputSection(".fini_array"); - if (initArray) { - _dt_init_array = addEntry(DT_INIT_ARRAY, 0); - _dt_init_arraysz = addEntry(DT_INIT_ARRAYSZ, 0); - } - if (finiArray) { - _dt_fini_array = addEntry(DT_FINI_ARRAY, 0); - _dt_fini_arraysz = addEntry(DT_FINI_ARRAYSZ, 0); - } - if (getInitAtomLayout()) - _dt_init = addEntry(DT_INIT, 0); - if (getFiniAtomLayout()) - _dt_fini = addEntry(DT_FINI, 0); -} - -template <class ELFT> void DynamicTable<ELFT>::finalize() { - StringTable<ELFT> *dynamicStringTable = _dynamicSymbolTable->getStringTable(); - this->_link = dynamicStringTable->ordinal(); - if (this->_outputSection) { - this->_outputSection->setType(this->_type); - this->_outputSection->setInfo(this->_info); - this->_outputSection->setLink(this->_link); - } -} - -template <class ELFT> void DynamicTable<ELFT>::updateDynamicTable() { - StringTable<ELFT> *dynamicStringTable = _dynamicSymbolTable->getStringTable(); - _entries[_dt_hash].d_un.d_val = _hashTable->virtualAddr(); - _entries[_dt_strtab].d_un.d_val = dynamicStringTable->virtualAddr(); - _entries[_dt_symtab].d_un.d_val = _dynamicSymbolTable->virtualAddr(); - _entries[_dt_strsz].d_un.d_val = dynamicStringTable->memSize(); - _entries[_dt_syment].d_un.d_val = _dynamicSymbolTable->getEntSize(); - auto initArray = _layout.findOutputSection(".init_array"); - if (initArray) { - _entries[_dt_init_array].d_un.d_val = initArray->virtualAddr(); - _entries[_dt_init_arraysz].d_un.d_val = initArray->memSize(); - } - auto finiArray = _layout.findOutputSection(".fini_array"); - if (finiArray) { - _entries[_dt_fini_array].d_un.d_val = finiArray->virtualAddr(); - _entries[_dt_fini_arraysz].d_un.d_val = finiArray->memSize(); - } - if (const auto *al = getInitAtomLayout()) - _entries[_dt_init].d_un.d_val = getAtomVirtualAddress(al); - if (const auto *al = getFiniAtomLayout()) - _entries[_dt_fini].d_un.d_val = getAtomVirtualAddress(al); - if (_layout.hasDynamicRelocationTable()) { - auto relaTbl = _layout.getDynamicRelocationTable(); - _entries[_dt_rela].d_un.d_val = relaTbl->virtualAddr(); - _entries[_dt_relasz].d_un.d_val = relaTbl->memSize(); - _entries[_dt_relaent].d_un.d_val = relaTbl->getEntSize(); - } - if (_layout.hasPLTRelocationTable()) { - auto relaTbl = _layout.getPLTRelocationTable(); - _entries[_dt_jmprel].d_un.d_val = relaTbl->virtualAddr(); - _entries[_dt_pltrelsz].d_un.d_val = relaTbl->memSize(); - auto gotplt = _layout.findOutputSection(".got.plt"); - _entries[_dt_pltgot].d_un.d_val = gotplt->virtualAddr(); - } -} - -template <class ELFT> -const AtomLayout *DynamicTable<ELFT>::getInitAtomLayout() { - auto al = _layout.findAtomLayoutByName(this->_ctx.initFunction()); - if (al && isa<DefinedAtom>(al->_atom)) - return al; - return nullptr; -} - -template <class ELFT> -const AtomLayout *DynamicTable<ELFT>::getFiniAtomLayout() { - auto al = _layout.findAtomLayoutByName(this->_ctx.finiFunction()); - if (al && isa<DefinedAtom>(al->_atom)) - return al; - return nullptr; -} - -template <class ELFT> -InterpSection<ELFT>::InterpSection(const ELFLinkingContext &ctx, StringRef str, - int32_t order, StringRef interp) - : Section<ELFT>(ctx, str, "Dynamic:Interp"), _interp(interp) { - this->setOrder(order); - this->_alignment = 1; - // + 1 for null term. - this->_fsize = interp.size() + 1; - this->_msize = this->_fsize; - this->_type = SHT_PROGBITS; - this->_flags = SHF_ALLOC; -} - -template <class ELFT> -void InterpSection<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) { - uint8_t *chunkBuffer = buffer.getBufferStart(); - uint8_t *dest = chunkBuffer + this->fileOffset(); - std::memcpy(dest, _interp.data(), _interp.size()); -} - -template <class ELFT> -HashSection<ELFT>::HashSection(const ELFLinkingContext &ctx, StringRef name, - int32_t order) - : Section<ELFT>(ctx, name, "Dynamic:Hash") { - this->setOrder(order); - this->_entSize = 4; - this->_type = SHT_HASH; - this->_flags = SHF_ALLOC; - this->_alignment = ELFT::Is64Bits ? 8 : 4; - this->_fsize = 0; - this->_msize = 0; -} - -template <class ELFT> -void HashSection<ELFT>::addSymbol(StringRef name, uint32_t index) { - SymbolTableEntry ste; - ste._name = name; - ste._index = index; - _entries.push_back(ste); -} - -/// \brief Set the dynamic symbol table -template <class ELFT> -void HashSection<ELFT>::setSymbolTable( - const DynamicSymbolTable<ELFT> *symbolTable) { - _symbolTable = symbolTable; -} - -template <class ELFT> void HashSection<ELFT>::doPreFlight() { - // The number of buckets to use for a certain number of symbols. - // If there are less than 3 symbols, 1 bucket will be used. If - // there are less than 17 symbols, 3 buckets will be used, and so - // forth. The bucket numbers are defined by GNU ld. We use the - // same rules here so we generate hash sections with the same - // size as those generated by GNU ld. - uint32_t hashBuckets[] = {1, 3, 17, 37, 67, 97, 131, - 197, 263, 521, 1031, 2053, 4099, 8209, - 16411, 32771, 65537, 131101, 262147}; - int hashBucketsCount = sizeof(hashBuckets) / sizeof(uint32_t); - - unsigned int bucketsCount = 0; - unsigned int dynSymCount = _entries.size(); - - // Get the number of buckes that we want to use - for (int i = 0; i < hashBucketsCount; ++i) { - if (dynSymCount < hashBuckets[i]) - break; - bucketsCount = hashBuckets[i]; - } - _buckets.resize(bucketsCount); - _chains.resize(_entries.size()); - - // Create the hash table for the dynamic linker - for (auto ai : _entries) { - unsigned int dynsymIndex = ai._index; - unsigned int bucketpos = llvm::object::elf_hash(ai._name) % bucketsCount; - _chains[dynsymIndex] = _buckets[bucketpos]; - _buckets[bucketpos] = dynsymIndex; - } - - this->_fsize = (2 + _chains.size() + _buckets.size()) * sizeof(uint32_t); - this->_msize = this->_fsize; -} - -template <class ELFT> void HashSection<ELFT>::finalize() { - this->_link = _symbolTable ? _symbolTable->ordinal() : 0; - if (this->_outputSection) - this->_outputSection->setLink(this->_link); -} - -template <class ELFT> -void HashSection<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) { - uint8_t *chunkBuffer = buffer.getBufferStart(); - uint8_t *dest = chunkBuffer + this->fileOffset(); - Elf_Word bucketChainCounts[2]; - bucketChainCounts[0] = _buckets.size(); - bucketChainCounts[1] = _chains.size(); - std::memcpy(dest, bucketChainCounts, sizeof(bucketChainCounts)); - dest += sizeof(bucketChainCounts); - // write bucket values - std::memcpy(dest, _buckets.data(), _buckets.size() * sizeof(Elf_Word)); - dest += _buckets.size() * sizeof(Elf_Word); - // write chain values - std::memcpy(dest, _chains.data(), _chains.size() * sizeof(Elf_Word)); -} - -template <class ELFT> -EHFrameHeader<ELFT>::EHFrameHeader(const ELFLinkingContext &ctx, StringRef name, - TargetLayout<ELFT> &layout, int32_t order) - : Section<ELFT>(ctx, name, "EHFrameHeader"), _layout(layout) { - this->setOrder(order); - this->_entSize = 0; - this->_type = SHT_PROGBITS; - this->_flags = SHF_ALLOC; - this->_alignment = ELFT::Is64Bits ? 8 : 4; - // Minimum size for empty .eh_frame_hdr. - this->_fsize = 1 + 1 + 1 + 1 + 4; - this->_msize = this->_fsize; -} - -template <class ELFT> void EHFrameHeader<ELFT>::doPreFlight() { - // TODO: Generate a proper binary search table. -} - -template <class ELFT> void EHFrameHeader<ELFT>::finalize() { - OutputSection<ELFT> *s = _layout.findOutputSection(".eh_frame"); - OutputSection<ELFT> *h = _layout.findOutputSection(".eh_frame_hdr"); - if (s && h) - _ehFrameOffset = s->virtualAddr() - (h->virtualAddr() + 4); -} - -template <class ELFT> -void EHFrameHeader<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout, - llvm::FileOutputBuffer &buffer) { - uint8_t *chunkBuffer = buffer.getBufferStart(); - uint8_t *dest = chunkBuffer + this->fileOffset(); - int pos = 0; - dest[pos++] = 1; // version - dest[pos++] = llvm::dwarf::DW_EH_PE_pcrel | - llvm::dwarf::DW_EH_PE_sdata4; // eh_frame_ptr_enc - dest[pos++] = llvm::dwarf::DW_EH_PE_omit; // fde_count_enc - dest[pos++] = llvm::dwarf::DW_EH_PE_omit; // table_enc - *reinterpret_cast<typename llvm::object::ELFFile<ELFT>::Elf_Sword *>( - dest + pos) = _ehFrameOffset; -} - -#define INSTANTIATE(klass) \ - template class klass<ELF32LE>; \ - template class klass<ELF32BE>; \ - template class klass<ELF64LE>; \ - template class klass<ELF64BE> - -INSTANTIATE(AtomSection); -INSTANTIATE(DynamicSymbolTable); -INSTANTIATE(DynamicTable); -INSTANTIATE(EHFrameHeader); -INSTANTIATE(HashSection); -INSTANTIATE(InterpSection); -INSTANTIATE(OutputSection); -INSTANTIATE(RelocationTable); -INSTANTIATE(Section); -INSTANTIATE(StringTable); -INSTANTIATE(SymbolTable); - -} // end namespace elf -} // end namespace lld |