| 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(Val: 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(Value: AArch64AuthMCExpr::create(Expr, Discriminator, Key, |
| 44 | HasAddressDiversity, |
| 45 | Ctx&: Streamer.getContext()), |
| 46 | Size: 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(Flags: 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(Section: ".note.gnu.property" , Type: ELF::SHT_NOTE, |
| 89 | Flags: ELF::SHF_ALLOC); |
| 90 | if (Nt->isRegistered()) { |
| 91 | SMLoc Loc; |
| 92 | Context.reportWarning( |
| 93 | L: Loc, |
| 94 | Msg: "The .note.gnu.property is not emitted because it is already present." ); |
| 95 | return; |
| 96 | } |
| 97 | MCSection *Cur = OutStreamer.getCurrentSectionOnly(); |
| 98 | OutStreamer.switchSection(Section: Nt); |
| 99 | |
| 100 | // Emit the note header. |
| 101 | OutStreamer.emitValueToAlignment(Alignment: Align(8)); |
| 102 | OutStreamer.emitIntValue(Value: 4, Size: 4); // data size for "GNU\0" |
| 103 | OutStreamer.emitIntValue(Value: DescSz, Size: 4); // Elf_Prop array size |
| 104 | OutStreamer.emitIntValue(Value: ELF::NT_GNU_PROPERTY_TYPE_0, Size: 4); |
| 105 | OutStreamer.emitBytes(Data: StringRef("GNU" , 4)); // note name |
| 106 | |
| 107 | // Emit the PAC/BTI properties. |
| 108 | if (Flags != 0) { |
| 109 | OutStreamer.emitIntValue(Value: ELF::GNU_PROPERTY_AARCH64_FEATURE_1_AND, Size: 4); |
| 110 | OutStreamer.emitIntValue(Value: 4, Size: 4); // data size |
| 111 | OutStreamer.emitIntValue(Value: Flags, Size: 4); // data |
| 112 | OutStreamer.emitIntValue(Value: 0, Size: 4); // pad |
| 113 | } |
| 114 | |
| 115 | // Emit the PAuth ABI compatibility info |
| 116 | if (PAuthABIPlatform != uint64_t(-1)) { |
| 117 | OutStreamer.emitIntValue(Value: ELF::GNU_PROPERTY_AARCH64_FEATURE_PAUTH, Size: 4); |
| 118 | OutStreamer.emitIntValue(Value: 8 * 2, Size: 4); // data size |
| 119 | OutStreamer.emitIntValue(Value: PAuthABIPlatform, Size: 8); |
| 120 | OutStreamer.emitIntValue(Value: PAuthABIVersion, Size: 8); |
| 121 | } |
| 122 | |
| 123 | OutStreamer.endSection(Section: Nt); |
| 124 | OutStreamer.switchSection(Section: 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(Data: 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(Elt: 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>(args&: 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>(args&: 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(Elt: MCELFStreamer::AttributeItem( |
| 229 | MCELFStreamer::AttributeItem::NumericAttribute, Tag, Value, "" )); |
| 230 | if ("" != String) |
| 231 | SubSection.Content.push_back(Elt: 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 | |