brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.8 KiB · 558351b Raw
299 lines · cpp
1//===-- PPCAsmBackend.cpp - PPC Assembler Backend -------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "MCTargetDesc/PPCFixupKinds.h"10#include "MCTargetDesc/PPCMCAsmInfo.h"11#include "MCTargetDesc/PPCMCTargetDesc.h"12#include "llvm/BinaryFormat/ELF.h"13#include "llvm/BinaryFormat/MachO.h"14#include "llvm/MC/MCAsmBackend.h"15#include "llvm/MC/MCAssembler.h"16#include "llvm/MC/MCContext.h"17#include "llvm/MC/MCELFObjectWriter.h"18#include "llvm/MC/MCMachObjectWriter.h"19#include "llvm/MC/MCObjectWriter.h"20#include "llvm/MC/MCSubtargetInfo.h"21#include "llvm/MC/MCSymbolELF.h"22#include "llvm/MC/MCSymbolXCOFF.h"23#include "llvm/MC/MCValue.h"24#include "llvm/MC/TargetRegistry.h"25#include "llvm/Support/ErrorHandling.h"26using namespace llvm;27 28static uint64_t adjustFixupValue(unsigned Kind, uint64_t Value) {29  switch (Kind) {30  default:31    llvm_unreachable("Unknown fixup kind!");32  case FK_Data_1:33  case FK_Data_2:34  case FK_Data_4:35  case FK_Data_8:36  case PPC::fixup_ppc_nofixup:37    return Value;38  case PPC::fixup_ppc_brcond14:39  case PPC::fixup_ppc_brcond14abs:40    return Value & 0xfffc;41  case PPC::fixup_ppc_br24:42  case PPC::fixup_ppc_br24abs:43  case PPC::fixup_ppc_br24_notoc:44    return Value & 0x3fffffc;45  case PPC::fixup_ppc_half16:46    return Value & 0xffff;47  case PPC::fixup_ppc_half16ds:48  case PPC::fixup_ppc_half16dq:49    return Value & 0xfffc;50  case PPC::fixup_ppc_pcrel32:51  case PPC::fixup_ppc_imm32:52    return Value & 0xffffffff;53  case PPC::fixup_ppc_pcrel34:54  case PPC::fixup_ppc_imm34:55    return Value & 0x3ffffffff;56  }57}58 59static unsigned getFixupKindNumBytes(unsigned Kind) {60  switch (Kind) {61  default:62    llvm_unreachable("Unknown fixup kind!");63  case FK_Data_1:64    return 1;65  case FK_Data_2:66  case PPC::fixup_ppc_half16:67  case PPC::fixup_ppc_half16ds:68  case PPC::fixup_ppc_half16dq:69    return 2;70  case FK_Data_4:71  case PPC::fixup_ppc_brcond14:72  case PPC::fixup_ppc_brcond14abs:73  case PPC::fixup_ppc_br24:74  case PPC::fixup_ppc_br24abs:75  case PPC::fixup_ppc_br24_notoc:76    return 4;77  case PPC::fixup_ppc_pcrel32:78  case PPC::fixup_ppc_imm32:79  case PPC::fixup_ppc_pcrel34:80  case PPC::fixup_ppc_imm34:81  case FK_Data_8:82    return 8;83  case PPC::fixup_ppc_nofixup:84    return 0;85  }86}87 88namespace {89 90class PPCAsmBackend : public MCAsmBackend {91protected:92  Triple TT;93public:94  PPCAsmBackend(const Target &T, const Triple &TT)95      : MCAsmBackend(TT.isLittleEndian() ? llvm::endianness::little96                                         : llvm::endianness::big),97        TT(TT) {}98 99  MCFixupKindInfo getFixupKindInfo(MCFixupKind Kind) const override;100 101  void applyFixup(const MCFragment &, const MCFixup &Fixup,102                  const MCValue &Target, uint8_t *Data, uint64_t Value,103                  bool IsResolved) override;104 105  bool shouldForceRelocation(const MCFixup &Fixup, const MCValue &Target) {106    // If there is a @ specifier, unless it is optimized out (e.g. constant @l),107    // force a relocation.108    if (Target.getSpecifier())109      return true;110    MCFixupKind Kind = Fixup.getKind();111    switch ((unsigned)Kind) {112    default:113      return false;114    case PPC::fixup_ppc_br24:115    case PPC::fixup_ppc_br24abs:116    case PPC::fixup_ppc_br24_notoc:117      // If the target symbol has a local entry point we must not attempt118      // to resolve the fixup directly.  Emit a relocation and leave119      // resolution of the final target address to the linker.120      if (const auto *A = Target.getAddSym()) {121        if (getContext().isELF()) {122          // The "other" values are stored in the last 6 bits of the second123          // byte. The traditional defines for STO values assume the full byte124          // and thus the shift to pack it.125          unsigned Other = static_cast<const MCSymbolELF *>(A)->getOther() << 2;126          if ((Other & ELF::STO_PPC64_LOCAL_MASK) != 0)127            return true;128        } else if (getContext().isXCOFF()) {129          auto *S = static_cast<const MCSymbolXCOFF *>(A);130          return !Target.isAbsolute() && S->isExternal() &&131                 S->getStorageClass() == XCOFF::C_WEAKEXT;132        }133      }134      return false;135    }136  }137 138  bool writeNopData(raw_ostream &OS, uint64_t Count,139                    const MCSubtargetInfo *STI) const override {140    uint64_t NumNops = Count / 4;141    for (uint64_t i = 0; i != NumNops; ++i)142      support::endian::write<uint32_t>(OS, 0x60000000, Endian);143 144    OS.write_zeros(Count % 4);145 146    return true;147  }148};149} // end anonymous namespace150 151MCFixupKindInfo PPCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {152  // clang-format off153  const static MCFixupKindInfo InfosBE[PPC::NumTargetFixupKinds] = {154      // name                    offset  bits  flags155      {"fixup_ppc_br24", 6, 24, 0},156      {"fixup_ppc_br24_notoc", 6, 24, 0},157      {"fixup_ppc_brcond14", 16, 14, 0},158      {"fixup_ppc_br24abs", 6, 24, 0},159      {"fixup_ppc_brcond14abs", 16, 14, 0},160      {"fixup_ppc_half16", 0, 16, 0},161      {"fixup_ppc_half16ds", 0, 14, 0},162      {"fixup_ppc_pcrel32", 0, 32, 0},163      {"fixup_ppc_imm32", 0, 32, 0},164      {"fixup_ppc_pcrel34", 0, 34, 0},165      {"fixup_ppc_imm34", 0, 34, 0},166      {"fixup_ppc_nofixup", 0, 0, 0}};167  const static MCFixupKindInfo InfosLE[PPC::NumTargetFixupKinds] = {168      // name                    offset  bits  flags169      {"fixup_ppc_br24", 2, 24, 0},170      {"fixup_ppc_br24_notoc", 2, 24, 0},171      {"fixup_ppc_brcond14", 2, 14, 0},172      {"fixup_ppc_br24abs", 2, 24, 0},173      {"fixup_ppc_brcond14abs", 2, 14, 0},174      {"fixup_ppc_half16", 0, 16, 0},175      {"fixup_ppc_half16ds", 2, 14, 0},176      {"fixup_ppc_pcrel32", 0, 32, 0},177      {"fixup_ppc_imm32", 0, 32, 0},178      {"fixup_ppc_pcrel34", 0, 34, 0},179      {"fixup_ppc_imm34", 0, 34, 0},180      {"fixup_ppc_nofixup", 0, 0, 0}};181  // clang-format on182 183  // Fixup kinds from .reloc directive are like R_PPC_NONE/R_PPC64_NONE. They184  // do not require any extra processing.185  if (mc::isRelocation(Kind))186    return {};187 188  if (Kind < FirstTargetFixupKind)189    return MCAsmBackend::getFixupKindInfo(Kind);190 191  assert(Kind - FirstTargetFixupKind < PPC::NumTargetFixupKinds &&192         "Invalid kind!");193  return (Endian == llvm::endianness::little194              ? InfosLE195              : InfosBE)[Kind - FirstTargetFixupKind];196}197 198void PPCAsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup,199                               const MCValue &TargetVal, uint8_t *Data,200                               uint64_t Value, bool IsResolved) {201  // In PPC64 ELFv1, .quad .TOC.@tocbase in the .opd section is expected to202  // reference the null symbol.203  auto Target = TargetVal;204  if (Target.getSpecifier() == PPC::S_TOCBASE)205    Target.setAddSym(nullptr);206  if (IsResolved && shouldForceRelocation(Fixup, Target))207    IsResolved = false;208  if (!IsResolved)209    Asm->getWriter().recordRelocation(F, Fixup, Target, Value);210 211  MCFixupKind Kind = Fixup.getKind();212  if (mc::isRelocation(Kind))213    return;214  Value = adjustFixupValue(Kind, Value);215  if (!Value)216    return; // Doesn't change encoding.217 218  unsigned NumBytes = getFixupKindNumBytes(Kind);219 220  // For each byte of the fragment that the fixup touches, mask in the bits221  // from the fixup value. The Value has been "split up" into the appropriate222  // bitfields above.223  for (unsigned i = 0; i != NumBytes; ++i) {224    unsigned Idx = Endian == llvm::endianness::little ? i : (NumBytes - 1 - i);225    Data[i] |= uint8_t((Value >> (Idx * 8)) & 0xff);226  }227}228 229// FIXME: This should be in a separate file.230namespace {231 232class ELFPPCAsmBackend : public PPCAsmBackend {233public:234  ELFPPCAsmBackend(const Target &T, const Triple &TT) : PPCAsmBackend(T, TT) {}235 236  std::unique_ptr<MCObjectTargetWriter>237  createObjectTargetWriter() const override {238    uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS());239    bool Is64 = TT.isPPC64();240    return createPPCELFObjectWriter(Is64, OSABI);241  }242 243  std::optional<MCFixupKind> getFixupKind(StringRef Name) const override;244};245 246class XCOFFPPCAsmBackend : public PPCAsmBackend {247public:248  XCOFFPPCAsmBackend(const Target &T, const Triple &TT)249      : PPCAsmBackend(T, TT) {}250 251  std::unique_ptr<MCObjectTargetWriter>252  createObjectTargetWriter() const override {253    return createPPCXCOFFObjectWriter(TT.isArch64Bit());254  }255};256 257} // end anonymous namespace258 259std::optional<MCFixupKind>260ELFPPCAsmBackend::getFixupKind(StringRef Name) const {261  if (TT.isOSBinFormatELF()) {262    unsigned Type;263    if (TT.isPPC64()) {264      Type = llvm::StringSwitch<unsigned>(Name)265#define ELF_RELOC(X, Y) .Case(#X, Y)266#include "llvm/BinaryFormat/ELFRelocs/PowerPC64.def"267#undef ELF_RELOC268                 .Case("BFD_RELOC_NONE", ELF::R_PPC64_NONE)269                 .Case("BFD_RELOC_16", ELF::R_PPC64_ADDR16)270                 .Case("BFD_RELOC_32", ELF::R_PPC64_ADDR32)271                 .Case("BFD_RELOC_64", ELF::R_PPC64_ADDR64)272                 .Default(-1u);273    } else {274      Type = llvm::StringSwitch<unsigned>(Name)275#define ELF_RELOC(X, Y) .Case(#X, Y)276#include "llvm/BinaryFormat/ELFRelocs/PowerPC.def"277#undef ELF_RELOC278                 .Case("BFD_RELOC_NONE", ELF::R_PPC_NONE)279                 .Case("BFD_RELOC_16", ELF::R_PPC_ADDR16)280                 .Case("BFD_RELOC_32", ELF::R_PPC_ADDR32)281                 .Default(-1u);282    }283    if (Type != -1u)284      return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type);285  }286  return std::nullopt;287}288 289MCAsmBackend *llvm::createPPCAsmBackend(const Target &T,290                                        const MCSubtargetInfo &STI,291                                        const MCRegisterInfo &MRI,292                                        const MCTargetOptions &Options) {293  const Triple &TT = STI.getTargetTriple();294  if (TT.isOSBinFormatXCOFF())295    return new XCOFFPPCAsmBackend(T, TT);296 297  return new ELFPPCAsmBackend(T, TT);298}299