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.
llvm-svn: 248214
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 00d9989..5253bac 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -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 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 @@
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 @@
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 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 @@
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 @@
}
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();