1 | //===- MCAsmBackend.cpp - Target MC Assembly Backend ----------------------===// |
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 "llvm/MC/MCAsmBackend.h" |
10 | #include "llvm/MC/MCAssembler.h" |
11 | #include "llvm/MC/MCDXContainerWriter.h" |
12 | #include "llvm/MC/MCELFObjectWriter.h" |
13 | #include "llvm/MC/MCFixupKindInfo.h" |
14 | #include "llvm/MC/MCGOFFObjectWriter.h" |
15 | #include "llvm/MC/MCMachObjectWriter.h" |
16 | #include "llvm/MC/MCObjectWriter.h" |
17 | #include "llvm/MC/MCSPIRVObjectWriter.h" |
18 | #include "llvm/MC/MCWasmObjectWriter.h" |
19 | #include "llvm/MC/MCWinCOFFObjectWriter.h" |
20 | #include "llvm/MC/MCXCOFFObjectWriter.h" |
21 | #include <cassert> |
22 | #include <cstddef> |
23 | #include <cstdint> |
24 | |
25 | using namespace llvm; |
26 | |
27 | MCAsmBackend::~MCAsmBackend() = default; |
28 | |
29 | MCContext &MCAsmBackend::getContext() const { return Asm->getContext(); } |
30 | |
31 | std::unique_ptr<MCObjectWriter> |
32 | MCAsmBackend::createObjectWriter(raw_pwrite_stream &OS) const { |
33 | auto TW = createObjectTargetWriter(); |
34 | bool IsLE = Endian == llvm::endianness::little; |
35 | switch (TW->getFormat()) { |
36 | case Triple::MachO: |
37 | return std::make_unique<MachObjectWriter>( |
38 | args: cast<MCMachObjectTargetWriter>(Val: std::move(TW)), args&: OS, args&: IsLE); |
39 | case Triple::COFF: |
40 | return createWinCOFFObjectWriter( |
41 | MOTW: cast<MCWinCOFFObjectTargetWriter>(Val: std::move(TW)), OS); |
42 | case Triple::ELF: |
43 | return std::make_unique<ELFObjectWriter>( |
44 | args: cast<MCELFObjectTargetWriter>(Val: std::move(TW)), args&: OS, args&: IsLE); |
45 | case Triple::SPIRV: |
46 | return createSPIRVObjectWriter( |
47 | MOTW: cast<MCSPIRVObjectTargetWriter>(Val: std::move(TW)), OS); |
48 | case Triple::Wasm: |
49 | return createWasmObjectWriter(MOTW: cast<MCWasmObjectTargetWriter>(Val: std::move(TW)), |
50 | OS); |
51 | case Triple::GOFF: |
52 | return createGOFFObjectWriter(MOTW: cast<MCGOFFObjectTargetWriter>(Val: std::move(TW)), |
53 | OS); |
54 | case Triple::XCOFF: |
55 | return createXCOFFObjectWriter( |
56 | MOTW: cast<MCXCOFFObjectTargetWriter>(Val: std::move(TW)), OS); |
57 | case Triple::DXContainer: |
58 | return std::make_unique<DXContainerObjectWriter>( |
59 | args: cast<MCDXContainerTargetWriter>(Val: std::move(TW)), args&: OS); |
60 | default: |
61 | llvm_unreachable("unexpected object format" ); |
62 | } |
63 | } |
64 | |
65 | std::unique_ptr<MCObjectWriter> |
66 | MCAsmBackend::createDwoObjectWriter(raw_pwrite_stream &OS, |
67 | raw_pwrite_stream &DwoOS) const { |
68 | auto TW = createObjectTargetWriter(); |
69 | switch (TW->getFormat()) { |
70 | case Triple::COFF: |
71 | return createWinCOFFDwoObjectWriter( |
72 | MOTW: cast<MCWinCOFFObjectTargetWriter>(Val: std::move(TW)), OS, DwoOS); |
73 | case Triple::ELF: |
74 | return std::make_unique<ELFObjectWriter>( |
75 | args: cast<MCELFObjectTargetWriter>(Val: std::move(TW)), args&: OS, args&: DwoOS, |
76 | args: Endian == llvm::endianness::little); |
77 | case Triple::Wasm: |
78 | return createWasmDwoObjectWriter( |
79 | MOTW: cast<MCWasmObjectTargetWriter>(Val: std::move(TW)), OS, DwoOS); |
80 | default: |
81 | report_fatal_error(reason: "dwo only supported with COFF, ELF, and Wasm" ); |
82 | } |
83 | } |
84 | |
85 | std::optional<MCFixupKind> MCAsmBackend::getFixupKind(StringRef Name) const { |
86 | return std::nullopt; |
87 | } |
88 | |
89 | MCFixupKindInfo MCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { |
90 | static const MCFixupKindInfo Builtins[] = { |
91 | {.Name: "FK_NONE" , .TargetOffset: 0, .TargetSize: 0, .Flags: 0}, |
92 | {.Name: "FK_Data_1" , .TargetOffset: 0, .TargetSize: 8, .Flags: 0}, |
93 | {.Name: "FK_Data_2" , .TargetOffset: 0, .TargetSize: 16, .Flags: 0}, |
94 | {.Name: "FK_Data_4" , .TargetOffset: 0, .TargetSize: 32, .Flags: 0}, |
95 | {.Name: "FK_Data_8" , .TargetOffset: 0, .TargetSize: 64, .Flags: 0}, |
96 | {.Name: "FK_Data_leb128" , .TargetOffset: 0, .TargetSize: 0, .Flags: 0}, |
97 | {.Name: "FK_PCRel_1" , .TargetOffset: 0, .TargetSize: 8, .Flags: MCFixupKindInfo::FKF_IsPCRel}, |
98 | {.Name: "FK_PCRel_2" , .TargetOffset: 0, .TargetSize: 16, .Flags: MCFixupKindInfo::FKF_IsPCRel}, |
99 | {.Name: "FK_PCRel_4" , .TargetOffset: 0, .TargetSize: 32, .Flags: MCFixupKindInfo::FKF_IsPCRel}, |
100 | {.Name: "FK_PCRel_8" , .TargetOffset: 0, .TargetSize: 64, .Flags: MCFixupKindInfo::FKF_IsPCRel}, |
101 | {.Name: "FK_SecRel_1" , .TargetOffset: 0, .TargetSize: 8, .Flags: 0}, |
102 | {.Name: "FK_SecRel_2" , .TargetOffset: 0, .TargetSize: 16, .Flags: 0}, |
103 | {.Name: "FK_SecRel_4" , .TargetOffset: 0, .TargetSize: 32, .Flags: 0}, |
104 | {.Name: "FK_SecRel_8" , .TargetOffset: 0, .TargetSize: 64, .Flags: 0}, |
105 | }; |
106 | |
107 | assert(size_t(Kind - FK_NONE) < std::size(Builtins) && "Unknown fixup kind" ); |
108 | return Builtins[Kind - FK_NONE]; |
109 | } |
110 | |
111 | bool MCAsmBackend::fixupNeedsRelaxationAdvanced(const MCFixup &Fixup, |
112 | const MCValue &, uint64_t Value, |
113 | bool Resolved) const { |
114 | if (!Resolved) |
115 | return true; |
116 | return fixupNeedsRelaxation(Fixup, Value); |
117 | } |
118 | |
119 | void MCAsmBackend::maybeAddReloc(const MCFragment &F, const MCFixup &Fixup, |
120 | const MCValue &Target, uint64_t &Value, |
121 | bool IsResolved) { |
122 | if (!IsResolved) |
123 | Asm->getWriter().recordRelocation(F, Fixup, Target, FixedValue&: Value); |
124 | } |
125 | |
126 | bool MCAsmBackend::isDarwinCanonicalPersonality(const MCSymbol *Sym) const { |
127 | // Consider a NULL personality (ie., no personality encoding) to be canonical |
128 | // because it's always at 0. |
129 | if (!Sym) |
130 | return true; |
131 | |
132 | if (!Sym->isMachO()) |
133 | llvm_unreachable("Expected MachO symbols only" ); |
134 | |
135 | StringRef name = Sym->getName(); |
136 | // XXX: We intentionally leave out "___gcc_personality_v0" because, despite |
137 | // being system-defined like these two, it is not very commonly-used. |
138 | // Reserving an empty slot for it seems silly. |
139 | return name == "___gxx_personality_v0" || name == "___objc_personality_v0" ; |
140 | } |
141 | |
142 | const MCSubtargetInfo *MCAsmBackend::getSubtargetInfo(const MCFragment &F) { |
143 | const MCSubtargetInfo *STI = nullptr; |
144 | switch (F.getKind()) { |
145 | case MCFragment::FT_Data: { |
146 | auto &DF = cast<MCDataFragment>(Val: F); |
147 | STI = DF.getSubtargetInfo(); |
148 | assert(!DF.hasInstructions() || STI != nullptr); |
149 | break; |
150 | } |
151 | case MCFragment::FT_Relaxable: { |
152 | auto &RF = cast<MCRelaxableFragment>(Val: F); |
153 | STI = RF.getSubtargetInfo(); |
154 | assert(!RF.hasInstructions() || STI != nullptr); |
155 | break; |
156 | } |
157 | default: |
158 | break; |
159 | } |
160 | return STI; |
161 | } |
162 | |