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, 59 raw_ostream &OS, MCCodeEmitter *Emitter) 60 : MCELFStreamer(Context, TAB, OS, Emitter), 61 MappingSymbolCounter(0), LastEMS(EMS_None) { 62 } 63 64 ~AArch64ELFStreamer() {} 65 66 virtual void ChangeSection(const MCSection *Section, 67 const MCExpr *Subsection) { 68 // We have to keep track of the mapping symbol state of any sections we 69 // use. Each one should start off as EMS_None, which is provided as the 70 // default constructor by DenseMap::lookup. 71 LastMappingSymbols[getPreviousSection().first] = LastEMS; 72 LastEMS = LastMappingSymbols.lookup(Section); 73 74 MCELFStreamer::ChangeSection(Section, Subsection); 75 } 76 77 /// This function is the one used to emit instruction data into the ELF 78 /// streamer. We override it to add the appropriate mapping symbol if 79 /// necessary. 80 virtual void EmitInstruction(const MCInst& Inst) { 81 EmitA64MappingSymbol(); 82 MCELFStreamer::EmitInstruction(Inst); 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 virtual void EmitBytes(StringRef Data, unsigned AddrSpace) { 89 EmitDataMappingSymbol(); 90 MCELFStreamer::EmitBytes(Data, AddrSpace); 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 virtual void EmitValueImpl(const MCExpr *Value, unsigned Size, 97 unsigned AddrSpace) { 98 EmitDataMappingSymbol(); 99 MCELFStreamer::EmitValueImpl(Value, Size, AddrSpace); 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) return; 111 EmitMappingSymbol("$d"); 112 LastEMS = EMS_Data; 113 } 114 115 void EmitA64MappingSymbol() { 116 if (LastEMS == EMS_A64) return; 117 EmitMappingSymbol("$x"); 118 LastEMS = EMS_A64; 119 } 120 121 void EmitMappingSymbol(StringRef Name) { 122 MCSymbol *Start = getContext().CreateTempSymbol(); 123 EmitLabel(Start); 124 125 MCSymbol *Symbol = 126 getContext().GetOrCreateSymbol(Name + "." + 127 Twine(MappingSymbolCounter++)); 128 129 MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); 130 MCELF::SetType(SD, ELF::STT_NOTYPE); 131 MCELF::SetBinding(SD, ELF::STB_LOCAL); 132 SD.setExternal(false); 133 Symbol->setSection(*getCurrentSection().first); 134 135 const MCExpr *Value = MCSymbolRefExpr::Create(Start, getContext()); 136 Symbol->setVariableValue(Value); 137 } 138 139 int64_t MappingSymbolCounter; 140 141 DenseMap<const MCSection *, ElfMappingSymbol> LastMappingSymbols; 142 ElfMappingSymbol LastEMS; 143 144 /// @} 145 }; 146 } 147 148 namespace llvm { 149 MCELFStreamer* createAArch64ELFStreamer(MCContext &Context, MCAsmBackend &TAB, 150 raw_ostream &OS, MCCodeEmitter *Emitter, 151 bool RelaxAll, bool NoExecStack) { 152 AArch64ELFStreamer *S = new AArch64ELFStreamer(Context, TAB, OS, Emitter); 153 if (RelaxAll) 154 S->getAssembler().setRelaxAll(true); 155 if (NoExecStack) 156 S->getAssembler().setNoExecStack(true); 157 return S; 158 } 159 } 160 161 162