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 | |
26 | using namespace llvm; |
27 | |
28 | namespace { |
29 | |
30 | class AArch64WinCOFFObjectWriter : public MCWinCOFFObjectTargetWriter { |
31 | public: |
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 | |
48 | unsigned 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 | |
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>(args: TheTriple); |
163 | } |
164 | |