diff options
author | Rafael Espindola <rafael.espindola@gmail.com> | 2015-09-21 22:01:00 +0000 |
---|---|---|
committer | Rafael Espindola <rafael.espindola@gmail.com> | 2015-09-21 22:01:00 +0000 |
commit | 4ea00210f2ba9e36451e7b020832a58ecac78aec (patch) | |
tree | 2fb68dbc9b78097a837f1e93c8335cab79aa4619 | |
parent | 5805c4f509427bf2011b076f793dc17591214306 (diff) | |
download | bcm5719-llvm-4ea00210f2ba9e36451e7b020832a58ecac78aec.tar.gz bcm5719-llvm-4ea00210f2ba9e36451e7b020832a58ecac78aec.zip |
Make InputSection able to relocate itself.
This matches the organization used in COFF.
llvm-svn: 248215
-rw-r--r-- | lld/ELF/Chunks.cpp | 128 | ||||
-rw-r--r-- | lld/ELF/Chunks.h | 18 | ||||
-rw-r--r-- | lld/ELF/OutputSections.cpp | 139 | ||||
-rw-r--r-- | lld/ELF/OutputSections.h | 11 |
4 files changed, 162 insertions, 134 deletions
diff --git a/lld/ELF/Chunks.cpp b/lld/ELF/Chunks.cpp index 22bca359748..b0829af71e5 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 <class ELFT> InputSection<ELFT>::InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header) : File(F), Header(Header) {} -template <class ELFT> void InputSection<ELFT>::writeTo(uint8_t *Buf) { +template <class ELFT> +void InputSection<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 InputSection<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 InputSection<ELFT>::relocate( + uint8_t *Buf, iterator_range<const Elf_Rel_Impl<ELFT, isRela> *> Rels, + const ObjectFile<ELFT> &File, uintX_t BaseAddr, + const PltSection<ELFT> &PltSec, const GotSection<ELFT> &GotSec) { + 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 InputSection<ELFT>::writeTo(uint8_t *Buf, const PltSection<ELFT> &PltSec, + const GotSection<ELFT> &GotSec) { if (Header->sh_type == SHT_NOBITS) return; // Copy section contents from source object file to output file. ArrayRef<uint8_t> Data = *File->getObj()->getSectionContents(Header); memcpy(Buf + OutputSectionOff, Data.data(), Data.size()); + + const ObjectFile<ELFT> *File = getFile(); + ELFFile<ELFT> *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 <class ELFT> StringRef InputSection<ELFT>::getSectionName() const { diff --git a/lld/ELF/Chunks.h b/lld/ELF/Chunks.h index 4888b70b4fb..c0db824367f 100644 --- a/lld/ELF/Chunks.h +++ b/lld/ELF/Chunks.h @@ -18,12 +18,15 @@ namespace elf2 { template <class ELFT> class ObjectFile; template <class ELFT> class OutputSection; +template <class ELFT> class PltSection; +template <class ELFT> class GotSection; // A chunk corresponding a section of an input file. template <class ELFT> class InputSection { typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela; typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel; + typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym; typedef typename llvm::object::ELFFile<ELFT>::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<ELFT> &PltSec, + const GotSection<ELFT> &GotSec); StringRef getSectionName() const; const Elf_Shdr *getSectionHdr() const { return Header; } @@ -56,6 +60,18 @@ public: SmallVector<const Elf_Shdr *, 1> 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 <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, + const PltSection<ELFT> &PltSec, const GotSection<ELFT> &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 a9a1ca2073b..d625094dbb8 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -260,53 +260,6 @@ void OutputSection<ELFT>::addChunk(InputSection<ELFT> *C) { } 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; @@ -329,81 +282,9 @@ lld::elf2::getLocalSymVA(const typename ELFFile<ELFT>::Elf_Sym *Sym, 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); - } - } + for (InputSection<ELFT> *C : Chunks) + C->writeTo(Buf, PltSec, GotSec); } template <bool Is64Bits> @@ -582,5 +463,21 @@ getSymVA(const DefinedRegular<ELF64LE> *DR); template typename ELFFile<ELF64BE>::uintX_t getSymVA(const DefinedRegular<ELF64BE> *DR); + +template typename ELFFile<ELF32LE>::uintX_t +lld::elf2::getLocalSymVA(const typename ELFFile<ELF32LE>::Elf_Sym *Sym, + const ObjectFile<ELF32LE> &File); + +template typename ELFFile<ELF32BE>::uintX_t +lld::elf2::getLocalSymVA(const typename ELFFile<ELF32BE>::Elf_Sym *Sym, + const ObjectFile<ELF32BE> &File); + +template typename ELFFile<ELF64LE>::uintX_t +lld::elf2::getLocalSymVA(const typename ELFFile<ELF64LE>::Elf_Sym *Sym, + const ObjectFile<ELF64LE> &File); + +template typename ELFFile<ELF64BE>::uintX_t +lld::elf2::getLocalSymVA(const typename ELFFile<ELF64BE>::Elf_Sym *Sym, + const ObjectFile<ELF64BE> &File); } } diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h index 2e100869576..13a4569e034 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -245,17 +245,6 @@ public: 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; |