diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp --- a/llvm/lib/MC/WasmObjectWriter.cpp +++ b/llvm/lib/MC/WasmObjectWriter.cpp @@ -331,7 +331,7 @@ void writeDataCountSection(); void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout, ArrayRef Functions); - void writeDataSection(); + void writeDataSection(const MCAsmLayout &Layout); void writeEventSection(ArrayRef Events); void writeGlobalSection(ArrayRef Globals); void writeRelocSection(uint32_t SectionIndex, StringRef Name, @@ -347,9 +347,10 @@ updateCustomSectionRelocations(const SmallVector &Functions, const MCAsmLayout &Layout); - uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry); + uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry, + const MCAsmLayout &Layout); void applyRelocations(ArrayRef Relocations, - uint64_t ContentsOffset); + uint64_t ContentsOffset, const MCAsmLayout &Layout); uint32_t getRelocationIndexValue(const WasmRelocationEntry &RelEntry); uint32_t getFunctionType(const MCSymbolWasm &Symbol); @@ -474,9 +475,9 @@ if (SymA->isVariable()) { const MCExpr *Expr = SymA->getVariableValue(); - const auto *Inner = cast(Expr); - if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) - llvm_unreachable("weakref used in reloc not yet implemented"); + if (const auto *Inner = dyn_cast(Expr)) + if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) + llvm_unreachable("weakref used in reloc not yet implemented"); } // Put any constant offset in an addend. Offsets can be negative, and @@ -535,22 +536,13 @@ } } -static const MCSymbolWasm *resolveSymbol(const MCSymbolWasm &Symbol) { - const MCSymbolWasm* Ret = &Symbol; - while (Ret->isVariable()) { - const MCExpr *Expr = Ret->getVariableValue(); - auto *Inner = cast(Expr); - Ret = cast(&Inner->getSymbol()); - } - return Ret; -} - // Compute a value to write into the code at the location covered // by RelEntry. This value isn't used by the static linker; it just serves // to make the object format more readable and more likely to be directly // useable. uint32_t -WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) { +WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry, + const MCAsmLayout &Layout) { if ((RelEntry.Type == wasm::R_WASM_GLOBAL_INDEX_LEB || RelEntry.Type == wasm::R_WASM_GLOBAL_INDEX_I32) && !RelEntry.Symbol->isGlobal()) { @@ -562,10 +554,11 @@ case wasm::R_WASM_TABLE_INDEX_REL_SLEB: case wasm::R_WASM_TABLE_INDEX_SLEB: case wasm::R_WASM_TABLE_INDEX_I32: { - // Provisional value is table address of the resolved symbol itself - const MCSymbolWasm *Sym = resolveSymbol(*RelEntry.Symbol); - assert(Sym->isFunction()); - return TableIndices[Sym]; + // Provisional value is table address of the Base symbol itself + const MCSymbolWasm *Base = + cast(Layout.getBaseSymbol(*RelEntry.Symbol)); + assert(Base->isFunction()); + return TableIndices[Base]; } case wasm::R_WASM_TYPE_INDEX_LEB: // Provisional value is same as the index @@ -588,11 +581,12 @@ case wasm::R_WASM_MEMORY_ADDR_REL_SLEB: case wasm::R_WASM_MEMORY_ADDR_SLEB: { // Provisional value is address of the global - const MCSymbolWasm *Sym = resolveSymbol(*RelEntry.Symbol); + const MCSymbolWasm *Base = + cast(Layout.getBaseSymbol(*RelEntry.Symbol)); // For undefined symbols, use zero - if (!Sym->isDefined()) + if (!Base->isDefined()) return 0; - const wasm::WasmDataReference &Ref = DataLocations[Sym]; + const wasm::WasmDataReference &Ref = DataLocations[Base]; const WasmDataSegment &Segment = DataSegments[Ref.Segment]; // Ignore overflow. LLVM allows address arithmetic to silently wrap. return Segment.Offset + Ref.Offset + RelEntry.Addend; @@ -655,7 +649,8 @@ // Apply the portions of the relocation records that we can handle ourselves // directly. void WasmObjectWriter::applyRelocations( - ArrayRef Relocations, uint64_t ContentsOffset) { + ArrayRef Relocations, uint64_t ContentsOffset, + const MCAsmLayout &Layout) { auto &Stream = static_cast(W.OS); for (const WasmRelocationEntry &RelEntry : Relocations) { uint64_t Offset = ContentsOffset + @@ -663,7 +658,7 @@ RelEntry.Offset; LLVM_DEBUG(dbgs() << "applyRelocation: " << RelEntry << "\n"); - uint32_t Value = getProvisionalValue(RelEntry); + uint32_t Value = getProvisionalValue(RelEntry, Layout); switch (RelEntry.Type) { case wasm::R_WASM_FUNCTION_INDEX_LEB: @@ -898,12 +893,12 @@ } // Apply fixups. - applyRelocations(CodeRelocations, Section.ContentsOffset); + applyRelocations(CodeRelocations, Section.ContentsOffset, Layout); endSection(Section); } -void WasmObjectWriter::writeDataSection() { +void WasmObjectWriter::writeDataSection(const MCAsmLayout &Layout) { if (DataSegments.empty()) return; @@ -928,7 +923,7 @@ } // Apply fixups. - applyRelocations(DataRelocations, Section.ContentsOffset); + applyRelocations(DataRelocations, Section.ContentsOffset, Layout); endSection(Section); } @@ -1081,7 +1076,7 @@ // Apply fixups. auto &Relocations = CustomSectionsRelocations[CustomSection.Section]; - applyRelocations(Relocations, CustomSection.OutputContentsOffset); + applyRelocations(Relocations, CustomSection.OutputContentsOffset, Layout); } uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm &Symbol) { @@ -1100,8 +1095,8 @@ assert(Symbol.isFunction()); WasmSignature S; - const MCSymbolWasm *ResolvedSym = resolveSymbol(Symbol); - if (auto *Sig = ResolvedSym->getSignature()) { + + if (auto *Sig = Symbol.getSignature()) { S.Returns = Sig->Returns; S.Params = Sig->Params; } @@ -1198,8 +1193,10 @@ // Register types for all functions, including those with private linkage // (because wasm always needs a type signature). - if (WS.isFunction()) - registerFunctionType(WS); + if (WS.isFunction()) { + const MCSymbolWasm *Base = cast(Layout.getBaseSymbol(S)); + registerFunctionType(*Base); + } if (WS.isEvent()) registerEventType(WS); @@ -1486,22 +1483,36 @@ assert(S.isDefined()); + const MCSymbolWasm *Base = cast(Layout.getBaseSymbol(S)); + // Find the target symbol of this weak alias and export that index const auto &WS = static_cast(S); - const MCSymbolWasm *ResolvedSym = resolveSymbol(WS); - LLVM_DEBUG(dbgs() << WS.getName() << ": weak alias of '" << *ResolvedSym - << "'\n"); + LLVM_DEBUG(dbgs() << WS.getName() << ": weak alias of '" << *Base << "'\n"); - if (ResolvedSym->isFunction()) { - assert(WasmIndices.count(ResolvedSym) > 0); - uint32_t WasmIndex = WasmIndices.find(ResolvedSym)->second; + if (Base->isFunction()) { + assert(WasmIndices.count(Base) > 0); + uint32_t WasmIndex = WasmIndices.find(Base)->second; assert(WasmIndices.count(&WS) == 0); WasmIndices[&WS] = WasmIndex; LLVM_DEBUG(dbgs() << " -> index:" << WasmIndex << "\n"); - } else if (ResolvedSym->isData()) { - assert(DataLocations.count(ResolvedSym) > 0); - const wasm::WasmDataReference &Ref = - DataLocations.find(ResolvedSym)->second; + } else if (Base->isData()) { + auto &DataSection = static_cast(WS.getSection()); + uint64_t Offset = Layout.getSymbolOffset(S); + int64_t Size = 0; + // For data symbol alias we use the size of the base symbol as the + // size of the alias. When an offset from the base is involved this + // can result in a offset + size goes past the end of the data section + // which out object format doesn't support. So we must clamp it. + if (!Base->getSize()->evaluateAsAbsolute(Size, Layout)) + report_fatal_error(".size expression must be evaluatable"); + const WasmDataSegment &Segment = + DataSegments[DataSection.getSegmentIndex()]; + Size = + std::min(static_cast(Size), Segment.Data.size() - Offset); + wasm::WasmDataReference Ref = wasm::WasmDataReference{ + DataSection.getSegmentIndex(), + static_cast(Layout.getSymbolOffset(S)), + static_cast(Size)}; DataLocations[&WS] = Ref; LLVM_DEBUG(dbgs() << " -> index:" << Ref.Segment << "\n"); } else { @@ -1562,14 +1573,15 @@ Rel.Type != wasm::R_WASM_TABLE_INDEX_SLEB) return; assert(Rel.Symbol->isFunction()); - const MCSymbolWasm &WS = *resolveSymbol(*Rel.Symbol); - uint32_t FunctionIndex = WasmIndices.find(&WS)->second; + const MCSymbolWasm *Base = + cast(Layout.getBaseSymbol(*Rel.Symbol)); + uint32_t FunctionIndex = WasmIndices.find(Base)->second; uint32_t TableIndex = TableElems.size() + InitialTableOffset; - if (TableIndices.try_emplace(&WS, TableIndex).second) { - LLVM_DEBUG(dbgs() << " -> adding " << WS.getName() + if (TableIndices.try_emplace(Base, TableIndex).second) { + LLVM_DEBUG(dbgs() << " -> adding " << Base->getName() << " to table: " << TableIndex << "\n"); TableElems.push_back(FunctionIndex); - registerFunctionType(WS); + registerFunctionType(*Base); } }; @@ -1658,7 +1670,7 @@ writeElemSection(TableElems); writeDataCountSection(); writeCodeSection(Asm, Layout, Functions); - writeDataSection(); + writeDataSection(Layout); for (auto &CustomSection : CustomSections) writeCustomSection(CustomSection, Asm, Layout); writeLinkingMetaDataSection(SymbolInfos, InitFuncs, Comdats); diff --git a/llvm/test/CodeGen/WebAssembly/aliases.ll b/llvm/test/CodeGen/WebAssembly/aliases.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/aliases.ll @@ -0,0 +1,71 @@ +; Based llvm/test/CodeGen/X86/aliases.ll +; RUN: llc < %s -mtriple=wasm32-unknown-uknown -asm-verbose=false | FileCheck %s + +@bar = global i32 42 + +; CHECK-DAG: .globl foo1 +; CHECK-DAG: .set foo1, bar +@foo1 = alias i32, i32* @bar + +; CHECK-DAG: .globl foo2 +; CHECK-DAG: .set foo2, bar +@foo2 = alias i32, i32* @bar + +%FunTy = type i32() + +define i32 @foo_f() { + ret i32 0 +} + +; CHECK-DAG: .weak bar_f +; CHECK-DAG: .type bar_f,@function +; CHECK-DAG: .set bar_f, foo_f +@bar_f = weak alias %FunTy, %FunTy* @foo_f + +; CHECK-DAG: .weak bar_l +; CHECK-DAG: .set bar_l, bar +@bar_l = linkonce_odr alias i32, i32* @bar + +; CHECK-DAG: .set bar_i, bar +@bar_i = internal alias i32, i32* @bar + +; CHECK-DAG: .globl A +@A = alias i64, bitcast (i32* @bar to i64*) + +; CHECK-DAG: .globl bar_h +; CHECK-DAG: .hidden bar_h +; CHECK-DAG: .set bar_h, bar +@bar_h = hidden alias i32, i32* @bar + +; CHECK-DAG: .globl bar_p +; CHECK-DAG: .protected bar_p +; CHECK-DAG: .set bar_p, bar +@bar_p = protected alias i32, i32* @bar + +; CHECK-DAG: .set test2, bar+4 +@test2 = alias i32, getelementptr(i32, i32* @bar, i32 1) + +; CHECK-DAG: .set test3, 42 +@test3 = alias i32, inttoptr(i32 42 to i32*) + +; CHECK-DAG: .set test4, bar +@test4 = alias i32, inttoptr(i64 ptrtoint (i32* @bar to i64) to i32*) + +; CHECK-DAG: .set test5, test2-bar +@test5 = alias i32, inttoptr(i32 sub (i32 ptrtoint (i32* @test2 to i32), + i32 ptrtoint (i32* @bar to i32)) to i32*) + +; CHECK-DAG: .globl test +define i32 @test() { +entry: + %tmp = load i32, i32* @foo1 + %tmp1 = load i32, i32* @foo2 + %tmp0 = load i32, i32* @bar_i + %tmp2 = call i32 @foo_f() + %tmp3 = add i32 %tmp, %tmp2 + %tmp4 = call i32 @bar_f() + %tmp5 = add i32 %tmp3, %tmp4 + %tmp6 = add i32 %tmp1, %tmp5 + %tmp7 = add i32 %tmp6, %tmp0 + ret i32 %tmp7 +} diff --git a/llvm/test/MC/WebAssembly/alias.s b/llvm/test/MC/WebAssembly/alias.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/WebAssembly/alias.s @@ -0,0 +1,15 @@ +# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj %s | llvm-objdump -t - | FileCheck %s + +.section .data,"",@ +foo: + .int32 1 + .size foo, 4 +sym_a: + .int32 2 + .size sym_a, 4 + +.set sym_b, sym_a + +# CHECK: 00000000 l O DATA foo +# CHECK: 00000004 l O DATA sym_a +# CHECK: 00000004 l O DATA sym_b diff --git a/llvm/test/MC/WebAssembly/offset.s b/llvm/test/MC/WebAssembly/offset.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/WebAssembly/offset.s @@ -0,0 +1,16 @@ +# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj %s | llvm-objdump -t - | FileCheck %s + +.section .data,"",@ +foo: + .int32 0 + .size foo, 4 +sym_a: + .int32 1 + .int32 2 + .size sym_a, 8 + +.set sym_b, sym_a + 4 + +# CHECK: 00000000 l O DATA foo +# CHECK: 00000004 l O DATA sym_a +# CHECK: 00000008 l O DATA sym_b