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/StringExtras.h" 19#include "llvm/ADT/Twine.h" 20#include "llvm/MC/MCAsmBackend.h" 21#include "llvm/MC/MCAsmInfo.h" 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" 39#include "llvm/Support/FormattedStream.h" 40#include "llvm/Support/raw_ostream.h" 41 42using namespace llvm; 43 44namespace { 45 46class AArch64ELFStreamer; 47 48class AArch64TargetAsmStreamer : public AArch64TargetStreamer { 49 formatted_raw_ostream &OS; 50 51 void emitInst(uint32_t Inst) override; 52 53public: 54 AArch64TargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS); 55}; 56 57AArch64TargetAsmStreamer::AArch64TargetAsmStreamer(MCStreamer &S, 58 formatted_raw_ostream &OS) 59 : AArch64TargetStreamer(S), OS(OS) {} 60 61void AArch64TargetAsmStreamer::emitInst(uint32_t Inst) { 62 OS << "\t.inst\t0x" << utohexstr(Inst) << "\n"; 63} 64 65class AArch64TargetELFStreamer : public AArch64TargetStreamer { 66private: 67 AArch64ELFStreamer &getStreamer(); 68 69 void emitInst(uint32_t Inst) override; 70 71public: 72 AArch64TargetELFStreamer(MCStreamer &S) : AArch64TargetStreamer(S) {} 73}; 74 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! 88class AArch64ELFStreamer : public MCELFStreamer { 89public: 90 friend class AArch64TargetELFStreamer; 91 92 AArch64ELFStreamer(MCContext &Context, MCAsmBackend &TAB, 93 raw_pwrite_stream &OS, MCCodeEmitter *Emitter) 94 : MCELFStreamer(Context, TAB, OS, Emitter), MappingSymbolCounter(0), 95 LastEMS(EMS_None) {} 96 97 ~AArch64ELFStreamer() override {} 98 99 void ChangeSection(const MCSection *Section, 100 const MCExpr *Subsection) override { 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. 104 LastMappingSymbols[getPreviousSection().first] = LastEMS; 105 LastEMS = LastMappingSymbols.lookup(Section); 106 107 MCELFStreamer::ChangeSection(Section, Subsection); 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. 113 void EmitInstruction(const MCInst &Inst, 114 const MCSubtargetInfo &STI) override { 115 EmitA64MappingSymbol(); 116 MCELFStreamer::EmitInstruction(Inst, STI); 117 } 118 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 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. 134 void EmitBytes(StringRef Data) override { 135 EmitDataMappingSymbol(); 136 MCELFStreamer::EmitBytes(Data); 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. 142 void EmitValueImpl(const MCExpr *Value, unsigned Size, 143 const SMLoc &Loc) override { 144 EmitDataMappingSymbol(); 145 MCELFStreamer::EmitValueImpl(Value, Size); 146 } 147 148private: 149 enum ElfMappingSymbol { 150 EMS_None, 151 EMS_A64, 152 EMS_Data 153 }; 154 155 void EmitDataMappingSymbol() { 156 if (LastEMS == EMS_Data) 157 return; 158 EmitMappingSymbol("$d"); 159 LastEMS = EMS_Data; 160 } 161 162 void EmitA64MappingSymbol() { 163 if (LastEMS == EMS_A64) 164 return; 165 EmitMappingSymbol("$x"); 166 LastEMS = EMS_A64; 167 } 168 169 void EmitMappingSymbol(StringRef Name) { 170 MCSymbol *Start = getContext().CreateTempSymbol(); 171 EmitLabel(Start); 172 173 MCSymbol *Symbol = getContext().GetOrCreateSymbol( 174 Name + "." + Twine(MappingSymbolCounter++)); 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); 180 auto Sec = getCurrentSection().first; 181 assert(Sec && "need a section"); 182 Symbol->setSection(*Sec); 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}; 195} // end anonymous namespace 196 197AArch64ELFStreamer &AArch64TargetELFStreamer::getStreamer() { 198 return static_cast<AArch64ELFStreamer &>(Streamer); 199} 200 201void AArch64TargetELFStreamer::emitInst(uint32_t Inst) { 202 getStreamer().emitInst(Inst); 203} 204 205namespace llvm { 206MCTargetStreamer *createAArch64AsmTargetStreamer(MCStreamer &S, 207 formatted_raw_ostream &OS, 208 MCInstPrinter *InstPrint, 209 bool isVerboseAsm) { 210 return new AArch64TargetAsmStreamer(S, OS); 211} 212 213MCELFStreamer *createAArch64ELFStreamer(MCContext &Context, MCAsmBackend &TAB, 214 raw_pwrite_stream &OS, 215 MCCodeEmitter *Emitter, bool RelaxAll) { 216 AArch64ELFStreamer *S = new AArch64ELFStreamer(Context, TAB, OS, Emitter); 217 if (RelaxAll) 218 S->getAssembler().setRelaxAll(true); 219 return S; 220} 221 222MCTargetStreamer * 223createAArch64ObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) { 224 Triple TT(STI.getTargetTriple()); 225 if (TT.getObjectFormat() == Triple::ELF) 226 return new AArch64TargetELFStreamer(S); 227 return nullptr; 228} 229} 230