xref: /llvm-project/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp (revision de4bbbfdccb6172c563b07889ecfb06bc4974a7e)
1 //===- AArch64TargetStreamer.cpp - AArch64TargetStreamer class ------------===//
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 implements the AArch64TargetStreamer class.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "AArch64TargetStreamer.h"
14 #include "AArch64MCAsmInfo.h"
15 #include "llvm/BinaryFormat/ELF.h"
16 #include "llvm/MC/ConstantPools.h"
17 #include "llvm/MC/MCContext.h"
18 #include "llvm/MC/MCSection.h"
19 #include "llvm/MC/MCSectionELF.h"
20 #include "llvm/MC/MCSubtargetInfo.h"
21 #include "llvm/Support/CommandLine.h"
22 
23 using namespace llvm;
24 
25 static cl::opt<bool> MarkBTIProperty(
26     "aarch64-mark-bti-property", cl::Hidden,
27     cl::desc("Add .note.gnu.property with BTI to assembly files"),
28     cl::init(false));
29 
30 //
31 // AArch64TargetStreamer Implemenation
32 //
33 AArch64TargetStreamer::AArch64TargetStreamer(MCStreamer &S)
34     : MCTargetStreamer(S), ConstantPools(new AssemblerConstantPools()) {}
35 
36 AArch64TargetStreamer::~AArch64TargetStreamer() = default;
37 
38 void AArch64TargetStreamer::emitAuthValue(const MCExpr *Expr,
39                                           uint16_t Discriminator,
40                                           AArch64PACKey::ID Key,
41                                           bool HasAddressDiversity) {
42   Streamer.emitValueImpl(AArch64AuthMCExpr::create(Expr, Discriminator, Key,
43                                                    HasAddressDiversity,
44                                                    Streamer.getContext()),
45                          8);
46 }
47 
48 // The constant pool handling is shared by all AArch64TargetStreamer
49 // implementations.
50 const MCExpr *AArch64TargetStreamer::addConstantPoolEntry(const MCExpr *Expr,
51                                                           unsigned Size,
52                                                           SMLoc Loc) {
53   return ConstantPools->addEntry(Streamer, Expr, Size, Loc);
54 }
55 
56 void AArch64TargetStreamer::emitCurrentConstantPool() {
57   ConstantPools->emitForCurrentSection(Streamer);
58 }
59 
60 void AArch64TargetStreamer::emitConstantPools() {
61   ConstantPools->emitAll(Streamer);
62 }
63 
64 // finish() - write out any non-empty assembler constant pools and
65 //   write out note.gnu.properties if need.
66 void AArch64TargetStreamer::finish() {
67   if (MarkBTIProperty)
68     emitNoteSection(ELF::GNU_PROPERTY_AARCH64_FEATURE_1_BTI);
69 }
70 
71 void AArch64TargetStreamer::emitNoteSection(unsigned Flags,
72                                             uint64_t PAuthABIPlatform,
73                                             uint64_t PAuthABIVersion) {
74   assert((PAuthABIPlatform == uint64_t(-1)) ==
75          (PAuthABIVersion == uint64_t(-1)));
76   uint64_t DescSz = 0;
77   if (Flags != 0)
78     DescSz += 4 * 4;
79   if (PAuthABIPlatform != uint64_t(-1))
80     DescSz += 4 + 4 + 8 * 2;
81   if (DescSz == 0)
82     return;
83 
84   MCStreamer &OutStreamer = getStreamer();
85   MCContext &Context = OutStreamer.getContext();
86   // Emit a .note.gnu.property section with the flags.
87   MCSectionELF *Nt = Context.getELFSection(".note.gnu.property", ELF::SHT_NOTE,
88                                            ELF::SHF_ALLOC);
89   if (Nt->isRegistered()) {
90     SMLoc Loc;
91     Context.reportWarning(
92         Loc,
93         "The .note.gnu.property is not emitted because it is already present.");
94     return;
95   }
96   MCSection *Cur = OutStreamer.getCurrentSectionOnly();
97   OutStreamer.switchSection(Nt);
98 
99   // Emit the note header.
100   OutStreamer.emitValueToAlignment(Align(8));
101   OutStreamer.emitIntValue(4, 4);     // data size for "GNU\0"
102   OutStreamer.emitIntValue(DescSz, 4); // Elf_Prop array size
103   OutStreamer.emitIntValue(ELF::NT_GNU_PROPERTY_TYPE_0, 4);
104   OutStreamer.emitBytes(StringRef("GNU", 4)); // note name
105 
106   // Emit the PAC/BTI properties.
107   if (Flags != 0) {
108     OutStreamer.emitIntValue(ELF::GNU_PROPERTY_AARCH64_FEATURE_1_AND, 4);
109     OutStreamer.emitIntValue(4, 4);     // data size
110     OutStreamer.emitIntValue(Flags, 4); // data
111     OutStreamer.emitIntValue(0, 4);     // pad
112   }
113 
114   // Emit the PAuth ABI compatibility info
115   if (PAuthABIPlatform != uint64_t(-1)) {
116     OutStreamer.emitIntValue(ELF::GNU_PROPERTY_AARCH64_FEATURE_PAUTH, 4);
117     OutStreamer.emitIntValue(8 * 2, 4); // data size
118     OutStreamer.emitIntValue(PAuthABIPlatform, 8);
119     OutStreamer.emitIntValue(PAuthABIVersion, 8);
120   }
121 
122   OutStreamer.endSection(Nt);
123   OutStreamer.switchSection(Cur);
124 }
125 
126 void AArch64TargetStreamer::emitInst(uint32_t Inst) {
127   char Buffer[4];
128 
129   // We can't just use EmitIntValue here, as that will swap the
130   // endianness on big-endian systems (instructions are always
131   // little-endian).
132   for (char &C : Buffer) {
133     C = uint8_t(Inst);
134     Inst >>= 8;
135   }
136 
137   getStreamer().emitBytes(StringRef(Buffer, 4));
138 }
139 
140 MCTargetStreamer *
141 llvm::createAArch64ObjectTargetStreamer(MCStreamer &S,
142                                         const MCSubtargetInfo &STI) {
143   const Triple &TT = STI.getTargetTriple();
144   if (TT.isOSBinFormatELF())
145     return new AArch64TargetELFStreamer(S);
146   if (TT.isOSBinFormatCOFF())
147     return new AArch64TargetWinCOFFStreamer(S);
148   return nullptr;
149 }
150 
151 MCTargetStreamer *llvm::createAArch64NullTargetStreamer(MCStreamer &S) {
152   return new AArch64TargetStreamer(S);
153 }
154 
155 void AArch64TargetStreamer::emitAtributesSubsection(
156     StringRef VendorName, AArch64BuildAttrs::SubsectionOptional IsOptional,
157     AArch64BuildAttrs::SubsectionType ParameterType) {
158 
159   // If exists, return.
160   for (MCELFStreamer::AttributeSubSection &SubSection : AttributeSubSections) {
161     if (VendorName == SubSection.VendorName) {
162       activateAtributesSubsection(VendorName);
163       return;
164     }
165   }
166   // else, add the subsection
167   MCELFStreamer::AttributeSubSection AttSubSection;
168   AttSubSection.VendorName = VendorName;
169   AttSubSection.IsOptional = IsOptional;
170   AttSubSection.ParameterType = ParameterType;
171   AttributeSubSections.push_back(AttSubSection);
172   activateAtributesSubsection(VendorName);
173 }
174 
175 std::unique_ptr<MCELFStreamer::AttributeSubSection>
176 AArch64TargetStreamer::getActiveAtributesSubsection() {
177   for (MCELFStreamer::AttributeSubSection &SubSection : AttributeSubSections) {
178     if (SubSection.IsActive) {
179       return std::make_unique<MCELFStreamer::AttributeSubSection>(SubSection);
180     }
181   }
182   return nullptr;
183 }
184 
185 std::unique_ptr<MCELFStreamer::AttributeSubSection>
186 AArch64TargetStreamer::getAtributesSubsectionByName(StringRef Name) {
187   for (MCELFStreamer::AttributeSubSection &SubSection : AttributeSubSections) {
188     if (Name == SubSection.VendorName) {
189       return std::make_unique<MCELFStreamer::AttributeSubSection>(SubSection);
190     }
191   }
192   return nullptr;
193 }
194 
195 void AArch64TargetStreamer::emitAttribute(StringRef VendorName, unsigned Tag,
196                                           unsigned Value, std::string String,
197                                           bool Override) {
198 
199   if (unsigned(-1) == Value && "" == String) {
200     assert(0 && "Arguments error");
201     return;
202   }
203   if (AttributeSubSections.size() == 0) {
204     assert(0 &&
205            "Can not add AArch64 build attribute: no AArch64 subsection exists");
206     return;
207   }
208 
209   for (MCELFStreamer::AttributeSubSection &SubSection : AttributeSubSections) {
210     if (VendorName == SubSection.VendorName) {
211       if (!SubSection.IsActive) {
212         assert(0 &&
213                "Can not add AArch64 build attribute: subsection is not active");
214         return;
215       }
216       for (MCELFStreamer::AttributeItem &Item : SubSection.Content) {
217         if (Item.Tag == Tag) {
218           if (!Override) {
219             if ((unsigned(-1) != Value && Item.IntValue != Value) ||
220                 ("" != String && Item.StringValue != String)) {
221               assert(0 &&
222                      "Can not add AArch64 build attribute: An attribute with "
223                      "the same tag and a different value already exists");
224               return;
225             } else {
226               // Case Item.IntValue == Value, no need to emit twice
227               assert(0 &&
228                      "AArch64 build attribute: An attribute with the same tag "
229                      "and a same value already exists");
230               return;
231             }
232           }
233         }
234       }
235       if (unsigned(-1) != Value)
236         SubSection.Content.push_back(MCELFStreamer::AttributeItem(
237             MCELFStreamer::AttributeItem::NumericAttribute, Tag, Value, ""));
238       if ("" != String)
239         SubSection.Content.push_back(MCELFStreamer::AttributeItem(
240             MCELFStreamer::AttributeItem::TextAttribute, Tag, unsigned(-1),
241             String));
242       return;
243     }
244   }
245   assert(0 && "Can not add AArch64 build attribute: required subsection does "
246               "not exist");
247 }
248 
249 void AArch64TargetStreamer::activateAtributesSubsection(StringRef VendorName) {
250   for (MCELFStreamer::AttributeSubSection &SubSection : AttributeSubSections) {
251     if (VendorName == SubSection.VendorName) {
252       SubSection.IsActive = true;
253     } else {
254       SubSection.IsActive = false;
255     }
256   }
257 }