xref: /freebsd/contrib/llvm-project/llvm/lib/Target/AArch64/MCTargetDesc/AArch64TargetStreamer.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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