diff --git a/lld/wasm/InputChunks.cpp b/lld/wasm/InputChunks.cpp --- a/lld/wasm/InputChunks.cpp +++ b/lld/wasm/InputChunks.cpp @@ -62,12 +62,14 @@ case R_WASM_TABLE_INDEX_REL_SLEB: case R_WASM_MEMORY_ADDR_SLEB: case R_WASM_MEMORY_ADDR_REL_SLEB: + case R_WASM_TABLE_INDEX_SLEB_ADDEND: existingValue = static_cast(decodeSLEB128(loc, &bytesRead)); break; case R_WASM_TABLE_INDEX_I32: case R_WASM_MEMORY_ADDR_I32: case R_WASM_FUNCTION_OFFSET_I32: case R_WASM_SECTION_OFFSET_I32: + case R_WASM_TABLE_INDEX_I32_ADDEND: existingValue = static_cast(read32le(loc)); break; default: @@ -126,12 +128,14 @@ case R_WASM_TABLE_INDEX_REL_SLEB: case R_WASM_MEMORY_ADDR_SLEB: case R_WASM_MEMORY_ADDR_REL_SLEB: + case R_WASM_TABLE_INDEX_SLEB_ADDEND: encodeSLEB128(static_cast(value), loc, 5); break; case R_WASM_TABLE_INDEX_I32: case R_WASM_MEMORY_ADDR_I32: case R_WASM_FUNCTION_OFFSET_I32: case R_WASM_SECTION_OFFSET_I32: + case R_WASM_TABLE_INDEX_I32_ADDEND: write32le(loc, value); break; default: @@ -188,6 +192,7 @@ return encodeULEB128(value, buf); case R_WASM_TABLE_INDEX_SLEB: case R_WASM_MEMORY_ADDR_SLEB: + case R_WASM_TABLE_INDEX_SLEB_ADDEND: return encodeSLEB128(static_cast(value), buf); default: llvm_unreachable("unexpected relocation type"); @@ -203,6 +208,7 @@ case R_WASM_MEMORY_ADDR_LEB: case R_WASM_TABLE_INDEX_SLEB: case R_WASM_MEMORY_ADDR_SLEB: + case R_WASM_TABLE_INDEX_SLEB_ADDEND: return 5; default: llvm_unreachable("unexpected relocation type"); @@ -331,7 +337,8 @@ } } else { const GlobalSymbol* baseSymbol = WasmSym::memoryBase; - if (rel.Type == R_WASM_TABLE_INDEX_I32) + if (rel.Type == R_WASM_TABLE_INDEX_I32 || + rel.Type == R_WASM_TABLE_INDEX_I32_ADDEND) baseSymbol = WasmSym::tableBase; writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET"); writeUleb128(os, baseSymbol->getGlobalIndex(), "base"); diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp --- a/lld/wasm/InputFiles.cpp +++ b/lld/wasm/InputFiles.cpp @@ -112,6 +112,8 @@ switch (reloc.Type) { case R_WASM_TABLE_INDEX_I32: case R_WASM_TABLE_INDEX_SLEB: + case R_WASM_TABLE_INDEX_I32_ADDEND: + case R_WASM_TABLE_INDEX_SLEB_ADDEND: case R_WASM_TABLE_INDEX_REL_SLEB: { const WasmSymbol &sym = wasmObj->syms()[reloc.Index]; return tableEntries[sym.Info.ElementIndex]; @@ -162,13 +164,18 @@ return 0; } + uint32_t Addend = 0; switch (reloc.Type) { + case R_WASM_TABLE_INDEX_I32_ADDEND: + case R_WASM_TABLE_INDEX_SLEB_ADDEND: + Addend = static_cast(reloc.Addend); + LLVM_FALLTHROUGH; case R_WASM_TABLE_INDEX_I32: case R_WASM_TABLE_INDEX_SLEB: case R_WASM_TABLE_INDEX_REL_SLEB: if (!getFunctionSymbol(reloc.Index)->hasTableIndex()) - return 0; - return getFunctionSymbol(reloc.Index)->getTableIndex(); + return 0; // Should this be Addend? + return getFunctionSymbol(reloc.Index)->getTableIndex() + Addend; case R_WASM_MEMORY_ADDR_SLEB: case R_WASM_MEMORY_ADDR_I32: case R_WASM_MEMORY_ADDR_LEB: diff --git a/llvm/include/llvm/BinaryFormat/WasmRelocs.def b/llvm/include/llvm/BinaryFormat/WasmRelocs.def --- a/llvm/include/llvm/BinaryFormat/WasmRelocs.def +++ b/llvm/include/llvm/BinaryFormat/WasmRelocs.def @@ -15,3 +15,5 @@ WASM_RELOC(R_WASM_EVENT_INDEX_LEB, 10) WASM_RELOC(R_WASM_MEMORY_ADDR_REL_SLEB, 11) WASM_RELOC(R_WASM_TABLE_INDEX_REL_SLEB, 12) +WASM_RELOC(R_WASM_TABLE_INDEX_SLEB_ADDEND, 13) +WASM_RELOC(R_WASM_TABLE_INDEX_I32_ADDEND, 14) \ No newline at end of file diff --git a/llvm/lib/BinaryFormat/Wasm.cpp b/llvm/lib/BinaryFormat/Wasm.cpp --- a/llvm/lib/BinaryFormat/Wasm.cpp +++ b/llvm/lib/BinaryFormat/Wasm.cpp @@ -44,6 +44,8 @@ case R_WASM_MEMORY_ADDR_I32: case R_WASM_FUNCTION_OFFSET_I32: case R_WASM_SECTION_OFFSET_I32: + case R_WASM_TABLE_INDEX_SLEB_ADDEND: + case R_WASM_TABLE_INDEX_I32_ADDEND: return true; default: return false; 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 @@ -543,7 +543,9 @@ switch (RelEntry.Type) { case wasm::R_WASM_TABLE_INDEX_REL_SLEB: case wasm::R_WASM_TABLE_INDEX_SLEB: - case wasm::R_WASM_TABLE_INDEX_I32: { + case wasm::R_WASM_TABLE_INDEX_I32: + case wasm::R_WASM_TABLE_INDEX_SLEB_ADDEND: + case wasm::R_WASM_TABLE_INDEX_I32_ADDEND: { // Provisional value is table address of the resolved symbol itself const MCSymbolWasm *Sym = resolveSymbol(*RelEntry.Symbol); assert(Sym->isFunction()); @@ -658,12 +660,14 @@ case wasm::R_WASM_MEMORY_ADDR_I32: case wasm::R_WASM_FUNCTION_OFFSET_I32: case wasm::R_WASM_SECTION_OFFSET_I32: + case wasm::R_WASM_TABLE_INDEX_I32_ADDEND: writeI32(Stream, Value, Offset); break; case wasm::R_WASM_TABLE_INDEX_SLEB: case wasm::R_WASM_TABLE_INDEX_REL_SLEB: case wasm::R_WASM_MEMORY_ADDR_SLEB: case wasm::R_WASM_MEMORY_ADDR_REL_SLEB: + case wasm::R_WASM_TABLE_INDEX_SLEB_ADDEND: writePatchableSLEB(Stream, Value, Offset); break; default: @@ -1473,9 +1477,15 @@ // Functions referenced by a relocation need to put in the table. This is // purely to make the object file's provisional values readable, and is // ignored by the linker, which re-calculates the relocations itself. - if (Rel.Type != wasm::R_WASM_TABLE_INDEX_I32 && - Rel.Type != wasm::R_WASM_TABLE_INDEX_SLEB) + switch (Rel.Type) { + case wasm::R_WASM_TABLE_INDEX_I32: + case wasm::R_WASM_TABLE_INDEX_SLEB: + case wasm::R_WASM_TABLE_INDEX_SLEB_ADDEND: + case wasm::R_WASM_TABLE_INDEX_I32_ADDEND: + break; + default: return; + } assert(Rel.Symbol->isFunction()); const MCSymbolWasm &WS = *resolveSymbol(*Rel.Symbol); uint32_t FunctionIndex = WasmIndices.find(&WS)->second; diff --git a/llvm/lib/Object/RelocationResolver.cpp b/llvm/lib/Object/RelocationResolver.cpp --- a/llvm/lib/Object/RelocationResolver.cpp +++ b/llvm/lib/Object/RelocationResolver.cpp @@ -490,6 +490,8 @@ case wasm::R_WASM_FUNCTION_OFFSET_I32: case wasm::R_WASM_SECTION_OFFSET_I32: case wasm::R_WASM_EVENT_INDEX_LEB: + case wasm::R_WASM_TABLE_INDEX_SLEB_ADDEND: + case wasm::R_WASM_TABLE_INDEX_I32_ADDEND: return true; default: return false; @@ -509,6 +511,8 @@ case wasm::R_WASM_FUNCTION_OFFSET_I32: case wasm::R_WASM_SECTION_OFFSET_I32: case wasm::R_WASM_EVENT_INDEX_LEB: + case wasm::R_WASM_TABLE_INDEX_SLEB_ADDEND: + case wasm::R_WASM_TABLE_INDEX_I32_ADDEND: // For wasm section, its offset at 0 -- ignoring Value return A; default: diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -770,6 +770,8 @@ case wasm::R_WASM_TABLE_INDEX_SLEB: case wasm::R_WASM_TABLE_INDEX_I32: case wasm::R_WASM_TABLE_INDEX_REL_SLEB: + case wasm::R_WASM_TABLE_INDEX_SLEB_ADDEND: + case wasm::R_WASM_TABLE_INDEX_I32_ADDEND: if (!isValidFunctionSymbol(Reloc.Index)) return make_error("Bad relocation function index", object_error::parse_failed); @@ -827,7 +829,8 @@ if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I32 || Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I32 || Reloc.Type == wasm::R_WASM_SECTION_OFFSET_I32 || - Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I32) + Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I32 || + Reloc.Type == wasm::R_WASM_TABLE_INDEX_I32_ADDEND) Size = 4; if (Reloc.Offset + Size > EndOffset) return make_error("Bad relocation offset", diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp @@ -88,7 +88,8 @@ switch (unsigned(Fixup.getKind())) { case WebAssembly::fixup_sleb128_i32: if (SymA.isFunction()) - return wasm::R_WASM_TABLE_INDEX_SLEB; + return Target.getConstant() == 0 ? + wasm::R_WASM_TABLE_INDEX_SLEB : wasm::R_WASM_TABLE_INDEX_SLEB_ADDEND; return wasm::R_WASM_MEMORY_ADDR_SLEB; case WebAssembly::fixup_sleb128_i64: llvm_unreachable("fixup_sleb128_i64 not implemented yet"); @@ -102,7 +103,8 @@ return wasm::R_WASM_MEMORY_ADDR_LEB; case FK_Data_4: if (SymA.isFunction()) - return wasm::R_WASM_TABLE_INDEX_I32; + return Target.getConstant() == 0 ? + wasm::R_WASM_TABLE_INDEX_I32 : wasm::R_WASM_TABLE_INDEX_I32_ADDEND; if (auto Section = static_cast( getFixupSection(Fixup.getValue()))) { if (Section->getKind().isText()) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp @@ -149,8 +149,6 @@ const auto *WasmSym = cast(Sym); if (TargetFlags == WebAssemblyII::MO_GOT) report_fatal_error("GOT symbol references do not support offsets"); - if (WasmSym->isFunction()) - report_fatal_error("Function addresses with offsets not supported"); if (WasmSym->isGlobal()) report_fatal_error("Global indexes with offsets not supported"); if (WasmSym->isEvent()) diff --git a/llvm/test/MC/WebAssembly/symbol-offsets.s b/llvm/test/MC/WebAssembly/symbol-offsets.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/WebAssembly/symbol-offsets.s @@ -0,0 +1,47 @@ +# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj < %s | obj2yaml | FileCheck %s + + .text +funcaddr: + .functype funcaddr () -> (i32) +# Function symbol with offset (table index reloc with addend) + i32.const f1 + 3 + call f2 +# Data symbol with offset (addr reloc with addend) + i32.const d1 + 4 + end_function + + .functype f2 (i32) -> () + .functype f1 () -> () + + .section .data,"",@ +d1: + .int32 1 + .size d1, 4 +d2: + .int32 f1 + 8 + .size d2, 4 + +# CHECK: --- !WASM +# CHECK-NEXT: FileHeader: +# CHECK-NEXT: Version: 0x00000001 + +# CHECK: - Type: CODE +# CHECK-NEXT: Relocations: +# CHECK-NEXT: - Type: R_WASM_TABLE_INDEX_SLEB_ADDEND +# CHECK-NEXT: Index: 1 +# CHECK-NEXT: Offset: 0x00000004 +# CHECK-NEXTT: Addend: 8 +# CHECK-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Offset: 0x0000000A +# CHECK-NEXT: - Type: R_WASM_MEMORY_ADDR_SLEB +# CHECK-NEXT: Index: 3 +# CHECK-NEXT: Offset: 0x00000010 +# CHECK-NEXT: Addend: 4 + +# CHECK: - Type: DATA +# CHECK-NEXT: Relocations: +# CHECK-NEXT: - Type: R_WASM_TABLE_INDEX_I32_ADDEND +# CHECK-NEXT: Index: 1 +# CHECK-NEXT: Offset: 0x0000000A +# CHECK-NEXT: Addend: 8 \ No newline at end of file