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 // 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()] = LastEMS; 71 LastEMS = LastMappingSymbols.lookup(Section); 72 73 MCELFStreamer::ChangeSection(Section); 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 virtual void EmitInstruction(const MCInst& Inst) { 80 EmitA64MappingSymbol(); 81 MCELFStreamer::EmitInstruction(Inst); 82 } 83 84 /// This is one of the functions used to emit data into an ELF section, so the 85 /// AArch64 streamer overrides it to add the appropriate mapping symbol ($d) 86 /// if necessary. 87 virtual void EmitBytes(StringRef Data, unsigned AddrSpace) { 88 EmitDataMappingSymbol(); 89 MCELFStreamer::EmitBytes(Data, AddrSpace); 90 } 91 92 /// This is one of the functions used to emit data into an ELF section, so the 93 /// AArch64 streamer overrides it to add the appropriate mapping symbol ($d) 94 /// if necessary. 95 virtual void EmitValueImpl(const MCExpr *Value, unsigned Size, 96 unsigned AddrSpace) { 97 EmitDataMappingSymbol(); 98 MCELFStreamer::EmitValueImpl(Value, Size, AddrSpace); 99 } 100 101 private: 102 enum ElfMappingSymbol { 103 EMS_None, 104 EMS_A64, 105 EMS_Data 106 }; 107 108 void EmitDataMappingSymbol() { 109 if (LastEMS == EMS_Data) return; 110 EmitMappingSymbol("$d"); 111 LastEMS = EMS_Data; 112 } 113 114 void EmitA64MappingSymbol() { 115 if (LastEMS == EMS_A64) return; 116 EmitMappingSymbol("$x"); 117 LastEMS = EMS_A64; 118 } 119 120 void EmitMappingSymbol(StringRef Name) { 121 MCSymbol *Start = getContext().CreateTempSymbol(); 122 EmitLabel(Start); 123 124 MCSymbol *Symbol = 125 getContext().GetOrCreateSymbol(Name + "." + 126 Twine(MappingSymbolCounter++)); 127 128 MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); 129 MCELF::SetType(SD, ELF::STT_NOTYPE); 130 MCELF::SetBinding(SD, ELF::STB_LOCAL); 131 SD.setExternal(false); 132 Symbol->setSection(*getCurrentSection()); 133 134 const MCExpr *Value = MCSymbolRefExpr::Create(Start, getContext()); 135 Symbol->setVariableValue(Value); 136 } 137 138 int64_t MappingSymbolCounter; 139 140 DenseMap<const MCSection *, ElfMappingSymbol> LastMappingSymbols; 141 ElfMappingSymbol LastEMS; 142 143 /// @} 144 }; 145 } 146 147 namespace llvm { 148 MCELFStreamer* createAArch64ELFStreamer(MCContext &Context, MCAsmBackend &TAB, 149 raw_ostream &OS, MCCodeEmitter *Emitter, 150 bool RelaxAll, bool NoExecStack) { 151 AArch64ELFStreamer *S = new AArch64ELFStreamer(Context, TAB, OS, Emitter); 152 if (RelaxAll) 153 S->getAssembler().setRelaxAll(true); 154 if (NoExecStack) 155 S->getAssembler().setNoExecStack(true); 156 return S; 157 } 158 } 159 160 161