[lld] r248214 - Move OutputSectionBase and derived classes out of Writer.cpp.
Rafael Espindola via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 21 14:38:09 PDT 2015
Author: rafael
Date: Mon Sep 21 16:38:08 2015
New Revision: 248214
URL: http://llvm.org/viewvc/llvm-project?rev=248214&view=rev
Log:
Move OutputSectionBase and derived classes out of Writer.cpp.
The file was getting a bit too big and OutputSection is a central enough
concept in ELF linking to justify its own file.
Added:
lld/trunk/ELF/OutputSections.cpp
lld/trunk/ELF/OutputSections.h
Modified:
lld/trunk/ELF/CMakeLists.txt
lld/trunk/ELF/Writer.cpp
Modified: lld/trunk/ELF/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/CMakeLists.txt?rev=248214&r1=248213&r2=248214&view=diff
==============================================================================
--- lld/trunk/ELF/CMakeLists.txt (original)
+++ lld/trunk/ELF/CMakeLists.txt Mon Sep 21 16:38:08 2015
@@ -8,6 +8,7 @@ add_llvm_library(lldELF2
DriverUtils.cpp
Error.cpp
InputFiles.cpp
+ OutputSections.cpp
SymbolTable.cpp
Symbols.cpp
Writer.cpp
Added: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=248214&view=auto
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (added)
+++ lld/trunk/ELF/OutputSections.cpp Mon Sep 21 16:38:08 2015
@@ -0,0 +1,586 @@
+//===- OutputSections.cpp -------------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "OutputSections.h"
+#include "Config.h"
+#include "InputFiles.h"
+#include "Symbols.h"
+#include "SymbolTable.h"
+
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::ELF;
+
+using namespace lld;
+using namespace lld::elf2;
+
+template <bool Is64Bits>
+OutputSectionBase<Is64Bits>::OutputSectionBase(StringRef Name, uint32_t sh_type,
+ uintX_t sh_flags)
+ : Name(Name) {
+ memset(&Header, 0, sizeof(HeaderT));
+ Header.sh_type = sh_type;
+ Header.sh_flags = sh_flags;
+}
+
+template <class ELFT> void GotSection<ELFT>::addEntry(SymbolBody *Sym) {
+ Sym->setGotIndex(Entries.size());
+ Entries.push_back(Sym);
+}
+
+template <class ELFT>
+typename GotSection<ELFT>::uintX_t
+GotSection<ELFT>::getEntryAddr(const SymbolBody &B) const {
+ return this->getVA() + B.getGotIndex() * this->getAddrSize();
+}
+
+template <class ELFT> void PltSection<ELFT>::writeTo(uint8_t *Buf) {
+ uintptr_t Start = reinterpret_cast<uintptr_t>(Buf);
+ ArrayRef<uint8_t> Jmp = {0xff, 0x25}; // jmpq *val(%rip)
+ for (const SymbolBody *E : Entries) {
+ uintptr_t InstPos = reinterpret_cast<uintptr_t>(Buf);
+
+ memcpy(Buf, Jmp.data(), Jmp.size());
+ Buf += Jmp.size();
+
+ uintptr_t OffsetInPLT = (InstPos + 6) - Start;
+ uintptr_t Delta = GotSec.getEntryAddr(*E) - (this->getVA() + OffsetInPLT);
+ assert(isInt<32>(Delta));
+ support::endian::write32le(Buf, Delta);
+ Buf += 4;
+
+ *Buf = 0x90; // nop
+ ++Buf;
+ *Buf = 0x90; // nop
+ ++Buf;
+ }
+}
+
+template <class ELFT> void PltSection<ELFT>::addEntry(SymbolBody *Sym) {
+ Sym->setPltIndex(Entries.size());
+ Entries.push_back(Sym);
+}
+
+template <class ELFT>
+typename PltSection<ELFT>::uintX_t
+PltSection<ELFT>::getEntryAddr(const SymbolBody &B) const {
+ return this->getVA() + B.getPltIndex() * EntrySize;
+}
+
+bool lld::elf2::relocNeedsPLT(uint32_t Type) {
+ switch (Type) {
+ default:
+ return false;
+ case R_X86_64_PLT32:
+ return true;
+ }
+}
+
+bool lld::elf2::relocNeedsGOT(uint32_t Type) {
+ if (relocNeedsPLT(Type))
+ return true;
+ switch (Type) {
+ default:
+ return false;
+ case R_X86_64_GOTPCREL:
+ return true;
+ }
+}
+
+template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
+ auto *P = reinterpret_cast<Elf_Rela *>(Buf);
+ bool IsMips64EL = Relocs[0].C.getFile()->getObj()->isMips64EL();
+ for (const DynamicReloc<ELFT> &Rel : Relocs) {
+ const InputSection<ELFT> &C = Rel.C;
+ const Elf_Rel &RI = Rel.RI;
+ OutputSection<ELFT> *Out = C.getOutputSection();
+ uint32_t SymIndex = RI.getSymbol(IsMips64EL);
+ const SymbolBody *Body = C.getFile()->getSymbolBody(SymIndex);
+ uint32_t Type = RI.getType(IsMips64EL);
+ if (relocNeedsGOT(Type)) {
+ P->r_offset = GotSec.getEntryAddr(*Body);
+ P->setSymbolAndType(Body->getDynamicSymbolTableIndex(), R_X86_64_GLOB_DAT,
+ IsMips64EL);
+ } else {
+ P->r_offset = RI.r_offset + C.getOutputSectionOff() + Out->getVA();
+ P->setSymbolAndType(Body->getDynamicSymbolTableIndex(), Type, IsMips64EL);
+ if (IsRela)
+ P->r_addend = static_cast<const Elf_Rela &>(RI).r_addend;
+ }
+
+ ++P;
+ }
+}
+
+template <class ELFT> void RelocationSection<ELFT>::finalize() {
+ this->Header.sh_link = DynSymSec.getSectionIndex();
+ this->Header.sh_size = Relocs.size() * this->Header.sh_entsize;
+}
+
+template <bool Is64Bits>
+InterpSection<Is64Bits>::InterpSection()
+ : OutputSectionBase<Is64Bits>(".interp", llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC) {
+ this->Header.sh_size = Config->DynamicLinker.size() + 1;
+ this->Header.sh_addralign = 1;
+}
+
+template <bool Is64Bits>
+template <endianness E>
+void OutputSectionBase<Is64Bits>::writeHeaderTo(
+ typename ELFFile<ELFType<E, Is64Bits>>::Elf_Shdr *SHdr) {
+ SHdr->sh_name = Header.sh_name;
+ SHdr->sh_type = Header.sh_type;
+ SHdr->sh_flags = Header.sh_flags;
+ SHdr->sh_addr = Header.sh_addr;
+ SHdr->sh_offset = Header.sh_offset;
+ SHdr->sh_size = Header.sh_size;
+ SHdr->sh_link = Header.sh_link;
+ SHdr->sh_info = Header.sh_info;
+ SHdr->sh_addralign = Header.sh_addralign;
+ SHdr->sh_entsize = Header.sh_entsize;
+}
+
+template <bool Is64Bits> void InterpSection<Is64Bits>::writeTo(uint8_t *Buf) {
+ memcpy(Buf, Config->DynamicLinker.data(), Config->DynamicLinker.size());
+}
+
+template <class ELFT> void HashTableSection<ELFT>::addSymbol(SymbolBody *S) {
+ StringRef Name = S->getName();
+ DynSymSec.addSymbol(Name);
+ Hashes.push_back(hash(Name));
+ S->setDynamicSymbolTableIndex(Hashes.size());
+}
+
+template <class ELFT> void DynamicSection<ELFT>::finalize() {
+ typename Base::HeaderT &Header = this->Header;
+ Header.sh_link = DynStrSec.getSectionIndex();
+
+ unsigned NumEntries = 0;
+ if (RelaDynSec.hasRelocs()) {
+ ++NumEntries; // DT_RELA / DT_REL
+ ++NumEntries; // DT_RELASZ / DTRELSZ
+ }
+ ++NumEntries; // DT_SYMTAB
+ ++NumEntries; // DT_STRTAB
+ ++NumEntries; // DT_STRSZ
+ ++NumEntries; // DT_HASH
+
+ StringRef RPath = Config->RPath;
+ if (!RPath.empty()) {
+ ++NumEntries; // DT_RUNPATH
+ DynStrSec.add(RPath);
+ }
+
+ const std::vector<std::unique_ptr<SharedFileBase>> &SharedFiles =
+ SymTab.getSharedFiles();
+ for (const std::unique_ptr<SharedFileBase> &File : SharedFiles)
+ DynStrSec.add(File->getName());
+ NumEntries += SharedFiles.size();
+
+ ++NumEntries; // DT_NULL
+
+ Header.sh_size = NumEntries * Header.sh_entsize;
+}
+
+template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) {
+ typedef typename std::conditional<ELFT::Is64Bits, Elf64_Dyn, Elf32_Dyn>::type
+ Elf_Dyn;
+ auto *P = reinterpret_cast<Elf_Dyn *>(Buf);
+
+ if (RelaDynSec.hasRelocs()) {
+ bool IsRela = RelaDynSec.isRela();
+ P->d_tag = IsRela ? DT_RELA : DT_REL;
+ P->d_un.d_ptr = RelaDynSec.getVA();
+ ++P;
+
+ P->d_tag = IsRela ? DT_RELASZ : DT_RELSZ;
+ P->d_un.d_val = RelaDynSec.getSize();
+ ++P;
+ }
+
+ P->d_tag = DT_SYMTAB;
+ P->d_un.d_ptr = DynSymSec.getVA();
+ ++P;
+
+ P->d_tag = DT_STRTAB;
+ P->d_un.d_ptr = DynStrSec.getVA();
+ ++P;
+
+ P->d_tag = DT_STRSZ;
+ P->d_un.d_val = DynStrSec.data().size();
+ ++P;
+
+ P->d_tag = DT_HASH;
+ P->d_un.d_ptr = HashSec.getVA();
+ ++P;
+
+ StringRef RPath = Config->RPath;
+ if (!RPath.empty()) {
+ P->d_tag = DT_RUNPATH;
+ P->d_un.d_val = DynStrSec.getFileOff(RPath);
+ ++P;
+ }
+
+ const std::vector<std::unique_ptr<SharedFileBase>> &SharedFiles =
+ SymTab.getSharedFiles();
+ for (const std::unique_ptr<SharedFileBase> &File : SharedFiles) {
+ P->d_tag = DT_NEEDED;
+ P->d_un.d_val = DynStrSec.getFileOff(File->getName());
+ ++P;
+ }
+
+ P->d_tag = DT_NULL;
+ P->d_un.d_val = 0;
+ ++P;
+}
+
+template <class ELFT>
+void OutputSection<ELFT>::addChunk(InputSection<ELFT> *C) {
+ Chunks.push_back(C);
+ C->setOutputSection(this);
+ uint32_t Align = C->getAlign();
+ if (Align > this->Header.sh_addralign)
+ this->Header.sh_addralign = Align;
+
+ uintX_t Off = this->Header.sh_size;
+ Off = RoundUpToAlignment(Off, Align);
+ C->setOutputSectionOff(Off);
+ Off += C->getSize();
+ this->Header.sh_size = Off;
+}
+
+template <class ELFT>
+void OutputSection<ELFT>::relocateOne(uint8_t *Buf, const Elf_Rel &Rel,
+ uint32_t Type, uintX_t BaseAddr,
+ uintX_t SymVA) {
+ uintX_t Offset = Rel.r_offset;
+ uint8_t *Location = Buf + Offset;
+ switch (Type) {
+ case R_386_32:
+ support::endian::write32le(Location, SymVA);
+ break;
+ default:
+ llvm::errs() << Twine("unrecognized reloc ") + Twine(Type) << '\n';
+ break;
+ }
+}
+
+template <class ELFT>
+void OutputSection<ELFT>::relocateOne(uint8_t *Buf, const Elf_Rela &Rel,
+ uint32_t Type, uintX_t BaseAddr,
+ uintX_t SymVA) {
+ uintX_t Offset = Rel.r_offset;
+ uint8_t *Location = Buf + Offset;
+ switch (Type) {
+ case R_X86_64_PC32:
+ support::endian::write32le(Location,
+ SymVA + (Rel.r_addend - (BaseAddr + Offset)));
+ break;
+ case R_X86_64_64:
+ support::endian::write64le(Location, SymVA + Rel.r_addend);
+ break;
+ case R_X86_64_32: {
+ case R_X86_64_32S:
+ uint64_t VA = SymVA + Rel.r_addend;
+ if (Type == R_X86_64_32 && !isUInt<32>(VA))
+ error("R_X86_64_32 out of range");
+ else if (!isInt<32>(VA))
+ error("R_X86_64_32S out of range");
+
+ support::endian::write32le(Location, VA);
+ break;
+ }
+ default:
+ llvm::errs() << Twine("unrecognized reloc ") + Twine(Type) << '\n';
+ break;
+ }
+}
+
+template <class ELFT>
+typename ELFFile<ELFT>::uintX_t
+lld::elf2::getSymVA(const DefinedRegular<ELFT> *DR) {
+ const InputSection<ELFT> *SC = &DR->Section;
+ OutputSection<ELFT> *OS = SC->getOutputSection();
+ return OS->getVA() + SC->getOutputSectionOff() + DR->Sym.st_value;
+}
+
+template <class ELFT>
+typename ELFFile<ELFT>::uintX_t
+lld::elf2::getLocalSymVA(const typename ELFFile<ELFT>::Elf_Sym *Sym,
+ const ObjectFile<ELFT> &File) {
+ uint32_t SecIndex = Sym->st_shndx;
+
+ if (SecIndex == SHN_XINDEX)
+ SecIndex = File.getObj()->getExtendedSymbolTableIndex(
+ Sym, File.getSymbolTable(), File.getSymbolTableShndx());
+ ArrayRef<InputSection<ELFT> *> Chunks = File.getChunks();
+ InputSection<ELFT> *Section = Chunks[SecIndex];
+ OutputSection<ELFT> *Out = Section->getOutputSection();
+ return Out->getVA() + Section->getOutputSectionOff() + Sym->st_value;
+}
+
+template <class ELFT>
+template <bool isRela>
+void OutputSection<ELFT>::relocate(
+ uint8_t *Buf, iterator_range<const Elf_Rel_Impl<ELFT, isRela> *> Rels,
+ const ObjectFile<ELFT> &File, uintX_t BaseAddr) {
+ typedef Elf_Rel_Impl<ELFT, isRela> RelType;
+ bool IsMips64EL = File.getObj()->isMips64EL();
+ for (const RelType &RI : Rels) {
+ uint32_t SymIndex = RI.getSymbol(IsMips64EL);
+ uint32_t Type = RI.getType(IsMips64EL);
+ uintX_t SymVA;
+
+ // Handle relocations for local symbols -- they never get
+ // resolved so we don't allocate a SymbolBody.
+ const Elf_Shdr *SymTab = File.getSymbolTable();
+ if (SymIndex < SymTab->sh_info) {
+ const Elf_Sym *Sym = File.getObj()->getRelocationSymbol(&RI, SymTab);
+ if (!Sym)
+ continue;
+ SymVA = getLocalSymVA(Sym, File);
+ } else {
+ const SymbolBody *Body = File.getSymbolBody(SymIndex);
+ if (!Body)
+ continue;
+ switch (Body->kind()) {
+ case SymbolBody::DefinedRegularKind:
+ SymVA = getSymVA<ELFT>(cast<DefinedRegular<ELFT>>(Body));
+ break;
+ case SymbolBody::DefinedAbsoluteKind:
+ SymVA = cast<DefinedAbsolute<ELFT>>(Body)->Sym.st_value;
+ break;
+ case SymbolBody::DefinedCommonKind: {
+ auto *DC = cast<DefinedCommon<ELFT>>(Body);
+ SymVA = DC->OutputSec->getVA() + DC->OffsetInBSS;
+ break;
+ }
+ case SymbolBody::SharedKind:
+ if (relocNeedsPLT(Type)) {
+ SymVA = PltSec.getEntryAddr(*Body);
+ Type = R_X86_64_PC32;
+ } else if (relocNeedsGOT(Type)) {
+ SymVA = GotSec.getEntryAddr(*Body);
+ Type = R_X86_64_PC32;
+ } else {
+ continue;
+ }
+ break;
+ case SymbolBody::UndefinedKind:
+ assert(Body->isWeak() && "Undefined symbol reached writer");
+ SymVA = 0;
+ break;
+ case SymbolBody::LazyKind:
+ llvm_unreachable("Lazy symbol reached writer");
+ }
+ }
+
+ relocateOne(Buf, RI, Type, BaseAddr, SymVA);
+ }
+}
+
+template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
+ for (InputSection<ELFT> *C : Chunks) {
+ C->writeTo(Buf);
+ const ObjectFile<ELFT> *File = C->getFile();
+ ELFFile<ELFT> *EObj = File->getObj();
+ uint8_t *Base = Buf + C->getOutputSectionOff();
+ uintX_t BaseAddr = this->getVA() + C->getOutputSectionOff();
+ // Iterate over all relocation sections that apply to this section.
+ for (const Elf_Shdr *RelSec : C->RelocSections) {
+ if (RelSec->sh_type == SHT_RELA)
+ relocate(Base, EObj->relas(RelSec), *File, BaseAddr);
+ else
+ relocate(Base, EObj->rels(RelSec), *File, BaseAddr);
+ }
+ }
+}
+
+template <bool Is64Bits>
+void StringTableSection<Is64Bits>::writeTo(uint8_t *Buf) {
+ StringRef Data = StrTabBuilder.data();
+ memcpy(Buf, Data.data(), Data.size());
+}
+
+bool lld::elf2::includeInSymtab(const SymbolBody &B) {
+ if (B.isLazy())
+ return false;
+ if (!B.isUsedInRegularObj())
+ return false;
+ uint8_t V = B.getMostConstrainingVisibility();
+ if (V != STV_DEFAULT && V != STV_PROTECTED)
+ return false;
+ return true;
+}
+
+template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
+ const OutputSection<ELFT> *Out = nullptr;
+ const InputSection<ELFT> *Section = nullptr;
+ Buf += sizeof(Elf_Sym);
+
+ // All symbols with STB_LOCAL binding precede the weak and global symbols.
+ // .dynsym only contains global symbols.
+ if (!Config->DiscardAll && !StrTabSec.isDynamic()) {
+ for (const std::unique_ptr<ObjectFileBase> &FileB :
+ Table.getObjectFiles()) {
+ auto &File = cast<ObjectFile<ELFT>>(*FileB);
+ Elf_Sym_Range Syms = File.getLocalSymbols();
+ for (const Elf_Sym &Sym : Syms) {
+ auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
+ uint32_t SecIndex = Sym.st_shndx;
+ ErrorOr<StringRef> SymName = Sym.getName(File.getStringTable());
+ if (Config->DiscardLocals && SymName->startswith(".L"))
+ continue;
+ ESym->st_name = (SymName) ? StrTabSec.getFileOff(*SymName) : 0;
+ ESym->st_size = Sym.st_size;
+ ESym->setBindingAndType(Sym.getBinding(), Sym.getType());
+ if (SecIndex == SHN_XINDEX)
+ SecIndex = File.getObj()->getExtendedSymbolTableIndex(
+ &Sym, File.getSymbolTable(), File.getSymbolTableShndx());
+ ArrayRef<InputSection<ELFT> *> Chunks = File.getChunks();
+ Section = Chunks[SecIndex];
+ assert(Section != nullptr);
+ Out = Section->getOutputSection();
+ assert(Out != nullptr);
+ ESym->st_shndx = Out->getSectionIndex();
+ ESym->st_value =
+ Out->getVA() + Section->getOutputSectionOff() + Sym.st_value;
+ Buf += sizeof(Elf_Sym);
+ }
+ }
+ }
+
+ for (auto &P : Table.getSymbols()) {
+ StringRef Name = P.first;
+ Symbol *Sym = P.second;
+ SymbolBody *Body = Sym->Body;
+ if (!includeInSymtab(*Body))
+ continue;
+ const Elf_Sym &InputSym = cast<ELFSymbolBody<ELFT>>(Body)->Sym;
+
+ auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
+ ESym->st_name = StrTabSec.getFileOff(Name);
+
+ Out = nullptr;
+ Section = nullptr;
+
+ switch (Body->kind()) {
+ case SymbolBody::DefinedRegularKind:
+ Section = &cast<DefinedRegular<ELFT>>(Body)->Section;
+ break;
+ case SymbolBody::DefinedCommonKind:
+ Out = BssSec;
+ break;
+ case SymbolBody::UndefinedKind:
+ case SymbolBody::DefinedAbsoluteKind:
+ case SymbolBody::SharedKind:
+ break;
+ case SymbolBody::LazyKind:
+ llvm_unreachable("Lazy symbol got to output symbol table!");
+ }
+
+ ESym->setBindingAndType(InputSym.getBinding(), InputSym.getType());
+ ESym->st_size = InputSym.st_size;
+ ESym->setVisibility(Body->getMostConstrainingVisibility());
+ if (InputSym.isAbsolute()) {
+ ESym->st_shndx = SHN_ABS;
+ ESym->st_value = InputSym.st_value;
+ }
+
+ if (Section)
+ Out = Section->getOutputSection();
+
+ if (Out) {
+ ESym->st_shndx = Out->getSectionIndex();
+ uintX_t VA = Out->getVA();
+ if (Section)
+ VA += Section->getOutputSectionOff();
+ if (auto *C = dyn_cast<DefinedCommon<ELFT>>(Body))
+ VA += C->OffsetInBSS;
+ else
+ VA += InputSym.st_value;
+ ESym->st_value = VA;
+ }
+
+ Buf += sizeof(Elf_Sym);
+ }
+}
+
+namespace lld {
+namespace elf2 {
+template class OutputSectionBase<false>;
+template class OutputSectionBase<true>;
+
+template void OutputSectionBase<false>::writeHeaderTo<support::little>(
+ typename ELFFile<ELFType<support::little, false>>::Elf_Shdr *SHdr);
+template void OutputSectionBase<true>::writeHeaderTo<support::little>(
+ typename ELFFile<ELFType<support::little, true>>::Elf_Shdr *SHdr);
+template void OutputSectionBase<false>::writeHeaderTo<support::big>(
+ typename ELFFile<ELFType<support::big, false>>::Elf_Shdr *SHdr);
+template void OutputSectionBase<true>::writeHeaderTo<support::big>(
+ typename ELFFile<ELFType<support::big, true>>::Elf_Shdr *SHdr);
+
+template class GotSection<ELF32LE>;
+template class GotSection<ELF32BE>;
+template class GotSection<ELF64LE>;
+template class GotSection<ELF64BE>;
+
+template class PltSection<ELF32LE>;
+template class PltSection<ELF32BE>;
+template class PltSection<ELF64LE>;
+template class PltSection<ELF64BE>;
+
+template class RelocationSection<ELF32LE>;
+template class RelocationSection<ELF32BE>;
+template class RelocationSection<ELF64LE>;
+template class RelocationSection<ELF64BE>;
+
+template class InterpSection<false>;
+template class InterpSection<true>;
+
+template class HashTableSection<ELF32LE>;
+template class HashTableSection<ELF32BE>;
+template class HashTableSection<ELF64LE>;
+template class HashTableSection<ELF64BE>;
+
+template class DynamicSection<ELF32LE>;
+template class DynamicSection<ELF32BE>;
+template class DynamicSection<ELF64LE>;
+template class DynamicSection<ELF64BE>;
+
+template class OutputSection<ELF32LE>;
+template class OutputSection<ELF32BE>;
+template class OutputSection<ELF64LE>;
+template class OutputSection<ELF64BE>;
+
+template class StringTableSection<false>;
+template class StringTableSection<true>;
+
+template class SymbolTableSection<ELF32LE>;
+template class SymbolTableSection<ELF32BE>;
+template class SymbolTableSection<ELF64LE>;
+template class SymbolTableSection<ELF64BE>;
+
+template typename ELFFile<ELF32LE>::uintX_t
+getSymVA(const DefinedRegular<ELF32LE> *DR);
+
+template typename ELFFile<ELF32BE>::uintX_t
+getSymVA(const DefinedRegular<ELF32BE> *DR);
+
+template typename ELFFile<ELF64LE>::uintX_t
+getSymVA(const DefinedRegular<ELF64LE> *DR);
+
+template typename ELFFile<ELF64BE>::uintX_t
+getSymVA(const DefinedRegular<ELF64BE> *DR);
+}
+}
Added: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=248214&view=auto
==============================================================================
--- lld/trunk/ELF/OutputSections.h (added)
+++ lld/trunk/ELF/OutputSections.h Mon Sep 21 16:38:08 2015
@@ -0,0 +1,396 @@
+//===- OutputSections.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_ELF_OUTPUT_SECTIONS_H
+#define LLD_ELF_OUTPUT_SECTIONS_H
+
+#include "lld/Core/LLVM.h"
+
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Object/ELF.h"
+
+#include <type_traits>
+
+namespace lld {
+namespace elf2 {
+
+class SymbolBody;
+class SymbolTable;
+template <class ELFT> class SymbolTableSection;
+template <bool Is64Bits> class StringTableSection;
+template <class ELFT> class InputSection;
+template <class ELFT> class OutputSection;
+template <class ELFT> class ObjectFile;
+template <class ELFT> class DefinedRegular;
+
+bool relocNeedsPLT(uint32_t Type);
+bool relocNeedsGOT(uint32_t Type);
+
+template <class ELFT>
+typename llvm::object::ELFFile<ELFT>::uintX_t
+getSymVA(const DefinedRegular<ELFT> *DR);
+
+template <class ELFT>
+typename llvm::object::ELFFile<ELFT>::uintX_t
+getLocalSymVA(const typename llvm::object::ELFFile<ELFT>::Elf_Sym *Sym,
+ const ObjectFile<ELFT> &File);
+
+bool includeInSymtab(const SymbolBody &B);
+
+// OutputSection represents a section in an output file. It's a
+// container of chunks. OutputSection and Chunk are 1:N relationship.
+// Chunks cannot belong to more than one OutputSections. The writer
+// creates multiple OutputSections and assign them unique,
+// non-overlapping file offsets and VAs.
+template <bool Is64Bits> class OutputSectionBase {
+public:
+ typedef typename std::conditional<Is64Bits, uint64_t, uint32_t>::type uintX_t;
+ typedef typename std::conditional<Is64Bits, llvm::ELF::Elf64_Shdr,
+ llvm::ELF::Elf32_Shdr>::type HeaderT;
+
+ OutputSectionBase(StringRef Name, uint32_t sh_type, uintX_t sh_flags);
+ void setVA(uintX_t VA) { Header.sh_addr = VA; }
+ uintX_t getVA() const { return Header.sh_addr; }
+ void setFileOffset(uintX_t Off) { Header.sh_offset = Off; }
+ template <llvm::object::endianness E>
+ void writeHeaderTo(typename llvm::object::ELFFile<
+ llvm::object::ELFType<E, Is64Bits>>::Elf_Shdr *SHdr);
+ StringRef getName() { return Name; }
+ void setNameOffset(uintX_t Offset) { Header.sh_name = Offset; }
+
+ unsigned getSectionIndex() const { return SectionIndex; }
+ void setSectionIndex(unsigned I) { SectionIndex = I; }
+
+ // Returns the size of the section in the output file.
+ uintX_t getSize() { return Header.sh_size; }
+ void setSize(uintX_t Val) { Header.sh_size = Val; }
+ uintX_t getFlags() { return Header.sh_flags; }
+ uintX_t getFileOff() { return Header.sh_offset; }
+ uintX_t getAlign() {
+ // The ELF spec states that a value of 0 means the section has no alignment
+ // constraits.
+ return std::max<uintX_t>(Header.sh_addralign, 1);
+ }
+ uint32_t getType() { return Header.sh_type; }
+
+ static unsigned getAddrSize() { return Is64Bits ? 8 : 4; }
+
+ virtual void finalize() {}
+ virtual void writeTo(uint8_t *Buf) = 0;
+
+protected:
+ StringRef Name;
+ HeaderT Header;
+ unsigned SectionIndex;
+ ~OutputSectionBase() = default;
+};
+
+template <class ELFT>
+class GotSection final : public OutputSectionBase<ELFT::Is64Bits> {
+ typedef OutputSectionBase<ELFT::Is64Bits> Base;
+ typedef typename Base::uintX_t uintX_t;
+
+public:
+ GotSection()
+ : OutputSectionBase<ELFT::Is64Bits>(".got", llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC |
+ llvm::ELF::SHF_WRITE) {
+ this->Header.sh_addralign = this->getAddrSize();
+ }
+ void finalize() override {
+ this->Header.sh_size = Entries.size() * this->getAddrSize();
+ }
+ void writeTo(uint8_t *Buf) override {}
+ void addEntry(SymbolBody *Sym);
+ bool empty() const { return Entries.empty(); }
+ uintX_t getEntryAddr(const SymbolBody &B) const;
+
+private:
+ std::vector<const SymbolBody *> Entries;
+};
+
+template <class ELFT>
+class PltSection final : public OutputSectionBase<ELFT::Is64Bits> {
+ typedef OutputSectionBase<ELFT::Is64Bits> Base;
+ typedef typename Base::uintX_t uintX_t;
+
+public:
+ PltSection(const GotSection<ELFT> &GotSec)
+ : OutputSectionBase<ELFT::Is64Bits>(".plt", llvm::ELF::SHT_PROGBITS,
+ llvm::ELF::SHF_ALLOC |
+ llvm::ELF::SHF_EXECINSTR),
+ GotSec(GotSec) {
+ this->Header.sh_addralign = 16;
+ }
+ void finalize() override {
+ this->Header.sh_size = Entries.size() * EntrySize;
+ }
+ void writeTo(uint8_t *Buf) override;
+ void addEntry(SymbolBody *Sym);
+ bool empty() const { return Entries.empty(); }
+ uintX_t getEntryAddr(const SymbolBody &B) const;
+ static const unsigned EntrySize = 8;
+
+private:
+ std::vector<const SymbolBody *> Entries;
+ const GotSection<ELFT> &GotSec;
+};
+
+template <class ELFT> struct DynamicReloc {
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
+ const InputSection<ELFT> &C;
+ const Elf_Rel &RI;
+};
+
+template <class ELFT>
+class SymbolTableSection final : public OutputSectionBase<ELFT::Is64Bits> {
+public:
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;
+ typedef typename OutputSectionBase<ELFT::Is64Bits>::uintX_t uintX_t;
+ SymbolTableSection(SymbolTable &Table,
+ StringTableSection<ELFT::Is64Bits> &StrTabSec)
+ : OutputSectionBase<ELFT::Is64Bits>(
+ StrTabSec.isDynamic() ? ".dynsym" : ".symtab",
+ StrTabSec.isDynamic() ? llvm::ELF::SHT_DYNSYM
+ : llvm::ELF::SHT_SYMTAB,
+ StrTabSec.isDynamic() ? (uintX_t)llvm::ELF::SHF_ALLOC : 0),
+ Table(Table), StrTabSec(StrTabSec) {
+ typedef OutputSectionBase<ELFT::Is64Bits> Base;
+ typename Base::HeaderT &Header = this->Header;
+
+ Header.sh_entsize = sizeof(Elf_Sym);
+ Header.sh_addralign = ELFT::Is64Bits ? 8 : 4;
+ }
+
+ void finalize() override {
+ this->Header.sh_size = getNumSymbols() * sizeof(Elf_Sym);
+ this->Header.sh_link = StrTabSec.getSectionIndex();
+ this->Header.sh_info = NumLocals + 1;
+ }
+
+ void writeTo(uint8_t *Buf) override;
+
+ const SymbolTable &getSymTable() const { return Table; }
+
+ void addSymbol(StringRef Name, bool isLocal = false) {
+ StrTabSec.add(Name);
+ ++NumVisible;
+ if (isLocal)
+ ++NumLocals;
+ }
+
+ StringTableSection<ELFT::Is64Bits> &getStrTabSec() { return StrTabSec; }
+ unsigned getNumSymbols() const { return NumVisible + 1; }
+ void setBssSec(const OutputSection<ELFT> *V) { BssSec = V; }
+
+private:
+ SymbolTable &Table;
+ StringTableSection<ELFT::Is64Bits> &StrTabSec;
+ unsigned NumVisible = 0;
+ unsigned NumLocals = 0;
+ const OutputSection<ELFT> *BssSec = nullptr;
+};
+
+template <class ELFT>
+class RelocationSection final : public OutputSectionBase<ELFT::Is64Bits> {
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela;
+
+public:
+ RelocationSection(SymbolTableSection<ELFT> &DynSymSec,
+ const GotSection<ELFT> &GotSec, bool IsRela)
+ : OutputSectionBase<ELFT::Is64Bits>(IsRela ? ".rela.dyn" : ".rel.dyn",
+ IsRela ? llvm::ELF::SHT_RELA
+ : llvm::ELF::SHT_REL,
+ llvm::ELF::SHF_ALLOC),
+ DynSymSec(DynSymSec), GotSec(GotSec), IsRela(IsRela) {
+ this->Header.sh_entsize = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
+ this->Header.sh_addralign = ELFT::Is64Bits ? 8 : 4;
+ }
+
+ void addReloc(const DynamicReloc<ELFT> &Reloc) { Relocs.push_back(Reloc); }
+ void finalize() override;
+ void writeTo(uint8_t *Buf) override;
+ bool hasRelocs() const { return !Relocs.empty(); }
+ bool isRela() const { return IsRela; }
+
+private:
+ std::vector<DynamicReloc<ELFT>> Relocs;
+ SymbolTableSection<ELFT> &DynSymSec;
+ const GotSection<ELFT> &GotSec;
+ const bool IsRela;
+};
+
+template <class ELFT>
+class OutputSection final : public OutputSectionBase<ELFT::Is64Bits> {
+public:
+ typedef typename OutputSectionBase<ELFT::Is64Bits>::uintX_t uintX_t;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela;
+ OutputSection(const PltSection<ELFT> &PltSec, const GotSection<ELFT> &GotSec,
+ StringRef Name, uint32_t sh_type, uintX_t sh_flags)
+ : OutputSectionBase<ELFT::Is64Bits>(Name, sh_type, sh_flags),
+ PltSec(PltSec), GotSec(GotSec) {}
+
+ void addChunk(InputSection<ELFT> *C);
+ void writeTo(uint8_t *Buf) override;
+
+ template <bool isRela>
+ void relocate(uint8_t *Buf,
+ llvm::iterator_range<
+ const llvm::object::Elf_Rel_Impl<ELFT, isRela> *> Rels,
+ const ObjectFile<ELFT> &File, uintX_t BaseAddr);
+
+ void relocateOne(uint8_t *Buf, const Elf_Rela &Rel, uint32_t Type,
+ uintX_t BaseAddr, uintX_t SymVA);
+ void relocateOne(uint8_t *Buf, const Elf_Rel &Rel, uint32_t Type,
+ uintX_t BaseAddr, uintX_t SymVA);
+
+private:
+ std::vector<InputSection<ELFT> *> Chunks;
+ const PltSection<ELFT> &PltSec;
+ const GotSection<ELFT> &GotSec;
+};
+
+template <bool Is64Bits>
+class InterpSection final : public OutputSectionBase<Is64Bits> {
+public:
+ InterpSection();
+
+ void writeTo(uint8_t *Buf);
+};
+
+template <bool Is64Bits>
+class StringTableSection final : public OutputSectionBase<Is64Bits> {
+public:
+ typedef typename OutputSectionBase<Is64Bits>::uintX_t uintX_t;
+ StringTableSection(bool Dynamic)
+ : OutputSectionBase<Is64Bits>(
+ Dynamic ? ".dynstr" : ".strtab", llvm::ELF::SHT_STRTAB,
+ Dynamic ? (uintX_t)llvm::ELF::SHF_ALLOC : 0),
+ Dynamic(Dynamic) {
+ this->Header.sh_addralign = 1;
+ }
+
+ void add(StringRef S) { StrTabBuilder.add(S); }
+ size_t getFileOff(StringRef S) const { return StrTabBuilder.getOffset(S); }
+ StringRef data() const { return StrTabBuilder.data(); }
+ void writeTo(uint8_t *Buf) override;
+
+ void finalize() override {
+ StrTabBuilder.finalize(llvm::StringTableBuilder::ELF);
+ this->Header.sh_size = StrTabBuilder.data().size();
+ }
+
+ bool isDynamic() const { return Dynamic; }
+
+private:
+ const bool Dynamic;
+ llvm::StringTableBuilder StrTabBuilder;
+};
+
+template <class ELFT>
+class HashTableSection final : public OutputSectionBase<ELFT::Is64Bits> {
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word;
+
+public:
+ HashTableSection(SymbolTableSection<ELFT> &DynSymSec)
+ : OutputSectionBase<ELFT::Is64Bits>(".hash", llvm::ELF::SHT_HASH,
+ llvm::ELF::SHF_ALLOC),
+ DynSymSec(DynSymSec) {
+ this->Header.sh_entsize = sizeof(Elf_Word);
+ this->Header.sh_addralign = sizeof(Elf_Word);
+ }
+
+ void addSymbol(SymbolBody *S);
+
+ void finalize() override {
+ this->Header.sh_link = DynSymSec.getSectionIndex();
+
+ assert(DynSymSec.getNumSymbols() == Hashes.size() + 1);
+ unsigned NumEntries = 2; // nbucket and nchain.
+ NumEntries += DynSymSec.getNumSymbols(); // The chain entries.
+
+ // Create as many buckets as there are symbols.
+ // FIXME: This is simplistic. We can try to optimize it, but implementing
+ // support for SHT_GNU_HASH is probably even more profitable.
+ NumEntries += DynSymSec.getNumSymbols();
+ this->Header.sh_size = NumEntries * sizeof(Elf_Word);
+ }
+
+ void writeTo(uint8_t *Buf) override {
+ unsigned NumSymbols = DynSymSec.getNumSymbols();
+ auto *P = reinterpret_cast<Elf_Word *>(Buf);
+ *P++ = NumSymbols; // nbucket
+ *P++ = NumSymbols; // nchain
+
+ Elf_Word *Buckets = P;
+ Elf_Word *Chains = P + NumSymbols;
+
+ for (unsigned I = 1; I < NumSymbols; ++I) {
+ uint32_t Hash = Hashes[I - 1] % NumSymbols;
+ Chains[I] = Buckets[Hash];
+ Buckets[Hash] = I;
+ }
+ }
+
+ SymbolTableSection<ELFT> &getDynSymSec() { return DynSymSec; }
+
+private:
+ uint32_t hash(StringRef Name) {
+ uint32_t H = 0;
+ for (char C : Name) {
+ H = (H << 4) + C;
+ uint32_t G = H & 0xf0000000;
+ if (G)
+ H ^= G >> 24;
+ H &= ~G;
+ }
+ return H;
+ }
+ SymbolTableSection<ELFT> &DynSymSec;
+ std::vector<uint32_t> Hashes;
+};
+
+template <class ELFT>
+class DynamicSection final : public OutputSectionBase<ELFT::Is64Bits> {
+ typedef OutputSectionBase<ELFT::Is64Bits> Base;
+ typedef typename Base::HeaderT HeaderT;
+
+public:
+ DynamicSection(SymbolTable &SymTab, HashTableSection<ELFT> &HashSec,
+ RelocationSection<ELFT> &RelaDynSec)
+ : OutputSectionBase<ELFT::Is64Bits>(".dynamic", llvm::ELF::SHT_DYNAMIC,
+ llvm::ELF::SHF_ALLOC |
+ llvm::ELF::SHF_WRITE),
+ HashSec(HashSec), DynSymSec(HashSec.getDynSymSec()),
+ DynStrSec(DynSymSec.getStrTabSec()), RelaDynSec(RelaDynSec),
+ SymTab(SymTab) {
+ typename Base::HeaderT &Header = this->Header;
+ Header.sh_addralign = ELFT::Is64Bits ? 8 : 4;
+ Header.sh_entsize = ELFT::Is64Bits ? 16 : 8;
+ }
+
+ void finalize() override;
+ void writeTo(uint8_t *Buf) override;
+
+private:
+ HashTableSection<ELFT> &HashSec;
+ SymbolTableSection<ELFT> &DynSymSec;
+ StringTableSection<ELFT::Is64Bits> &DynStrSec;
+ RelocationSection<ELFT> &RelaDynSec;
+ SymbolTable &SymTab;
+};
+}
+}
+#endif
Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=248214&r1=248213&r2=248214&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Mon Sep 21 16:38:08 2015
@@ -8,17 +8,11 @@
//===----------------------------------------------------------------------===//
#include "Writer.h"
-#include "Chunks.h"
#include "Config.h"
-#include "Error.h"
-#include "Symbols.h"
+#include "OutputSections.h"
#include "SymbolTable.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Support/FileOutputBuffer.h"
-#include "llvm/Support/raw_ostream.h"
using namespace llvm;
using namespace llvm::ELF;
@@ -39,525 +33,6 @@ static const int PageSize = 4096;
static const int VAStart = 0x10000;
namespace {
-// OutputSection represents a section in an output file. It's a
-// container of chunks. OutputSection and Chunk are 1:N relationship.
-// Chunks cannot belong to more than one OutputSections. The writer
-// creates multiple OutputSections and assign them unique,
-// non-overlapping file offsets and VAs.
-template <bool Is64Bits> class OutputSectionBase {
-public:
- typedef
- typename std::conditional<Is64Bits, Elf64_Dyn, Elf32_Dyn>::type Elf_Dyn;
- typedef typename std::conditional<Is64Bits, uint64_t, uint32_t>::type uintX_t;
- typedef
- typename std::conditional<Is64Bits, Elf64_Shdr, Elf32_Shdr>::type HeaderT;
-
- OutputSectionBase(StringRef Name, uint32_t sh_type, uintX_t sh_flags)
- : Name(Name) {
- memset(&Header, 0, sizeof(HeaderT));
- Header.sh_type = sh_type;
- Header.sh_flags = sh_flags;
- }
- void setVA(uintX_t VA) { Header.sh_addr = VA; }
- uintX_t getVA() const { return Header.sh_addr; }
- void setFileOffset(uintX_t Off) { Header.sh_offset = Off; }
- template <endianness E>
- void writeHeaderTo(typename ELFFile<ELFType<E, Is64Bits>>::Elf_Shdr *SHdr);
- StringRef getName() { return Name; }
- void setNameOffset(uintX_t Offset) { Header.sh_name = Offset; }
-
- unsigned getSectionIndex() const { return SectionIndex; }
- void setSectionIndex(unsigned I) { SectionIndex = I; }
-
- // Returns the size of the section in the output file.
- uintX_t getSize() { return Header.sh_size; }
- void setSize(uintX_t Val) { Header.sh_size = Val; }
- uintX_t getFlags() { return Header.sh_flags; }
- uintX_t getFileOff() { return Header.sh_offset; }
- uintX_t getAlign() {
- // The ELF spec states that a value of 0 means the section has no alignment
- // constraits.
- return std::max<uintX_t>(Header.sh_addralign, 1);
- }
- uint32_t getType() { return Header.sh_type; }
-
- static unsigned getAddrSize() { return Is64Bits ? 8 : 4; }
-
- virtual void finalize() {}
- virtual void writeTo(uint8_t *Buf) = 0;
-
-protected:
- StringRef Name;
- HeaderT Header;
- unsigned SectionIndex;
- ~OutputSectionBase() = default;
-};
-template <class ELFT> class SymbolTableSection;
-
-template <class ELFT> struct DynamicReloc {
- typedef typename ELFFile<ELFT>::Elf_Rel Elf_Rel;
- const InputSection<ELFT> &C;
- const Elf_Rel &RI;
-};
-
-static bool relocNeedsPLT(uint32_t Type) {
- switch (Type) {
- default:
- return false;
- case R_X86_64_PLT32:
- return true;
- }
-}
-
-static bool relocNeedsGOT(uint32_t Type) {
- if (relocNeedsPLT(Type))
- return true;
- switch (Type) {
- default:
- return false;
- case R_X86_64_GOTPCREL:
- return true;
- }
-}
-
-template <class ELFT>
-class GotSection final : public OutputSectionBase<ELFT::Is64Bits> {
- typedef OutputSectionBase<ELFT::Is64Bits> Base;
- typedef typename Base::uintX_t uintX_t;
-
-public:
- GotSection()
- : OutputSectionBase<ELFT::Is64Bits>(".got", SHT_PROGBITS,
- SHF_ALLOC | SHF_WRITE) {
- this->Header.sh_addralign = this->getAddrSize();
- }
- void finalize() override {
- this->Header.sh_size = Entries.size() * this->getAddrSize();
- }
- void writeTo(uint8_t *Buf) override {}
- void addEntry(SymbolBody *Sym) {
- Sym->setGotIndex(Entries.size());
- Entries.push_back(Sym);
- }
- bool empty() const { return Entries.empty(); }
- uintX_t getEntryAddr(const SymbolBody &B) const {
- return this->getVA() + B.getGotIndex() * this->getAddrSize();
- }
-
-private:
- std::vector<const SymbolBody *> Entries;
-};
-
-template <class ELFT>
-class PltSection final : public OutputSectionBase<ELFT::Is64Bits> {
- typedef OutputSectionBase<ELFT::Is64Bits> Base;
- typedef typename Base::uintX_t uintX_t;
-
-public:
- PltSection(const GotSection<ELFT> &GotSec)
- : OutputSectionBase<ELFT::Is64Bits>(".plt", SHT_PROGBITS,
- SHF_ALLOC | SHF_EXECINSTR),
- GotSec(GotSec) {
- this->Header.sh_addralign = 16;
- }
- void finalize() override {
- this->Header.sh_size = Entries.size() * EntrySize;
- }
- void writeTo(uint8_t *Buf) override {
- uintptr_t Start = reinterpret_cast<uintptr_t>(Buf);
- ArrayRef<uint8_t> Jmp = {0xff, 0x25}; // jmpq *val(%rip)
- for (const SymbolBody *E : Entries) {
- uintptr_t InstPos = reinterpret_cast<uintptr_t>(Buf);
-
- memcpy(Buf, Jmp.data(), Jmp.size());
- Buf += Jmp.size();
-
- uintptr_t OffsetInPLT = (InstPos + 6) - Start;
- uintptr_t Delta = GotSec.getEntryAddr(*E) - (this->getVA() + OffsetInPLT);
- assert(isInt<32>(Delta));
- support::endian::write32le(Buf, Delta);
- Buf += 4;
-
- *Buf = 0x90; // nop
- ++Buf;
- *Buf = 0x90; // nop
- ++Buf;
- }
- }
- void addEntry(SymbolBody *Sym) {
- Sym->setPltIndex(Entries.size());
- Entries.push_back(Sym);
- }
- bool empty() const { return Entries.empty(); }
- uintX_t getEntryAddr(const SymbolBody &B) const {
- return this->getVA() + B.getPltIndex() * EntrySize;
- }
-
- static const unsigned EntrySize = 8;
-
-private:
- std::vector<const SymbolBody *> Entries;
- const GotSection<ELFT> &GotSec;
-};
-
-template <class ELFT>
-class RelocationSection final : public OutputSectionBase<ELFT::Is64Bits> {
- typedef typename ELFFile<ELFT>::Elf_Rel Elf_Rel;
- typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
-
-public:
- RelocationSection(SymbolTableSection<ELFT> &DynSymSec,
- const GotSection<ELFT> &GotSec, bool IsRela)
- : OutputSectionBase<ELFT::Is64Bits>(IsRela ? ".rela.dyn" : ".rel.dyn",
- IsRela ? SHT_RELA : SHT_REL,
- SHF_ALLOC),
- DynSymSec(DynSymSec), GotSec(GotSec), IsRela(IsRela) {
- this->Header.sh_entsize = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
- this->Header.sh_addralign = ELFT::Is64Bits ? 8 : 4;
- }
-
- void addReloc(const DynamicReloc<ELFT> &Reloc) { Relocs.push_back(Reloc); }
- void finalize() override {
- this->Header.sh_link = DynSymSec.getSectionIndex();
- this->Header.sh_size = Relocs.size() * this->Header.sh_entsize;
- }
- void writeTo(uint8_t *Buf) override {
- auto *P = reinterpret_cast<Elf_Rela *>(Buf);
- bool IsMips64EL = Relocs[0].C.getFile()->getObj()->isMips64EL();
- for (const DynamicReloc<ELFT> &Rel : Relocs) {
- const InputSection<ELFT> &C = Rel.C;
- const Elf_Rel &RI = Rel.RI;
- OutputSection<ELFT> *Out = C.getOutputSection();
- uint32_t SymIndex = RI.getSymbol(IsMips64EL);
- const SymbolBody *Body = C.getFile()->getSymbolBody(SymIndex);
- uint32_t Type = RI.getType(IsMips64EL);
- if (relocNeedsGOT(Type)) {
- P->r_offset = GotSec.getEntryAddr(*Body);
- P->setSymbolAndType(Body->getDynamicSymbolTableIndex(),
- R_X86_64_GLOB_DAT, IsMips64EL);
- } else {
- P->r_offset = RI.r_offset + C.getOutputSectionOff() + Out->getVA();
- P->setSymbolAndType(Body->getDynamicSymbolTableIndex(), Type,
- IsMips64EL);
- if (IsRela)
- P->r_addend = static_cast<const Elf_Rela &>(RI).r_addend;
- }
-
- ++P;
- }
- }
- bool hasRelocs() const { return !Relocs.empty(); }
- bool isRela() const { return IsRela; }
-
-private:
- std::vector<DynamicReloc<ELFT>> Relocs;
- SymbolTableSection<ELFT> &DynSymSec;
- const GotSection<ELFT> &GotSec;
- const bool IsRela;
-};
-}
-
-template <class ELFT>
-class lld::elf2::OutputSection final
- : public OutputSectionBase<ELFT::Is64Bits> {
-public:
- typedef typename OutputSectionBase<ELFT::Is64Bits>::uintX_t uintX_t;
- typedef typename ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
- typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
- typedef typename ELFFile<ELFT>::Elf_Rel Elf_Rel;
- typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
- OutputSection(const PltSection<ELFT> &PltSec, const GotSection<ELFT> &GotSec,
- StringRef Name, uint32_t sh_type, uintX_t sh_flags)
- : OutputSectionBase<ELFT::Is64Bits>(Name, sh_type, sh_flags),
- PltSec(PltSec), GotSec(GotSec) {}
-
- void addChunk(InputSection<ELFT> *C);
- void writeTo(uint8_t *Buf) override;
-
- template <bool isRela>
- void relocate(uint8_t *Buf,
- iterator_range<const Elf_Rel_Impl<ELFT, isRela> *> Rels,
- const ObjectFile<ELFT> &File, uintX_t BaseAddr);
-
- void relocateOne(uint8_t *Buf, const Elf_Rela &Rel, uint32_t Type,
- uintX_t BaseAddr, uintX_t SymVA);
- void relocateOne(uint8_t *Buf, const Elf_Rel &Rel, uint32_t Type,
- uintX_t BaseAddr, uintX_t SymVA);
-
-private:
- std::vector<InputSection<ELFT> *> Chunks;
- const PltSection<ELFT> &PltSec;
- const GotSection<ELFT> &GotSec;
-};
-
-namespace {
-template <bool Is64Bits>
-class InterpSection final : public OutputSectionBase<Is64Bits> {
-public:
- InterpSection()
- : OutputSectionBase<Is64Bits>(".interp", SHT_PROGBITS, SHF_ALLOC) {
- this->Header.sh_size = Config->DynamicLinker.size() + 1;
- this->Header.sh_addralign = 1;
- }
-
- void writeTo(uint8_t *Buf) override {
- memcpy(Buf, Config->DynamicLinker.data(), Config->DynamicLinker.size());
- }
-};
-
-template <bool Is64Bits>
-class StringTableSection final : public OutputSectionBase<Is64Bits> {
-public:
- typedef typename OutputSectionBase<Is64Bits>::uintX_t uintX_t;
- StringTableSection(bool Dynamic)
- : OutputSectionBase<Is64Bits>(Dynamic ? ".dynstr" : ".strtab", SHT_STRTAB,
- Dynamic ? (uintX_t)SHF_ALLOC : 0),
- Dynamic(Dynamic) {
- this->Header.sh_addralign = 1;
- }
-
- void add(StringRef S) { StrTabBuilder.add(S); }
- size_t getFileOff(StringRef S) const { return StrTabBuilder.getOffset(S); }
- StringRef data() const { return StrTabBuilder.data(); }
- void writeTo(uint8_t *Buf) override;
-
- void finalize() override {
- StrTabBuilder.finalize(StringTableBuilder::ELF);
- this->Header.sh_size = StrTabBuilder.data().size();
- }
-
- bool isDynamic() const { return Dynamic; }
-
-private:
- const bool Dynamic;
- llvm::StringTableBuilder StrTabBuilder;
-};
-
-template <class ELFT> class Writer;
-
-template <class ELFT>
-class SymbolTableSection final : public OutputSectionBase<ELFT::Is64Bits> {
-public:
- typedef typename ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
- typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
- typedef typename ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;
- typedef typename OutputSectionBase<ELFT::Is64Bits>::uintX_t uintX_t;
- SymbolTableSection(Writer<ELFT> &W, SymbolTable &Table,
- StringTableSection<ELFT::Is64Bits> &StrTabSec)
- : OutputSectionBase<ELFT::Is64Bits>(
- StrTabSec.isDynamic() ? ".dynsym" : ".symtab",
- StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB,
- StrTabSec.isDynamic() ? (uintX_t)SHF_ALLOC : 0),
- Table(Table), StrTabSec(StrTabSec), W(W) {
- typedef OutputSectionBase<ELFT::Is64Bits> Base;
- typename Base::HeaderT &Header = this->Header;
-
- Header.sh_entsize = sizeof(Elf_Sym);
- Header.sh_addralign = ELFT::Is64Bits ? 8 : 4;
- }
-
- void finalize() override {
- this->Header.sh_size = getNumSymbols() * sizeof(Elf_Sym);
- this->Header.sh_link = StrTabSec.getSectionIndex();
- this->Header.sh_info = NumLocals + 1;
- }
-
- void writeTo(uint8_t *Buf) override;
-
- const SymbolTable &getSymTable() const { return Table; }
-
- void addSymbol(StringRef Name, bool isLocal = false) {
- StrTabSec.add(Name);
- ++NumVisible;
- if (isLocal)
- ++NumLocals;
- }
-
- StringTableSection<ELFT::Is64Bits> &getStrTabSec() { return StrTabSec; }
- unsigned getNumSymbols() const { return NumVisible + 1; }
-
-private:
- SymbolTable &Table;
- StringTableSection<ELFT::Is64Bits> &StrTabSec;
- unsigned NumVisible = 0;
- unsigned NumLocals = 0;
- const Writer<ELFT> &W;
-};
-
-template <class ELFT>
-class HashTableSection final : public OutputSectionBase<ELFT::Is64Bits> {
- typedef typename ELFFile<ELFT>::Elf_Word Elf_Word;
-
-public:
- HashTableSection(SymbolTableSection<ELFT> &DynSymSec)
- : OutputSectionBase<ELFT::Is64Bits>(".hash", SHT_HASH, SHF_ALLOC),
- DynSymSec(DynSymSec) {
- this->Header.sh_entsize = sizeof(Elf_Word);
- this->Header.sh_addralign = sizeof(Elf_Word);
- }
-
- void addSymbol(SymbolBody *S) {
- StringRef Name = S->getName();
- DynSymSec.addSymbol(Name);
- Hashes.push_back(hash(Name));
- S->setDynamicSymbolTableIndex(Hashes.size());
- }
-
- void finalize() override {
- this->Header.sh_link = DynSymSec.getSectionIndex();
-
- assert(DynSymSec.getNumSymbols() == Hashes.size() + 1);
- unsigned NumEntries = 2; // nbucket and nchain.
- NumEntries += DynSymSec.getNumSymbols(); // The chain entries.
-
- // Create as many buckets as there are symbols.
- // FIXME: This is simplistic. We can try to optimize it, but implementing
- // support for SHT_GNU_HASH is probably even more profitable.
- NumEntries += DynSymSec.getNumSymbols();
- this->Header.sh_size = NumEntries * sizeof(Elf_Word);
- }
-
- void writeTo(uint8_t *Buf) override {
- unsigned NumSymbols = DynSymSec.getNumSymbols();
- auto *P = reinterpret_cast<Elf_Word *>(Buf);
- *P++ = NumSymbols; // nbucket
- *P++ = NumSymbols; // nchain
-
- Elf_Word *Buckets = P;
- Elf_Word *Chains = P + NumSymbols;
-
- for (unsigned I = 1; I < NumSymbols; ++I) {
- uint32_t Hash = Hashes[I - 1] % NumSymbols;
- Chains[I] = Buckets[Hash];
- Buckets[Hash] = I;
- }
- }
-
- SymbolTableSection<ELFT> &getDynSymSec() { return DynSymSec; }
-
-private:
- uint32_t hash(StringRef Name) {
- uint32_t H = 0;
- for (char C : Name) {
- H = (H << 4) + C;
- uint32_t G = H & 0xf0000000;
- if (G)
- H ^= G >> 24;
- H &= ~G;
- }
- return H;
- }
- SymbolTableSection<ELFT> &DynSymSec;
- std::vector<uint32_t> Hashes;
-};
-
-template <class ELFT>
-class DynamicSection final : public OutputSectionBase<ELFT::Is64Bits> {
- typedef OutputSectionBase<ELFT::Is64Bits> Base;
- typedef typename Base::HeaderT HeaderT;
- typedef typename Base::Elf_Dyn Elf_Dyn;
-
-public:
- DynamicSection(SymbolTable &SymTab, HashTableSection<ELFT> &HashSec,
- RelocationSection<ELFT> &RelaDynSec)
- : OutputSectionBase<ELFT::Is64Bits>(".dynamic", SHT_DYNAMIC,
- SHF_ALLOC | SHF_WRITE),
- HashSec(HashSec), DynSymSec(HashSec.getDynSymSec()),
- DynStrSec(DynSymSec.getStrTabSec()), RelaDynSec(RelaDynSec),
- SymTab(SymTab) {
- typename Base::HeaderT &Header = this->Header;
- Header.sh_addralign = ELFT::Is64Bits ? 8 : 4;
- Header.sh_entsize = ELFT::Is64Bits ? 16 : 8;
- }
-
- void finalize() override {
- typename Base::HeaderT &Header = this->Header;
- Header.sh_link = DynStrSec.getSectionIndex();
-
- unsigned NumEntries = 0;
- if (RelaDynSec.hasRelocs()) {
- ++NumEntries; // DT_RELA / DT_REL
- ++NumEntries; // DT_RELASZ / DTRELSZ
- }
- ++NumEntries; // DT_SYMTAB
- ++NumEntries; // DT_STRTAB
- ++NumEntries; // DT_STRSZ
- ++NumEntries; // DT_HASH
-
- StringRef RPath = Config->RPath;
- if (!RPath.empty()) {
- ++NumEntries; // DT_RUNPATH
- DynStrSec.add(RPath);
- }
-
- const std::vector<std::unique_ptr<SharedFileBase>> &SharedFiles =
- SymTab.getSharedFiles();
- for (const std::unique_ptr<SharedFileBase> &File : SharedFiles)
- DynStrSec.add(File->getName());
- NumEntries += SharedFiles.size();
-
- ++NumEntries; // DT_NULL
-
- Header.sh_size = NumEntries * Header.sh_entsize;
- }
-
- void writeTo(uint8_t *Buf) override {
- auto *P = reinterpret_cast<Elf_Dyn *>(Buf);
-
- if (RelaDynSec.hasRelocs()) {
- bool IsRela = RelaDynSec.isRela();
- P->d_tag = IsRela ? DT_RELA : DT_REL;
- P->d_un.d_ptr = RelaDynSec.getVA();
- ++P;
-
- P->d_tag = IsRela ? DT_RELASZ : DT_RELSZ;
- P->d_un.d_val = RelaDynSec.getSize();
- ++P;
- }
-
- P->d_tag = DT_SYMTAB;
- P->d_un.d_ptr = DynSymSec.getVA();
- ++P;
-
- P->d_tag = DT_STRTAB;
- P->d_un.d_ptr = DynStrSec.getVA();
- ++P;
-
- P->d_tag = DT_STRSZ;
- P->d_un.d_val = DynStrSec.data().size();
- ++P;
-
- P->d_tag = DT_HASH;
- P->d_un.d_ptr = HashSec.getVA();
- ++P;
-
- StringRef RPath = Config->RPath;
- if (!RPath.empty()) {
- P->d_tag = DT_RUNPATH;
- P->d_un.d_val = DynStrSec.getFileOff(RPath);
- ++P;
- }
-
- const std::vector<std::unique_ptr<SharedFileBase>> &SharedFiles =
- SymTab.getSharedFiles();
- for (const std::unique_ptr<SharedFileBase> &File : SharedFiles) {
- P->d_tag = DT_NEEDED;
- P->d_un.d_val = DynStrSec.getFileOff(File->getName());
- ++P;
- }
-
- P->d_tag = DT_NULL;
- P->d_un.d_val = 0;
- ++P;
- }
-
-private:
- HashTableSection<ELFT> &HashSec;
- SymbolTableSection<ELFT> &DynSymSec;
- StringTableSection<ELFT::Is64Bits> &DynStrSec;
- RelocationSection<ELFT> &RelaDynSec;
- SymbolTable &SymTab;
-};
static uint32_t convertSectionFlagsToPHDRFlags(uint64_t Flags) {
uint32_t Ret = PF_R;
@@ -621,16 +96,11 @@ public:
typedef typename ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;
typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
Writer(SymbolTable *T)
- : SymTabSec(*this, *T, StrTabSec), DynSymSec(*this, *T, DynStrSec),
+ : SymTabSec(*T, StrTabSec), DynSymSec(*T, DynStrSec),
RelaDynSec(DynSymSec, GotSec, T->shouldUseRela()), PltSec(GotSec),
HashSec(DynSymSec), DynamicSec(*T, HashSec, RelaDynSec) {}
void run();
- const OutputSection<ELFT> &getBSS() const {
- assert(BSSSec);
- return *BSSSec;
- }
-
private:
void createSections();
template <bool isRela>
@@ -669,8 +139,8 @@ private:
StringTableSection<ELFT::Is64Bits> StrTabSec = { /*dynamic=*/false };
StringTableSection<ELFT::Is64Bits> DynStrSec = { /*dynamic=*/true };
- SymbolTableSection<ELFT> SymTabSec;
- SymbolTableSection<ELFT> DynSymSec;
+ lld::elf2::SymbolTableSection<ELFT> SymTabSec;
+ lld::elf2::SymbolTableSection<ELFT> DynSymSec;
RelocationSection<ELFT> RelaDynSec;
@@ -712,174 +182,6 @@ template <class ELFT> void Writer<ELFT>:
}
template <class ELFT>
-void OutputSection<ELFT>::addChunk(InputSection<ELFT> *C) {
- Chunks.push_back(C);
- C->setOutputSection(this);
- uint32_t Align = C->getAlign();
- if (Align > this->Header.sh_addralign)
- this->Header.sh_addralign = Align;
-
- uintX_t Off = this->Header.sh_size;
- Off = RoundUpToAlignment(Off, Align);
- C->setOutputSectionOff(Off);
- Off += C->getSize();
- this->Header.sh_size = Off;
-}
-
-template <class ELFT>
-static typename ELFFile<ELFT>::uintX_t
-getSymVA(const DefinedRegular<ELFT> *DR) {
- const InputSection<ELFT> *SC = &DR->Section;
- OutputSection<ELFT> *OS = SC->getOutputSection();
- return OS->getVA() + SC->getOutputSectionOff() + DR->Sym.st_value;
-}
-
-template <class ELFT>
-static typename ELFFile<ELFT>::uintX_t
-getLocalSymVA(const typename ELFFile<ELFT>::Elf_Sym *Sym,
- const ObjectFile<ELFT> &File) {
- uint32_t SecIndex = Sym->st_shndx;
-
- if (SecIndex == SHN_XINDEX)
- SecIndex = File.getObj()->getExtendedSymbolTableIndex(
- Sym, File.getSymbolTable(), File.getSymbolTableShndx());
- ArrayRef<InputSection<ELFT> *> Chunks = File.getChunks();
- InputSection<ELFT> *Section = Chunks[SecIndex];
- OutputSection<ELFT> *Out = Section->getOutputSection();
- return Out->getVA() + Section->getOutputSectionOff() + Sym->st_value;
-}
-
-template <class ELFT>
-void OutputSection<ELFT>::relocateOne(uint8_t *Buf, const Elf_Rel &Rel,
- uint32_t Type, uintX_t BaseAddr,
- uintX_t SymVA) {
- uintX_t Offset = Rel.r_offset;
- uint8_t *Location = Buf + Offset;
- switch (Type) {
- case R_386_32:
- support::endian::write32le(Location, SymVA);
- break;
- default:
- llvm::errs() << Twine("unrecognized reloc ") + Twine(Type) << '\n';
- break;
- }
-}
-
-template <class ELFT>
-void OutputSection<ELFT>::relocateOne(uint8_t *Buf, const Elf_Rela &Rel,
- uint32_t Type, uintX_t BaseAddr,
- uintX_t SymVA) {
- uintX_t Offset = Rel.r_offset;
- uint8_t *Location = Buf + Offset;
- switch (Type) {
- case R_X86_64_PC32:
- support::endian::write32le(Location,
- SymVA + (Rel.r_addend - (BaseAddr + Offset)));
- break;
- case R_X86_64_64:
- support::endian::write64le(Location, SymVA + Rel.r_addend);
- break;
- case R_X86_64_32: {
- case R_X86_64_32S:
- uint64_t VA = SymVA + Rel.r_addend;
- if (Type == R_X86_64_32 && !isUInt<32>(VA))
- error("R_X86_64_32 out of range");
- else if (!isInt<32>(VA))
- error("R_X86_64_32S out of range");
-
- support::endian::write32le(Location, VA);
- break;
- }
- default:
- llvm::errs() << Twine("unrecognized reloc ") + Twine(Type) << '\n';
- break;
- }
-}
-
-template <class ELFT>
-template <bool isRela>
-void OutputSection<ELFT>::relocate(
- uint8_t *Buf, iterator_range<const Elf_Rel_Impl<ELFT, isRela> *> Rels,
- const ObjectFile<ELFT> &File, uintX_t BaseAddr) {
- typedef Elf_Rel_Impl<ELFT, isRela> RelType;
- bool IsMips64EL = File.getObj()->isMips64EL();
- for (const RelType &RI : Rels) {
- uint32_t SymIndex = RI.getSymbol(IsMips64EL);
- uint32_t Type = RI.getType(IsMips64EL);
- uintX_t SymVA;
-
- // Handle relocations for local symbols -- they never get
- // resolved so we don't allocate a SymbolBody.
- const Elf_Shdr *SymTab = File.getSymbolTable();
- if (SymIndex < SymTab->sh_info) {
- const Elf_Sym *Sym = File.getObj()->getRelocationSymbol(&RI, SymTab);
- if (!Sym)
- continue;
- SymVA = getLocalSymVA(Sym, File);
- } else {
- const SymbolBody *Body = File.getSymbolBody(SymIndex);
- if (!Body)
- continue;
- switch (Body->kind()) {
- case SymbolBody::DefinedRegularKind:
- SymVA = getSymVA<ELFT>(cast<DefinedRegular<ELFT>>(Body));
- break;
- case SymbolBody::DefinedAbsoluteKind:
- SymVA = cast<DefinedAbsolute<ELFT>>(Body)->Sym.st_value;
- break;
- case SymbolBody::DefinedCommonKind: {
- auto *DC = cast<DefinedCommon<ELFT>>(Body);
- SymVA = DC->OutputSec->getVA() + DC->OffsetInBSS;
- break;
- }
- case SymbolBody::SharedKind:
- if (relocNeedsPLT(Type)) {
- SymVA = PltSec.getEntryAddr(*Body);
- Type = R_X86_64_PC32;
- } else if (relocNeedsGOT(Type)) {
- SymVA = GotSec.getEntryAddr(*Body);
- Type = R_X86_64_PC32;
- } else {
- continue;
- }
- break;
- case SymbolBody::UndefinedKind:
- assert(Body->isWeak() && "Undefined symbol reached writer");
- SymVA = 0;
- break;
- case SymbolBody::LazyKind:
- llvm_unreachable("Lazy symbol reached writer");
- }
- }
-
- relocateOne(Buf, RI, Type, BaseAddr, SymVA);
- }
-}
-
-template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
- for (InputSection<ELFT> *C : Chunks) {
- C->writeTo(Buf);
- const ObjectFile<ELFT> *File = C->getFile();
- ELFFile<ELFT> *EObj = File->getObj();
- uint8_t *Base = Buf + C->getOutputSectionOff();
- uintX_t BaseAddr = this->getVA() + C->getOutputSectionOff();
- // Iterate over all relocation sections that apply to this section.
- for (const Elf_Shdr *RelSec : C->RelocSections) {
- if (RelSec->sh_type == SHT_RELA)
- relocate(Base, EObj->relas(RelSec), *File, BaseAddr);
- else
- relocate(Base, EObj->rels(RelSec), *File, BaseAddr);
- }
- }
-}
-
-template <bool Is64Bits>
-void StringTableSection<Is64Bits>::writeTo(uint8_t *Buf) {
- StringRef Data = StrTabBuilder.data();
- memcpy(Buf, Data.data(), Data.size());
-}
-
-template <class ELFT>
static int compareSym(const typename ELFFile<ELFT>::Elf_Sym *A,
const typename ELFFile<ELFT>::Elf_Sym *B) {
uint32_t AN = A->st_name;
@@ -888,126 +190,6 @@ static int compareSym(const typename ELF
return AN - BN;
}
-static bool includeInSymtab(const SymbolBody &B) {
- if (B.isLazy())
- return false;
- if (!B.isUsedInRegularObj())
- return false;
- uint8_t V = B.getMostConstrainingVisibility();
- if (V != STV_DEFAULT && V != STV_PROTECTED)
- return false;
- return true;
-}
-
-template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) {
- const OutputSection<ELFT> *Out = nullptr;
- const InputSection<ELFT> *Section = nullptr;
- Buf += sizeof(Elf_Sym);
-
- // All symbols with STB_LOCAL binding precede the weak and global symbols.
- // .dynsym only contains global symbols.
- if (!Config->DiscardAll && !StrTabSec.isDynamic()) {
- for (const std::unique_ptr<ObjectFileBase> &FileB :
- Table.getObjectFiles()) {
- auto &File = cast<ObjectFile<ELFT>>(*FileB);
- Elf_Sym_Range Syms = File.getLocalSymbols();
- for (const Elf_Sym &Sym : Syms) {
- auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
- uint32_t SecIndex = Sym.st_shndx;
- ErrorOr<StringRef> SymName = Sym.getName(File.getStringTable());
- if (Config->DiscardLocals && SymName->startswith(".L"))
- continue;
- ESym->st_name = (SymName) ? StrTabSec.getFileOff(*SymName) : 0;
- ESym->st_size = Sym.st_size;
- ESym->setBindingAndType(Sym.getBinding(), Sym.getType());
- if (SecIndex == SHN_XINDEX)
- SecIndex = File.getObj()->getExtendedSymbolTableIndex(
- &Sym, File.getSymbolTable(), File.getSymbolTableShndx());
- ArrayRef<InputSection<ELFT> *> Chunks = File.getChunks();
- Section = Chunks[SecIndex];
- assert(Section != nullptr);
- Out = Section->getOutputSection();
- assert(Out != nullptr);
- ESym->st_shndx = Out->getSectionIndex();
- ESym->st_value =
- Out->getVA() + Section->getOutputSectionOff() + Sym.st_value;
- Buf += sizeof(Elf_Sym);
- }
- }
- }
-
- for (auto &P : Table.getSymbols()) {
- StringRef Name = P.first;
- Symbol *Sym = P.second;
- SymbolBody *Body = Sym->Body;
- if (!includeInSymtab(*Body))
- continue;
- const Elf_Sym &InputSym = cast<ELFSymbolBody<ELFT>>(Body)->Sym;
-
- auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
- ESym->st_name = StrTabSec.getFileOff(Name);
-
- Out = nullptr;
- Section = nullptr;
-
- switch (Body->kind()) {
- case SymbolBody::DefinedRegularKind:
- Section = &cast<DefinedRegular<ELFT>>(Body)->Section;
- break;
- case SymbolBody::DefinedCommonKind:
- Out = &W.getBSS();
- break;
- case SymbolBody::UndefinedKind:
- case SymbolBody::DefinedAbsoluteKind:
- case SymbolBody::SharedKind:
- break;
- case SymbolBody::LazyKind:
- llvm_unreachable("Lazy symbol got to output symbol table!");
- }
-
- ESym->setBindingAndType(InputSym.getBinding(), InputSym.getType());
- ESym->st_size = InputSym.st_size;
- ESym->setVisibility(Body->getMostConstrainingVisibility());
- if (InputSym.isAbsolute()) {
- ESym->st_shndx = SHN_ABS;
- ESym->st_value = InputSym.st_value;
- }
-
- if (Section)
- Out = Section->getOutputSection();
-
- if (Out) {
- ESym->st_shndx = Out->getSectionIndex();
- uintX_t VA = Out->getVA();
- if (Section)
- VA += Section->getOutputSectionOff();
- if (auto *C = dyn_cast<DefinedCommon<ELFT>>(Body))
- VA += C->OffsetInBSS;
- else
- VA += InputSym.st_value;
- ESym->st_value = VA;
- }
-
- Buf += sizeof(Elf_Sym);
- }
-}
-
-template <bool Is64Bits>
-template <endianness E>
-void OutputSectionBase<Is64Bits>::writeHeaderTo(
- typename ELFFile<ELFType<E, Is64Bits>>::Elf_Shdr *SHdr) {
- SHdr->sh_name = Header.sh_name;
- SHdr->sh_type = Header.sh_type;
- SHdr->sh_flags = Header.sh_flags;
- SHdr->sh_addr = Header.sh_addr;
- SHdr->sh_offset = Header.sh_offset;
- SHdr->sh_size = Header.sh_size;
- SHdr->sh_link = Header.sh_link;
- SHdr->sh_info = Header.sh_info;
- SHdr->sh_addralign = Header.sh_addralign;
- SHdr->sh_entsize = Header.sh_entsize;
-}
-
namespace {
template <bool Is64Bits> struct SectionKey {
typedef typename std::conditional<Is64Bits, uint64_t, uint32_t>::type uintX_t;
@@ -1163,6 +345,9 @@ template <class ELFT> void Writer<ELFT>:
}
BSSSec = getSection(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
+ SymTabSec.setBssSec(BSSSec);
+ DynSymSec.setBssSec(BSSSec);
+
// Sort the common symbols by alignment as an heuristic to pack them better.
std::stable_sort(CommonSymbols.begin(), CommonSymbols.end(), cmpAlign<ELFT>);
uintX_t Off = BSSSec->getSize();
More information about the llvm-commits
mailing list