]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | //===-- MipsTargetStreamer.cpp - Mips Target Streamer Methods -------------===// |
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 provides Mips specific target streamer methods. | |
11 | // | |
12 | //===----------------------------------------------------------------------===// | |
13 | ||
14 | #include "InstPrinter/MipsInstPrinter.h" | |
15 | #include "MipsELFStreamer.h" | |
16 | #include "MipsMCTargetDesc.h" | |
17 | #include "MipsTargetObjectFile.h" | |
18 | #include "MipsTargetStreamer.h" | |
19 | #include "llvm/MC/MCContext.h" | |
20 | #include "llvm/MC/MCELF.h" | |
21 | #include "llvm/MC/MCSectionELF.h" | |
22 | #include "llvm/MC/MCSubtargetInfo.h" | |
23 | #include "llvm/MC/MCSymbol.h" | |
24 | #include "llvm/Support/CommandLine.h" | |
25 | #include "llvm/Support/ELF.h" | |
26 | #include "llvm/Support/ErrorHandling.h" | |
27 | #include "llvm/Support/FormattedStream.h" | |
28 | ||
29 | using namespace llvm; | |
30 | ||
31 | MipsTargetStreamer::MipsTargetStreamer(MCStreamer &S) | |
32 | : MCTargetStreamer(S), ModuleDirectiveAllowed(true) { | |
33 | GPRInfoSet = FPRInfoSet = FrameInfoSet = false; | |
34 | } | |
35 | void MipsTargetStreamer::emitDirectiveSetMicroMips() {} | |
36 | void MipsTargetStreamer::emitDirectiveSetNoMicroMips() {} | |
37 | void MipsTargetStreamer::emitDirectiveSetMips16() {} | |
38 | void MipsTargetStreamer::emitDirectiveSetNoMips16() { forbidModuleDirective(); } | |
39 | void MipsTargetStreamer::emitDirectiveSetReorder() { forbidModuleDirective(); } | |
40 | void MipsTargetStreamer::emitDirectiveSetNoReorder() {} | |
41 | void MipsTargetStreamer::emitDirectiveSetMacro() { forbidModuleDirective(); } | |
42 | void MipsTargetStreamer::emitDirectiveSetNoMacro() { forbidModuleDirective(); } | |
43 | void MipsTargetStreamer::emitDirectiveSetMsa() { forbidModuleDirective(); } | |
44 | void MipsTargetStreamer::emitDirectiveSetNoMsa() { forbidModuleDirective(); } | |
45 | void MipsTargetStreamer::emitDirectiveSetAt() { forbidModuleDirective(); } | |
46 | void MipsTargetStreamer::emitDirectiveSetNoAt() { forbidModuleDirective(); } | |
47 | void MipsTargetStreamer::emitDirectiveEnd(StringRef Name) {} | |
48 | void MipsTargetStreamer::emitDirectiveEnt(const MCSymbol &Symbol) {} | |
49 | void MipsTargetStreamer::emitDirectiveAbiCalls() {} | |
50 | void MipsTargetStreamer::emitDirectiveNaN2008() {} | |
51 | void MipsTargetStreamer::emitDirectiveNaNLegacy() {} | |
52 | void MipsTargetStreamer::emitDirectiveOptionPic0() {} | |
53 | void MipsTargetStreamer::emitDirectiveOptionPic2() {} | |
54 | void MipsTargetStreamer::emitFrame(unsigned StackReg, unsigned StackSize, | |
55 | unsigned ReturnReg) {} | |
56 | void MipsTargetStreamer::emitMask(unsigned CPUBitmask, int CPUTopSavedRegOff) {} | |
57 | void MipsTargetStreamer::emitFMask(unsigned FPUBitmask, int FPUTopSavedRegOff) { | |
58 | } | |
59 | void MipsTargetStreamer::emitDirectiveSetArch(StringRef Arch) { | |
60 | forbidModuleDirective(); | |
61 | } | |
62 | void MipsTargetStreamer::emitDirectiveSetMips0() {} | |
63 | void MipsTargetStreamer::emitDirectiveSetMips1() { forbidModuleDirective(); } | |
64 | void MipsTargetStreamer::emitDirectiveSetMips2() { forbidModuleDirective(); } | |
65 | void MipsTargetStreamer::emitDirectiveSetMips3() { forbidModuleDirective(); } | |
66 | void MipsTargetStreamer::emitDirectiveSetMips4() { forbidModuleDirective(); } | |
67 | void MipsTargetStreamer::emitDirectiveSetMips5() { forbidModuleDirective(); } | |
68 | void MipsTargetStreamer::emitDirectiveSetMips32() { forbidModuleDirective(); } | |
69 | void MipsTargetStreamer::emitDirectiveSetMips32R2() { forbidModuleDirective(); } | |
70 | void MipsTargetStreamer::emitDirectiveSetMips32R6() { forbidModuleDirective(); } | |
71 | void MipsTargetStreamer::emitDirectiveSetMips64() { forbidModuleDirective(); } | |
72 | void MipsTargetStreamer::emitDirectiveSetMips64R2() { forbidModuleDirective(); } | |
73 | void MipsTargetStreamer::emitDirectiveSetMips64R6() { forbidModuleDirective(); } | |
74 | void MipsTargetStreamer::emitDirectiveSetPop() {} | |
75 | void MipsTargetStreamer::emitDirectiveSetPush() {} | |
76 | void MipsTargetStreamer::emitDirectiveSetDsp() { forbidModuleDirective(); } | |
77 | void MipsTargetStreamer::emitDirectiveSetNoDsp() { forbidModuleDirective(); } | |
78 | void MipsTargetStreamer::emitDirectiveCpLoad(unsigned RegNo) {} | |
79 | void MipsTargetStreamer::emitDirectiveCpsetup(unsigned RegNo, int RegOrOffset, | |
80 | const MCSymbol &Sym, bool IsReg) { | |
81 | } | |
82 | void MipsTargetStreamer::emitDirectiveModuleOddSPReg(bool Enabled, | |
83 | bool IsO32ABI) { | |
84 | if (!Enabled && !IsO32ABI) | |
85 | report_fatal_error("+nooddspreg is only valid for O32"); | |
86 | } | |
87 | ||
88 | MipsTargetAsmStreamer::MipsTargetAsmStreamer(MCStreamer &S, | |
89 | formatted_raw_ostream &OS) | |
90 | : MipsTargetStreamer(S), OS(OS) {} | |
91 | ||
92 | void MipsTargetAsmStreamer::emitDirectiveSetMicroMips() { | |
93 | OS << "\t.set\tmicromips\n"; | |
94 | forbidModuleDirective(); | |
95 | } | |
96 | ||
97 | void MipsTargetAsmStreamer::emitDirectiveSetNoMicroMips() { | |
98 | OS << "\t.set\tnomicromips\n"; | |
99 | forbidModuleDirective(); | |
100 | } | |
101 | ||
102 | void MipsTargetAsmStreamer::emitDirectiveSetMips16() { | |
103 | OS << "\t.set\tmips16\n"; | |
104 | forbidModuleDirective(); | |
105 | } | |
106 | ||
107 | void MipsTargetAsmStreamer::emitDirectiveSetNoMips16() { | |
108 | OS << "\t.set\tnomips16\n"; | |
109 | MipsTargetStreamer::emitDirectiveSetNoMips16(); | |
110 | } | |
111 | ||
112 | void MipsTargetAsmStreamer::emitDirectiveSetReorder() { | |
113 | OS << "\t.set\treorder\n"; | |
114 | MipsTargetStreamer::emitDirectiveSetReorder(); | |
115 | } | |
116 | ||
117 | void MipsTargetAsmStreamer::emitDirectiveSetNoReorder() { | |
118 | OS << "\t.set\tnoreorder\n"; | |
119 | forbidModuleDirective(); | |
120 | } | |
121 | ||
122 | void MipsTargetAsmStreamer::emitDirectiveSetMacro() { | |
123 | OS << "\t.set\tmacro\n"; | |
124 | MipsTargetStreamer::emitDirectiveSetMacro(); | |
125 | } | |
126 | ||
127 | void MipsTargetAsmStreamer::emitDirectiveSetNoMacro() { | |
128 | OS << "\t.set\tnomacro\n"; | |
129 | MipsTargetStreamer::emitDirectiveSetNoMacro(); | |
130 | } | |
131 | ||
132 | void MipsTargetAsmStreamer::emitDirectiveSetMsa() { | |
133 | OS << "\t.set\tmsa\n"; | |
134 | MipsTargetStreamer::emitDirectiveSetMsa(); | |
135 | } | |
136 | ||
137 | void MipsTargetAsmStreamer::emitDirectiveSetNoMsa() { | |
138 | OS << "\t.set\tnomsa\n"; | |
139 | MipsTargetStreamer::emitDirectiveSetNoMsa(); | |
140 | } | |
141 | ||
142 | void MipsTargetAsmStreamer::emitDirectiveSetAt() { | |
143 | OS << "\t.set\tat\n"; | |
144 | MipsTargetStreamer::emitDirectiveSetAt(); | |
145 | } | |
146 | ||
147 | void MipsTargetAsmStreamer::emitDirectiveSetNoAt() { | |
148 | OS << "\t.set\tnoat\n"; | |
149 | MipsTargetStreamer::emitDirectiveSetNoAt(); | |
150 | } | |
151 | ||
152 | void MipsTargetAsmStreamer::emitDirectiveEnd(StringRef Name) { | |
153 | OS << "\t.end\t" << Name << '\n'; | |
154 | } | |
155 | ||
156 | void MipsTargetAsmStreamer::emitDirectiveEnt(const MCSymbol &Symbol) { | |
157 | OS << "\t.ent\t" << Symbol.getName() << '\n'; | |
158 | } | |
159 | ||
160 | void MipsTargetAsmStreamer::emitDirectiveAbiCalls() { OS << "\t.abicalls\n"; } | |
161 | ||
162 | void MipsTargetAsmStreamer::emitDirectiveNaN2008() { OS << "\t.nan\t2008\n"; } | |
163 | ||
164 | void MipsTargetAsmStreamer::emitDirectiveNaNLegacy() { | |
165 | OS << "\t.nan\tlegacy\n"; | |
166 | } | |
167 | ||
168 | void MipsTargetAsmStreamer::emitDirectiveOptionPic0() { | |
169 | OS << "\t.option\tpic0\n"; | |
170 | } | |
171 | ||
172 | void MipsTargetAsmStreamer::emitDirectiveOptionPic2() { | |
173 | OS << "\t.option\tpic2\n"; | |
174 | } | |
175 | ||
176 | void MipsTargetAsmStreamer::emitFrame(unsigned StackReg, unsigned StackSize, | |
177 | unsigned ReturnReg) { | |
178 | OS << "\t.frame\t$" | |
179 | << StringRef(MipsInstPrinter::getRegisterName(StackReg)).lower() << "," | |
180 | << StackSize << ",$" | |
181 | << StringRef(MipsInstPrinter::getRegisterName(ReturnReg)).lower() << '\n'; | |
182 | } | |
183 | ||
184 | void MipsTargetAsmStreamer::emitDirectiveSetArch(StringRef Arch) { | |
185 | OS << "\t.set arch=" << Arch << "\n"; | |
186 | MipsTargetStreamer::emitDirectiveSetArch(Arch); | |
187 | } | |
188 | ||
189 | void MipsTargetAsmStreamer::emitDirectiveSetMips0() { OS << "\t.set\tmips0\n"; } | |
190 | ||
191 | void MipsTargetAsmStreamer::emitDirectiveSetMips1() { | |
192 | OS << "\t.set\tmips1\n"; | |
193 | MipsTargetStreamer::emitDirectiveSetMips1(); | |
194 | } | |
195 | ||
196 | void MipsTargetAsmStreamer::emitDirectiveSetMips2() { | |
197 | OS << "\t.set\tmips2\n"; | |
198 | MipsTargetStreamer::emitDirectiveSetMips2(); | |
199 | } | |
200 | ||
201 | void MipsTargetAsmStreamer::emitDirectiveSetMips3() { | |
202 | OS << "\t.set\tmips3\n"; | |
203 | MipsTargetStreamer::emitDirectiveSetMips3(); | |
204 | } | |
205 | ||
206 | void MipsTargetAsmStreamer::emitDirectiveSetMips4() { | |
207 | OS << "\t.set\tmips4\n"; | |
208 | MipsTargetStreamer::emitDirectiveSetMips4(); | |
209 | } | |
210 | ||
211 | void MipsTargetAsmStreamer::emitDirectiveSetMips5() { | |
212 | OS << "\t.set\tmips5\n"; | |
213 | MipsTargetStreamer::emitDirectiveSetMips5(); | |
214 | } | |
215 | ||
216 | void MipsTargetAsmStreamer::emitDirectiveSetMips32() { | |
217 | OS << "\t.set\tmips32\n"; | |
218 | MipsTargetStreamer::emitDirectiveSetMips32(); | |
219 | } | |
220 | ||
221 | void MipsTargetAsmStreamer::emitDirectiveSetMips32R2() { | |
222 | OS << "\t.set\tmips32r2\n"; | |
223 | MipsTargetStreamer::emitDirectiveSetMips32R2(); | |
224 | } | |
225 | ||
226 | void MipsTargetAsmStreamer::emitDirectiveSetMips32R6() { | |
227 | OS << "\t.set\tmips32r6\n"; | |
228 | MipsTargetStreamer::emitDirectiveSetMips32R6(); | |
229 | } | |
230 | ||
231 | void MipsTargetAsmStreamer::emitDirectiveSetMips64() { | |
232 | OS << "\t.set\tmips64\n"; | |
233 | MipsTargetStreamer::emitDirectiveSetMips64(); | |
234 | } | |
235 | ||
236 | void MipsTargetAsmStreamer::emitDirectiveSetMips64R2() { | |
237 | OS << "\t.set\tmips64r2\n"; | |
238 | MipsTargetStreamer::emitDirectiveSetMips64R2(); | |
239 | } | |
240 | ||
241 | void MipsTargetAsmStreamer::emitDirectiveSetMips64R6() { | |
242 | OS << "\t.set\tmips64r6\n"; | |
243 | MipsTargetStreamer::emitDirectiveSetMips64R6(); | |
244 | } | |
245 | ||
246 | void MipsTargetAsmStreamer::emitDirectiveSetDsp() { | |
247 | OS << "\t.set\tdsp\n"; | |
248 | MipsTargetStreamer::emitDirectiveSetDsp(); | |
249 | } | |
250 | ||
251 | void MipsTargetAsmStreamer::emitDirectiveSetNoDsp() { | |
252 | OS << "\t.set\tnodsp\n"; | |
253 | MipsTargetStreamer::emitDirectiveSetNoDsp(); | |
254 | } | |
255 | ||
256 | void MipsTargetAsmStreamer::emitDirectiveSetPop() { OS << "\t.set\tpop\n"; } | |
257 | ||
258 | void MipsTargetAsmStreamer::emitDirectiveSetPush() { OS << "\t.set\tpush\n"; } | |
259 | ||
260 | // Print a 32 bit hex number with all numbers. | |
261 | static void printHex32(unsigned Value, raw_ostream &OS) { | |
262 | OS << "0x"; | |
263 | for (int i = 7; i >= 0; i--) | |
264 | OS.write_hex((Value & (0xF << (i * 4))) >> (i * 4)); | |
265 | } | |
266 | ||
267 | void MipsTargetAsmStreamer::emitMask(unsigned CPUBitmask, | |
268 | int CPUTopSavedRegOff) { | |
269 | OS << "\t.mask \t"; | |
270 | printHex32(CPUBitmask, OS); | |
271 | OS << ',' << CPUTopSavedRegOff << '\n'; | |
272 | } | |
273 | ||
274 | void MipsTargetAsmStreamer::emitFMask(unsigned FPUBitmask, | |
275 | int FPUTopSavedRegOff) { | |
276 | OS << "\t.fmask\t"; | |
277 | printHex32(FPUBitmask, OS); | |
278 | OS << "," << FPUTopSavedRegOff << '\n'; | |
279 | } | |
280 | ||
281 | void MipsTargetAsmStreamer::emitDirectiveCpLoad(unsigned RegNo) { | |
282 | OS << "\t.cpload\t$" | |
283 | << StringRef(MipsInstPrinter::getRegisterName(RegNo)).lower() << "\n"; | |
284 | forbidModuleDirective(); | |
285 | } | |
286 | ||
287 | void MipsTargetAsmStreamer::emitDirectiveCpsetup(unsigned RegNo, | |
288 | int RegOrOffset, | |
289 | const MCSymbol &Sym, | |
290 | bool IsReg) { | |
291 | OS << "\t.cpsetup\t$" | |
292 | << StringRef(MipsInstPrinter::getRegisterName(RegNo)).lower() << ", "; | |
293 | ||
294 | if (IsReg) | |
295 | OS << "$" | |
296 | << StringRef(MipsInstPrinter::getRegisterName(RegOrOffset)).lower(); | |
297 | else | |
298 | OS << RegOrOffset; | |
299 | ||
300 | OS << ", "; | |
301 | ||
302 | OS << Sym.getName() << "\n"; | |
303 | forbidModuleDirective(); | |
304 | } | |
305 | ||
306 | void MipsTargetAsmStreamer::emitDirectiveModuleFP( | |
307 | MipsABIFlagsSection::FpABIKind Value, bool Is32BitABI) { | |
308 | MipsTargetStreamer::emitDirectiveModuleFP(Value, Is32BitABI); | |
309 | ||
310 | StringRef ModuleValue; | |
311 | OS << "\t.module\tfp="; | |
312 | OS << ABIFlagsSection.getFpABIString(Value) << "\n"; | |
313 | } | |
314 | ||
315 | void MipsTargetAsmStreamer::emitDirectiveSetFp( | |
316 | MipsABIFlagsSection::FpABIKind Value) { | |
317 | StringRef ModuleValue; | |
318 | OS << "\t.set\tfp="; | |
319 | OS << ABIFlagsSection.getFpABIString(Value) << "\n"; | |
320 | } | |
321 | ||
322 | void MipsTargetAsmStreamer::emitMipsAbiFlags() { | |
323 | // No action required for text output. | |
324 | } | |
325 | ||
326 | void MipsTargetAsmStreamer::emitDirectiveModuleOddSPReg(bool Enabled, | |
327 | bool IsO32ABI) { | |
328 | MipsTargetStreamer::emitDirectiveModuleOddSPReg(Enabled, IsO32ABI); | |
329 | ||
330 | OS << "\t.module\t" << (Enabled ? "" : "no") << "oddspreg\n"; | |
331 | } | |
332 | ||
333 | // This part is for ELF object output. | |
334 | MipsTargetELFStreamer::MipsTargetELFStreamer(MCStreamer &S, | |
335 | const MCSubtargetInfo &STI) | |
336 | : MipsTargetStreamer(S), MicroMipsEnabled(false), STI(STI) { | |
337 | MCAssembler &MCA = getStreamer().getAssembler(); | |
338 | uint64_t Features = STI.getFeatureBits(); | |
339 | Triple T(STI.getTargetTriple()); | |
340 | Pic = (MCA.getContext().getObjectFileInfo()->getRelocM() == Reloc::PIC_) | |
341 | ? true | |
342 | : false; | |
343 | ||
344 | // Update e_header flags | |
345 | unsigned EFlags = 0; | |
346 | ||
347 | // Architecture | |
348 | if (Features & Mips::FeatureMips64r6) | |
349 | EFlags |= ELF::EF_MIPS_ARCH_64R6; | |
350 | else if (Features & Mips::FeatureMips64r2) | |
351 | EFlags |= ELF::EF_MIPS_ARCH_64R2; | |
352 | else if (Features & Mips::FeatureMips64) | |
353 | EFlags |= ELF::EF_MIPS_ARCH_64; | |
354 | else if (Features & Mips::FeatureMips5) | |
355 | EFlags |= ELF::EF_MIPS_ARCH_5; | |
356 | else if (Features & Mips::FeatureMips4) | |
357 | EFlags |= ELF::EF_MIPS_ARCH_4; | |
358 | else if (Features & Mips::FeatureMips3) | |
359 | EFlags |= ELF::EF_MIPS_ARCH_3; | |
360 | else if (Features & Mips::FeatureMips32r6) | |
361 | EFlags |= ELF::EF_MIPS_ARCH_32R6; | |
362 | else if (Features & Mips::FeatureMips32r2) | |
363 | EFlags |= ELF::EF_MIPS_ARCH_32R2; | |
364 | else if (Features & Mips::FeatureMips32) | |
365 | EFlags |= ELF::EF_MIPS_ARCH_32; | |
366 | else if (Features & Mips::FeatureMips2) | |
367 | EFlags |= ELF::EF_MIPS_ARCH_2; | |
368 | else | |
369 | EFlags |= ELF::EF_MIPS_ARCH_1; | |
370 | ||
371 | // ABI | |
372 | // N64 does not require any ABI bits. | |
373 | if (Features & Mips::FeatureO32) | |
374 | EFlags |= ELF::EF_MIPS_ABI_O32; | |
375 | else if (Features & Mips::FeatureN32) | |
376 | EFlags |= ELF::EF_MIPS_ABI2; | |
377 | ||
378 | if (Features & Mips::FeatureGP64Bit) { | |
379 | if (Features & Mips::FeatureO32) | |
380 | EFlags |= ELF::EF_MIPS_32BITMODE; /* Compatibility Mode */ | |
381 | } else if (Features & Mips::FeatureMips64r2 || Features & Mips::FeatureMips64) | |
382 | EFlags |= ELF::EF_MIPS_32BITMODE; | |
383 | ||
384 | // Other options. | |
385 | if (Features & Mips::FeatureNaN2008) | |
386 | EFlags |= ELF::EF_MIPS_NAN2008; | |
387 | ||
388 | // -mabicalls and -mplt are not implemented but we should act as if they were | |
389 | // given. | |
390 | EFlags |= ELF::EF_MIPS_CPIC; | |
391 | if (Features & Mips::FeatureN64) | |
392 | EFlags |= ELF::EF_MIPS_PIC; | |
393 | ||
394 | MCA.setELFHeaderEFlags(EFlags); | |
395 | } | |
396 | ||
397 | void MipsTargetELFStreamer::emitLabel(MCSymbol *Symbol) { | |
398 | if (!isMicroMipsEnabled()) | |
399 | return; | |
400 | MCSymbolData &Data = getStreamer().getOrCreateSymbolData(Symbol); | |
401 | uint8_t Type = MCELF::GetType(Data); | |
402 | if (Type != ELF::STT_FUNC) | |
403 | return; | |
404 | ||
405 | // The "other" values are stored in the last 6 bits of the second byte | |
406 | // The traditional defines for STO values assume the full byte and thus | |
407 | // the shift to pack it. | |
408 | MCELF::setOther(Data, ELF::STO_MIPS_MICROMIPS >> 2); | |
409 | } | |
410 | ||
411 | void MipsTargetELFStreamer::finish() { | |
412 | MCAssembler &MCA = getStreamer().getAssembler(); | |
413 | const MCObjectFileInfo &OFI = *MCA.getContext().getObjectFileInfo(); | |
414 | ||
415 | // .bss, .text and .data are always at least 16-byte aligned. | |
416 | MCSectionData &TextSectionData = | |
417 | MCA.getOrCreateSectionData(*OFI.getTextSection()); | |
418 | MCSectionData &DataSectionData = | |
419 | MCA.getOrCreateSectionData(*OFI.getDataSection()); | |
420 | MCSectionData &BSSSectionData = | |
421 | MCA.getOrCreateSectionData(*OFI.getBSSSection()); | |
422 | ||
423 | TextSectionData.setAlignment(std::max(16u, TextSectionData.getAlignment())); | |
424 | DataSectionData.setAlignment(std::max(16u, DataSectionData.getAlignment())); | |
425 | BSSSectionData.setAlignment(std::max(16u, BSSSectionData.getAlignment())); | |
426 | ||
427 | // Emit all the option records. | |
428 | // At the moment we are only emitting .Mips.options (ODK_REGINFO) and | |
429 | // .reginfo. | |
430 | MipsELFStreamer &MEF = static_cast<MipsELFStreamer &>(Streamer); | |
431 | MEF.EmitMipsOptionRecords(); | |
432 | ||
433 | emitMipsAbiFlags(); | |
434 | } | |
435 | ||
436 | void MipsTargetELFStreamer::emitAssignment(MCSymbol *Symbol, | |
437 | const MCExpr *Value) { | |
438 | // If on rhs is micromips symbol then mark Symbol as microMips. | |
439 | if (Value->getKind() != MCExpr::SymbolRef) | |
440 | return; | |
441 | const MCSymbol &RhsSym = | |
442 | static_cast<const MCSymbolRefExpr *>(Value)->getSymbol(); | |
443 | MCSymbolData &Data = getStreamer().getOrCreateSymbolData(&RhsSym); | |
444 | uint8_t Type = MCELF::GetType(Data); | |
445 | if ((Type != ELF::STT_FUNC) || | |
446 | !(MCELF::getOther(Data) & (ELF::STO_MIPS_MICROMIPS >> 2))) | |
447 | return; | |
448 | ||
449 | MCSymbolData &SymbolData = getStreamer().getOrCreateSymbolData(Symbol); | |
450 | // The "other" values are stored in the last 6 bits of the second byte. | |
451 | // The traditional defines for STO values assume the full byte and thus | |
452 | // the shift to pack it. | |
453 | MCELF::setOther(SymbolData, ELF::STO_MIPS_MICROMIPS >> 2); | |
454 | } | |
455 | ||
456 | MCELFStreamer &MipsTargetELFStreamer::getStreamer() { | |
457 | return static_cast<MCELFStreamer &>(Streamer); | |
458 | } | |
459 | ||
460 | void MipsTargetELFStreamer::emitDirectiveSetMicroMips() { | |
461 | MicroMipsEnabled = true; | |
462 | ||
463 | MCAssembler &MCA = getStreamer().getAssembler(); | |
464 | unsigned Flags = MCA.getELFHeaderEFlags(); | |
465 | Flags |= ELF::EF_MIPS_MICROMIPS; | |
466 | MCA.setELFHeaderEFlags(Flags); | |
467 | forbidModuleDirective(); | |
468 | } | |
469 | ||
470 | void MipsTargetELFStreamer::emitDirectiveSetNoMicroMips() { | |
471 | MicroMipsEnabled = false; | |
472 | forbidModuleDirective(); | |
473 | } | |
474 | ||
475 | void MipsTargetELFStreamer::emitDirectiveSetMips16() { | |
476 | MCAssembler &MCA = getStreamer().getAssembler(); | |
477 | unsigned Flags = MCA.getELFHeaderEFlags(); | |
478 | Flags |= ELF::EF_MIPS_ARCH_ASE_M16; | |
479 | MCA.setELFHeaderEFlags(Flags); | |
480 | forbidModuleDirective(); | |
481 | } | |
482 | ||
483 | void MipsTargetELFStreamer::emitDirectiveSetNoReorder() { | |
484 | MCAssembler &MCA = getStreamer().getAssembler(); | |
485 | unsigned Flags = MCA.getELFHeaderEFlags(); | |
486 | Flags |= ELF::EF_MIPS_NOREORDER; | |
487 | MCA.setELFHeaderEFlags(Flags); | |
488 | forbidModuleDirective(); | |
489 | } | |
490 | ||
491 | void MipsTargetELFStreamer::emitDirectiveEnd(StringRef Name) { | |
492 | MCAssembler &MCA = getStreamer().getAssembler(); | |
493 | MCContext &Context = MCA.getContext(); | |
494 | MCStreamer &OS = getStreamer(); | |
495 | ||
496 | const MCSectionELF *Sec = Context.getELFSection(".pdr", ELF::SHT_PROGBITS, | |
497 | ELF::SHF_ALLOC | ELF::SHT_REL, | |
498 | SectionKind::getMetadata()); | |
499 | ||
500 | const MCSymbolRefExpr *ExprRef = | |
501 | MCSymbolRefExpr::Create(Name, MCSymbolRefExpr::VK_None, Context); | |
502 | ||
503 | MCSectionData &SecData = MCA.getOrCreateSectionData(*Sec); | |
504 | SecData.setAlignment(4); | |
505 | ||
506 | OS.PushSection(); | |
507 | ||
508 | OS.SwitchSection(Sec); | |
509 | ||
510 | OS.EmitValueImpl(ExprRef, 4); | |
511 | ||
512 | OS.EmitIntValue(GPRInfoSet ? GPRBitMask : 0, 4); // reg_mask | |
513 | OS.EmitIntValue(GPRInfoSet ? GPROffset : 0, 4); // reg_offset | |
514 | ||
515 | OS.EmitIntValue(FPRInfoSet ? FPRBitMask : 0, 4); // fpreg_mask | |
516 | OS.EmitIntValue(FPRInfoSet ? FPROffset : 0, 4); // fpreg_offset | |
517 | ||
518 | OS.EmitIntValue(FrameInfoSet ? FrameOffset : 0, 4); // frame_offset | |
519 | OS.EmitIntValue(FrameInfoSet ? FrameReg : 0, 4); // frame_reg | |
520 | OS.EmitIntValue(FrameInfoSet ? ReturnReg : 0, 4); // return_reg | |
521 | ||
522 | // The .end directive marks the end of a procedure. Invalidate | |
523 | // the information gathered up until this point. | |
524 | GPRInfoSet = FPRInfoSet = FrameInfoSet = false; | |
525 | ||
526 | OS.PopSection(); | |
527 | } | |
528 | ||
529 | void MipsTargetELFStreamer::emitDirectiveEnt(const MCSymbol &Symbol) { | |
530 | GPRInfoSet = FPRInfoSet = FrameInfoSet = false; | |
531 | } | |
532 | ||
533 | void MipsTargetELFStreamer::emitDirectiveAbiCalls() { | |
534 | MCAssembler &MCA = getStreamer().getAssembler(); | |
535 | unsigned Flags = MCA.getELFHeaderEFlags(); | |
536 | Flags |= ELF::EF_MIPS_CPIC | ELF::EF_MIPS_PIC; | |
537 | MCA.setELFHeaderEFlags(Flags); | |
538 | } | |
539 | ||
540 | void MipsTargetELFStreamer::emitDirectiveNaN2008() { | |
541 | MCAssembler &MCA = getStreamer().getAssembler(); | |
542 | unsigned Flags = MCA.getELFHeaderEFlags(); | |
543 | Flags |= ELF::EF_MIPS_NAN2008; | |
544 | MCA.setELFHeaderEFlags(Flags); | |
545 | } | |
546 | ||
547 | void MipsTargetELFStreamer::emitDirectiveNaNLegacy() { | |
548 | MCAssembler &MCA = getStreamer().getAssembler(); | |
549 | unsigned Flags = MCA.getELFHeaderEFlags(); | |
550 | Flags &= ~ELF::EF_MIPS_NAN2008; | |
551 | MCA.setELFHeaderEFlags(Flags); | |
552 | } | |
553 | ||
554 | void MipsTargetELFStreamer::emitDirectiveOptionPic0() { | |
555 | MCAssembler &MCA = getStreamer().getAssembler(); | |
556 | unsigned Flags = MCA.getELFHeaderEFlags(); | |
557 | // This option overrides other PIC options like -KPIC. | |
558 | Pic = false; | |
559 | Flags &= ~ELF::EF_MIPS_PIC; | |
560 | MCA.setELFHeaderEFlags(Flags); | |
561 | } | |
562 | ||
563 | void MipsTargetELFStreamer::emitDirectiveOptionPic2() { | |
564 | MCAssembler &MCA = getStreamer().getAssembler(); | |
565 | unsigned Flags = MCA.getELFHeaderEFlags(); | |
566 | Pic = true; | |
567 | // NOTE: We are following the GAS behaviour here which means the directive | |
568 | // 'pic2' also sets the CPIC bit in the ELF header. This is different from | |
569 | // what is stated in the SYSV ABI which consider the bits EF_MIPS_PIC and | |
570 | // EF_MIPS_CPIC to be mutually exclusive. | |
571 | Flags |= ELF::EF_MIPS_PIC | ELF::EF_MIPS_CPIC; | |
572 | MCA.setELFHeaderEFlags(Flags); | |
573 | } | |
574 | ||
575 | void MipsTargetELFStreamer::emitFrame(unsigned StackReg, unsigned StackSize, | |
576 | unsigned ReturnReg_) { | |
577 | MCContext &Context = getStreamer().getAssembler().getContext(); | |
578 | const MCRegisterInfo *RegInfo = Context.getRegisterInfo(); | |
579 | ||
580 | FrameInfoSet = true; | |
581 | FrameReg = RegInfo->getEncodingValue(StackReg); | |
582 | FrameOffset = StackSize; | |
583 | ReturnReg = RegInfo->getEncodingValue(ReturnReg_); | |
584 | } | |
585 | ||
586 | void MipsTargetELFStreamer::emitMask(unsigned CPUBitmask, | |
587 | int CPUTopSavedRegOff) { | |
588 | GPRInfoSet = true; | |
589 | GPRBitMask = CPUBitmask; | |
590 | GPROffset = CPUTopSavedRegOff; | |
591 | } | |
592 | ||
593 | void MipsTargetELFStreamer::emitFMask(unsigned FPUBitmask, | |
594 | int FPUTopSavedRegOff) { | |
595 | FPRInfoSet = true; | |
596 | FPRBitMask = FPUBitmask; | |
597 | FPROffset = FPUTopSavedRegOff; | |
598 | } | |
599 | ||
600 | void MipsTargetELFStreamer::emitDirectiveCpLoad(unsigned RegNo) { | |
601 | // .cpload $reg | |
602 | // This directive expands to: | |
603 | // lui $gp, %hi(_gp_disp) | |
604 | // addui $gp, $gp, %lo(_gp_disp) | |
605 | // addu $gp, $gp, $reg | |
606 | // when support for position independent code is enabled. | |
607 | if (!Pic || (isN32() || isN64())) | |
608 | return; | |
609 | ||
610 | // There's a GNU extension controlled by -mno-shared that allows | |
611 | // locally-binding symbols to be accessed using absolute addresses. | |
612 | // This is currently not supported. When supported -mno-shared makes | |
613 | // .cpload expand to: | |
614 | // lui $gp, %hi(__gnu_local_gp) | |
615 | // addiu $gp, $gp, %lo(__gnu_local_gp) | |
616 | ||
617 | StringRef SymName("_gp_disp"); | |
618 | MCAssembler &MCA = getStreamer().getAssembler(); | |
619 | MCSymbol *GP_Disp = MCA.getContext().GetOrCreateSymbol(SymName); | |
620 | MCA.getOrCreateSymbolData(*GP_Disp); | |
621 | ||
622 | MCInst TmpInst; | |
623 | TmpInst.setOpcode(Mips::LUi); | |
624 | TmpInst.addOperand(MCOperand::CreateReg(Mips::GP)); | |
625 | const MCSymbolRefExpr *HiSym = MCSymbolRefExpr::Create( | |
626 | "_gp_disp", MCSymbolRefExpr::VK_Mips_ABS_HI, MCA.getContext()); | |
627 | TmpInst.addOperand(MCOperand::CreateExpr(HiSym)); | |
628 | getStreamer().EmitInstruction(TmpInst, STI); | |
629 | ||
630 | TmpInst.clear(); | |
631 | ||
632 | TmpInst.setOpcode(Mips::ADDiu); | |
633 | TmpInst.addOperand(MCOperand::CreateReg(Mips::GP)); | |
634 | TmpInst.addOperand(MCOperand::CreateReg(Mips::GP)); | |
635 | const MCSymbolRefExpr *LoSym = MCSymbolRefExpr::Create( | |
636 | "_gp_disp", MCSymbolRefExpr::VK_Mips_ABS_LO, MCA.getContext()); | |
637 | TmpInst.addOperand(MCOperand::CreateExpr(LoSym)); | |
638 | getStreamer().EmitInstruction(TmpInst, STI); | |
639 | ||
640 | TmpInst.clear(); | |
641 | ||
642 | TmpInst.setOpcode(Mips::ADDu); | |
643 | TmpInst.addOperand(MCOperand::CreateReg(Mips::GP)); | |
644 | TmpInst.addOperand(MCOperand::CreateReg(Mips::GP)); | |
645 | TmpInst.addOperand(MCOperand::CreateReg(RegNo)); | |
646 | getStreamer().EmitInstruction(TmpInst, STI); | |
647 | ||
648 | forbidModuleDirective(); | |
649 | } | |
650 | ||
651 | void MipsTargetELFStreamer::emitDirectiveCpsetup(unsigned RegNo, | |
652 | int RegOrOffset, | |
653 | const MCSymbol &Sym, | |
654 | bool IsReg) { | |
655 | // Only N32 and N64 emit anything for .cpsetup iff PIC is set. | |
656 | if (!Pic || !(isN32() || isN64())) | |
657 | return; | |
658 | ||
659 | MCAssembler &MCA = getStreamer().getAssembler(); | |
660 | MCInst Inst; | |
661 | ||
662 | // Either store the old $gp in a register or on the stack | |
663 | if (IsReg) { | |
664 | // move $save, $gpreg | |
665 | Inst.setOpcode(Mips::DADDu); | |
666 | Inst.addOperand(MCOperand::CreateReg(RegOrOffset)); | |
667 | Inst.addOperand(MCOperand::CreateReg(Mips::GP)); | |
668 | Inst.addOperand(MCOperand::CreateReg(Mips::ZERO)); | |
669 | } else { | |
670 | // sd $gpreg, offset($sp) | |
671 | Inst.setOpcode(Mips::SD); | |
672 | Inst.addOperand(MCOperand::CreateReg(Mips::GP)); | |
673 | Inst.addOperand(MCOperand::CreateReg(Mips::SP)); | |
674 | Inst.addOperand(MCOperand::CreateImm(RegOrOffset)); | |
675 | } | |
676 | getStreamer().EmitInstruction(Inst, STI); | |
677 | Inst.clear(); | |
678 | ||
679 | const MCSymbolRefExpr *HiExpr = MCSymbolRefExpr::Create( | |
680 | Sym.getName(), MCSymbolRefExpr::VK_Mips_GPOFF_HI, MCA.getContext()); | |
681 | const MCSymbolRefExpr *LoExpr = MCSymbolRefExpr::Create( | |
682 | Sym.getName(), MCSymbolRefExpr::VK_Mips_GPOFF_LO, MCA.getContext()); | |
683 | // lui $gp, %hi(%neg(%gp_rel(funcSym))) | |
684 | Inst.setOpcode(Mips::LUi); | |
685 | Inst.addOperand(MCOperand::CreateReg(Mips::GP)); | |
686 | Inst.addOperand(MCOperand::CreateExpr(HiExpr)); | |
687 | getStreamer().EmitInstruction(Inst, STI); | |
688 | Inst.clear(); | |
689 | ||
690 | // addiu $gp, $gp, %lo(%neg(%gp_rel(funcSym))) | |
691 | Inst.setOpcode(Mips::ADDiu); | |
692 | Inst.addOperand(MCOperand::CreateReg(Mips::GP)); | |
693 | Inst.addOperand(MCOperand::CreateReg(Mips::GP)); | |
694 | Inst.addOperand(MCOperand::CreateExpr(LoExpr)); | |
695 | getStreamer().EmitInstruction(Inst, STI); | |
696 | Inst.clear(); | |
697 | ||
698 | // daddu $gp, $gp, $funcreg | |
699 | Inst.setOpcode(Mips::DADDu); | |
700 | Inst.addOperand(MCOperand::CreateReg(Mips::GP)); | |
701 | Inst.addOperand(MCOperand::CreateReg(Mips::GP)); | |
702 | Inst.addOperand(MCOperand::CreateReg(RegNo)); | |
703 | getStreamer().EmitInstruction(Inst, STI); | |
704 | ||
705 | forbidModuleDirective(); | |
706 | } | |
707 | ||
708 | void MipsTargetELFStreamer::emitMipsAbiFlags() { | |
709 | MCAssembler &MCA = getStreamer().getAssembler(); | |
710 | MCContext &Context = MCA.getContext(); | |
711 | MCStreamer &OS = getStreamer(); | |
712 | const MCSectionELF *Sec = | |
713 | Context.getELFSection(".MIPS.abiflags", ELF::SHT_MIPS_ABIFLAGS, | |
714 | ELF::SHF_ALLOC, SectionKind::getMetadata(), 24, ""); | |
715 | MCSectionData &ABIShndxSD = MCA.getOrCreateSectionData(*Sec); | |
716 | ABIShndxSD.setAlignment(8); | |
717 | OS.SwitchSection(Sec); | |
718 | ||
719 | OS << ABIFlagsSection; | |
720 | } | |
721 | ||
722 | void MipsTargetELFStreamer::emitDirectiveModuleOddSPReg(bool Enabled, | |
723 | bool IsO32ABI) { | |
724 | MipsTargetStreamer::emitDirectiveModuleOddSPReg(Enabled, IsO32ABI); | |
725 | ||
726 | ABIFlagsSection.OddSPReg = Enabled; | |
727 | } |