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" 18 #include "llvm/ADT/Twine.h" 19 #include "llvm/MC/MCAsmBackend.h" 20 #include "llvm/MC/MCAssembler.h" 21 #include "llvm/MC/MCCodeEmitter.h" 22 #include "llvm/MC/MCContext.h" 23 #include "llvm/MC/MCELF.h" 24 #include "llvm/MC/MCELFStreamer.h" 25 #include "llvm/MC/MCELFSymbolFlags.h" 26 #include "llvm/MC/MCExpr.h" 27 #include "llvm/MC/MCInst.h" 28 #include "llvm/MC/MCObjectStreamer.h" 29 #include "llvm/MC/MCSection.h" 30 #include "llvm/MC/MCSectionELF.h" 31 #include "llvm/MC/MCStreamer.h" 32 #include "llvm/MC/MCSymbol.h" 33 #include "llvm/MC/MCValue.h" 34 #include "llvm/Support/Debug.h" 35 #include "llvm/Support/ELF.h" 36 #include "llvm/Support/ErrorHandling.h" 37 #include "llvm/Support/raw_ostream.h" 38 39 using namespace llvm; 40 41 namespace { 42 43 /// Extend the generic ELFStreamer class so that it can emit mapping symbols at 44 /// the appropriate points in the object files. These symbols are defined in the 45 /// AArch64 ELF ABI: 46 /// infocenter.arm.com/help/topic/com.arm.doc.ihi0056a/IHI0056A_aaelf64.pdf 47 /// 48 /// In brief: $x or $d should be emitted at the start of each contiguous region 49 /// of A64 code or data in a section. In practice, this emission does not rely 50 /// on explicit assembler directives but on inherent properties of the 51 /// directives doing the emission (e.g. ".byte" is data, "add x0, x0, x0" an 52 /// instruction). 53 /// 54 /// As a result this system is orthogonal to the DataRegion infrastructure used 55 /// by MachO. Beware! 56 class AArch64ELFStreamer : public MCELFStreamer { 57 public: 58 AArch64ELFStreamer(MCContext &Context, MCAsmBackend &TAB, raw_ostream &OS, 59 MCCodeEmitter *Emitter) 60 : MCELFStreamer(Context, TAB, OS, Emitter), MappingSymbolCounter(0), 61 LastEMS(EMS_None) {} 62 63 ~AArch64ELFStreamer() {} 64 65 void ChangeSection(const MCSection *Section, 66 const MCExpr *Subsection) override { 67 // We have to keep track of the mapping symbol state of any sections we 68 // use. Each one should start off as EMS_None, which is provided as the 69 // default constructor by DenseMap::lookup. 70 LastMappingSymbols[getPreviousSection().first] = LastEMS; 71 LastEMS = LastMappingSymbols.lookup(Section); 72 73 MCELFStreamer::ChangeSection(Section, Subsection); 74 } 75 76 /// This function is the one used to emit instruction data into the ELF 77 /// streamer. We override it to add the appropriate mapping symbol if 78 /// necessary. 79 void EmitInstruction(const MCInst &Inst, 80 const MCSubtargetInfo &STI) override { 81 EmitA64MappingSymbol(); 82 MCELFStreamer::EmitInstruction(Inst, STI); 83 } 84 85 /// This is one of the functions used to emit data into an ELF section, so the 86 /// AArch64 streamer overrides it to add the appropriate mapping symbol ($d) 87 /// if necessary. 88 void EmitBytes(StringRef Data) override { 89 EmitDataMappingSymbol(); 90 MCELFStreamer::EmitBytes(Data); 91 } 92 93 /// This is one of the functions used to emit data into an ELF section, so the 94 /// AArch64 streamer overrides it to add the appropriate mapping symbol ($d) 95 /// if necessary. 96 void EmitValueImpl(const MCExpr *Value, unsigned Size, 97 const SMLoc &Loc) override { 98 EmitDataMappingSymbol(); 99 MCELFStreamer::EmitValueImpl(Value, Size); 100 } 101 102 private: 103 enum ElfMappingSymbol { 104 EMS_None, 105 EMS_A64, 106 EMS_Data 107 }; 108 109 void EmitDataMappingSymbol() { 110 if (LastEMS == EMS_Data) 111 return; 112 EmitMappingSymbol("$d"); 113 LastEMS = EMS_Data; 114 } 115 116 void EmitA64MappingSymbol() { 117 if (LastEMS == EMS_A64) 118 return; 119 EmitMappingSymbol("$x"); 120 LastEMS = EMS_A64; 121 } 122 123 void EmitMappingSymbol(StringRef Name) { 124 MCSymbol *Start = getContext().CreateTempSymbol(); 125 EmitLabel(Start); 126 127 MCSymbol *Symbol = getContext().GetOrCreateSymbol( 128 Name + "." + Twine(MappingSymbolCounter++)); 129 130 MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); 131 MCELF::SetType(SD, ELF::STT_NOTYPE); 132 MCELF::SetBinding(SD, ELF::STB_LOCAL); 133 SD.setExternal(false); 134 Symbol->setSection(*getCurrentSection().first); 135 136 const MCExpr *Value = MCSymbolRefExpr::Create(Start, getContext()); 137 Symbol->setVariableValue(Value); 138 } 139 140 int64_t MappingSymbolCounter; 141 142 DenseMap<const MCSection *, ElfMappingSymbol> LastMappingSymbols; 143 ElfMappingSymbol LastEMS; 144 145 /// @} 146 }; 147 } 148 149 namespace llvm { 150 MCELFStreamer *createAArch64ELFStreamer(MCContext &Context, MCAsmBackend &TAB, 151 raw_ostream &OS, MCCodeEmitter *Emitter, 152 bool RelaxAll, bool NoExecStack) { 153 AArch64ELFStreamer *S = new AArch64ELFStreamer(Context, TAB, OS, Emitter); 154 if (RelaxAll) 155 S->getAssembler().setRelaxAll(true); 156 if (NoExecStack) 157 S->getAssembler().setNoExecStack(true); 158 return S; 159 } 160 } 161