ARMELFStreamer.cpp revision 38b06020dbd804f01ee3802779a52c05cffdf87d
1//===- lib/MC/ARMELFStreamer.cpp - ELF Object Output for ARM --------------===// 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 ARM ELF .o object files. Different 11// from generic ELF streamer in emitting mapping symbols ($a, $t and $d) to 12// delimit regions of data and code. 13// 14//===----------------------------------------------------------------------===// 15 16#include "llvm/ADT/SmallPtrSet.h" 17#include "llvm/ADT/Twine.h" 18#include "llvm/MC/MCAsmBackend.h" 19#include "llvm/MC/MCAssembler.h" 20#include "llvm/MC/MCCodeEmitter.h" 21#include "llvm/MC/MCContext.h" 22#include "llvm/MC/MCELF.h" 23#include "llvm/MC/MCELFStreamer.h" 24#include "llvm/MC/MCELFSymbolFlags.h" 25#include "llvm/MC/MCExpr.h" 26#include "llvm/MC/MCInst.h" 27#include "llvm/MC/MCObjectStreamer.h" 28#include "llvm/MC/MCSection.h" 29#include "llvm/MC/MCSectionELF.h" 30#include "llvm/MC/MCStreamer.h" 31#include "llvm/MC/MCSymbol.h" 32#include "llvm/MC/MCValue.h" 33#include "llvm/Support/Debug.h" 34#include "llvm/Support/ELF.h" 35#include "llvm/Support/ErrorHandling.h" 36#include "llvm/Support/raw_ostream.h" 37 38using namespace llvm; 39 40namespace { 41 42/// Extend the generic ELFStreamer class so that it can emit mapping symbols at 43/// the appropriate points in the object files. These symbols are defined in the 44/// ARM ELF ABI: infocenter.arm.com/help/topic/com.arm.../IHI0044D_aaelf.pdf. 45/// 46/// In brief: $a, $t or $d should be emitted at the start of each contiguous 47/// region of ARM code, Thumb code or data in a section. In practice, this 48/// emission does not rely on explicit assembler directives but on inherent 49/// properties of the directives doing the emission (e.g. ".byte" is data, "add 50/// r0, r0, r0" an instruction). 51/// 52/// As a result this system is orthogonal to the DataRegion infrastructure used 53/// by MachO. Beware! 54class ARMELFStreamer : public MCELFStreamer { 55public: 56 ARMELFStreamer(MCContext &Context, MCAsmBackend &TAB, 57 raw_ostream &OS, MCCodeEmitter *Emitter, bool IsThumb) 58 : MCELFStreamer(Context, TAB, OS, Emitter), 59 IsThumb(IsThumb), MappingSymbolCounter(0), LastEMS(EMS_None) { 60 } 61 62 ~ARMELFStreamer() {} 63 64 virtual void ChangeSection(const MCSection *Section) { 65 // We have to keep track of the mapping symbol state of any sections we 66 // use. Each one should start off as EMS_None, which is provided as the 67 // default constructor by DenseMap::lookup. 68 LastMappingSymbols[getPreviousSection()] = LastEMS; 69 LastEMS = LastMappingSymbols.lookup(Section); 70 71 MCELFStreamer::ChangeSection(Section); 72 } 73 74 /// This function is the one used to emit instruction data into the ELF 75 /// streamer. We override it to add the appropriate mapping symbol if 76 /// necessary. 77 virtual void EmitInstruction(const MCInst& Inst) { 78 if (IsThumb) 79 EmitThumbMappingSymbol(); 80 else 81 EmitARMMappingSymbol(); 82 83 MCELFStreamer::EmitInstruction(Inst); 84 } 85 86 /// This is one of the functions used to emit data into an ELF section, so the 87 /// ARM streamer overrides it to add the appropriate mapping symbol ($d) if 88 /// necessary. 89 virtual void EmitBytes(StringRef Data, unsigned AddrSpace) { 90 EmitDataMappingSymbol(); 91 MCELFStreamer::EmitBytes(Data, AddrSpace); 92 } 93 94 /// This is one of the functions used to emit data into an ELF section, so the 95 /// ARM streamer overrides it to add the appropriate mapping symbol ($d) if 96 /// necessary. 97 virtual void EmitValueImpl(const MCExpr *Value, unsigned Size, 98 unsigned AddrSpace) { 99 EmitDataMappingSymbol(); 100 MCELFStreamer::EmitValueImpl(Value, Size, AddrSpace); 101 } 102 103 virtual void EmitAssemblerFlag(MCAssemblerFlag Flag) { 104 MCELFStreamer::EmitAssemblerFlag(Flag); 105 106 switch (Flag) { 107 case MCAF_SyntaxUnified: 108 return; // no-op here. 109 case MCAF_Code16: 110 IsThumb = true; 111 return; // Change to Thumb mode 112 case MCAF_Code32: 113 IsThumb = false; 114 return; // Change to ARM mode 115 case MCAF_Code64: 116 return; 117 case MCAF_SubsectionsViaSymbols: 118 return; 119 } 120 } 121 122private: 123 enum ElfMappingSymbol { 124 EMS_None, 125 EMS_ARM, 126 EMS_Thumb, 127 EMS_Data 128 }; 129 130 void EmitDataMappingSymbol() { 131 if (LastEMS == EMS_Data) return; 132 EmitMappingSymbol("$d"); 133 LastEMS = EMS_Data; 134 } 135 136 void EmitThumbMappingSymbol() { 137 if (LastEMS == EMS_Thumb) return; 138 EmitMappingSymbol("$t"); 139 LastEMS = EMS_Thumb; 140 } 141 142 void EmitARMMappingSymbol() { 143 if (LastEMS == EMS_ARM) return; 144 EmitMappingSymbol("$a"); 145 LastEMS = EMS_ARM; 146 } 147 148 void EmitMappingSymbol(StringRef Name) { 149 MCSymbol *Start = getContext().CreateTempSymbol(); 150 EmitLabel(Start); 151 152 MCSymbol *Symbol = 153 getContext().GetOrCreateSymbol(Name + "." + 154 Twine(MappingSymbolCounter++)); 155 156 MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); 157 MCELF::SetType(SD, ELF::STT_NOTYPE); 158 MCELF::SetBinding(SD, ELF::STB_LOCAL); 159 SD.setExternal(false); 160 Symbol->setSection(*getCurrentSection()); 161 162 const MCExpr *Value = MCSymbolRefExpr::Create(Start, getContext()); 163 Symbol->setVariableValue(Value); 164 } 165 166 void EmitThumbFunc(MCSymbol *Func) { 167 // FIXME: Anything needed here to flag the function as thumb? 168 169 getAssembler().setIsThumbFunc(Func); 170 171 MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Func); 172 SD.setFlags(SD.getFlags() | ELF_Other_ThumbFunc); 173 } 174 175 176 bool IsThumb; 177 int64_t MappingSymbolCounter; 178 179 DenseMap<const MCSection *, ElfMappingSymbol> LastMappingSymbols; 180 ElfMappingSymbol LastEMS; 181 182 /// @} 183}; 184} 185 186namespace llvm { 187 MCELFStreamer* createARMELFStreamer(MCContext &Context, MCAsmBackend &TAB, 188 raw_ostream &OS, MCCodeEmitter *Emitter, 189 bool RelaxAll, bool NoExecStack, 190 bool IsThumb) { 191 ARMELFStreamer *S = new ARMELFStreamer(Context, TAB, OS, Emitter, IsThumb); 192 if (RelaxAll) 193 S->getAssembler().setRelaxAll(true); 194 if (NoExecStack) 195 S->getAssembler().setNoExecStack(true); 196 return S; 197 } 198 199} 200 201 202