[llvm] aa0c571 - [WebAssembly] Add new relocation for location relative data

Sam Clegg via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 8 11:34:42 PST 2021


Author: Yuta Saito
Date: 2021-03-08T11:34:10-08:00
New Revision: aa0c571a5fa9130ccd932f9b6970440a1bae177f

URL: https://github.com/llvm/llvm-project/commit/aa0c571a5fa9130ccd932f9b6970440a1bae177f
DIFF: https://github.com/llvm/llvm-project/commit/aa0c571a5fa9130ccd932f9b6970440a1bae177f.diff

LOG: [WebAssembly] Add new relocation for location relative data

This `R_WASM_MEMORY_ADDR_SELFREL_I32` relocation represents an offset
between its relocating address and the symbol address. It's very similar
to `R_X86_64_PC32` but restricted to be used for only data segments.

```
S + A - P
```

A: Represents the addend used to compute the value of the relocatable
field.
P: Represents the place of the storage unit being relocated.
S: Represents the value of the symbol whose index resides in the
relocation entry.

Proposal: https://github.com/WebAssembly/tool-conventions/issues/162

Differential Revision: https://reviews.llvm.org/D96659

Added: 
    lld/test/wasm/reloc-relative.s
    llvm/test/MC/WebAssembly/reloc-relative.ll

Modified: 
    lld/wasm/InputChunks.cpp
    lld/wasm/InputFiles.cpp
    lld/wasm/InputFiles.h
    llvm/include/llvm/BinaryFormat/WasmRelocs.def
    llvm/include/llvm/MC/MCWasmObjectWriter.h
    llvm/lib/BinaryFormat/Wasm.cpp
    llvm/lib/MC/WasmObjectWriter.cpp
    llvm/lib/Object/RelocationResolver.cpp
    llvm/lib/Object/WasmObjectFile.cpp
    llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp
    llvm/test/MC/WebAssembly/bad-fixup-expr.s

Removed: 
    


################################################################################
diff  --git a/lld/test/wasm/reloc-relative.s b/lld/test/wasm/reloc-relative.s
new file mode 100644
index 000000000000..fde1d1dd0824
--- /dev/null
+++ b/lld/test/wasm/reloc-relative.s
@@ -0,0 +1,89 @@
+# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/hello.s -o %t.hello32.o
+# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %s -o %t.o
+# RUN: wasm-ld --no-entry --no-gc-sections --allow-undefined -fatal-warnings -o %t.wasm %t.o %t.hello32.o
+# RUN: obj2yaml %t.wasm | FileCheck %s
+
+.section .x_sec,"",@
+internal_x_seg_pad:
+  # padding for provisioning value assertion
+  .int32 0
+  .size internal_x_seg_pad, 4
+internal_x_seg:
+  .int32 42
+  .size internal_x_seg, 4
+
+# internal cross segment subtraction
+.section .foo,"",@
+.globl  foo
+foo:
+  .int32 internal_x_seg - foo
+  .size foo, 4
+foo_addend:
+  .int32 internal_x_seg - foo
+  .size foo_addend, 4
+
+# external cross segment subtraction
+.section .bar,"",@
+.globl  bar
+bar:
+  .int32 hello_str - bar
+  .size bar, 4
+bar_addend:
+  .int32 hello_str - bar
+  .size bar_addend, 4
+
+# positive calc result
+.section .fizz,"",@
+.globl  fizz
+fizz:
+  .int32 far - fizz
+  .size fizz, 4
+fizz_addend:
+  .int32 far - fizz
+  .size fizz_addend, 4
+
+.section .far,"",@
+.globl  far
+far:
+  .int32 21
+  .size far, 4
+
+# CHECK:      - Type:            DATA
+# CHECK-NEXT:    Segments:
+# CHECK-NEXT:      - SectionOffset:   7
+# CHECK-NEXT:        InitFlags:       0
+# CHECK-NEXT:        Offset:
+# CHECK-NEXT:          Opcode:          I32_CONST
+# CHECK-NEXT:          Value:           1024
+# CHECK-NEXT:        Content:         68656C6C6F0A00
+# CHECK-NEXT:      - SectionOffset:   20
+# CHECK-NEXT:        InitFlags:       0
+# CHECK-NEXT:        Offset:
+# CHECK-NEXT:          Opcode:          I32_CONST
+# CHECK-NEXT:          Value:           1031
+# CHECK-NEXT:        Content:         000000002A000000
+# CHECK-NEXT:      - SectionOffset:   34
+# CHECK-NEXT:        InitFlags:       0
+# CHECK-NEXT:        Offset:
+# CHECK-NEXT:          Opcode:          I32_CONST
+# CHECK-NEXT:          Value:           1039
+# CHECK-NEXT:        Content:         FCFFFFFFFCFFFFFF
+# CHECK-NEXT:      - SectionOffset:   48
+# CHECK-NEXT:        InitFlags:       0
+# CHECK-NEXT:        Offset:
+# CHECK-NEXT:          Opcode:          I32_CONST
+# CHECK-NEXT:          Value:           1047
+# CHECK-NEXT:        Content:         E9FFFFFFE9FFFFFF
+# CHECK-NEXT:      - SectionOffset:   62
+# CHECK-NEXT:        InitFlags:       0
+# CHECK-NEXT:        Offset:
+# CHECK-NEXT:          Opcode:          I32_CONST
+# CHECK-NEXT:          Value:           1055
+# CHECK-NEXT:        Content:         '0800000008000000'
+# CHECK-NEXT:      - SectionOffset:   76
+# CHECK-NEXT:        InitFlags:       0
+# CHECK-NEXT:        Offset:
+# CHECK-NEXT:          Opcode:          I32_CONST
+# CHECK-NEXT:          Value:           1063
+# CHECK-NEXT:        Content:         '15000000'
+

