277 lines · cpp
1//===-- SparcAsmBackend.cpp - Sparc 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/SparcFixupKinds.h"10#include "MCTargetDesc/SparcMCTargetDesc.h"11#include "llvm/ADT/StringSwitch.h"12#include "llvm/MC/MCAsmBackend.h"13#include "llvm/MC/MCELFObjectWriter.h"14#include "llvm/MC/MCExpr.h"15#include "llvm/MC/MCObjectWriter.h"16#include "llvm/MC/MCSubtargetInfo.h"17#include "llvm/MC/MCValue.h"18#include "llvm/MC/TargetRegistry.h"19#include "llvm/Support/EndianStream.h"20 21using namespace llvm;22 23static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) {24 switch (Kind) {25 default:26 assert(uint16_t(Kind) < FirstTargetFixupKind && "Unknown fixup kind!");27 return Value;28 case FK_Data_1:29 case FK_Data_2:30 case FK_Data_4:31 case FK_Data_8:32 return Value;33 34 case Sparc::fixup_sparc_call30:35 return (Value >> 2) & 0x3fffffff;36 37 case ELF::R_SPARC_WDISP22:38 return (Value >> 2) & 0x3fffff;39 40 case ELF::R_SPARC_WDISP19:41 return (Value >> 2) & 0x7ffff;42 43 case ELF::R_SPARC_WDISP16: {44 // A.3 Branch on Integer Register with Prediction (BPr)45 // Inst{21-20} = d16hi;46 // Inst{13-0} = d16lo;47 unsigned d16hi = (Value >> 16) & 0x3;48 unsigned d16lo = (Value >> 2) & 0x3fff;49 return (d16hi << 20) | d16lo;50 }51 52 case ELF::R_SPARC_WDISP10: {53 // FIXME this really should be an error reporting check.54 assert((Value & 0x3) == 0);55 56 // 7.17 Compare and Branch57 // Inst{20-19} = d10hi;58 // Inst{12-5} = d10lo;59 unsigned d10hi = (Value >> 10) & 0x3;60 unsigned d10lo = (Value >> 2) & 0xff;61 return (d10hi << 19) | (d10lo << 5);62 }63 64 case ELF::R_SPARC_HIX22:65 return (~Value >> 10) & 0x3fffff;66 67 case ELF::R_SPARC_PC22:68 case ELF::R_SPARC_HI22:69 case ELF::R_SPARC_LM22:70 return (Value >> 10) & 0x3fffff;71 72 case Sparc::fixup_sparc_13:73 return Value & 0x1fff;74 75 case ELF::R_SPARC_5:76 return Value & 0x1f;77 78 case ELF::R_SPARC_LOX10:79 return (Value & 0x3ff) | 0x1c00;80 81 case ELF::R_SPARC_PC10:82 case ELF::R_SPARC_LO10:83 return Value & 0x3ff;84 85 case ELF::R_SPARC_H44:86 return (Value >> 22) & 0x3fffff;87 case ELF::R_SPARC_M44:88 return (Value >> 12) & 0x3ff;89 case ELF::R_SPARC_L44:90 return Value & 0xfff;91 92 case ELF::R_SPARC_HH22:93 return (Value >> 42) & 0x3fffff;94 case ELF::R_SPARC_HM10:95 return (Value >> 32) & 0x3ff;96 }97}98 99/// getFixupKindNumBytes - The number of bytes the fixup may change.100static unsigned getFixupKindNumBytes(unsigned Kind) {101 switch (Kind) {102 default:103 return 4;104 case FK_Data_1:105 return 1;106 case FK_Data_2:107 return 2;108 case FK_Data_8:109 return 8;110 }111}112 113namespace {114class SparcAsmBackend : public MCAsmBackend {115protected:116 bool Is64Bit;117 bool IsV8Plus;118 119public:120 SparcAsmBackend(const MCSubtargetInfo &STI)121 : MCAsmBackend(STI.getTargetTriple().isLittleEndian()122 ? llvm::endianness::little123 : llvm::endianness::big),124 Is64Bit(STI.getTargetTriple().isArch64Bit()),125 IsV8Plus(STI.hasFeature(Sparc::FeatureV8Plus)) {}126 127 std::optional<MCFixupKind> getFixupKind(StringRef Name) const override;128 MCFixupKindInfo getFixupKindInfo(MCFixupKind Kind) const override;129 void applyFixup(const MCFragment &, const MCFixup &, const MCValue &Target,130 uint8_t *Data, uint64_t Value, bool IsResolved) override;131 132 bool writeNopData(raw_ostream &OS, uint64_t Count,133 const MCSubtargetInfo *STI) const override {134 135 // If the count is not 4-byte aligned, we must be writing data into the136 // text section (otherwise we have unaligned instructions, and thus have137 // far bigger problems), so just write zeros instead.138 OS.write_zeros(Count % 4);139 140 uint64_t NumNops = Count / 4;141 for (uint64_t i = 0; i != NumNops; ++i)142 support::endian::write<uint32_t>(OS, 0x01000000, Endian);143 144 return true;145 }146};147 148class ELFSparcAsmBackend : public SparcAsmBackend {149 Triple::OSType OSType;150 151public:152 ELFSparcAsmBackend(const MCSubtargetInfo &STI, Triple::OSType OSType)153 : SparcAsmBackend(STI), OSType(OSType) {}154 155 std::unique_ptr<MCObjectTargetWriter>156 createObjectTargetWriter() const override {157 uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(OSType);158 return createSparcELFObjectWriter(Is64Bit, IsV8Plus, OSABI);159 }160};161} // end anonymous namespace162 163std::optional<MCFixupKind> SparcAsmBackend::getFixupKind(StringRef Name) const {164 unsigned Type;165 Type = llvm::StringSwitch<unsigned>(Name)166#define ELF_RELOC(X, Y) .Case(#X, Y)167#include "llvm/BinaryFormat/ELFRelocs/Sparc.def"168#undef ELF_RELOC169 .Case("BFD_RELOC_NONE", ELF::R_SPARC_NONE)170 .Case("BFD_RELOC_8", ELF::R_SPARC_8)171 .Case("BFD_RELOC_16", ELF::R_SPARC_16)172 .Case("BFD_RELOC_32", ELF::R_SPARC_32)173 .Case("BFD_RELOC_64", ELF::R_SPARC_64)174 .Default(-1u);175 if (Type == -1u)176 return std::nullopt;177 return static_cast<MCFixupKind>(FirstLiteralRelocationKind + Type);178}179 180MCFixupKindInfo SparcAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {181 // clang-format off182 const static MCFixupKindInfo InfosBE[Sparc::NumTargetFixupKinds] = {183 // name offset bits flags184 {"fixup_sparc_call30", 2, 30, 0},185 {"fixup_sparc_13", 19, 13, 0},186 };187 188 const static MCFixupKindInfo InfosLE[Sparc::NumTargetFixupKinds] = {189 // name offset bits flags190 {"fixup_sparc_call30", 0, 30, 0},191 {"fixup_sparc_13", 0, 13, 0},192 };193 // clang-format on194 195 if (!mc::isRelocation(Kind)) {196 if (Kind < FirstTargetFixupKind)197 return MCAsmBackend::getFixupKindInfo(Kind);198 assert(unsigned(Kind - FirstTargetFixupKind) < Sparc::NumTargetFixupKinds &&199 "Invalid kind!");200 if (Endian == llvm::endianness::little)201 return InfosLE[Kind - FirstTargetFixupKind];202 203 return InfosBE[Kind - FirstTargetFixupKind];204 }205 206 MCFixupKindInfo Info{};207 switch (uint16_t(Kind)) {208 case ELF::R_SPARC_PC10:209 Info = {"", 22, 10, 0};210 break;211 case ELF::R_SPARC_PC22:212 Info = {"", 10, 22, 0};213 break;214 case ELF::R_SPARC_WDISP10:215 Info = {"", 0, 32, 0};216 break;217 case ELF::R_SPARC_WDISP16:218 Info = {"", 0, 32, 0};219 break;220 case ELF::R_SPARC_WDISP19:221 Info = {"", 13, 19, 0};222 break;223 case ELF::R_SPARC_WDISP22:224 Info = {"", 10, 22, 0};225 break;226 227 case ELF::R_SPARC_HI22:228 Info = {"", 10, 22, 0};229 break;230 case ELF::R_SPARC_LO10:231 Info = {"", 22, 10, 0};232 break;233 case ELF::R_SPARC_HH22:234 Info = {"", 10, 22, 0};235 break;236 case ELF::R_SPARC_HM10:237 Info = {"", 22, 10, 0};238 break;239 case ELF::R_SPARC_LM22:240 Info = {"", 10, 22, 0};241 break;242 case ELF::R_SPARC_HIX22:243 Info = {"", 10, 22, 0};244 break;245 case ELF::R_SPARC_LOX10:246 Info = {"", 19, 13, 0};247 break;248 }249 if (Endian == llvm::endianness::little)250 Info.TargetOffset = 32 - Info.TargetOffset - Info.TargetSize;251 return Info;252}253 254void SparcAsmBackend::applyFixup(const MCFragment &F, const MCFixup &Fixup,255 const MCValue &Target, uint8_t *Data,256 uint64_t Value, bool IsResolved) {257 maybeAddReloc(F, Fixup, Target, Value, IsResolved);258 if (!IsResolved)259 return;260 Value = adjustFixupValue(Fixup.getKind(), Value);261 262 unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind());263 // For each byte of the fragment that the fixup touches, mask in the264 // bits from the fixup value.265 for (unsigned i = 0; i != NumBytes; ++i) {266 unsigned Idx = Endian == llvm::endianness::little ? i : (NumBytes - 1) - i;267 Data[Idx] |= uint8_t((Value >> (i * 8)) & 0xff);268 }269}270 271MCAsmBackend *llvm::createSparcAsmBackend(const Target &T,272 const MCSubtargetInfo &STI,273 const MCRegisterInfo &MRI,274 const MCTargetOptions &Options) {275 return new ELFSparcAsmBackend(STI, STI.getTargetTriple().getOS());276}277