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