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/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 <cassert>
25
26using namespace llvm;
27
28namespace {
29
30class AArch64WinCOFFObjectWriter : public MCWinCOFFObjectTargetWriter {
31public:
32 AArch64WinCOFFObjectWriter(const Triple &TheTriple)
33 : MCWinCOFFObjectTargetWriter(TheTriple.isWindowsArm64EC()
34 ? COFF::IMAGE_FILE_MACHINE_ARM64EC
35 : COFF::IMAGE_FILE_MACHINE_ARM64) {}
36
37 ~AArch64WinCOFFObjectWriter() override = default;
38
39 unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
40 const MCFixup &Fixup, bool IsCrossSection,
41 const MCAsmBackend &MAB) const override;
42
43 bool recordRelocation(const MCFixup &) const override;
44};
45
46} // end anonymous namespace
47
48unsigned AArch64WinCOFFObjectWriter::getRelocType(
49 MCContext &Ctx, const MCValue &Target, const MCFixup &Fixup,
50 bool IsCrossSection, const MCAsmBackend &MAB) const {
51 unsigned FixupKind = Fixup.getKind();
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 (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_PCRel_4;
62 }
63
64 auto Spec = Target.getSpecifier();
65 const MCExpr *Expr = Fixup.getValue();
66
67 if (auto *A64E = dyn_cast<MCSpecifierExpr>(Val: Expr)) {
68 AArch64::Specifier Spec = A64E->getSpecifier();
69 switch (AArch64::getSymbolLoc(S: Spec)) {
70 case AArch64::S_ABS:
71 case AArch64::S_SECREL:
72 // Supported
73 break;
74 default:
75 Ctx.reportError(L: Fixup.getLoc(), Msg: "relocation specifier " +
76 AArch64::getSpecifierName(Expr: *A64E) +
77 " unsupported on COFF targets");
78 return COFF::IMAGE_REL_ARM64_ABSOLUTE; // Dummy return value
79 }
80 }
81
82 switch (FixupKind) {
83 default: {
84 if (auto *A64E = dyn_cast<MCSpecifierExpr>(Val: Expr)) {
85 Ctx.reportError(L: Fixup.getLoc(), Msg: "relocation specifier " +
86 AArch64::getSpecifierName(Expr: *A64E) +
87 " unsupported on COFF targets");
88 } else {
89 MCFixupKindInfo Info = MAB.getFixupKindInfo(Kind: Fixup.getKind());
90 Ctx.reportError(L: Fixup.getLoc(), Msg: Twine("relocation type ") + Info.Name +
91 " unsupported on COFF targets");
92 }
93 return COFF::IMAGE_REL_ARM64_ABSOLUTE; // Dummy return value
94 }
95
96 case FK_PCRel_4:
97 return COFF::IMAGE_REL_ARM64_REL32;
98
99 case FK_Data_4:
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>(Val: 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>(Val: 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
156bool AArch64WinCOFFObjectWriter::recordRelocation(const MCFixup &Fixup) const {
157 return true;
158}
159
160std::unique_ptr<MCObjectTargetWriter>
161llvm::createAArch64WinCOFFObjectWriter(const Triple &TheTriple) {
162 return std::make_unique<AArch64WinCOFFObjectWriter>(args: TheTriple);
163}
164