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