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(Fixup.getLoc(), "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>(Expr)) {
70    AArch64MCExpr::VariantKind RefKind = A64E->getKind();
71    switch (AArch64MCExpr::getSymbolLoc(RefKind)) {
72    case AArch64MCExpr::VK_ABS:
73    case AArch64MCExpr::VK_SECREL:
74      // Supported
75      break;
76    default:
77      Ctx.reportError(Fixup.getLoc(), "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>(Expr)) {
87      Ctx.reportError(Fixup.getLoc(), "relocation type " +
88                                          A64E->getVariantKindName() +
89                                          " unsupported on COFF targets");
90    } else {
91      const MCFixupKindInfo &Info = MAB.getFixupKindInfo(Fixup.getKind());
92      Ctx.reportError(Fixup.getLoc(), 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>(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>(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>(TheTriple);
167}
168