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