1 //===- lib/MC/MCWasmStreamer.cpp - Wasm Object Output ---------------------===// 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 Wasm .o object files. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/MC/MCWasmStreamer.h" 14 #include "llvm/ADT/STLExtras.h" 15 #include "llvm/ADT/SmallPtrSet.h" 16 #include "llvm/MC/MCAsmBackend.h" 17 #include "llvm/MC/MCAsmLayout.h" 18 #include "llvm/MC/MCAssembler.h" 19 #include "llvm/MC/MCCodeEmitter.h" 20 #include "llvm/MC/MCContext.h" 21 #include "llvm/MC/MCExpr.h" 22 #include "llvm/MC/MCInst.h" 23 #include "llvm/MC/MCObjectStreamer.h" 24 #include "llvm/MC/MCSection.h" 25 #include "llvm/MC/MCSectionWasm.h" 26 #include "llvm/MC/MCSymbol.h" 27 #include "llvm/MC/MCSymbolWasm.h" 28 #include "llvm/MC/MCValue.h" 29 #include "llvm/MC/TargetRegistry.h" 30 #include "llvm/Support/Casting.h" 31 #include "llvm/Support/Debug.h" 32 #include "llvm/Support/ErrorHandling.h" 33 #include "llvm/Support/raw_ostream.h" 34 35 using namespace llvm; 36 37 MCWasmStreamer::~MCWasmStreamer() = default; // anchor. 38 39 void MCWasmStreamer::mergeFragment(MCDataFragment *DF, MCDataFragment *EF) { 40 flushPendingLabels(DF, DF->getContents().size()); 41 42 for (unsigned I = 0, E = EF->getFixups().size(); I != E; ++I) { 43 EF->getFixups()[I].setOffset(EF->getFixups()[I].getOffset() + 44 DF->getContents().size()); 45 DF->getFixups().push_back(EF->getFixups()[I]); 46 } 47 if (DF->getSubtargetInfo() == nullptr && EF->getSubtargetInfo()) 48 DF->setHasInstructions(*EF->getSubtargetInfo()); 49 DF->getContents().append(EF->getContents().begin(), EF->getContents().end()); 50 } 51 52 void MCWasmStreamer::emitLabel(MCSymbol *S, SMLoc Loc) { 53 auto *Symbol = cast<MCSymbolWasm>(S); 54 MCObjectStreamer::emitLabel(Symbol, Loc); 55 56 const MCSectionWasm &Section = 57 static_cast<const MCSectionWasm &>(*getCurrentSectionOnly()); 58 if (Section.getSegmentFlags() & wasm::WASM_SEG_FLAG_TLS) 59 Symbol->setTLS(); 60 } 61 62 void MCWasmStreamer::emitLabelAtPos(MCSymbol *S, SMLoc Loc, MCFragment *F, 63 uint64_t Offset) { 64 auto *Symbol = cast<MCSymbolWasm>(S); 65 MCObjectStreamer::emitLabelAtPos(Symbol, Loc, F, Offset); 66 67 const MCSectionWasm &Section = 68 static_cast<const MCSectionWasm &>(*getCurrentSectionOnly()); 69 if (Section.getSegmentFlags() & wasm::WASM_SEG_FLAG_TLS) 70 Symbol->setTLS(); 71 } 72 73 void MCWasmStreamer::emitAssemblerFlag(MCAssemblerFlag Flag) { 74 // Let the target do whatever target specific stuff it needs to do. 75 getAssembler().getBackend().handleAssemblerFlag(Flag); 76 77 // Do any generic stuff we need to do. 78 llvm_unreachable("invalid assembler flag!"); 79 } 80 81 void MCWasmStreamer::changeSection(MCSection *Section, 82 const MCExpr *Subsection) { 83 MCAssembler &Asm = getAssembler(); 84 auto *SectionWasm = cast<MCSectionWasm>(Section); 85 const MCSymbol *Grp = SectionWasm->getGroup(); 86 if (Grp) 87 Asm.registerSymbol(*Grp); 88 89 this->MCObjectStreamer::changeSection(Section, Subsection); 90 Asm.registerSymbol(*Section->getBeginSymbol()); 91 } 92 93 void MCWasmStreamer::emitWeakReference(MCSymbol *Alias, 94 const MCSymbol *Symbol) { 95 getAssembler().registerSymbol(*Symbol); 96 const MCExpr *Value = MCSymbolRefExpr::create( 97 Symbol, MCSymbolRefExpr::VK_WEAKREF, getContext()); 98 Alias->setVariableValue(Value); 99 } 100 101 bool MCWasmStreamer::emitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) { 102 assert(Attribute != MCSA_IndirectSymbol && "indirect symbols not supported"); 103 104 auto *Symbol = cast<MCSymbolWasm>(S); 105 106 // Adding a symbol attribute always introduces the symbol; note that an 107 // important side effect of calling registerSymbol here is to register the 108 // symbol with the assembler. 109 getAssembler().registerSymbol(*Symbol); 110 111 switch (Attribute) { 112 case MCSA_LazyReference: 113 case MCSA_Reference: 114 case MCSA_SymbolResolver: 115 case MCSA_PrivateExtern: 116 case MCSA_WeakDefinition: 117 case MCSA_WeakDefAutoPrivate: 118 case MCSA_Invalid: 119 case MCSA_IndirectSymbol: 120 case MCSA_Protected: 121 return false; 122 123 case MCSA_Hidden: 124 Symbol->setHidden(true); 125 break; 126 127 case MCSA_Weak: 128 case MCSA_WeakReference: 129 Symbol->setWeak(true); 130 Symbol->setExternal(true); 131 break; 132 133 case MCSA_Global: 134 Symbol->setExternal(true); 135 break; 136 137 case MCSA_ELF_TypeFunction: 138 Symbol->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); 139 break; 140 141 case MCSA_ELF_TypeTLS: 142 Symbol->setTLS(); 143 break; 144 145 case MCSA_ELF_TypeObject: 146 case MCSA_Cold: 147 break; 148 149 case MCSA_NoDeadStrip: 150 Symbol->setNoStrip(); 151 break; 152 153 default: 154 // unrecognized directive 155 llvm_unreachable("unexpected MCSymbolAttr"); 156 return false; 157 } 158 159 return true; 160 } 161 162 void MCWasmStreamer::emitCommonSymbol(MCSymbol *S, uint64_t Size, 163 unsigned ByteAlignment) { 164 llvm_unreachable("Common symbols are not yet implemented for Wasm"); 165 } 166 167 void MCWasmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) { 168 cast<MCSymbolWasm>(Symbol)->setSize(Value); 169 } 170 171 void MCWasmStreamer::emitLocalCommonSymbol(MCSymbol *S, uint64_t Size, 172 unsigned ByteAlignment) { 173 llvm_unreachable("Local common symbols are not yet implemented for Wasm"); 174 } 175 176 void MCWasmStreamer::emitIdent(StringRef IdentString) { 177 // TODO(sbc): Add the ident section once we support mergable strings 178 // sections in the object format 179 } 180 181 void MCWasmStreamer::emitInstToFragment(const MCInst &Inst, 182 const MCSubtargetInfo &STI) { 183 this->MCObjectStreamer::emitInstToFragment(Inst, STI); 184 MCRelaxableFragment &F = *cast<MCRelaxableFragment>(getCurrentFragment()); 185 186 for (auto &Fixup : F.getFixups()) 187 fixSymbolsInTLSFixups(Fixup.getValue()); 188 } 189 190 void MCWasmStreamer::emitInstToData(const MCInst &Inst, 191 const MCSubtargetInfo &STI) { 192 MCAssembler &Assembler = getAssembler(); 193 SmallVector<MCFixup, 4> Fixups; 194 SmallString<256> Code; 195 raw_svector_ostream VecOS(Code); 196 Assembler.getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI); 197 198 for (auto &Fixup : Fixups) 199 fixSymbolsInTLSFixups(Fixup.getValue()); 200 201 // Append the encoded instruction to the current data fragment (or create a 202 // new such fragment if the current fragment is not a data fragment). 203 MCDataFragment *DF = getOrCreateDataFragment(); 204 205 // Add the fixups and data. 206 for (unsigned I = 0, E = Fixups.size(); I != E; ++I) { 207 Fixups[I].setOffset(Fixups[I].getOffset() + DF->getContents().size()); 208 DF->getFixups().push_back(Fixups[I]); 209 } 210 DF->setHasInstructions(STI); 211 DF->getContents().append(Code.begin(), Code.end()); 212 } 213 214 void MCWasmStreamer::finishImpl() { 215 emitFrames(nullptr); 216 217 this->MCObjectStreamer::finishImpl(); 218 } 219 220 void MCWasmStreamer::fixSymbolsInTLSFixups(const MCExpr *expr) { 221 switch (expr->getKind()) { 222 case MCExpr::Target: 223 case MCExpr::Constant: 224 break; 225 226 case MCExpr::Binary: { 227 const MCBinaryExpr *be = cast<MCBinaryExpr>(expr); 228 fixSymbolsInTLSFixups(be->getLHS()); 229 fixSymbolsInTLSFixups(be->getRHS()); 230 break; 231 } 232 233 case MCExpr::SymbolRef: { 234 const MCSymbolRefExpr &symRef = *cast<MCSymbolRefExpr>(expr); 235 switch (symRef.getKind()) { 236 case MCSymbolRefExpr::VK_WASM_TLSREL: 237 case MCSymbolRefExpr::VK_WASM_GOT_TLS: 238 getAssembler().registerSymbol(symRef.getSymbol()); 239 cast<MCSymbolWasm>(symRef.getSymbol()).setTLS(); 240 break; 241 default: 242 break; 243 } 244 break; 245 } 246 247 case MCExpr::Unary: 248 fixSymbolsInTLSFixups(cast<MCUnaryExpr>(expr)->getSubExpr()); 249 break; 250 } 251 } 252 253 void MCWasmStreamer::emitThumbFunc(MCSymbol *Func) { 254 llvm_unreachable("Generic Wasm doesn't support this directive"); 255 } 256 257 void MCWasmStreamer::emitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { 258 llvm_unreachable("Wasm doesn't support this directive"); 259 } 260 261 void MCWasmStreamer::emitZerofill(MCSection *Section, MCSymbol *Symbol, 262 uint64_t Size, unsigned ByteAlignment, 263 SMLoc Loc) { 264 llvm_unreachable("Wasm doesn't support this directive"); 265 } 266 267 void MCWasmStreamer::emitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, 268 uint64_t Size, unsigned ByteAlignment) { 269 llvm_unreachable("Wasm doesn't support this directive"); 270 } 271 272 MCStreamer *llvm::createWasmStreamer(MCContext &Context, 273 std::unique_ptr<MCAsmBackend> &&MAB, 274 std::unique_ptr<MCObjectWriter> &&OW, 275 std::unique_ptr<MCCodeEmitter> &&CE, 276 bool RelaxAll) { 277 MCWasmStreamer *S = 278 new MCWasmStreamer(Context, std::move(MAB), std::move(OW), std::move(CE)); 279 if (RelaxAll) 280 S->getAssembler().setRelaxAll(true); 281 return S; 282 } 283