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(Val: 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(Flags: 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(Section: ".note.gnu.property" , Type: ELF::SHT_NOTE, |
78 | Flags: ELF::SHF_ALLOC); |
79 | if (Nt->isRegistered()) { |
80 | SMLoc Loc; |
81 | Context.reportWarning( |
82 | L: Loc, |
83 | Msg: "The .note.gnu.property is not emitted because it is already present." ); |
84 | return; |
85 | } |
86 | MCSection *Cur = OutStreamer.getCurrentSectionOnly(); |
87 | OutStreamer.switchSection(Section: Nt); |
88 | |
89 | // Emit the note header. |
90 | OutStreamer.emitValueToAlignment(Alignment: Align(8)); |
91 | OutStreamer.emitIntValue(Value: 4, Size: 4); // data size for "GNU\0" |
92 | OutStreamer.emitIntValue(Value: DescSz, Size: 4); // Elf_Prop array size |
93 | OutStreamer.emitIntValue(Value: ELF::NT_GNU_PROPERTY_TYPE_0, Size: 4); |
94 | OutStreamer.emitBytes(Data: StringRef("GNU" , 4)); // note name |
95 | |
96 | // Emit the PAC/BTI properties. |
97 | if (Flags != 0) { |
98 | OutStreamer.emitIntValue(Value: ELF::GNU_PROPERTY_AARCH64_FEATURE_1_AND, Size: 4); |
99 | OutStreamer.emitIntValue(Value: 4, Size: 4); // data size |
100 | OutStreamer.emitIntValue(Value: Flags, Size: 4); // data |
101 | OutStreamer.emitIntValue(Value: 0, Size: 4); // pad |
102 | } |
103 | |
104 | // Emit the PAuth ABI compatibility info |
105 | if (PAuthABIPlatform != uint64_t(-1)) { |
106 | OutStreamer.emitIntValue(Value: ELF::GNU_PROPERTY_AARCH64_FEATURE_PAUTH, Size: 4); |
107 | OutStreamer.emitIntValue(Value: 8 * 2, Size: 4); // data size |
108 | OutStreamer.emitIntValue(Value: PAuthABIPlatform, Size: 8); |
109 | OutStreamer.emitIntValue(Value: PAuthABIVersion, Size: 8); |
110 | } |
111 | |
112 | OutStreamer.endSection(Section: Nt); |
113 | OutStreamer.switchSection(Section: 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(Data: 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 | |