1 //===- lib/MC/AArch64ELFStreamer.cpp - ELF Object Output for AArch64 ------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file assembles .s files and emits AArch64 ELF .o object files. Different 10 // from generic ELF streamer in emitting mapping symbols ($x and $d) to delimit 11 // regions of data and code. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "AArch64TargetStreamer.h" 16 #include "AArch64WinCOFFStreamer.h" 17 #include "llvm/ADT/DenseMap.h" 18 #include "llvm/ADT/StringRef.h" 19 #include "llvm/ADT/Triple.h" 20 #include "llvm/ADT/Twine.h" 21 #include "llvm/BinaryFormat/ELF.h" 22 #include "llvm/MC/MCAsmBackend.h" 23 #include "llvm/MC/MCAssembler.h" 24 #include "llvm/MC/MCCodeEmitter.h" 25 #include "llvm/MC/MCContext.h" 26 #include "llvm/MC/MCELFStreamer.h" 27 #include "llvm/MC/MCExpr.h" 28 #include "llvm/MC/MCInst.h" 29 #include "llvm/MC/MCObjectWriter.h" 30 #include "llvm/MC/MCSection.h" 31 #include "llvm/MC/MCStreamer.h" 32 #include "llvm/MC/MCSubtargetInfo.h" 33 #include "llvm/MC/MCSymbolELF.h" 34 #include "llvm/MC/MCWinCOFFStreamer.h" 35 #include "llvm/Support/Casting.h" 36 #include "llvm/Support/FormattedStream.h" 37 #include "llvm/Support/raw_ostream.h" 38 39 using namespace llvm; 40 41 namespace { 42 43 class AArch64ELFStreamer; 44 45 class AArch64TargetAsmStreamer : public AArch64TargetStreamer { 46 formatted_raw_ostream &OS; 47 48 void emitInst(uint32_t Inst) override; 49 50 void emitDirectiveVariantPCS(MCSymbol *Symbol) override { 51 OS << "\t.variant_pcs " << Symbol->getName() << "\n"; 52 } 53 54 void EmitARM64WinCFIAllocStack(unsigned Size) override { 55 OS << "\t.seh_stackalloc " << Size << "\n"; 56 } 57 void EmitARM64WinCFISaveR19R20X(int Offset) override { 58 OS << "\t.seh_save_r19r20_x " << Offset << "\n"; 59 } 60 void EmitARM64WinCFISaveFPLR(int Offset) override { 61 OS << "\t.seh_save_fplr " << Offset << "\n"; 62 } 63 void EmitARM64WinCFISaveFPLRX(int Offset) override { 64 OS << "\t.seh_save_fplr_x " << Offset << "\n"; 65 } 66 void EmitARM64WinCFISaveReg(unsigned Reg, int Offset) override { 67 OS << "\t.seh_save_reg x" << Reg << ", " << Offset << "\n"; 68 } 69 void EmitARM64WinCFISaveRegX(unsigned Reg, int Offset) override { 70 OS << "\t.seh_save_reg_x x" << Reg << ", " << Offset << "\n"; 71 } 72 void EmitARM64WinCFISaveRegP(unsigned Reg, int Offset) override { 73 OS << "\t.seh_save_regp x" << Reg << ", " << Offset << "\n"; 74 } 75 void EmitARM64WinCFISaveRegPX(unsigned Reg, int Offset) override { 76 OS << "\t.seh_save_regp_x x" << Reg << ", " << Offset << "\n"; 77 } 78 void EmitARM64WinCFISaveLRPair(unsigned Reg, int Offset) override { 79 OS << "\t.seh_save_lrpair x" << Reg << ", " << Offset << "\n"; 80 } 81 void EmitARM64WinCFISaveFReg(unsigned Reg, int Offset) override { 82 OS << "\t.seh_save_freg d" << Reg << ", " << Offset << "\n"; 83 } 84 void EmitARM64WinCFISaveFRegX(unsigned Reg, int Offset) override { 85 OS << "\t.seh_save_freg_x d" << Reg << ", " << Offset << "\n"; 86 } 87 void EmitARM64WinCFISaveFRegP(unsigned Reg, int Offset) override { 88 OS << "\t.seh_save_fregp d" << Reg << ", " << Offset << "\n"; 89 } 90 void EmitARM64WinCFISaveFRegPX(unsigned Reg, int Offset) override { 91 OS << "\t.seh_save_fregp_x d" << Reg << ", " << Offset << "\n"; 92 } 93 void EmitARM64WinCFISetFP() override { OS << "\t.seh_set_fp\n"; } 94 void EmitARM64WinCFIAddFP(unsigned Size) override { 95 OS << "\t.seh_add_fp " << Size << "\n"; 96 } 97 void EmitARM64WinCFINop() override { OS << "\t.seh_nop\n"; } 98 void EmitARM64WinCFISaveNext() override { OS << "\t.seh_save_next\n"; } 99 void EmitARM64WinCFIPrologEnd() override { OS << "\t.seh_endprologue\n"; } 100 void EmitARM64WinCFIEpilogStart() override { OS << "\t.seh_startepilogue\n"; } 101 void EmitARM64WinCFIEpilogEnd() override { OS << "\t.seh_endepilogue\n"; } 102 void EmitARM64WinCFITrapFrame() override { OS << "\t.seh_trap_frame\n"; } 103 void EmitARM64WinCFIMachineFrame() override { OS << "\t.seh_pushframe\n"; } 104 void EmitARM64WinCFIContext() override { OS << "\t.seh_context\n"; } 105 void EmitARM64WinCFIClearUnwoundToCall() override { 106 OS << "\t.seh_clear_unwound_to_call\n"; 107 } 108 109 public: 110 AArch64TargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS); 111 }; 112 113 AArch64TargetAsmStreamer::AArch64TargetAsmStreamer(MCStreamer &S, 114 formatted_raw_ostream &OS) 115 : AArch64TargetStreamer(S), OS(OS) {} 116 117 void AArch64TargetAsmStreamer::emitInst(uint32_t Inst) { 118 OS << "\t.inst\t0x" << Twine::utohexstr(Inst) << "\n"; 119 } 120 121 /// Extend the generic ELFStreamer class so that it can emit mapping symbols at 122 /// the appropriate points in the object files. These symbols are defined in the 123 /// AArch64 ELF ABI: 124 /// infocenter.arm.com/help/topic/com.arm.doc.ihi0056a/IHI0056A_aaelf64.pdf 125 /// 126 /// In brief: $x or $d should be emitted at the start of each contiguous region 127 /// of A64 code or data in a section. In practice, this emission does not rely 128 /// on explicit assembler directives but on inherent properties of the 129 /// directives doing the emission (e.g. ".byte" is data, "add x0, x0, x0" an 130 /// instruction). 131 /// 132 /// As a result this system is orthogonal to the DataRegion infrastructure used 133 /// by MachO. Beware! 134 class AArch64ELFStreamer : public MCELFStreamer { 135 public: 136 AArch64ELFStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> TAB, 137 std::unique_ptr<MCObjectWriter> OW, 138 std::unique_ptr<MCCodeEmitter> Emitter) 139 : MCELFStreamer(Context, std::move(TAB), std::move(OW), 140 std::move(Emitter)), 141 MappingSymbolCounter(0), LastEMS(EMS_None) {} 142 143 void changeSection(MCSection *Section, const MCExpr *Subsection) override { 144 // We have to keep track of the mapping symbol state of any sections we 145 // use. Each one should start off as EMS_None, which is provided as the 146 // default constructor by DenseMap::lookup. 147 LastMappingSymbols[getPreviousSection().first] = LastEMS; 148 LastEMS = LastMappingSymbols.lookup(Section); 149 150 MCELFStreamer::changeSection(Section, Subsection); 151 } 152 153 // Reset state between object emissions 154 void reset() override { 155 MappingSymbolCounter = 0; 156 MCELFStreamer::reset(); 157 LastMappingSymbols.clear(); 158 LastEMS = EMS_None; 159 } 160 161 /// This function is the one used to emit instruction data into the ELF 162 /// streamer. We override it to add the appropriate mapping symbol if 163 /// necessary. 164 void emitInstruction(const MCInst &Inst, 165 const MCSubtargetInfo &STI) override { 166 EmitA64MappingSymbol(); 167 MCELFStreamer::emitInstruction(Inst, STI); 168 } 169 170 /// Emit a 32-bit value as an instruction. This is only used for the .inst 171 /// directive, EmitInstruction should be used in other cases. 172 void emitInst(uint32_t Inst) { 173 char Buffer[4]; 174 175 // We can't just use EmitIntValue here, as that will emit a data mapping 176 // symbol, and swap the endianness on big-endian systems (instructions are 177 // always little-endian). 178 for (unsigned I = 0; I < 4; ++I) { 179 Buffer[I] = uint8_t(Inst); 180 Inst >>= 8; 181 } 182 183 EmitA64MappingSymbol(); 184 MCELFStreamer::emitBytes(StringRef(Buffer, 4)); 185 } 186 187 /// This is one of the functions used to emit data into an ELF section, so the 188 /// AArch64 streamer overrides it to add the appropriate mapping symbol ($d) 189 /// if necessary. 190 void emitBytes(StringRef Data) override { 191 emitDataMappingSymbol(); 192 MCELFStreamer::emitBytes(Data); 193 } 194 195 /// This is one of the functions used to emit data into an ELF section, so the 196 /// AArch64 streamer overrides it to add the appropriate mapping symbol ($d) 197 /// if necessary. 198 void emitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc) override { 199 emitDataMappingSymbol(); 200 MCELFStreamer::emitValueImpl(Value, Size, Loc); 201 } 202 203 void emitFill(const MCExpr &NumBytes, uint64_t FillValue, 204 SMLoc Loc) override { 205 emitDataMappingSymbol(); 206 MCObjectStreamer::emitFill(NumBytes, FillValue, Loc); 207 } 208 private: 209 enum ElfMappingSymbol { 210 EMS_None, 211 EMS_A64, 212 EMS_Data 213 }; 214 215 void emitDataMappingSymbol() { 216 if (LastEMS == EMS_Data) 217 return; 218 EmitMappingSymbol("$d"); 219 LastEMS = EMS_Data; 220 } 221 222 void EmitA64MappingSymbol() { 223 if (LastEMS == EMS_A64) 224 return; 225 EmitMappingSymbol("$x"); 226 LastEMS = EMS_A64; 227 } 228 229 void EmitMappingSymbol(StringRef Name) { 230 auto *Symbol = cast<MCSymbolELF>(getContext().getOrCreateSymbol( 231 Name + "." + Twine(MappingSymbolCounter++))); 232 emitLabel(Symbol); 233 Symbol->setType(ELF::STT_NOTYPE); 234 Symbol->setBinding(ELF::STB_LOCAL); 235 Symbol->setExternal(false); 236 } 237 238 int64_t MappingSymbolCounter; 239 240 DenseMap<const MCSection *, ElfMappingSymbol> LastMappingSymbols; 241 ElfMappingSymbol LastEMS; 242 }; 243 244 } // end anonymous namespace 245 246 namespace llvm { 247 248 AArch64ELFStreamer &AArch64TargetELFStreamer::getStreamer() { 249 return static_cast<AArch64ELFStreamer &>(Streamer); 250 } 251 252 void AArch64TargetELFStreamer::emitInst(uint32_t Inst) { 253 getStreamer().emitInst(Inst); 254 } 255 256 void AArch64TargetELFStreamer::emitDirectiveVariantPCS(MCSymbol *Symbol) { 257 cast<MCSymbolELF>(Symbol)->setOther(ELF::STO_AARCH64_VARIANT_PCS); 258 } 259 260 MCTargetStreamer *createAArch64AsmTargetStreamer(MCStreamer &S, 261 formatted_raw_ostream &OS, 262 MCInstPrinter *InstPrint, 263 bool isVerboseAsm) { 264 return new AArch64TargetAsmStreamer(S, OS); 265 } 266 267 MCELFStreamer *createAArch64ELFStreamer(MCContext &Context, 268 std::unique_ptr<MCAsmBackend> TAB, 269 std::unique_ptr<MCObjectWriter> OW, 270 std::unique_ptr<MCCodeEmitter> Emitter, 271 bool RelaxAll) { 272 AArch64ELFStreamer *S = new AArch64ELFStreamer( 273 Context, std::move(TAB), std::move(OW), std::move(Emitter)); 274 if (RelaxAll) 275 S->getAssembler().setRelaxAll(true); 276 return S; 277 } 278 279 } // end namespace llvm 280