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