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 const FeatureBitset &Features = STI.getFeatureBits();
33 auto &MAB = static_cast<RISCVAsmBackend &>(MCA.getBackend());
34 setTargetABI(RISCVABI::computeTargetABI(TT: STI.getTargetTriple(), FeatureBits: Features,
35 ABIName: MAB.getTargetOptions().getABIName()));
36 setFlagsFromFeatures(STI);
37}
38
39RISCVELFStreamer::RISCVELFStreamer(MCContext &C,
40 std::unique_ptr<MCAsmBackend> MAB,
41 std::unique_ptr<MCObjectWriter> MOW,
42 std::unique_ptr<MCCodeEmitter> MCE)
43 : MCELFStreamer(C, std::move(MAB), std::move(MOW), std::move(MCE)) {}
44
45RISCVELFStreamer &RISCVTargetELFStreamer::getStreamer() {
46 return static_cast<RISCVELFStreamer &>(Streamer);
47}
48
49void RISCVTargetELFStreamer::emitDirectiveOptionExact() {}
50void RISCVTargetELFStreamer::emitDirectiveOptionNoExact() {}
51void RISCVTargetELFStreamer::emitDirectiveOptionPIC() {}
52void RISCVTargetELFStreamer::emitDirectiveOptionNoPIC() {}
53void RISCVTargetELFStreamer::emitDirectiveOptionPop() {}
54void RISCVTargetELFStreamer::emitDirectiveOptionPush() {}
55void RISCVTargetELFStreamer::emitDirectiveOptionRelax() {}
56void RISCVTargetELFStreamer::emitDirectiveOptionNoRelax() {}
57void RISCVTargetELFStreamer::emitDirectiveOptionRVC() {}
58void RISCVTargetELFStreamer::emitDirectiveOptionNoRVC() {}
59
60void RISCVTargetELFStreamer::emitAttribute(unsigned Attribute, unsigned Value) {
61 getStreamer().setAttributeItem(Attribute, Value, /*OverwriteExisting=*/true);
62}
63
64void RISCVTargetELFStreamer::emitTextAttribute(unsigned Attribute,
65 StringRef String) {
66 getStreamer().setAttributeItem(Attribute, Value: String, /*OverwriteExisting=*/true);
67}
68
69void RISCVTargetELFStreamer::emitIntTextAttribute(unsigned Attribute,
70 unsigned IntValue,
71 StringRef StringValue) {
72 getStreamer().setAttributeItems(Attribute, IntValue, StringValue,
73 /*OverwriteExisting=*/true);
74}
75
76void RISCVTargetELFStreamer::finishAttributeSection() {
77 RISCVELFStreamer &S = getStreamer();
78 if (S.Contents.empty())
79 return;
80
81 S.emitAttributesSection(Vendor: CurrentVendor, Section: ".riscv.attributes",
82 Type: ELF::SHT_RISCV_ATTRIBUTES, AttributeSection);
83}
84
85void RISCVTargetELFStreamer::finish() {
86 RISCVTargetStreamer::finish();
87 ELFObjectWriter &W = getStreamer().getWriter();
88 RISCVABI::ABI ABI = getTargetABI();
89
90 unsigned EFlags = W.getELFHeaderEFlags();
91
92 if (hasRVC())
93 EFlags |= ELF::EF_RISCV_RVC;
94 if (hasTSO())
95 EFlags |= ELF::EF_RISCV_TSO;
96
97 switch (ABI) {
98 case RISCVABI::ABI_ILP32:
99 case RISCVABI::ABI_LP64:
100 break;
101 case RISCVABI::ABI_ILP32F:
102 case RISCVABI::ABI_LP64F:
103 EFlags |= ELF::EF_RISCV_FLOAT_ABI_SINGLE;
104 break;
105 case RISCVABI::ABI_ILP32D:
106 case RISCVABI::ABI_LP64D:
107 EFlags |= ELF::EF_RISCV_FLOAT_ABI_DOUBLE;
108 break;
109 case RISCVABI::ABI_ILP32E:
110 case RISCVABI::ABI_LP64E:
111 EFlags |= ELF::EF_RISCV_RVE;
112 break;
113 case RISCVABI::ABI_Unknown:
114 llvm_unreachable("Improperly initialised target ABI");
115 }
116
117 W.setELFHeaderEFlags(EFlags);
118}
119
120void RISCVTargetELFStreamer::reset() {
121 AttributeSection = nullptr;
122}
123
124void RISCVTargetELFStreamer::emitDirectiveVariantCC(MCSymbol &Symbol) {
125 getStreamer().getAssembler().registerSymbol(Symbol);
126 static_cast<MCSymbolELF &>(Symbol).setOther(ELF::STO_RISCV_VARIANT_CC);
127}
128
129void RISCVELFStreamer::reset() {
130 static_cast<RISCVTargetStreamer *>(getTargetStreamer())->reset();
131 MCELFStreamer::reset();
132 LastMappingSymbols.clear();
133 LastEMS = EMS_None;
134}
135
136void RISCVELFStreamer::emitDataMappingSymbol() {
137 if (LastEMS == EMS_Data)
138 return;
139 emitMappingSymbol(Name: "$d");
140 LastEMS = EMS_Data;
141}
142
143void RISCVELFStreamer::emitInstructionsMappingSymbol() {
144 if (LastEMS == EMS_Instructions)
145 return;
146 emitMappingSymbol(Name: "$x");
147 LastEMS = EMS_Instructions;
148}
149
150void RISCVELFStreamer::emitMappingSymbol(StringRef Name) {
151 auto *Symbol =
152 static_cast<MCSymbolELF *>(getContext().createLocalSymbol(Name));
153 emitLabel(Symbol);
154 Symbol->setType(ELF::STT_NOTYPE);
155 Symbol->setBinding(ELF::STB_LOCAL);
156}
157
158void RISCVELFStreamer::changeSection(MCSection *Section, uint32_t Subsection) {
159 // We have to keep track of the mapping symbol state of any sections we
160 // use. Each one should start off as EMS_None, which is provided as the
161 // default constructor by DenseMap::lookup.
162 LastMappingSymbols[getPreviousSection().first] = LastEMS;
163 LastEMS = LastMappingSymbols.lookup(Val: Section);
164
165 MCELFStreamer::changeSection(Section, Subsection);
166}
167
168void RISCVELFStreamer::emitInstruction(const MCInst &Inst,
169 const MCSubtargetInfo &STI) {
170 emitInstructionsMappingSymbol();
171 MCELFStreamer::emitInstruction(Inst, STI);
172}
173
174void RISCVELFStreamer::emitBytes(StringRef Data) {
175 emitDataMappingSymbol();
176 MCELFStreamer::emitBytes(Data);
177}
178
179void RISCVELFStreamer::emitFill(const MCExpr &NumBytes, uint64_t FillValue,
180 SMLoc Loc) {
181 emitDataMappingSymbol();
182 MCELFStreamer::emitFill(NumBytes, FillValue, Loc);
183}
184
185void RISCVELFStreamer::emitValueImpl(const MCExpr *Value, unsigned Size,
186 SMLoc Loc) {
187 emitDataMappingSymbol();
188 MCELFStreamer::emitValueImpl(Value, Size, Loc);
189}
190
191MCStreamer *llvm::createRISCVELFStreamer(const Triple &, MCContext &C,
192 std::unique_ptr<MCAsmBackend> &&MAB,
193 std::unique_ptr<MCObjectWriter> &&MOW,
194 std::unique_ptr<MCCodeEmitter> &&MCE) {
195 return new RISCVELFStreamer(C, std::move(MAB), std::move(MOW),
196 std::move(MCE));
197}
198
199void RISCVTargetELFStreamer::emitNoteGnuPropertySection(
200 const uint32_t Feature1And) {
201 MCStreamer &OutStreamer = getStreamer();
202 MCContext &Ctx = OutStreamer.getContext();
203
204 const Triple &Triple = Ctx.getTargetTriple();
205 Align NoteAlign;
206 uint64_t DescSize;
207 if (Triple.isArch64Bit()) {
208 NoteAlign = Align(8);
209 DescSize = 16;
210 } else {
211 assert(Triple.isArch32Bit());
212 NoteAlign = Align(4);
213 DescSize = 12;
214 }
215
216 assert(Ctx.getObjectFileType() == MCContext::Environment::IsELF);
217 MCSection *const NoteSection =
218 Ctx.getELFSection(Section: ".note.gnu.property", Type: ELF::SHT_NOTE, Flags: ELF::SHF_ALLOC);
219 OutStreamer.pushSection();
220 OutStreamer.switchSection(Section: NoteSection);
221
222 // Emit the note header
223 OutStreamer.emitValueToAlignment(Alignment: NoteAlign);
224 OutStreamer.emitIntValue(Value: 4, Size: 4); // n_namsz
225 OutStreamer.emitIntValue(Value: DescSize, Size: 4); // n_descsz
226 OutStreamer.emitIntValue(Value: ELF::NT_GNU_PROPERTY_TYPE_0, Size: 4); // n_type
227 OutStreamer.emitBytes(Data: StringRef("GNU", 4)); // n_name
228
229 // Emit n_desc field
230
231 // Emit the feature_1_and property
232 OutStreamer.emitIntValue(Value: ELF::GNU_PROPERTY_RISCV_FEATURE_1_AND, Size: 4); // pr_type
233 OutStreamer.emitIntValue(Value: 4, Size: 4); // pr_datasz
234 OutStreamer.emitIntValue(Value: Feature1And, Size: 4); // pr_data
235 OutStreamer.emitValueToAlignment(Alignment: NoteAlign); // pr_padding
236
237 OutStreamer.popSection();
238}
239