10b57cec5SDimitry Andric //===- AArch64TargetStreamer.cpp - AArch64TargetStreamer class ------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements the AArch64TargetStreamer class.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric
130b57cec5SDimitry Andric #include "AArch64TargetStreamer.h"
14e8d8bef9SDimitry Andric #include "AArch64MCAsmInfo.h"
15e8d8bef9SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
160b57cec5SDimitry Andric #include "llvm/MC/ConstantPools.h"
17e8d8bef9SDimitry Andric #include "llvm/MC/MCContext.h"
180b57cec5SDimitry Andric #include "llvm/MC/MCSection.h"
19e8d8bef9SDimitry Andric #include "llvm/MC/MCSectionELF.h"
200b57cec5SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
21e8d8bef9SDimitry Andric #include "llvm/Support/CommandLine.h"
220b57cec5SDimitry Andric
230b57cec5SDimitry Andric using namespace llvm;
240b57cec5SDimitry Andric
25e8d8bef9SDimitry Andric static cl::opt<bool> MarkBTIProperty(
26e8d8bef9SDimitry Andric "aarch64-mark-bti-property", cl::Hidden,
27e8d8bef9SDimitry Andric cl::desc("Add .note.gnu.property with BTI to assembly files"),
28e8d8bef9SDimitry Andric cl::init(false));
29e8d8bef9SDimitry Andric
300b57cec5SDimitry Andric //
310b57cec5SDimitry Andric // AArch64TargetStreamer Implemenation
320b57cec5SDimitry Andric //
AArch64TargetStreamer(MCStreamer & S)330b57cec5SDimitry Andric AArch64TargetStreamer::AArch64TargetStreamer(MCStreamer &S)
340b57cec5SDimitry Andric : MCTargetStreamer(S), ConstantPools(new AssemblerConstantPools()) {}
350b57cec5SDimitry Andric
360b57cec5SDimitry Andric AArch64TargetStreamer::~AArch64TargetStreamer() = default;
370b57cec5SDimitry Andric
380b57cec5SDimitry Andric // The constant pool handling is shared by all AArch64TargetStreamer
390b57cec5SDimitry Andric // implementations.
addConstantPoolEntry(const MCExpr * Expr,unsigned Size,SMLoc Loc)400b57cec5SDimitry Andric const MCExpr *AArch64TargetStreamer::addConstantPoolEntry(const MCExpr *Expr,
410b57cec5SDimitry Andric unsigned Size,
420b57cec5SDimitry Andric SMLoc Loc) {
430b57cec5SDimitry Andric return ConstantPools->addEntry(Streamer, Expr, Size, Loc);
440b57cec5SDimitry Andric }
450b57cec5SDimitry Andric
emitCurrentConstantPool()460b57cec5SDimitry Andric void AArch64TargetStreamer::emitCurrentConstantPool() {
470b57cec5SDimitry Andric ConstantPools->emitForCurrentSection(Streamer);
480b57cec5SDimitry Andric }
490b57cec5SDimitry Andric
emitConstantPools()50349cc55cSDimitry Andric void AArch64TargetStreamer::emitConstantPools() {
51349cc55cSDimitry Andric ConstantPools->emitAll(Streamer);
52349cc55cSDimitry Andric }
53349cc55cSDimitry Andric
54e8d8bef9SDimitry Andric // finish() - write out any non-empty assembler constant pools and
55e8d8bef9SDimitry Andric // write out note.gnu.properties if need.
finish()56e8d8bef9SDimitry Andric void AArch64TargetStreamer::finish() {
57e8d8bef9SDimitry Andric if (MarkBTIProperty)
58e8d8bef9SDimitry Andric emitNoteSection(ELF::GNU_PROPERTY_AARCH64_FEATURE_1_BTI);
59e8d8bef9SDimitry Andric }
60e8d8bef9SDimitry Andric
emitNoteSection(unsigned Flags,uint64_t PAuthABIPlatform,uint64_t PAuthABIVersion)61*0fca6ea1SDimitry Andric void AArch64TargetStreamer::emitNoteSection(unsigned Flags,
62*0fca6ea1SDimitry Andric uint64_t PAuthABIPlatform,
63*0fca6ea1SDimitry Andric uint64_t PAuthABIVersion) {
64*0fca6ea1SDimitry Andric assert((PAuthABIPlatform == uint64_t(-1)) ==
65*0fca6ea1SDimitry Andric (PAuthABIVersion == uint64_t(-1)));
66*0fca6ea1SDimitry Andric uint64_t DescSz = 0;
67*0fca6ea1SDimitry Andric if (Flags != 0)
68*0fca6ea1SDimitry Andric DescSz += 4 * 4;
69*0fca6ea1SDimitry Andric if (PAuthABIPlatform != uint64_t(-1))
70*0fca6ea1SDimitry Andric DescSz += 4 + 4 + 8 * 2;
71*0fca6ea1SDimitry Andric if (DescSz == 0)
72e8d8bef9SDimitry Andric return;
73e8d8bef9SDimitry Andric
74e8d8bef9SDimitry Andric MCStreamer &OutStreamer = getStreamer();
75e8d8bef9SDimitry Andric MCContext &Context = OutStreamer.getContext();
76e8d8bef9SDimitry Andric // Emit a .note.gnu.property section with the flags.
77e8d8bef9SDimitry Andric MCSectionELF *Nt = Context.getELFSection(".note.gnu.property", ELF::SHT_NOTE,
78e8d8bef9SDimitry Andric ELF::SHF_ALLOC);
79e8d8bef9SDimitry Andric if (Nt->isRegistered()) {
80e8d8bef9SDimitry Andric SMLoc Loc;
81e8d8bef9SDimitry Andric Context.reportWarning(
82e8d8bef9SDimitry Andric Loc,
83e8d8bef9SDimitry Andric "The .note.gnu.property is not emitted because it is already present.");
84e8d8bef9SDimitry Andric return;
85e8d8bef9SDimitry Andric }
86e8d8bef9SDimitry Andric MCSection *Cur = OutStreamer.getCurrentSectionOnly();
8781ad6265SDimitry Andric OutStreamer.switchSection(Nt);
88e8d8bef9SDimitry Andric
89e8d8bef9SDimitry Andric // Emit the note header.
90bdd1243dSDimitry Andric OutStreamer.emitValueToAlignment(Align(8));
91e8d8bef9SDimitry Andric OutStreamer.emitIntValue(4, 4); // data size for "GNU\0"
92*0fca6ea1SDimitry Andric OutStreamer.emitIntValue(DescSz, 4); // Elf_Prop array size
93e8d8bef9SDimitry Andric OutStreamer.emitIntValue(ELF::NT_GNU_PROPERTY_TYPE_0, 4);
94e8d8bef9SDimitry Andric OutStreamer.emitBytes(StringRef("GNU", 4)); // note name
95e8d8bef9SDimitry Andric
96e8d8bef9SDimitry Andric // Emit the PAC/BTI properties.
97*0fca6ea1SDimitry Andric if (Flags != 0) {
98e8d8bef9SDimitry Andric OutStreamer.emitIntValue(ELF::GNU_PROPERTY_AARCH64_FEATURE_1_AND, 4);
99e8d8bef9SDimitry Andric OutStreamer.emitIntValue(4, 4); // data size
100e8d8bef9SDimitry Andric OutStreamer.emitIntValue(Flags, 4); // data
101e8d8bef9SDimitry Andric OutStreamer.emitIntValue(0, 4); // pad
102*0fca6ea1SDimitry Andric }
103*0fca6ea1SDimitry Andric
104*0fca6ea1SDimitry Andric // Emit the PAuth ABI compatibility info
105*0fca6ea1SDimitry Andric if (PAuthABIPlatform != uint64_t(-1)) {
106*0fca6ea1SDimitry Andric OutStreamer.emitIntValue(ELF::GNU_PROPERTY_AARCH64_FEATURE_PAUTH, 4);
107*0fca6ea1SDimitry Andric OutStreamer.emitIntValue(8 * 2, 4); // data size
108*0fca6ea1SDimitry Andric OutStreamer.emitIntValue(PAuthABIPlatform, 8);
109*0fca6ea1SDimitry Andric OutStreamer.emitIntValue(PAuthABIVersion, 8);
110*0fca6ea1SDimitry Andric }
111e8d8bef9SDimitry Andric
112e8d8bef9SDimitry Andric OutStreamer.endSection(Nt);
11381ad6265SDimitry Andric OutStreamer.switchSection(Cur);
114e8d8bef9SDimitry Andric }
1150b57cec5SDimitry Andric
emitInst(uint32_t Inst)1160b57cec5SDimitry Andric void AArch64TargetStreamer::emitInst(uint32_t Inst) {
1170b57cec5SDimitry Andric char Buffer[4];
1180b57cec5SDimitry Andric
1190b57cec5SDimitry Andric // We can't just use EmitIntValue here, as that will swap the
1200b57cec5SDimitry Andric // endianness on big-endian systems (instructions are always
1210b57cec5SDimitry Andric // little-endian).
1224824e7fdSDimitry Andric for (char &C : Buffer) {
1234824e7fdSDimitry Andric C = uint8_t(Inst);
1240b57cec5SDimitry Andric Inst >>= 8;
1250b57cec5SDimitry Andric }
1260b57cec5SDimitry Andric
1275ffd83dbSDimitry Andric getStreamer().emitBytes(StringRef(Buffer, 4));
1280b57cec5SDimitry Andric }
1290b57cec5SDimitry Andric
1300b57cec5SDimitry Andric MCTargetStreamer *
createAArch64ObjectTargetStreamer(MCStreamer & S,const MCSubtargetInfo & STI)131fe6060f1SDimitry Andric llvm::createAArch64ObjectTargetStreamer(MCStreamer &S,
132fe6060f1SDimitry Andric const MCSubtargetInfo &STI) {
1330b57cec5SDimitry Andric const Triple &TT = STI.getTargetTriple();
1340b57cec5SDimitry Andric if (TT.isOSBinFormatELF())
1350b57cec5SDimitry Andric return new AArch64TargetELFStreamer(S);
1360b57cec5SDimitry Andric if (TT.isOSBinFormatCOFF())
1370b57cec5SDimitry Andric return new AArch64TargetWinCOFFStreamer(S);
1380b57cec5SDimitry Andric return nullptr;
1390b57cec5SDimitry Andric }
140bdd1243dSDimitry Andric
createAArch64NullTargetStreamer(MCStreamer & S)141bdd1243dSDimitry Andric MCTargetStreamer *llvm::createAArch64NullTargetStreamer(MCStreamer &S) {
142bdd1243dSDimitry Andric return new AArch64TargetStreamer(S);
143bdd1243dSDimitry Andric }
144