diff --git a/include/llvm/BinaryFormat/WasmRelocs.def b/include/llvm/BinaryFormat/WasmRelocs.def index dca63eca945..b83efc26e58 100644 --- a/include/llvm/BinaryFormat/WasmRelocs.def +++ b/include/llvm/BinaryFormat/WasmRelocs.def @@ -25,3 +25,4 @@ WASM_RELOC(R_WASM_TABLE_INDEX_I64, 19) WASM_RELOC(R_WASM_TABLE_NUMBER_LEB, 20) WASM_RELOC(R_WASM_MEMORY_ADDR_TLS_SLEB, 21) WASM_RELOC(R_WASM_FUNCTION_OFFSET_I64, 22) +WASM_RELOC(R_WASM_MEMORY_ADDR_LOCREL_I32, 23) diff --git a/include/llvm/MC/MCWasmObjectWriter.h b/include/llvm/MC/MCWasmObjectWriter.h index 00da632bbcc..4c75ea15579 100644 --- a/include/llvm/MC/MCWasmObjectWriter.h +++ b/include/llvm/MC/MCWasmObjectWriter.h @@ -33,8 +33,8 @@ public: return W->getFormat() == Triple::Wasm; } - virtual unsigned getRelocType(const MCValue &Target, - const MCFixup &Fixup) const = 0; + virtual unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup, + bool IsLocRel) const = 0; /// \name Accessors /// @{ diff --git a/lib/BinaryFormat/Wasm.cpp b/lib/BinaryFormat/Wasm.cpp index 126680ac41c..81264a940ce 100644 --- a/lib/BinaryFormat/Wasm.cpp +++ b/lib/BinaryFormat/Wasm.cpp @@ -52,6 +52,7 @@ bool llvm::wasm::relocTypeHasAddend(uint32_t Type) { case R_WASM_FUNCTION_OFFSET_I32: case R_WASM_FUNCTION_OFFSET_I64: case R_WASM_SECTION_OFFSET_I32: + case R_WASM_MEMORY_ADDR_LOCREL_I32: return true; default: return false; diff --git a/lib/MC/WasmObjectWriter.cpp b/lib/MC/WasmObjectWriter.cpp index c8bc65467b8..25138d651b5 100644 --- a/lib/MC/WasmObjectWriter.cpp +++ b/lib/MC/WasmObjectWriter.cpp @@ -445,17 +445,35 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm, uint64_t C = Target.getConstant(); uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); MCContext &Ctx = Asm.getContext(); + bool IsLocRel = false; if (const MCSymbolRefExpr *RefB = Target.getSymB()) { - // To get here the A - B expression must have failed evaluateAsRelocatable. - // This means either A or B must be undefined and in WebAssembly we can't - // support either of those cases. + const auto &SymB = cast(RefB->getSymbol()); - Ctx.reportError( - Fixup.getLoc(), - Twine("symbol '") + SymB.getName() + - "': unsupported subtraction expression used in relocation."); - return; + + if (FixupSection.getKind().isText()) { + Ctx.reportError(Fixup.getLoc(), + Twine("symbol '") + SymB.getName() + + "' unsupported subtraction expression used in " + "relocation in code section."); + return; + } + + if (SymB.isUndefined()) { + Ctx.reportError(Fixup.getLoc(), + Twine("symbol '") + SymB.getName() + + "' can not be undefined in a subtraction expression"); + return; + } + const MCSection &SecB = SymB.getSection(); + if (&SecB != &FixupSection) { + Ctx.reportError(Fixup.getLoc(), + Twine("symbol '") + SymB.getName() + + "' can not be placed in a different section"); + return; + } + IsLocRel = true; + C += FixupOffset - Layout.getSymbolOffset(SymB); } // We either rejected the fixup or folded B into C at this point. @@ -480,7 +498,7 @@ void WasmObjectWriter::recordRelocation(MCAssembler &Asm, // be negative and don't wrap. FixedValue = 0; - unsigned Type = TargetObjectWriter->getRelocType(Target, Fixup); + unsigned Type = TargetObjectWriter->getRelocType(Target, Fixup, IsLocRel); // Absolute offset within a section or a function. // Currently only supported for for metadata sections. @@ -611,7 +629,8 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry, case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64: case wasm::R_WASM_MEMORY_ADDR_I32: case wasm::R_WASM_MEMORY_ADDR_I64: - case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB: { + case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB: + case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32: { // Provisional value is address of the global plus the offset // For undefined symbols, use zero if (!RelEntry.Symbol->isDefined()) @@ -707,6 +726,7 @@ void WasmObjectWriter::applyRelocations( case wasm::R_WASM_FUNCTION_OFFSET_I32: case wasm::R_WASM_SECTION_OFFSET_I32: case wasm::R_WASM_GLOBAL_INDEX_I32: + case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32: patchI32(Stream, Value, Offset); break; case wasm::R_WASM_TABLE_INDEX_I64: diff --git a/lib/Object/RelocationResolver.cpp b/lib/Object/RelocationResolver.cpp index 204577af723..eee36f7f3de 100644 --- a/lib/Object/RelocationResolver.cpp +++ b/lib/Object/RelocationResolver.cpp @@ -575,6 +575,7 @@ static bool supportsWasm32(uint64_t Type) { case wasm::R_WASM_EVENT_INDEX_LEB: case wasm::R_WASM_GLOBAL_INDEX_I32: case wasm::R_WASM_TABLE_NUMBER_LEB: + case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32: return true; default: return false; @@ -611,6 +612,7 @@ static uint64_t resolveWasm32(uint64_t Type, uint64_t Offset, uint64_t S, case wasm::R_WASM_EVENT_INDEX_LEB: case wasm::R_WASM_GLOBAL_INDEX_I32: case wasm::R_WASM_TABLE_NUMBER_LEB: + case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32: // For wasm section, its offset at 0 -- ignoring Value return LocData; default: diff --git a/lib/Object/WasmObjectFile.cpp b/lib/Object/WasmObjectFile.cpp index 7fbb1862e05..1a0958ad039 100644 --- a/lib/Object/WasmObjectFile.cpp +++ b/lib/Object/WasmObjectFile.cpp @@ -905,6 +905,7 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) { case wasm::R_WASM_MEMORY_ADDR_I32: case wasm::R_WASM_MEMORY_ADDR_REL_SLEB: case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB: + case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32: if (!isValidDataSymbol(Reloc.Index)) return make_error("invalid relocation data index", object_error::parse_failed); @@ -953,6 +954,7 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) { Size = 10; if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I32 || Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I32 || + Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LOCREL_I32 || Reloc.Type == wasm::R_WASM_SECTION_OFFSET_I32 || Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I32 || Reloc.Type == wasm::R_WASM_GLOBAL_INDEX_I32) diff --git a/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp b/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp index aa7e2311d24..1a79a2d597b 100644 --- a/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp +++ b/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp @@ -34,8 +34,8 @@ public: explicit WebAssemblyWasmObjectWriter(bool Is64Bit, bool IsEmscripten); private: - unsigned getRelocType(const MCValue &Target, - const MCFixup &Fixup) const override; + unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup, + bool IsLocRel) const override; }; } // end anonymous namespace @@ -63,7 +63,8 @@ static const MCSection *getFixupSection(const MCExpr *Expr) { } unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target, - const MCFixup &Fixup) const { + const MCFixup &Fixup, + bool IsLocRel) const { const MCSymbolRefExpr *RefA = Target.getSymA(); assert(RefA); auto& SymA = cast(RefA->getSymbol()); @@ -122,7 +123,8 @@ unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target, else if (!Section->isWasmData()) return wasm::R_WASM_SECTION_OFFSET_I32; } - return wasm::R_WASM_MEMORY_ADDR_I32; + return IsLocRel ? wasm::R_WASM_MEMORY_ADDR_LOCREL_I32 + : wasm::R_WASM_MEMORY_ADDR_I32; case FK_Data_8: if (SymA.isFunction()) return wasm::R_WASM_TABLE_INDEX_I64; diff --git a/test/MC/WebAssembly/bad-fixup-expr.s b/test/MC/WebAssembly/bad-fixup-expr.s index 3bd7e6e2f06..c00f6d4462b 100644 --- a/test/MC/WebAssembly/bad-fixup-expr.s +++ b/test/MC/WebAssembly/bad-fixup-expr.s @@ -13,6 +13,22 @@ bar: .int8 1 .size bar, 1 + .section .data.fizz,"",@ +fizz: + .int8 1 + .size fizz, 1 + + .section .data.segment1,"",@ +segment1: +// CHECK: 'bar' can not be placed in a different section + .int32 fizz-bar +// CHECK: 'undef_baz' can not be undefined in a subtraction expression + .int32 fizz-undef_baz +// CHECK: 'fizz' can not be placed in a different section + .int32 undef_baz-fizz + .size segment1, 12 + + .text .section .text.main,"",@ main: @@ -23,10 +39,10 @@ main: i32.const foo-foo_other+2 i32.const foo_other-foo-10 -// CHECK: 'bar': unsupported subtraction expression used in relocation +// CHECK: 'bar' unsupported subtraction expression used in relocation in code section. i32.const foo-bar -// CHECK: 'undef_baz': unsupported subtraction expression used in relocation +// CHECK: 'undef_baz' unsupported subtraction expression used in relocation in code section. i32.const foo-undef_baz -// CHECK: 'foo': unsupported subtraction expression used in relocation +// CHECK: 'foo' unsupported subtraction expression used in relocation in code section. i32.const undef_baz-foo end_function diff --git a/test/MC/WebAssembly/reloc-relative.ll b/test/MC/WebAssembly/reloc-relative.ll new file mode 100644 index 00000000000..a581f78c3ed --- /dev/null +++ b/test/MC/WebAssembly/reloc-relative.ll @@ -0,0 +1,48 @@ +; RUN: llc -O0 -filetype=obj %s -o - | llvm-readobj -r --expand-relocs - | FileCheck %s + +; CHECK: Format: WASM +; CHECK: Relocations [ +; CHECK-NEXT: Section (3) DATA { +; CHECK-NEXT: Relocation { +; CHECK-NEXT: Type: R_WASM_MEMORY_ADDR_LOCREL_I32 (23) +; CHECK-NEXT: Offset: 0x6 +; CHECK-NEXT: Symbol: foo +; CHECK-NEXT: Addend: 0 +; CHECK-NEXT: } +; CHECK-NEXT: Relocation { +; CHECK-NEXT: Type: R_WASM_MEMORY_ADDR_LOCREL_I32 (23) +; CHECK-NEXT: Offset: 0xA +; CHECK-NEXT: Symbol: fizz +; CHECK-NEXT: Addend: 0 +; CHECK-NEXT: } +; CHECK-NEXT: Relocation { +; CHECK-NEXT: Type: R_WASM_MEMORY_ADDR_LOCREL_I32 (23) +; CHECK-NEXT: Offset: 0x17 +; CHECK-NEXT: Symbol: foo +; CHECK-NEXT: Addend: 4 +; CHECK-NEXT: } +; CHECK-NEXT: } +; CHECK-NEXT: ] + +target triple = "wasm32-unknown-unknown" + + +; @foo - @bar +@foo = external global i32, align 4 +@bar = constant i32 sub ( + i32 ptrtoint (i32* @foo to i32), + i32 ptrtoint (i32* @bar to i32) +), section ".sec1" + + +; @foo - @addend + 4 +@fizz = constant i32 42, align 4, section ".sec2" +@addend = constant i32 sub ( + i32 ptrtoint (i32* @foo to i32), + i32 ptrtoint (i32* @fizz to i32) +), section ".sec2" + +@x_sec = constant i32 sub ( + i32 ptrtoint (i32* @fizz to i32), + i32 ptrtoint (i32* @x_sec to i32) +), section ".sec1"