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 }