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(llvm::endianness Endian, unsigned RelaxFixupKind) |
28 | : Endian(Endian), RelaxFixupKind(RelaxFixupKind) {} |
29 | |
30 | MCAsmBackend::~MCAsmBackend() = default; |
31 | |
32 | std::unique_ptr<MCObjectWriter> |
33 | MCAsmBackend::createObjectWriter(raw_pwrite_stream &OS) const { |
34 | auto TW = createObjectTargetWriter(); |
35 | bool IsLE = Endian == llvm::endianness::little; |
36 | switch (TW->getFormat()) { |
37 | case Triple::MachO: |
38 | return createMachObjectWriter(MOTW: cast<MCMachObjectTargetWriter>(Val: std::move(TW)), |
39 | OS, IsLittleEndian: IsLE); |
40 | case Triple::COFF: |
41 | return createWinCOFFObjectWriter( |
42 | MOTW: cast<MCWinCOFFObjectTargetWriter>(Val: std::move(TW)), OS); |
43 | case Triple::ELF: |
44 | return std::make_unique<ELFObjectWriter>( |
45 | args: cast<MCELFObjectTargetWriter>(Val: std::move(TW)), args&: OS, args&: IsLE); |
46 | case Triple::SPIRV: |
47 | return createSPIRVObjectWriter( |
48 | MOTW: cast<MCSPIRVObjectTargetWriter>(Val: std::move(TW)), OS); |
49 | case Triple::Wasm: |
50 | return createWasmObjectWriter(MOTW: cast<MCWasmObjectTargetWriter>(Val: std::move(TW)), |
51 | OS); |
52 | case Triple::GOFF: |
53 | return createGOFFObjectWriter(MOTW: cast<MCGOFFObjectTargetWriter>(Val: std::move(TW)), |
54 | OS); |
55 | case Triple::XCOFF: |
56 | return createXCOFFObjectWriter( |
57 | MOTW: cast<MCXCOFFObjectTargetWriter>(Val: std::move(TW)), OS); |
58 | case Triple::DXContainer: |
59 | return createDXContainerObjectWriter( |
60 | MOTW: cast<MCDXContainerTargetWriter>(Val: std::move(TW)), OS); |
61 | default: |
62 | llvm_unreachable("unexpected object format" ); |
63 | } |
64 | } |
65 | |
66 | std::unique_ptr<MCObjectWriter> |
67 | MCAsmBackend::createDwoObjectWriter(raw_pwrite_stream &OS, |
68 | raw_pwrite_stream &DwoOS) const { |
69 | auto TW = createObjectTargetWriter(); |
70 | switch (TW->getFormat()) { |
71 | case Triple::COFF: |
72 | return createWinCOFFDwoObjectWriter( |
73 | MOTW: cast<MCWinCOFFObjectTargetWriter>(Val: std::move(TW)), OS, DwoOS); |
74 | case Triple::ELF: |
75 | return std::make_unique<ELFObjectWriter>( |
76 | args: cast<MCELFObjectTargetWriter>(Val: std::move(TW)), args&: OS, args&: DwoOS, |
77 | args: Endian == llvm::endianness::little); |
78 | case Triple::Wasm: |
79 | return createWasmDwoObjectWriter( |
80 | MOTW: cast<MCWasmObjectTargetWriter>(Val: std::move(TW)), OS, DwoOS); |
81 | default: |
82 | report_fatal_error(reason: "dwo only supported with COFF, ELF, and Wasm" ); |
83 | } |
84 | } |
85 | |
86 | std::optional<MCFixupKind> MCAsmBackend::getFixupKind(StringRef Name) const { |
87 | return std::nullopt; |
88 | } |
89 | |
90 | const MCFixupKindInfo &MCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { |
91 | static const MCFixupKindInfo Builtins[] = { |
92 | {.Name: "FK_NONE" , .TargetOffset: 0, .TargetSize: 0, .Flags: 0}, |
93 | {.Name: "FK_Data_1" , .TargetOffset: 0, .TargetSize: 8, .Flags: 0}, |
94 | {.Name: "FK_Data_2" , .TargetOffset: 0, .TargetSize: 16, .Flags: 0}, |
95 | {.Name: "FK_Data_4" , .TargetOffset: 0, .TargetSize: 32, .Flags: 0}, |
96 | {.Name: "FK_Data_8" , .TargetOffset: 0, .TargetSize: 64, .Flags: 0}, |
97 | {.Name: "FK_Data_leb128" , .TargetOffset: 0, .TargetSize: 0, .Flags: 0}, |
98 | {.Name: "FK_PCRel_1" , .TargetOffset: 0, .TargetSize: 8, .Flags: MCFixupKindInfo::FKF_IsPCRel}, |
99 | {.Name: "FK_PCRel_2" , .TargetOffset: 0, .TargetSize: 16, .Flags: MCFixupKindInfo::FKF_IsPCRel}, |
100 | {.Name: "FK_PCRel_4" , .TargetOffset: 0, .TargetSize: 32, .Flags: MCFixupKindInfo::FKF_IsPCRel}, |
101 | {.Name: "FK_PCRel_8" , .TargetOffset: 0, .TargetSize: 64, .Flags: MCFixupKindInfo::FKF_IsPCRel}, |
102 | {.Name: "FK_GPRel_1" , .TargetOffset: 0, .TargetSize: 8, .Flags: 0}, |
103 | {.Name: "FK_GPRel_2" , .TargetOffset: 0, .TargetSize: 16, .Flags: 0}, |
104 | {.Name: "FK_GPRel_4" , .TargetOffset: 0, .TargetSize: 32, .Flags: 0}, |
105 | {.Name: "FK_GPRel_8" , .TargetOffset: 0, .TargetSize: 64, .Flags: 0}, |
106 | {.Name: "FK_DTPRel_4" , .TargetOffset: 0, .TargetSize: 32, .Flags: 0}, |
107 | {.Name: "FK_DTPRel_8" , .TargetOffset: 0, .TargetSize: 64, .Flags: 0}, |
108 | {.Name: "FK_TPRel_4" , .TargetOffset: 0, .TargetSize: 32, .Flags: 0}, |
109 | {.Name: "FK_TPRel_8" , .TargetOffset: 0, .TargetSize: 64, .Flags: 0}, |
110 | {.Name: "FK_SecRel_1" , .TargetOffset: 0, .TargetSize: 8, .Flags: 0}, |
111 | {.Name: "FK_SecRel_2" , .TargetOffset: 0, .TargetSize: 16, .Flags: 0}, |
112 | {.Name: "FK_SecRel_4" , .TargetOffset: 0, .TargetSize: 32, .Flags: 0}, |
113 | {.Name: "FK_SecRel_8" , .TargetOffset: 0, .TargetSize: 64, .Flags: 0}, |
114 | }; |
115 | |
116 | assert((size_t)Kind <= std::size(Builtins) && "Unknown fixup kind" ); |
117 | return Builtins[Kind]; |
118 | } |
119 | |
120 | bool MCAsmBackend::fixupNeedsRelaxationAdvanced(const MCAssembler &Asm, |
121 | const MCFixup &Fixup, |
122 | bool Resolved, uint64_t Value, |
123 | const MCRelaxableFragment *DF, |
124 | const bool WasForced) const { |
125 | if (!Resolved) |
126 | return true; |
127 | return fixupNeedsRelaxation(Fixup, Value); |
128 | } |
129 | |
130 | bool MCAsmBackend::isDarwinCanonicalPersonality(const MCSymbol *Sym) const { |
131 | // Consider a NULL personality (ie., no personality encoding) to be canonical |
132 | // because it's always at 0. |
133 | if (!Sym) |
134 | return true; |
135 | |
136 | if (!Sym->isMachO()) |
137 | llvm_unreachable("Expected MachO symbols only" ); |
138 | |
139 | StringRef name = Sym->getName(); |
140 | // XXX: We intentionally leave out "___gcc_personality_v0" because, despite |
141 | // being system-defined like these two, it is not very commonly-used. |
142 | // Reserving an empty slot for it seems silly. |
143 | return name == "___gxx_personality_v0" || name == "___objc_personality_v0" ; |
144 | } |
145 | |