diff  --git a/lld/wasm/InputChunks.cpp b/lld/wasm/InputChunks.cpp
index 5e965124880e..75343cf699f8 100644
--- a/lld/wasm/InputChunks.cpp
+++ b/lld/wasm/InputChunks.cpp
@@ -94,6 +94,7 @@ void InputChunk::verifyRelocTargets() const {
     case R_WASM_FUNCTION_OFFSET_I32:
     case R_WASM_SECTION_OFFSET_I32:
     case R_WASM_GLOBAL_INDEX_I32:
+    case R_WASM_MEMORY_ADDR_LOCREL_I32:
       existingValue = read32le(loc);
       break;
     case R_WASM_TABLE_INDEX_I64:
@@ -139,7 +140,7 @@ void InputChunk::writeTo(uint8_t *buf) const {
 
   for (const WasmRelocation &rel : relocations) {
     uint8_t *loc = buf + rel.Offset + off;
-    auto value = file->calcNewValue(rel, tombstone);
+    auto value = file->calcNewValue(rel, tombstone, this);
     LLVM_DEBUG(dbgs() << "apply reloc: type=" << relocTypeToString(rel.Type));
     if (rel.Type != R_WASM_TYPE_INDEX_LEB)
       LLVM_DEBUG(dbgs() << " sym=" << file->getSymbols()[rel.Index]->getName());
@@ -176,6 +177,7 @@ void InputChunk::writeTo(uint8_t *buf) const {
     case R_WASM_FUNCTION_OFFSET_I32:
     case R_WASM_SECTION_OFFSET_I32:
     case R_WASM_GLOBAL_INDEX_I32:
+    case R_WASM_MEMORY_ADDR_LOCREL_I32:
       write32le(loc, value);
       break;
     case R_WASM_TABLE_INDEX_I64:
@@ -302,7 +304,8 @@ void InputFunction::calculateSize() {
   for (const WasmRelocation &rel : relocations) {
     LLVM_DEBUG(dbgs() << "  region: " << (rel.Offset - lastRelocEnd) << "\n");
     compressedFuncSize += rel.Offset - lastRelocEnd;
-    compressedFuncSize += getRelocWidth(rel, file->calcNewValue(rel, tombstone));
+    compressedFuncSize +=
+        getRelocWidth(rel, file->calcNewValue(rel, tombstone, this));
     lastRelocEnd = rel.Offset + getRelocWidthPadded(rel);
   }
   LLVM_DEBUG(dbgs() << "  final region: " << (end - lastRelocEnd) << "\n");
@@ -343,7 +346,8 @@ void InputFunction::writeTo(uint8_t *buf) const {
     LLVM_DEBUG(dbgs() << "  write chunk: " << chunkSize << "\n");
     memcpy(buf, lastRelocEnd, chunkSize);
     buf += chunkSize;
-    buf += writeCompressedReloc(buf, rel, file->calcNewValue(rel, tombstone));
+    buf += writeCompressedReloc(buf, rel,
+                                file->calcNewValue(rel, tombstone, this));
     lastRelocEnd = secStart + rel.Offset + getRelocWidthPadded(rel);
   }
 
@@ -416,7 +420,7 @@ void InputSegment::generateRelocationCode(raw_ostream &os) const {
       writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
       writeUleb128(os, baseSymbol->getGlobalIndex(), "base");
       writeU8(os, opcode_reloc_const, "CONST");
-      writeSleb128(os, file->calcNewValue(rel, tombstone), "offset");
+      writeSleb128(os, file->calcNewValue(rel, tombstone, this), "offset");
       writeU8(os, opcode_reloc_add, "ADD");
     }
 

diff  --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp
index d650c2a3fd7b..6b3b0d2c2e52 100644
--- a/lld/wasm/InputFiles.cpp
+++ b/lld/wasm/InputFiles.cpp
@@ -126,6 +126,7 @@ uint64_t ObjFile::calcNewAddend(const WasmRelocation &reloc) const {
   case R_WASM_MEMORY_ADDR_TLS_SLEB:
   case R_WASM_FUNCTION_OFFSET_I32:
   case R_WASM_FUNCTION_OFFSET_I64:
+  case R_WASM_MEMORY_ADDR_LOCREL_I32:
     return reloc.Addend;
   case R_WASM_SECTION_OFFSET_I32:
     return getSectionSymbol(reloc.Index)->section->getOffset(reloc.Addend);
@@ -158,7 +159,8 @@ uint64_t ObjFile::calcExpectedValue(const WasmRelocation &reloc) const {
   case R_WASM_MEMORY_ADDR_REL_SLEB64:
   case R_WASM_MEMORY_ADDR_I32:
   case R_WASM_MEMORY_ADDR_I64:
-  case R_WASM_MEMORY_ADDR_TLS_SLEB: {
+  case R_WASM_MEMORY_ADDR_TLS_SLEB:
+  case R_WASM_MEMORY_ADDR_LOCREL_I32: {
     const WasmSymbol &sym = wasmObj->syms()[reloc.Index];
     if (sym.isUndefined())
       return 0;
@@ -199,7 +201,8 @@ uint64_t ObjFile::calcExpectedValue(const WasmRelocation &reloc) const {
 }
 
 // Translate from the relocation's index into the final linked output value.
-uint64_t ObjFile::calcNewValue(const WasmRelocation &reloc, uint64_t tombstone) const {
+uint64_t ObjFile::calcNewValue(const WasmRelocation &reloc, uint64_t tombstone,
+                               const InputChunk *chunk) const {
   const Symbol* sym = nullptr;
   if (reloc.Type != R_WASM_TYPE_INDEX_LEB) {
     sym = symbols[reloc.Index];
@@ -234,7 +237,8 @@ uint64_t ObjFile::calcNewValue(const WasmRelocation &reloc, uint64_t tombstone)
   case R_WASM_MEMORY_ADDR_REL_SLEB:
   case R_WASM_MEMORY_ADDR_REL_SLEB64:
   case R_WASM_MEMORY_ADDR_I32:
-  case R_WASM_MEMORY_ADDR_I64: {
+  case R_WASM_MEMORY_ADDR_I64:
+  case R_WASM_MEMORY_ADDR_LOCREL_I32: {
     if (isa<UndefinedData>(sym) || sym->isUndefWeak())
       return 0;
     auto D = cast<DefinedData>(sym);
@@ -245,7 +249,15 @@ uint64_t ObjFile::calcNewValue(const WasmRelocation &reloc, uint64_t tombstone)
     // backward compat with old object files built with `-fPIC`.
     if (D->segment && D->segment->outputSeg->name == ".tdata")
       return D->getOutputSegmentOffset() + reloc.Addend;
-    return D->getVA(reloc.Addend);
+
+    uint64_t value = D->getVA(reloc.Addend);
+    if (reloc.Type == R_WASM_MEMORY_ADDR_LOCREL_I32) {
+      const auto *segment = cast<InputSegment>(chunk);
+      uint64_t p = segment->outputSeg->startVA + segment->outputSegmentOffset +
+                   reloc.Offset - segment->getInputSectionOffset();
+      value -= p;
+    }
+    return value;
   }
   case R_WASM_MEMORY_ADDR_TLS_SLEB:
     if (isa<UndefinedData>(sym) || sym->isUndefWeak())

diff  --git a/lld/wasm/InputFiles.h b/lld/wasm/InputFiles.h
index 8152420cb639..78b3ceea0a05 100644
--- a/lld/wasm/InputFiles.h
+++ b/lld/wasm/InputFiles.h
@@ -119,7 +119,8 @@ class ObjFile : public InputFile {
   void dumpInfo() const;
 
   uint32_t calcNewIndex(const WasmRelocation &reloc) const;
-  uint64_t calcNewValue(const WasmRelocation &reloc, uint64_t tombstone) const;
+  uint64_t calcNewValue(const WasmRelocation &reloc, uint64_t tombstone,
+                        const InputChunk *chunk) const;
   uint64_t calcNewAddend(const WasmRelocation &reloc) const;
   uint64_t calcExpectedValue(const WasmRelocation &reloc) const;
   Symbol *getSymbol(const WasmRelocation &reloc) const {

diff  --git a/llvm/include/llvm/BinaryFormat/WasmRelocs.def b/llvm/include/llvm/BinaryFormat/WasmRelocs.def
index dca63eca9455..b83efc26e58d 100644
--- a/llvm/include/llvm/BinaryFormat/WasmRelocs.def
+++ b/llvm/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/llvm/include/llvm/MC/MCWasmObjectWriter.h b/llvm/include/llvm/MC/MCWasmObjectWriter.h
index 00da632bbcc6..4c75ea155794 100644
--- a/llvm/include/llvm/MC/MCWasmObjectWriter.h
+++ b/llvm/include/llvm/MC/MCWasmObjectWriter.h
@@ -33,8 +33,8 @@ class MCWasmObjectTargetWriter : public MCObjectTargetWriter {
     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/llvm/lib/BinaryFormat/Wasm.cpp b/llvm/lib/BinaryFormat/Wasm.cpp
index 126680ac41c2..81264a940ce1 100644
--- a/llvm/lib/BinaryFormat/Wasm.cpp
+++ b/llvm/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/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp
index c8bc65467b8c..25138d651b5b 100644
--- a/llvm/lib/MC/WasmObjectWriter.cpp
+++ b/llvm/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<MCSymbolWasm>(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 
diff erent 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/llvm/lib/Object/RelocationResolver.cpp b/llvm/lib/Object/RelocationResolver.cpp
index 204577af7239..eee36f7f3de9 100644
--- a/llvm/lib/Object/RelocationResolver.cpp
+++ b/llvm/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/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp
index 7fbb1862e05f..1a0958ad039d 100644
--- a/llvm/lib/Object/WasmObjectFile.cpp
+++ b/llvm/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<GenericBinaryError>("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/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp
index aa7e2311d240..1a79a2d597bb 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp
@@ -34,8 +34,8 @@ class WebAssemblyWasmObjectWriter final : public MCWasmObjectTargetWriter {
   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<MCSymbolWasm>(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/llvm/test/MC/WebAssembly/bad-fixup-expr.s b/llvm/test/MC/WebAssembly/bad-fixup-expr.s
index 3bd7e6e2f06b..c00f6d4462bb 100644
--- a/llvm/test/MC/WebAssembly/bad-fixup-expr.s
+++ b/llvm/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 
diff erent 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 
diff erent 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/llvm/test/MC/WebAssembly/reloc-relative.ll b/llvm/test/MC/WebAssembly/reloc-relative.ll
new file mode 100644
index 000000000000..a581f78c3edd
--- /dev/null
+++ b/llvm/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
+ at foo = external global i32, align 4
+ at bar = constant i32 sub (
+    i32 ptrtoint (i32* @foo to i32),
+    i32 ptrtoint (i32* @bar to i32)
+), section ".sec1"
+
+
+; @foo - @addend + 4
+ at fizz = constant i32 42, align 4, section ".sec2"
+ at addend = constant i32 sub (
+    i32 ptrtoint (i32* @foo to i32),
+    i32 ptrtoint (i32* @fizz to i32)
+), section ".sec2"
+
+ at x_sec = constant i32 sub (
+    i32 ptrtoint (i32* @fizz to i32),
+    i32 ptrtoint (i32* @x_sec to i32)
+), section ".sec1"


        


More information about the llvm-commits mailing list