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