xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AArch64/MCTargetDesc/AArch64WinCOFFObjectWriter.cpp (revision 9c77fb6aaa366cbabc80ee1b834bcfe4df135491)
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:
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 
47 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 
156 bool AArch64WinCOFFObjectWriter::recordRelocation(const MCFixup &Fixup) const {
157   return true;
158 }
159 
160 std::unique_ptr<MCObjectTargetWriter>
161 llvm::createAArch64WinCOFFObjectWriter(const Triple &TheTriple) {
162   return std::make_unique<AArch64WinCOFFObjectWriter>(TheTriple);
163 }
164