250 lines · cpp
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-exception6//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 24using namespace llvm;25 26static 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 Implementation33//34AArch64TargetStreamer::AArch64TargetStreamer(MCStreamer &S)35 : MCTargetStreamer(S), ConstantPools(new AssemblerConstantPools()) {}36 37AArch64TargetStreamer::~AArch64TargetStreamer() = default;38 39void 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 AArch64TargetStreamer50// implementations.51const MCExpr *AArch64TargetStreamer::addConstantPoolEntry(const MCExpr *Expr,52 unsigned Size,53 SMLoc Loc) {54 return ConstantPools->addEntry(Streamer, Expr, Size, Loc);55}56 57void AArch64TargetStreamer::emitCurrentConstantPool() {58 ConstantPools->emitForCurrentSection(Streamer);59}60 61void AArch64TargetStreamer::emitConstantPools() {62 ConstantPools->emitAll(Streamer);63}64 65// finish() - write out any non-empty assembler constant pools and66// write out note.gnu.properties if need.67void AArch64TargetStreamer::finish() {68 if (MarkBTIProperty)69 emitNoteSection(ELF::GNU_PROPERTY_AARCH64_FEATURE_1_BTI);70}71 72void 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 size104 OutStreamer.emitIntValue(ELF::NT_GNU_PROPERTY_TYPE_0, 4);105 OutStreamer.emitBytes(StringRef("GNU", 4)); // note name106 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 size111 OutStreamer.emitIntValue(Flags, 4); // data112 OutStreamer.emitIntValue(0, 4); // pad113 }114 115 // Emit the PAuth ABI compatibility info116 if (PAuthABIPlatform != uint64_t(-1)) {117 OutStreamer.emitIntValue(ELF::GNU_PROPERTY_AARCH64_FEATURE_PAUTH, 4);118 OutStreamer.emitIntValue(8 * 2, 4); // data size119 OutStreamer.emitIntValue(PAuthABIPlatform, 8);120 OutStreamer.emitIntValue(PAuthABIVersion, 8);121 }122 123 OutStreamer.endSection(Nt);124 OutStreamer.switchSection(Cur);125}126 127void AArch64TargetStreamer::emitInst(uint32_t Inst) {128 char Buffer[4];129 130 // We can't just use EmitIntValue here, as that will swap the131 // endianness on big-endian systems (instructions are always132 // 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 141MCTargetStreamer *142llvm::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 152MCTargetStreamer *llvm::createAArch64NullTargetStreamer(MCStreamer &S) {153 return new AArch64TargetStreamer(S);154}155 156void 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 subsection168 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 176std::unique_ptr<MCELFStreamer::AttributeSubSection>177AArch64TargetStreamer::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 186std::unique_ptr<MCELFStreamer::AttributeSubSection>187AArch64TargetStreamer::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 196void 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 exists218 if (Item.Tag == Tag) {219 Item.Type = unsigned(-1) != Value220 ? MCELFStreamer::AttributeItem::NumericAttribute221 : 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 241void 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