1 //= AArch64WinCOFFObjectWriter.cpp - AArch64 Windows COFF Object Writer C++ =// 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-exception 6 // 7 //===---------------------------------------------------------------------===// 8 9 #include "AArch64MCTargetDesc.h" 10 #include "MCTargetDesc/AArch64FixupKinds.h" 11 #include "MCTargetDesc/AArch64MCExpr.h" 12 #include "llvm/ADT/Twine.h" 13 #include "llvm/BinaryFormat/COFF.h" 14 #include "llvm/MC/MCAsmBackend.h" 15 #include "llvm/MC/MCContext.h" 16 #include "llvm/MC/MCExpr.h" 17 #include "llvm/MC/MCFixup.h" 18 #include "llvm/MC/MCFixupKindInfo.h" 19 #include "llvm/MC/MCObjectWriter.h" 20 #include "llvm/MC/MCValue.h" 21 #include "llvm/MC/MCWinCOFFObjectWriter.h" 22 #include "llvm/Support/ErrorHandling.h" 23 #include "llvm/Support/raw_ostream.h" 24 #include <cassert> 25 26 using namespace llvm; 27 28 namespace { 29 30 class AArch64WinCOFFObjectWriter : public MCWinCOFFObjectTargetWriter { 31 public: 32 AArch64WinCOFFObjectWriter() 33 : MCWinCOFFObjectTargetWriter(COFF::IMAGE_FILE_MACHINE_ARM64) {} 34 35 ~AArch64WinCOFFObjectWriter() override = default; 36 37 unsigned getRelocType(MCContext &Ctx, const MCValue &Target, 38 const MCFixup &Fixup, bool IsCrossSection, 39 const MCAsmBackend &MAB) const override; 40 41 bool recordRelocation(const MCFixup &) const override; 42 }; 43 44 } // end anonymous namespace 45 46 unsigned AArch64WinCOFFObjectWriter::getRelocType( 47 MCContext &Ctx, const MCValue &Target, const MCFixup &Fixup, 48 bool IsCrossSection, const MCAsmBackend &MAB) const { 49 unsigned FixupKind = Fixup.getKind(); 50 if (IsCrossSection) { 51 // IMAGE_REL_ARM64_REL64 does not exist. We treat FK_Data_8 as FK_PCRel_4 so 52 // that .xword a-b can lower to IMAGE_REL_ARM64_REL32. This allows generic 53 // instrumentation to not bother with the COFF limitation. A negative value 54 // needs attention. 55 if (FixupKind != FK_Data_4 && FixupKind != FK_Data_8) { 56 Ctx.reportError(Fixup.getLoc(), "Cannot represent this expression"); 57 return COFF::IMAGE_REL_ARM64_ADDR32; 58 } 59 FixupKind = FK_PCRel_4; 60 } 61 62 auto Modifier = Target.isAbsolute() ? MCSymbolRefExpr::VK_None 63 : Target.getSymA()->getKind(); 64 const MCExpr *Expr = Fixup.getValue(); 65 66 if (const AArch64MCExpr *A64E = dyn_cast<AArch64MCExpr>(Expr)) { 67 AArch64MCExpr::VariantKind RefKind = A64E->getKind(); 68 switch (AArch64MCExpr::getSymbolLoc(RefKind)) { 69 case AArch64MCExpr::VK_ABS: 70 case AArch64MCExpr::VK_SECREL: 71 // Supported 72 break; 73 default: 74 Ctx.reportError(Fixup.getLoc(), "relocation variant " + 75 A64E->getVariantKindName() + 76 " unsupported on COFF targets"); 77 return COFF::IMAGE_REL_ARM64_ABSOLUTE; // Dummy return value 78 } 79 } 80 81 switch (FixupKind) { 82 default: { 83 if (const AArch64MCExpr *A64E = dyn_cast<AArch64MCExpr>(Expr)) { 84 Ctx.reportError(Fixup.getLoc(), "relocation type " + 85 A64E->getVariantKindName() + 86 " unsupported on COFF targets"); 87 } else { 88 const MCFixupKindInfo &Info = MAB.getFixupKindInfo(Fixup.getKind()); 89 Ctx.reportError(Fixup.getLoc(), Twine("relocation type ") + Info.Name + 90 " unsupported on COFF targets"); 91 } 92 return COFF::IMAGE_REL_ARM64_ABSOLUTE; // Dummy return value 93 } 94 95 case FK_PCRel_4: 96 return COFF::IMAGE_REL_ARM64_REL32; 97 98 case FK_Data_4: 99 switch (Modifier) { 100 default: 101 return COFF::IMAGE_REL_ARM64_ADDR32; 102 case MCSymbolRefExpr::VK_COFF_IMGREL32: 103 return COFF::IMAGE_REL_ARM64_ADDR32NB; 104 case MCSymbolRefExpr::VK_SECREL: 105 return COFF::IMAGE_REL_ARM64_SECREL; 106 } 107 108 case FK_Data_8: 109 return COFF::IMAGE_REL_ARM64_ADDR64; 110 111 case FK_SecRel_2: 112 return COFF::IMAGE_REL_ARM64_SECTION; 113 114 case FK_SecRel_4: 115 return COFF::IMAGE_REL_ARM64_SECREL; 116 117 case AArch64::fixup_aarch64_add_imm12: 118 if (const AArch64MCExpr *A64E = dyn_cast<AArch64MCExpr>(Expr)) { 119 AArch64MCExpr::VariantKind RefKind = A64E->getKind(); 120 if (RefKind == AArch64MCExpr::VK_SECREL_LO12) 121 return COFF::IMAGE_REL_ARM64_SECREL_LOW12A; 122 if (RefKind == AArch64MCExpr::VK_SECREL_HI12) 123 return COFF::IMAGE_REL_ARM64_SECREL_HIGH12A; 124 } 125 return COFF::IMAGE_REL_ARM64_PAGEOFFSET_12A; 126 127 case AArch64::fixup_aarch64_ldst_imm12_scale1: 128 case AArch64::fixup_aarch64_ldst_imm12_scale2: 129 case AArch64::fixup_aarch64_ldst_imm12_scale4: 130 case AArch64::fixup_aarch64_ldst_imm12_scale8: 131 case AArch64::fixup_aarch64_ldst_imm12_scale16: 132 if (const AArch64MCExpr *A64E = dyn_cast<AArch64MCExpr>(Expr)) { 133 AArch64MCExpr::VariantKind RefKind = A64E->getKind(); 134 if (RefKind == AArch64MCExpr::VK_SECREL_LO12) 135 return COFF::IMAGE_REL_ARM64_SECREL_LOW12L; 136 } 137 return COFF::IMAGE_REL_ARM64_PAGEOFFSET_12L; 138 139 case AArch64::fixup_aarch64_pcrel_adr_imm21: 140 return COFF::IMAGE_REL_ARM64_REL21; 141 142 case AArch64::fixup_aarch64_pcrel_adrp_imm21: 143 return COFF::IMAGE_REL_ARM64_PAGEBASE_REL21; 144 145 case AArch64::fixup_aarch64_pcrel_branch14: 146 return COFF::IMAGE_REL_ARM64_BRANCH14; 147 148 case AArch64::fixup_aarch64_pcrel_branch19: 149 return COFF::IMAGE_REL_ARM64_BRANCH19; 150 151 case AArch64::fixup_aarch64_pcrel_branch26: 152 case AArch64::fixup_aarch64_pcrel_call26: 153 return COFF::IMAGE_REL_ARM64_BRANCH26; 154 } 155 } 156 157 bool AArch64WinCOFFObjectWriter::recordRelocation(const MCFixup &Fixup) const { 158 return true; 159 } 160 161 std::unique_ptr<MCObjectTargetWriter> llvm::createAArch64WinCOFFObjectWriter() { 162 return std::make_unique<AArch64WinCOFFObjectWriter>(); 163 } 164