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 // The constant pool handling is shared by all AArch64TargetStreamer 39 // implementations. 40 const MCExpr *AArch64TargetStreamer::addConstantPoolEntry(const MCExpr *Expr, 41 unsigned Size, 42 SMLoc Loc) { 43 return ConstantPools->addEntry(Streamer, Expr, Size, Loc); 44 } 45 46 void AArch64TargetStreamer::emitCurrentConstantPool() { 47 ConstantPools->emitForCurrentSection(Streamer); 48 } 49 50 void AArch64TargetStreamer::emitConstantPools() { 51 ConstantPools->emitAll(Streamer); 52 } 53 54 // finish() - write out any non-empty assembler constant pools and 55 // write out note.gnu.properties if need. 56 void AArch64TargetStreamer::finish() { 57 if (MarkBTIProperty) 58 emitNoteSection(ELF::GNU_PROPERTY_AARCH64_FEATURE_1_BTI); 59 } 60 61 void AArch64TargetStreamer::emitNoteSection(unsigned Flags, 62 uint64_t PAuthABIPlatform, 63 uint64_t PAuthABIVersion) { 64 assert((PAuthABIPlatform == uint64_t(-1)) == 65 (PAuthABIVersion == uint64_t(-1))); 66 uint64_t DescSz = 0; 67 if (Flags != 0) 68 DescSz += 4 * 4; 69 if (PAuthABIPlatform != uint64_t(-1)) 70 DescSz += 4 + 4 + 8 * 2; 71 if (DescSz == 0) 72 return; 73 74 MCStreamer &OutStreamer = getStreamer(); 75 MCContext &Context = OutStreamer.getContext(); 76 // Emit a .note.gnu.property section with the flags. 77 MCSectionELF *Nt = Context.getELFSection(".note.gnu.property", ELF::SHT_NOTE, 78 ELF::SHF_ALLOC); 79 if (Nt->isRegistered()) { 80 SMLoc Loc; 81 Context.reportWarning( 82 Loc, 83 "The .note.gnu.property is not emitted because it is already present."); 84 return; 85 } 86 MCSection *Cur = OutStreamer.getCurrentSectionOnly(); 87 OutStreamer.switchSection(Nt); 88 89 // Emit the note header. 90 OutStreamer.emitValueToAlignment(Align(8)); 91 OutStreamer.emitIntValue(4, 4); // data size for "GNU\0" 92 OutStreamer.emitIntValue(DescSz, 4); // Elf_Prop array size 93 OutStreamer.emitIntValue(ELF::NT_GNU_PROPERTY_TYPE_0, 4); 94 OutStreamer.emitBytes(StringRef("GNU", 4)); // note name 95 96 // Emit the PAC/BTI properties. 97 if (Flags != 0) { 98 OutStreamer.emitIntValue(ELF::GNU_PROPERTY_AARCH64_FEATURE_1_AND, 4); 99 OutStreamer.emitIntValue(4, 4); // data size 100 OutStreamer.emitIntValue(Flags, 4); // data 101 OutStreamer.emitIntValue(0, 4); // pad 102 } 103 104 // Emit the PAuth ABI compatibility info 105 if (PAuthABIPlatform != uint64_t(-1)) { 106 OutStreamer.emitIntValue(ELF::GNU_PROPERTY_AARCH64_FEATURE_PAUTH, 4); 107 OutStreamer.emitIntValue(8 * 2, 4); // data size 108 OutStreamer.emitIntValue(PAuthABIPlatform, 8); 109 OutStreamer.emitIntValue(PAuthABIVersion, 8); 110 } 111 112 OutStreamer.endSection(Nt); 113 OutStreamer.switchSection(Cur); 114 } 115 116 void AArch64TargetStreamer::emitInst(uint32_t Inst) { 117 char Buffer[4]; 118 119 // We can't just use EmitIntValue here, as that will swap the 120 // endianness on big-endian systems (instructions are always 121 // little-endian). 122 for (char &C : Buffer) { 123 C = uint8_t(Inst); 124 Inst >>= 8; 125 } 126 127 getStreamer().emitBytes(StringRef(Buffer, 4)); 128 } 129 130 MCTargetStreamer * 131 llvm::createAArch64ObjectTargetStreamer(MCStreamer &S, 132 const MCSubtargetInfo &STI) { 133 const Triple &TT = STI.getTargetTriple(); 134 if (TT.isOSBinFormatELF()) 135 return new AArch64TargetELFStreamer(S); 136 if (TT.isOSBinFormatCOFF()) 137 return new AArch64TargetWinCOFFStreamer(S); 138 return nullptr; 139 } 140 141 MCTargetStreamer *llvm::createAArch64NullTargetStreamer(MCStreamer &S) { 142 return new AArch64TargetStreamer(S); 143 } 144