//===- PPC.cpp ------------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Symbols.h" #include "Target.h" #include "lld/Common/ErrorHandler.h" #include "llvm/Support/Endian.h" using namespace llvm; using namespace llvm::support::endian; using namespace llvm::ELF; using namespace lld; using namespace lld::elf; namespace { class PPC final : public TargetInfo { public: PPC(); void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; }; } // namespace PPC::PPC() { NoneRel = R_PPC_NONE; GotBaseSymOff = 0x8000; GotBaseSymInGotPlt = false; } RelExpr PPC::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { switch (Type) { case R_PPC_REL14: case R_PPC_REL24: case R_PPC_REL32: return R_PC; case R_PPC_PLTREL24: return R_PLT_PC; default: return R_ABS; } } void PPC::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { switch (Type) { case R_PPC_ADDR16_HA: write16be(Loc, (Val + 0x8000) >> 16); break; case R_PPC_ADDR16_HI: write16be(Loc, Val >> 16); break; case R_PPC_ADDR16_LO: write16be(Loc, Val); break; case R_PPC_ADDR32: case R_PPC_REL32: write32be(Loc, Val); break; case R_PPC_REL14: write32be(Loc, read32be(Loc) | (Val & 0xFFFC)); break; case R_PPC_PLTREL24: case R_PPC_REL24: write32be(Loc, read32be(Loc) | (Val & 0x3FFFFFC)); break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } TargetInfo *elf::getPPCTargetInfo() { static PPC Target; return &Target; }