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