]>
Commit | Line | Data |
---|---|---|
970d7e83 LB |
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 "llvm/MC/MCELFStreamer.h" | |
17 | #include "llvm/ADT/SmallPtrSet.h" | |
85aaf69f | 18 | #include "llvm/ADT/StringExtras.h" |
970d7e83 LB |
19 | #include "llvm/ADT/Twine.h" |
20 | #include "llvm/MC/MCAsmBackend.h" | |
85aaf69f | 21 | #include "llvm/MC/MCAsmInfo.h" |
970d7e83 LB |
22 | #include "llvm/MC/MCAssembler.h" |
23 | #include "llvm/MC/MCCodeEmitter.h" | |
24 | #include "llvm/MC/MCContext.h" | |
25 | #include "llvm/MC/MCELF.h" | |
26 | #include "llvm/MC/MCELFStreamer.h" | |
27 | #include "llvm/MC/MCELFSymbolFlags.h" | |
28 | #include "llvm/MC/MCExpr.h" | |
29 | #include "llvm/MC/MCInst.h" | |
30 | #include "llvm/MC/MCObjectStreamer.h" | |
31 | #include "llvm/MC/MCSection.h" | |
32 | #include "llvm/MC/MCSectionELF.h" | |
33 | #include "llvm/MC/MCStreamer.h" | |
34 | #include "llvm/MC/MCSymbol.h" | |
35 | #include "llvm/MC/MCValue.h" | |
36 | #include "llvm/Support/Debug.h" | |
37 | #include "llvm/Support/ELF.h" | |
38 | #include "llvm/Support/ErrorHandling.h" | |
85aaf69f | 39 | #include "llvm/Support/FormattedStream.h" |
970d7e83 LB |
40 | #include "llvm/Support/raw_ostream.h" |
41 | ||
42 | using namespace llvm; | |
43 | ||
44 | namespace { | |
45 | ||
85aaf69f SL |
46 | class AArch64ELFStreamer; |
47 | ||
48 | class AArch64TargetAsmStreamer : public AArch64TargetStreamer { | |
49 | formatted_raw_ostream &OS; | |
50 | ||
51 | void emitInst(uint32_t Inst) override; | |
52 | ||
53 | public: | |
54 | AArch64TargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS); | |
55 | }; | |
56 | ||
57 | AArch64TargetAsmStreamer::AArch64TargetAsmStreamer(MCStreamer &S, | |
58 | formatted_raw_ostream &OS) | |
59 | : AArch64TargetStreamer(S), OS(OS) {} | |
60 | ||
61 | void AArch64TargetAsmStreamer::emitInst(uint32_t Inst) { | |
62 | OS << "\t.inst\t0x" << utohexstr(Inst) << "\n"; | |
63 | } | |
64 | ||
65 | class AArch64TargetELFStreamer : public AArch64TargetStreamer { | |
66 | private: | |
67 | AArch64ELFStreamer &getStreamer(); | |
68 | ||
69 | void emitInst(uint32_t Inst) override; | |
70 | ||
71 | public: | |
72 | AArch64TargetELFStreamer(MCStreamer &S) : AArch64TargetStreamer(S) {} | |
73 | }; | |
74 | ||
970d7e83 LB |
75 | /// Extend the generic ELFStreamer class so that it can emit mapping symbols at |
76 | /// the appropriate points in the object files. These symbols are defined in the | |
77 | /// AArch64 ELF ABI: | |
78 | /// infocenter.arm.com/help/topic/com.arm.doc.ihi0056a/IHI0056A_aaelf64.pdf | |
79 | /// | |
80 | /// In brief: $x or $d should be emitted at the start of each contiguous region | |
81 | /// of A64 code or data in a section. In practice, this emission does not rely | |
82 | /// on explicit assembler directives but on inherent properties of the | |
83 | /// directives doing the emission (e.g. ".byte" is data, "add x0, x0, x0" an | |
84 | /// instruction). | |
85 | /// | |
86 | /// As a result this system is orthogonal to the DataRegion infrastructure used | |
87 | /// by MachO. Beware! | |
88 | class AArch64ELFStreamer : public MCELFStreamer { | |
89 | public: | |
85aaf69f SL |
90 | friend class AArch64TargetELFStreamer; |
91 | ||
1a4d82fc JJ |
92 | AArch64ELFStreamer(MCContext &Context, MCAsmBackend &TAB, raw_ostream &OS, |
93 | MCCodeEmitter *Emitter) | |
94 | : MCELFStreamer(Context, TAB, OS, Emitter), MappingSymbolCounter(0), | |
95 | LastEMS(EMS_None) {} | |
970d7e83 LB |
96 | |
97 | ~AArch64ELFStreamer() {} | |
98 | ||
1a4d82fc JJ |
99 | void ChangeSection(const MCSection *Section, |
100 | const MCExpr *Subsection) override { | |
970d7e83 LB |
101 | // We have to keep track of the mapping symbol state of any sections we |
102 | // use. Each one should start off as EMS_None, which is provided as the | |
103 | // default constructor by DenseMap::lookup. | |
1a4d82fc | 104 | LastMappingSymbols[getPreviousSection().first] = LastEMS; |
970d7e83 LB |
105 | LastEMS = LastMappingSymbols.lookup(Section); |
106 | ||
1a4d82fc | 107 | MCELFStreamer::ChangeSection(Section, Subsection); |
970d7e83 LB |
108 | } |
109 | ||
110 | /// This function is the one used to emit instruction data into the ELF | |
111 | /// streamer. We override it to add the appropriate mapping symbol if | |
112 | /// necessary. | |
1a4d82fc JJ |
113 | void EmitInstruction(const MCInst &Inst, |
114 | const MCSubtargetInfo &STI) override { | |
970d7e83 | 115 | EmitA64MappingSymbol(); |
1a4d82fc | 116 | MCELFStreamer::EmitInstruction(Inst, STI); |
970d7e83 LB |
117 | } |
118 | ||
85aaf69f SL |
119 | void emitInst(uint32_t Inst) { |
120 | char Buffer[4]; | |
121 | const bool LittleEndian = getContext().getAsmInfo()->isLittleEndian(); | |
122 | ||
123 | EmitA64MappingSymbol(); | |
124 | for (unsigned II = 0; II != 4; ++II) { | |
125 | const unsigned I = LittleEndian ? (4 - II - 1) : II; | |
126 | Buffer[4 - II - 1] = uint8_t(Inst >> I * CHAR_BIT); | |
127 | } | |
128 | MCELFStreamer::EmitBytes(StringRef(Buffer, 4)); | |
129 | } | |
130 | ||
970d7e83 LB |
131 | /// This is one of the functions used to emit data into an ELF section, so the |
132 | /// AArch64 streamer overrides it to add the appropriate mapping symbol ($d) | |
133 | /// if necessary. | |
1a4d82fc | 134 | void EmitBytes(StringRef Data) override { |
970d7e83 | 135 | EmitDataMappingSymbol(); |
1a4d82fc | 136 | MCELFStreamer::EmitBytes(Data); |
970d7e83 LB |
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. | |
1a4d82fc JJ |
142 | void EmitValueImpl(const MCExpr *Value, unsigned Size, |
143 | const SMLoc &Loc) override { | |
970d7e83 | 144 | EmitDataMappingSymbol(); |
1a4d82fc | 145 | MCELFStreamer::EmitValueImpl(Value, Size); |
970d7e83 LB |
146 | } |
147 | ||
148 | private: | |
149 | enum ElfMappingSymbol { | |
150 | EMS_None, | |
151 | EMS_A64, | |
152 | EMS_Data | |
153 | }; | |
154 | ||
155 | void EmitDataMappingSymbol() { | |
1a4d82fc JJ |
156 | if (LastEMS == EMS_Data) |
157 | return; | |
970d7e83 LB |
158 | EmitMappingSymbol("$d"); |
159 | LastEMS = EMS_Data; | |
160 | } | |
161 | ||
162 | void EmitA64MappingSymbol() { | |
1a4d82fc JJ |
163 | if (LastEMS == EMS_A64) |
164 | return; | |
970d7e83 LB |
165 | EmitMappingSymbol("$x"); |
166 | LastEMS = EMS_A64; | |
167 | } | |
168 | ||
169 | void EmitMappingSymbol(StringRef Name) { | |
170 | MCSymbol *Start = getContext().CreateTempSymbol(); | |
171 | EmitLabel(Start); | |
172 | ||
1a4d82fc JJ |
173 | MCSymbol *Symbol = getContext().GetOrCreateSymbol( |
174 | Name + "." + Twine(MappingSymbolCounter++)); | |
970d7e83 LB |
175 | |
176 | MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); | |
177 | MCELF::SetType(SD, ELF::STT_NOTYPE); | |
178 | MCELF::SetBinding(SD, ELF::STB_LOCAL); | |
179 | SD.setExternal(false); | |
85aaf69f SL |
180 | auto Sec = getCurrentSection().first; |
181 | assert(Sec && "need a section"); | |
182 | Symbol->setSection(*Sec); | |
970d7e83 LB |
183 | |
184 | const MCExpr *Value = MCSymbolRefExpr::Create(Start, getContext()); | |
185 | Symbol->setVariableValue(Value); | |
186 | } | |
187 | ||
188 | int64_t MappingSymbolCounter; | |
189 | ||
190 | DenseMap<const MCSection *, ElfMappingSymbol> LastMappingSymbols; | |
191 | ElfMappingSymbol LastEMS; | |
192 | ||
193 | /// @} | |
194 | }; | |
85aaf69f SL |
195 | } // end anonymous namespace |
196 | ||
197 | AArch64ELFStreamer &AArch64TargetELFStreamer::getStreamer() { | |
198 | return static_cast<AArch64ELFStreamer &>(Streamer); | |
199 | } | |
200 | ||
201 | void AArch64TargetELFStreamer::emitInst(uint32_t Inst) { | |
202 | getStreamer().emitInst(Inst); | |
970d7e83 LB |
203 | } |
204 | ||
205 | namespace llvm { | |
85aaf69f SL |
206 | MCStreamer * |
207 | createAArch64MCAsmStreamer(MCContext &Ctx, formatted_raw_ostream &OS, | |
208 | bool isVerboseAsm, bool useDwarfDirectory, | |
209 | MCInstPrinter *InstPrint, MCCodeEmitter *CE, | |
210 | MCAsmBackend *TAB, bool ShowInst) { | |
211 | MCStreamer *S = llvm::createAsmStreamer( | |
212 | Ctx, OS, isVerboseAsm, useDwarfDirectory, InstPrint, CE, TAB, ShowInst); | |
213 | new AArch64TargetAsmStreamer(*S, OS); | |
214 | return S; | |
215 | } | |
216 | ||
1a4d82fc JJ |
217 | MCELFStreamer *createAArch64ELFStreamer(MCContext &Context, MCAsmBackend &TAB, |
218 | raw_ostream &OS, MCCodeEmitter *Emitter, | |
85aaf69f | 219 | bool RelaxAll) { |
1a4d82fc | 220 | AArch64ELFStreamer *S = new AArch64ELFStreamer(Context, TAB, OS, Emitter); |
85aaf69f | 221 | new AArch64TargetELFStreamer(*S); |
1a4d82fc JJ |
222 | if (RelaxAll) |
223 | S->getAssembler().setRelaxAll(true); | |
1a4d82fc JJ |
224 | return S; |
225 | } | |
970d7e83 | 226 | } |