diff options
Diffstat (limited to 'lld/ELF/InputSection.cpp')
| -rw-r--r-- | lld/ELF/InputSection.cpp | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp new file mode 100644 index 00000000000..e5ef5c07d0c --- /dev/null +++ b/lld/ELF/InputSection.cpp @@ -0,0 +1,171 @@ +//===- InputSection.cpp ---------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "InputSection.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; + +template <class ELFT> +InputSection<ELFT>::InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header) + : File(F), Header(Header) {} + +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 { + ErrorOr<StringRef> Name = File->getObj()->getSectionName(Header); + error(Name); + return *Name; +} + +namespace lld { +namespace elf2 { +template class InputSection<object::ELF32LE>; +template class InputSection<object::ELF32BE>; +template class InputSection<object::ELF64LE>; +template class InputSection<object::ELF64BE>; +} +} |

