1 //===- lib/MC/AArch64ELFStreamer.cpp - ELF Object Output for AArch64 ------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file assembles .s files and emits AArch64 ELF .o object files. Different
11 // from generic ELF streamer in emitting mapping symbols ($x and $d) to delimit
12 // regions of data and code.
13 //
14 //===----------------------------------------------------------------------===//
15 
16 #include "AArch64TargetStreamer.h"
17 #include "AArch64WinCOFFStreamer.h"
18 #include "llvm/ADT/DenseMap.h"
19 #include "llvm/ADT/StringRef.h"
20 #include "llvm/ADT/Triple.h"
21 #include "llvm/ADT/Twine.h"
22 #include "llvm/BinaryFormat/ELF.h"
23 #include "llvm/MC/MCAsmBackend.h"
24 #include "llvm/MC/MCAssembler.h"
25 #include "llvm/MC/MCCodeEmitter.h"
26 #include "llvm/MC/MCContext.h"
27 #include "llvm/MC/MCELFStreamer.h"
28 #include "llvm/MC/MCExpr.h"
29 #include "llvm/MC/MCInst.h"
30 #include "llvm/MC/MCSection.h"
31 #include "llvm/MC/MCStreamer.h"
32 #include "llvm/MC/MCSubtargetInfo.h"
33 #include "llvm/MC/MCSymbolELF.h"
34 #include "llvm/MC/MCWinCOFFStreamer.h"
35 #include "llvm/Support/Casting.h"
36 #include "llvm/Support/FormattedStream.h"
37 #include "llvm/Support/raw_ostream.h"
38 
39 using namespace llvm;
40 
41 namespace {
42 
43 class AArch64ELFStreamer;
44 
45 class AArch64TargetAsmStreamer : public AArch64TargetStreamer {
46   formatted_raw_ostream &OS;
47 
48   void emitInst(uint32_t Inst) override;
49 
50 public:
51   AArch64TargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS);
52 };
53 
54 AArch64TargetAsmStreamer::AArch64TargetAsmStreamer(MCStreamer &S,
55                                                    formatted_raw_ostream &OS)
56   : AArch64TargetStreamer(S), OS(OS) {}
57 
58 void AArch64TargetAsmStreamer::emitInst(uint32_t Inst) {
59   OS << "\t.inst\t0x" << Twine::utohexstr(Inst) << "\n";
60 }
61 
62 class AArch64TargetELFStreamer : public AArch64TargetStreamer {
63 private:
64   AArch64ELFStreamer &getStreamer();
65 
66   void emitInst(uint32_t Inst) override;
67 
68 public:
69   AArch64TargetELFStreamer(MCStreamer &S) : AArch64TargetStreamer(S) {}
70 };
71 
72 /// Extend the generic ELFStreamer class so that it can emit mapping symbols at
73 /// the appropriate points in the object files. These symbols are defined in the
74 /// AArch64 ELF ABI:
75 ///    infocenter.arm.com/help/topic/com.arm.doc.ihi0056a/IHI0056A_aaelf64.pdf
76 ///
77 /// In brief: $x or $d should be emitted at the start of each contiguous region
78 /// of A64 code or data in a section. In practice, this emission does not rely
79 /// on explicit assembler directives but on inherent properties of the
80 /// directives doing the emission (e.g. ".byte" is data, "add x0, x0, x0" an
81 /// instruction).
82 ///
83 /// As a result this system is orthogonal to the DataRegion infrastructure used
84 /// by MachO. Beware!
85 class AArch64ELFStreamer : public MCELFStreamer {
86 public:
87   friend class AArch64TargetELFStreamer;
88 
89   AArch64ELFStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> TAB,
90                      raw_pwrite_stream &OS,
91                      std::unique_ptr<MCCodeEmitter> Emitter)
92       : MCELFStreamer(Context, std::move(TAB), OS, std::move(Emitter)),
93         MappingSymbolCounter(0), LastEMS(EMS_None) {}
94 
95   void ChangeSection(MCSection *Section, const MCExpr *Subsection) override {
96     // We have to keep track of the mapping symbol state of any sections we
97     // use. Each one should start off as EMS_None, which is provided as the
98     // default constructor by DenseMap::lookup.
99     LastMappingSymbols[getPreviousSection().first] = LastEMS;
100     LastEMS = LastMappingSymbols.lookup(Section);
101 
102     MCELFStreamer::ChangeSection(Section, Subsection);
103   }
104 
105   // Reset state between object emissions
106   void reset() override {
107     MappingSymbolCounter = 0;
108     MCELFStreamer::reset();
109     LastMappingSymbols.clear();
110     LastEMS = EMS_None;
111   }
112 
113   /// This function is the one used to emit instruction data into the ELF
114   /// streamer. We override it to add the appropriate mapping symbol if
115   /// necessary.
116   void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI,
117                        bool) override {
118     EmitA64MappingSymbol();
119     MCELFStreamer::EmitInstruction(Inst, STI);
120   }
121 
122   /// Emit a 32-bit value as an instruction. This is only used for the .inst
123   /// directive, EmitInstruction should be used in other cases.
124   void emitInst(uint32_t Inst) {
125     char Buffer[4];
126 
127     // We can't just use EmitIntValue here, as that will emit a data mapping
128     // symbol, and swap the endianness on big-endian systems (instructions are
129     // always little-endian).
130     for (unsigned I = 0; I < 4; ++I) {
131       Buffer[I] = uint8_t(Inst);
132       Inst >>= 8;
133     }
134 
135     EmitA64MappingSymbol();
136     MCELFStreamer::EmitBytes(StringRef(Buffer, 4));
137   }
138 
139   /// This is one of the functions used to emit data into an ELF section, so the
140   /// AArch64 streamer overrides it to add the appropriate mapping symbol ($d)
141   /// if necessary.
142   void EmitBytes(StringRef Data) override {
143     EmitDataMappingSymbol();
144     MCELFStreamer::EmitBytes(Data);
145   }
146 
147   /// This is one of the functions used to emit data into an ELF section, so the
148   /// AArch64 streamer overrides it to add the appropriate mapping symbol ($d)
149   /// if necessary.
150   void EmitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc) override {
151     EmitDataMappingSymbol();
152     MCELFStreamer::EmitValueImpl(Value, Size, Loc);
153   }
154 
155 private:
156   enum ElfMappingSymbol {
157     EMS_None,
158     EMS_A64,
159     EMS_Data
160   };
161 
162   void EmitDataMappingSymbol() {
163     if (LastEMS == EMS_Data)
164       return;
165     EmitMappingSymbol("$d");
166     LastEMS = EMS_Data;
167   }
168 
169   void EmitA64MappingSymbol() {
170     if (LastEMS == EMS_A64)
171       return;
172     EmitMappingSymbol("$x");
173     LastEMS = EMS_A64;
174   }
175 
176   void EmitMappingSymbol(StringRef Name) {
177     auto *Symbol = cast<MCSymbolELF>(getContext().getOrCreateSymbol(
178         Name + "." + Twine(MappingSymbolCounter++)));
179     EmitLabel(Symbol);
180     Symbol->setType(ELF::STT_NOTYPE);
181     Symbol->setBinding(ELF::STB_LOCAL);
182     Symbol->setExternal(false);
183   }
184 
185   int64_t MappingSymbolCounter;
186 
187   DenseMap<const MCSection *, ElfMappingSymbol> LastMappingSymbols;
188   ElfMappingSymbol LastEMS;
189 };
190 
191 } // end anonymous namespace
192 
193 AArch64ELFStreamer &AArch64TargetELFStreamer::getStreamer() {
194   return static_cast<AArch64ELFStreamer &>(Streamer);
195 }
196 
197 void AArch64TargetELFStreamer::emitInst(uint32_t Inst) {
198   getStreamer().emitInst(Inst);
199 }
200 
201 namespace llvm {
202 
203 MCTargetStreamer *createAArch64AsmTargetStreamer(MCStreamer &S,
204                                                  formatted_raw_ostream &OS,
205                                                  MCInstPrinter *InstPrint,
206                                                  bool isVerboseAsm) {
207   return new AArch64TargetAsmStreamer(S, OS);
208 }
209 
210 MCELFStreamer *createAArch64ELFStreamer(MCContext &Context,
211                                         std::unique_ptr<MCAsmBackend> TAB,
212                                         raw_pwrite_stream &OS,
213                                         std::unique_ptr<MCCodeEmitter> Emitter,
214                                         bool RelaxAll) {
215   AArch64ELFStreamer *S =
216       new AArch64ELFStreamer(Context, std::move(TAB), OS, std::move(Emitter));
217   if (RelaxAll)
218     S->getAssembler().setRelaxAll(true);
219   return S;
220 }
221 
222 MCTargetStreamer *
223 createAArch64ObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
224   const Triple &TT = STI.getTargetTriple();
225   if (TT.isOSBinFormatELF())
226     return new AArch64TargetELFStreamer(S);
227   if (TT.isOSBinFormatCOFF())
228     return new AArch64TargetWinCOFFStreamer(S);
229   return nullptr;
230 }
231 
232 } // end namespace llvm
233