1//===-- RISCVELFStreamer.cpp - RISC-V ELF Target Streamer Methods ---------===//
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// This file provides RISC-V specific target streamer methods.
10//
11//===----------------------------------------------------------------------===//
12
13#include "RISCVELFStreamer.h"
14#include "RISCVAsmBackend.h"
15#include "RISCVBaseInfo.h"
16#include "RISCVMCTargetDesc.h"
17#include "llvm/BinaryFormat/ELF.h"
18#include "llvm/MC/MCAsmBackend.h"
19#include "llvm/MC/MCAssembler.h"
20#include "llvm/MC/MCCodeEmitter.h"
21#include "llvm/MC/MCContext.h"
22#include "llvm/MC/MCELFObjectWriter.h"
23#include "llvm/MC/MCSubtargetInfo.h"
24
25using namespace llvm;
26
27// This part is for ELF object output.
28RISCVTargetELFStreamer::RISCVTargetELFStreamer(MCStreamer &S,
29 const MCSubtargetInfo &STI)
30 : RISCVTargetStreamer(S), CurrentVendor("riscv") {
31 MCAssembler &MCA = getStreamer().getAssembler();
32 auto &MAB = static_cast<RISCVAsmBackend &>(MCA.getBackend());
33 setTargetABI(
34 RISCVABI::computeTargetABI(STI, ABIName: MAB.getTargetOptions().getABIName()));
35 setFlagsFromFeatures(STI);
36
37 // Compute the initial ISA string. This serves two purposes:
38 // 1. Deduplication: subsequent .option arch/rvc/norvc directives compare
39 // against ArchString to avoid propagating redundant ISA updates.
40 // 2. Initial symbol: seed the streamer's active ISA so a "$x<ArchString>"
41 // mapping symbol is emitted before the first instruction, recording
42 // the full ISA in the object even when no .option directive is present.
43 if (auto ParseResult = RISCVFeatures::parseFeatureBits(STI)) {
44 InitialArchString = (*ParseResult)->toString();
45 ArchString = InitialArchString;
46 getStreamer().setMappingSymbolArch(ArchString);
47 }
48}
49
50RISCVELFStreamer::RISCVELFStreamer(MCContext &C,
51 std::unique_ptr<MCAsmBackend> MAB,
52 std::unique_ptr<MCObjectWriter> MOW,
53 std::unique_ptr<MCCodeEmitter> MCE)
54 : MCELFStreamer(C, std::move(MAB), std::move(MOW), std::move(MCE)) {}
55
56RISCVELFStreamer &RISCVTargetELFStreamer::getStreamer() {
57 return static_cast<RISCVELFStreamer &>(Streamer);
58}
59
60void RISCVTargetELFStreamer::setArchString(StringRef Arch) {
61 if (Arch == ArchString)
62 return;
63 ArchString = std::string(Arch);
64 getStreamer().setMappingSymbolArch(Arch);
65}
66
67void RISCVTargetELFStreamer::emitDirectiveOptionPush() {
68 ArchStringStack.push_back(Elt: ArchString);
69}
70
71void RISCVTargetELFStreamer::emitDirectiveOptionPop() {
72 if (!ArchStringStack.empty())
73 setArchString(ArchStringStack.pop_back_val());
74}
75
76void RISCVTargetELFStreamer::emitDirectiveOptionExact() {}
77void RISCVTargetELFStreamer::emitDirectiveOptionNoExact() {}
78void RISCVTargetELFStreamer::emitDirectiveOptionPIC() {}
79void RISCVTargetELFStreamer::emitDirectiveOptionNoPIC() {}
80void RISCVTargetELFStreamer::emitDirectiveOptionRelax() {}
81void RISCVTargetELFStreamer::emitDirectiveOptionNoRelax() {}
82void RISCVTargetELFStreamer::emitDirectiveOptionRVC() {}
83void RISCVTargetELFStreamer::emitDirectiveOptionNoRVC() {}
84
85void RISCVTargetELFStreamer::emitAttribute(unsigned Attribute, unsigned Value) {
86 getStreamer().setAttributeItem(Attribute, Value, /*OverwriteExisting=*/true);
87}
88
89void RISCVTargetELFStreamer::emitTextAttribute(unsigned Attribute,
90 StringRef String) {
91 getStreamer().setAttributeItem(Attribute, Value: String, /*OverwriteExisting=*/true);
92}
93
94void RISCVTargetELFStreamer::emitIntTextAttribute(unsigned Attribute,
95 unsigned IntValue,
96 StringRef StringValue) {
97 getStreamer().setAttributeItems(Attribute, IntValue, StringValue,
98 /*OverwriteExisting=*/true);
99}
100
101void RISCVTargetELFStreamer::finishAttributeSection() {
102 RISCVELFStreamer &S = getStreamer();
103 if (S.Contents.empty())
104 return;
105
106 S.emitAttributesSection(Vendor: CurrentVendor, Section: ".riscv.attributes",
107 Type: ELF::SHT_RISCV_ATTRIBUTES, AttributeSection);
108}
109
110void RISCVTargetELFStreamer::finish() {
111 RISCVTargetStreamer::finish();
112 ELFObjectWriter &W = getStreamer().getWriter();
113 RISCVABI::ABI ABI = getTargetABI();
114
115 unsigned EFlags = W.getELFHeaderEFlags();
116
117 if (hasRVC())
118 EFlags |= ELF::EF_RISCV_RVC;
119 if (hasTSO())
120 EFlags |= ELF::EF_RISCV_TSO;
121
122 switch (ABI) {
123 case RISCVABI::ABI_ILP32:
124 case RISCVABI::ABI_IL32PC64:
125 case RISCVABI::ABI_LP64:
126 case RISCVABI::ABI_L64PC128:
127 break;
128 case RISCVABI::ABI_ILP32F:
129 case RISCVABI::ABI_IL32PC64F:
130 case RISCVABI::ABI_LP64F:
131 case RISCVABI::ABI_L64PC128F:
132 EFlags |= ELF::EF_RISCV_FLOAT_ABI_SINGLE;
133 break;
134 case RISCVABI::ABI_ILP32D:
135 case RISCVABI::ABI_IL32PC64D:
136 case RISCVABI::ABI_LP64D:
137 case RISCVABI::ABI_L64PC128D:
138 EFlags |= ELF::EF_RISCV_FLOAT_ABI_DOUBLE;
139 break;
140 case RISCVABI::ABI_ILP32E:
141 case RISCVABI::ABI_IL32PC64E:
142 case RISCVABI::ABI_LP64E:
143 case RISCVABI::ABI_CHERIOT:
144 EFlags |= ELF::EF_RISCV_RVE;
145 break;
146 case RISCVABI::ABI_Unknown:
147 llvm_unreachable("Improperly initialised target ABI");
148 }
149
150 W.setELFHeaderEFlags(EFlags);
151}
152
153void RISCVTargetELFStreamer::reset() {
154 AttributeSection = nullptr;
155 ArchString = InitialArchString;
156 ArchStringStack.clear();
157 // Re-seed the streamer's active ISA so the first instruction after reset
158 // still records the full ISA via "$x<ISA>", matching the behaviour set up
159 // in the constructor.
160 if (!InitialArchString.empty())
161 getStreamer().setMappingSymbolArch(InitialArchString);
162}
163
164void RISCVTargetELFStreamer::emitDirectiveVariantCC(MCSymbol &Symbol) {
165 getStreamer().getAssembler().registerSymbol(Symbol);
166 static_cast<MCSymbolELF &>(Symbol).setOther(ELF::STO_RISCV_VARIANT_CC);
167}
168
169void RISCVELFStreamer::reset() {
170 MCELFStreamer::reset();
171 LastMappingSymbols.clear();
172 LastEMS = EMS_None;
173 MappingSymbolArch.clear();
174 LastEmittedArch.clear();
175 LastEmittedArchInSection.clear();
176 // Call target streamer reset last: it may call setMappingSymbolArch to
177 // re-seed the initial ISA after our state has been cleared.
178 static_cast<RISCVTargetStreamer *>(getTargetStreamer())->reset();
179}
180
181void RISCVELFStreamer::emitDataMappingSymbol() {
182 if (LastEMS == EMS_Data)
183 return;
184 emitMappingSymbol(Name: "$d");
185 LastEMS = EMS_Data;
186}
187
188void RISCVELFStreamer::emitInstructionsMappingSymbol() {
189 // Emit a mapping symbol at the start of each instruction run, and whenever
190 // the active ISA has changed since the last one emitted in this section.
191 // The symbol takes the form "$x<ISA>" when MappingSymbolArch is known, or
192 // plain "$x" as a fallback. The comparison with LastEmittedArch provides
193 // deduplication: repeating .option arch with the same ISA, or re-entering a
194 // section whose last mapping symbol already matches the active ISA, emits
195 // no redundant symbol.
196 bool NeedSymbol =
197 LastEMS != EMS_Instructions || LastEmittedArch != MappingSymbolArch;
198 if (NeedSymbol) {
199 if (MappingSymbolArch.empty())
200 emitMappingSymbol(Name: "$x");
201 else
202 emitMappingSymbol(Name: "$x" + MappingSymbolArch);
203 LastEmittedArch = MappingSymbolArch;
204 }
205 LastEMS = EMS_Instructions;
206}
207
208void RISCVELFStreamer::emitMappingSymbol(StringRef Name) {
209 auto *Symbol =
210 static_cast<MCSymbolELF *>(getContext().createLocalSymbol(Name));
211 emitLabel(Symbol);
212 Symbol->setType(ELF::STT_NOTYPE);
213 Symbol->setBinding(ELF::STB_LOCAL);
214}
215
216void RISCVELFStreamer::setMappingSymbolArch(StringRef Arch) {
217 MappingSymbolArch = std::string(Arch);
218}
219
220void RISCVELFStreamer::changeSection(MCSection *Section, uint32_t Subsection) {
221 // We have to keep track of the mapping symbol state of any sections we
222 // use. Each one should start off as EMS_None, which is provided as the
223 // default constructor by DenseMap::lookup. The last ISA suffix emitted in
224 // each section is also preserved so that re-entering a section only emits a
225 // new "$x<ISA>" symbol when the active ISA has actually changed.
226 const MCSection *Prev = getPreviousSection().first;
227 LastMappingSymbols[Prev] = LastEMS;
228 LastEmittedArchInSection[Prev] = LastEmittedArch;
229 LastEMS = LastMappingSymbols.lookup(Val: Section);
230 auto It = LastEmittedArchInSection.find(Val: Section);
231 LastEmittedArch = It != LastEmittedArchInSection.end() ? It->second : "";
232
233 MCELFStreamer::changeSection(Section, Subsection);
234}
235
236void RISCVELFStreamer::emitInstruction(const MCInst &Inst,
237 const MCSubtargetInfo &STI) {
238 emitInstructionsMappingSymbol();
239 MCELFStreamer::emitInstruction(Inst, STI);
240}
241
242void RISCVELFStreamer::emitBytes(StringRef Data) {
243 emitDataMappingSymbol();
244 MCELFStreamer::emitBytes(Data);
245}
246
247void RISCVELFStreamer::emitFill(const MCExpr &NumBytes, uint64_t FillValue,
248 SMLoc Loc) {
249 emitDataMappingSymbol();
250 MCELFStreamer::emitFill(NumBytes, FillValue, Loc);
251}
252
253void RISCVELFStreamer::emitValueImpl(const MCExpr *Value, unsigned Size,
254 SMLoc Loc) {
255 emitDataMappingSymbol();
256 MCELFStreamer::emitValueImpl(Value, Size, Loc);
257}
258
259MCStreamer *llvm::createRISCVELFStreamer(const Triple &, MCContext &C,
260 std::unique_ptr<MCAsmBackend> &&MAB,
261 std::unique_ptr<MCObjectWriter> &&MOW,
262 std::unique_ptr<MCCodeEmitter> &&MCE) {
263 return new RISCVELFStreamer(C, std::move(MAB), std::move(MOW),
264 std::move(MCE));
265}
266
267void RISCVTargetELFStreamer::emitNoteGnuPropertySection(
268 const uint32_t Feature1And) {
269 MCStreamer &OutStreamer = getStreamer();
270 MCContext &Ctx = OutStreamer.getContext();
271
272 const Triple &Triple = Ctx.getTargetTriple();
273 Align NoteAlign;
274 uint64_t DescSize;
275 if (Triple.isArch64Bit()) {
276 NoteAlign = Align(8);
277 DescSize = 16;
278 } else {
279 assert(Triple.isArch32Bit());
280 NoteAlign = Align(4);
281 DescSize = 12;
282 }
283
284 assert(Ctx.getObjectFileType() == MCContext::Environment::IsELF);
285 MCSection *const NoteSection =
286 Ctx.getELFSection(Section: ".note.gnu.property", Type: ELF::SHT_NOTE, Flags: ELF::SHF_ALLOC);
287 OutStreamer.pushSection();
288 OutStreamer.switchSection(Section: NoteSection);
289
290 // Emit the note header
291 OutStreamer.emitValueToAlignment(Alignment: NoteAlign);
292 OutStreamer.emitIntValue(Value: 4, Size: 4); // n_namsz
293 OutStreamer.emitIntValue(Value: DescSize, Size: 4); // n_descsz
294 OutStreamer.emitIntValue(Value: ELF::NT_GNU_PROPERTY_TYPE_0, Size: 4); // n_type
295 OutStreamer.emitBytes(Data: StringRef("GNU", 4)); // n_name
296
297 // Emit n_desc field
298
299 // Emit the feature_1_and property
300 OutStreamer.emitIntValue(Value: ELF::GNU_PROPERTY_RISCV_FEATURE_1_AND, Size: 4); // pr_type
301 OutStreamer.emitIntValue(Value: 4, Size: 4); // pr_datasz
302 OutStreamer.emitIntValue(Value: Feature1And, Size: 4); // pr_data
303 OutStreamer.emitValueToAlignment(Alignment: NoteAlign); // pr_padding
304
305 OutStreamer.popSection();
306}
307