diff --git a/lld/ELF/Chunks.cpp b/lld/ELF/Chunks.cpp index 22bca359748a..b0829af71e5f 100644 --- a/lld/ELF/Chunks.cpp +++ b/lld/ELF/Chunks.cpp @@ -10,9 +10,13 @@ #include "Chunks.h" #include "Error.h" #include "InputFiles.h" +#include "OutputSections.h" + +#include "llvm/Support/raw_ostream.h" using namespace llvm; using namespace llvm::ELF; +using namespace llvm::object; using namespace lld; using namespace lld::elf2; @@ -21,12 +25,134 @@ template InputSection::InputSection(ObjectFile *F, const Elf_Shdr *Header) : File(F), Header(Header) {} -template void InputSection::writeTo(uint8_t *Buf) { +template +void InputSection::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 +void InputSection::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 +template +void InputSection::relocate( + uint8_t *Buf, iterator_range *> Rels, + const ObjectFile &File, uintX_t BaseAddr, + const PltSection &PltSec, const GotSection &GotSec) { + typedef Elf_Rel_Impl 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(cast>(Body)); + break; + case SymbolBody::DefinedAbsoluteKind: + SymVA = cast>(Body)->Sym.st_value; + break; + case SymbolBody::DefinedCommonKind: { + auto *DC = cast>(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 +void InputSection::writeTo(uint8_t *Buf, const PltSection &PltSec, + const GotSection &GotSec) { if (Header->sh_type == SHT_NOBITS) return; // Copy section contents from source object file to output file. ArrayRef Data = *File->getObj()->getSectionContents(Header); memcpy(Buf + OutputSectionOff, Data.data(), Data.size()); + + const ObjectFile *File = getFile(); + ELFFile *EObj = File->getObj(); + uint8_t *Base = Buf + getOutputSectionOff(); + uintX_t BaseAddr = Out->getVA() + getOutputSectionOff(); + // Iterate over all relocation sections that apply to this section. + for (const Elf_Shdr *RelSec : RelocSections) { + if (RelSec->sh_type == SHT_RELA) + relocate(Base, EObj->relas(RelSec), *File, BaseAddr, PltSec, GotSec); + else + relocate(Base, EObj->rels(RelSec), *File, BaseAddr, PltSec, GotSec); + } } template StringRef InputSection::getSectionName() const { diff --git a/lld/ELF/Chunks.h b/lld/ELF/Chunks.h index 4888b70b4fb6..c0db824367fd 100644 --- a/lld/ELF/Chunks.h +++ b/lld/ELF/Chunks.h @@ -18,12 +18,15 @@ namespace elf2 { template class ObjectFile; template class OutputSection; +template class PltSection; +template class GotSection; // A chunk corresponding a section of an input file. template class InputSection { typedef typename llvm::object::ELFFile::Elf_Shdr Elf_Shdr; typedef typename llvm::object::ELFFile::Elf_Rela Elf_Rela; typedef typename llvm::object::ELFFile::Elf_Rel Elf_Rel; + typedef typename llvm::object::ELFFile::Elf_Sym Elf_Sym; typedef typename llvm::object::ELFFile::uintX_t uintX_t; public: @@ -34,7 +37,8 @@ public: // Write this chunk to a mmap'ed file, assuming Buf is pointing to // beginning of the output section. - void writeTo(uint8_t *Buf); + void writeTo(uint8_t *Buf, const PltSection &PltSec, + const GotSection &GotSec); StringRef getSectionName() const; const Elf_Shdr *getSectionHdr() const { return Header; } @@ -56,6 +60,18 @@ public: SmallVector RelocSections; private: + 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); + + template + void relocate(uint8_t *Buf, + llvm::iterator_range< + const llvm::object::Elf_Rel_Impl *> Rels, + const ObjectFile &File, uintX_t BaseAddr, + const PltSection &PltSec, const GotSection &GotSec); + // The offset from beginning of the output sections this chunk was assigned // to. The writer sets a value. uint64_t OutputSectionOff = 0; diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index a9a1ca2073bd..d625094dbb83 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -259,53 +259,6 @@ void OutputSection::addChunk(InputSection *C) { this->Header.sh_size = Off; } -template -void OutputSection::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 -void OutputSection::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 typename ELFFile::uintX_t lld::elf2::getSymVA(const DefinedRegular *DR) { @@ -329,81 +282,9 @@ lld::elf2::getLocalSymVA(const typename ELFFile::Elf_Sym *Sym, return Out->getVA() + Section->getOutputSectionOff() + Sym->st_value; } -template -template -void OutputSection::relocate( - uint8_t *Buf, iterator_range *> Rels, - const ObjectFile &File, uintX_t BaseAddr) { - typedef Elf_Rel_Impl 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(cast>(Body)); - break; - case SymbolBody::DefinedAbsoluteKind: - SymVA = cast>(Body)->Sym.st_value; - break; - case SymbolBody::DefinedCommonKind: { - auto *DC = cast>(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 void OutputSection::writeTo(uint8_t *Buf) { - for (InputSection *C : Chunks) { - C->writeTo(Buf); - const ObjectFile *File = C->getFile(); - ELFFile *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); - } - } + for (InputSection *C : Chunks) + C->writeTo(Buf, PltSec, GotSec); } template @@ -582,5 +463,21 @@ getSymVA(const DefinedRegular *DR); template typename ELFFile::uintX_t getSymVA(const DefinedRegular *DR); + +template typename ELFFile::uintX_t +lld::elf2::getLocalSymVA(const typename ELFFile::Elf_Sym *Sym, + const ObjectFile &File); + +template typename ELFFile::uintX_t +lld::elf2::getLocalSymVA(const typename ELFFile::Elf_Sym *Sym, + const ObjectFile &File); + +template typename ELFFile::uintX_t +lld::elf2::getLocalSymVA(const typename ELFFile::Elf_Sym *Sym, + const ObjectFile &File); + +template typename ELFFile::uintX_t +lld::elf2::getLocalSymVA(const typename ELFFile::Elf_Sym *Sym, + const ObjectFile &File); } } diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h index 2e1008695766..13a4569e034b 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -245,17 +245,6 @@ public: void addChunk(InputSection *C); void writeTo(uint8_t *Buf) override; - template - void relocate(uint8_t *Buf, - llvm::iterator_range< - const llvm::object::Elf_Rel_Impl *> Rels, - const ObjectFile &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 *> Chunks; const PltSection &PltSec;