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
25using namespace llvm;
26
27namespace {
28
29class AArch64WinCOFFObjectWriter : public MCWinCOFFObjectTargetWriter {
30public:
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
47unsigned 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(L: Fixup.getLoc(), Msg: "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>(Val: Expr)) {
69 AArch64::Specifier Spec = A64E->getSpecifier();
70 switch (AArch64::getSymbolLoc(S: Spec)) {
71 case AArch64::S_ABS:
72 case AArch64::S_SECREL:
73 // Supported
74 break;
75 default:
76 Ctx.reportError(L: Fixup.getLoc(),
77 Msg: "relocation specifier " +
78 AArch64::getSpecifierName(S: A64E->getSpecifier()) +
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 (auto *A64E = dyn_cast<MCSpecifierExpr>(Val: Expr)) {
87 Ctx.reportError(L: Fixup.getLoc(),
88 Msg: "relocation specifier " +
89 AArch64::getSpecifierName(S: A64E->getSpecifier()) +
90 " unsupported on COFF targets");
91 } else {
92 MCFixupKindInfo Info = MAB.getFixupKindInfo(Kind: Fixup.getKind());
93 Ctx.reportError(L: Fixup.getLoc(), Msg: Twine("relocation type ") + Info.Name +
94 " unsupported on COFF targets");
95 }
96 return COFF::IMAGE_REL_ARM64_ABSOLUTE; // Dummy return value
97 }
98
99 case FK_Data_4:
100 if (PCRel)
101 return COFF::IMAGE_REL_ARM64_REL32;
102 switch (Spec) {
103 default:
104 return COFF::IMAGE_REL_ARM64_ADDR32;
105 case MCSymbolRefExpr::VK_COFF_IMGREL32:
106 return COFF::IMAGE_REL_ARM64_ADDR32NB;
107 }
108
109 case FK_Data_8:
110 return COFF::IMAGE_REL_ARM64_ADDR64;
111
112 case FK_SecRel_2:
113 return COFF::IMAGE_REL_ARM64_SECTION;
114
115 case FK_SecRel_4:
116 return COFF::IMAGE_REL_ARM64_SECREL;
117
118 case AArch64::fixup_aarch64_add_imm12:
119 if (auto *A64E = dyn_cast<MCSpecifierExpr>(Val: Expr)) {
120 AArch64::Specifier Spec = A64E->getSpecifier();
121 if (Spec == AArch64::S_SECREL_LO12)
122 return COFF::IMAGE_REL_ARM64_SECREL_LOW12A;
123 if (Spec == AArch64::S_SECREL_HI12)
124 return COFF::IMAGE_REL_ARM64_SECREL_HIGH12A;
125 }
126 return COFF::IMAGE_REL_ARM64_PAGEOFFSET_12A;
127
128 case AArch64::fixup_aarch64_ldst_imm12_scale1:
129 case AArch64::fixup_aarch64_ldst_imm12_scale2:
130 case AArch64::fixup_aarch64_ldst_imm12_scale4:
131 case AArch64::fixup_aarch64_ldst_imm12_scale8:
132 case AArch64::fixup_aarch64_ldst_imm12_scale16:
133 if (auto *A64E = dyn_cast<MCSpecifierExpr>(Val: Expr)) {
134 AArch64::Specifier Spec = A64E->getSpecifier();
135 if (Spec == AArch64::S_SECREL_LO12)
136 return COFF::IMAGE_REL_ARM64_SECREL_LOW12L;
137 }
138 return COFF::IMAGE_REL_ARM64_PAGEOFFSET_12L;
139
140 case AArch64::fixup_aarch64_pcrel_adr_imm21:
141 return COFF::IMAGE_REL_ARM64_REL21;
142
143 case AArch64::fixup_aarch64_pcrel_adrp_imm21:
144 return COFF::IMAGE_REL_ARM64_PAGEBASE_REL21;
145
146 case AArch64::fixup_aarch64_pcrel_branch14:
147 return COFF::IMAGE_REL_ARM64_BRANCH14;
148
149 case AArch64::fixup_aarch64_pcrel_branch19:
150 return COFF::IMAGE_REL_ARM64_BRANCH19;
151
152 case AArch64::fixup_aarch64_pcrel_branch26:
153 case AArch64::fixup_aarch64_pcrel_call26:
154 return COFF::IMAGE_REL_ARM64_BRANCH26;
155 }
156}
157
158bool AArch64WinCOFFObjectWriter::recordRelocation(const MCFixup &Fixup) const {
159 return true;
160}
161
162std::unique_ptr<MCObjectTargetWriter>
163llvm::createAArch64WinCOFFObjectWriter(const Triple &TheTriple) {
164 return std::make_unique<AArch64WinCOFFObjectWriter>(args: TheTriple);
165}
166