[llvm-branch-commits] [lld] e6d2aa9 - [MC][WebAssembly] Fix crash when relocation addend underlows U32

Tom Stellard via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Mar 7 14:46:48 PST 2022


Author: Sam Clegg
Date: 2022-03-07T14:30:23-08:00
New Revision: e6d2aa9b0f131a141166d1d90560f1a2d1d9ec5c

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

LOG: [MC][WebAssembly] Fix crash when relocation addend underlows U32

For the object file writer we need to allow the underflow (ar write
zero), but for the final linker output we should probably generate an
error (I've left that as a TODO for now).

Fixes: https://github.com/llvm/llvm-project/issues/54012

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

(cherry picked from commit 4c75521ce0b1ac55fba1a91ef5156fc811f5dfcb)

Added: 
    

Modified: 
    lld/test/wasm/reloc-addend.s
    lld/wasm/InputChunks.cpp
    lld/wasm/InputFiles.cpp
    lld/wasm/InputFiles.h
    llvm/lib/MC/WasmObjectWriter.cpp
    llvm/test/MC/WebAssembly/reloc-code.s

Removed: 
    


################################################################################
diff  --git a/lld/test/wasm/reloc-addend.s b/lld/test/wasm/reloc-addend.s
index acd57ce357a72..4b23ed1120faa 100644
--- a/lld/test/wasm/reloc-addend.s
+++ b/lld/test/wasm/reloc-addend.s
@@ -1,6 +1,7 @@
 # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s
 # RUN: wasm-ld -r -o %t.wasm %t.o
 # RUN: obj2yaml %t.wasm | FileCheck %s
+# RUN: llvm-objdump --disassemble-symbols=_start --no-show-raw-insn --no-leading-addr %t.wasm | FileCheck %s --check-prefixes DIS
 
 .hidden foo
 .hidden bar
@@ -30,6 +31,39 @@ negative_addend:
   .int32  foo-16
   .size negative_addend, 4
 
+.globl _start
+.section .text,"",@
+_start:
+  .functype _start () -> ()
+  i32.const 0
+  i32.load foo + 10
+  drop
+  i32.const 0
+  i32.load foo - 10
+  drop
+  i32.const 0
+  # This will underflow because i32.load (and the
+  # corresponding relocation type) take an unsgiend (U32)
+  # immediate.
+  i32.load foo - 2048
+  drop
+  end_function
+
+# CHECK:       - Type:            CODE
+# CHECK-NEXT:    Relocations:
+# CHECK-NEXT:      - Type:            R_WASM_MEMORY_ADDR_LEB
+# CHECK-NEXT:        Index:           0
+# CHECK-NEXT:        Offset:          0x7
+# CHECK-NEXT:        Addend:          10
+# CHECK-NEXT:      - Type:            R_WASM_MEMORY_ADDR_LEB
+# CHECK-NEXT:        Index:           0
+# CHECK-NEXT:        Offset:          0x11
+# CHECK-NEXT:        Addend:          -10
+# CHECK-NEXT:      - Type:            R_WASM_MEMORY_ADDR_LEB
+# CHECK-NEXT:        Index:           0
+# CHECK-NEXT:        Offset:          0x1B
+# CHECK-NEXT:        Addend:          -2048
+
 # CHECK:        - Type:            DATA
 # CHECK-NEXT:     Relocations:
 # CHECK-NEXT:       - Type:            R_WASM_MEMORY_ADDR_I32
@@ -40,3 +74,17 @@ negative_addend:
 # CHECK-NEXT:         Index:           0
 # CHECK-NEXT:         Offset:          0xF
 # CHECK-NEXT:         Addend:          -16
+
+# DIS: <_start>:
+# DIS-EMPTY:
+# DIS-NEXT:    i32.const 0
+# DIS-NEXT:    i32.load 26
+# DIS-NEXT:    drop
+# DIS-NEXT:    i32.const 0
+# DIS-NEXT:    i32.load 6
+# DIS-NEXT:    drop
+# DIS-NEXT:    i32.const 0
+# TODO(sbc): We should probably error here rather than allowing u32 to wrap
+# DIS-NEXT:    i32.load 4294965264
+# DIS-NEXT:    drop
+# DIS-NEXT:    end

diff  --git a/lld/wasm/InputChunks.cpp b/lld/wasm/InputChunks.cpp
index 7973dce6827e2..242378504c3b8 100644
--- a/lld/wasm/InputChunks.cpp
+++ b/lld/wasm/InputChunks.cpp
@@ -116,7 +116,10 @@ void InputChunk::relocate(uint8_t *buf) const {
       LLVM_DEBUG(dbgs() << " sym=" << file->getSymbols()[rel.Index]->getName());
     LLVM_DEBUG(dbgs() << " addend=" << rel.Addend << " index=" << rel.Index
                       << " offset=" << rel.Offset << "\n");
-    auto value = file->calcNewValue(rel, tombstone, this);
+    // TODO(sbc): Check that the value is within the range of the
+    // relocation type below.  Most likely we must error out here
+    // if its not with range.
+    uint64_t value = file->calcNewValue(rel, tombstone, this);
 
     switch (rel.Type) {
     case R_WASM_TYPE_INDEX_LEB:
@@ -125,7 +128,7 @@ void InputChunk::relocate(uint8_t *buf) const {
     case R_WASM_TAG_INDEX_LEB:
     case R_WASM_MEMORY_ADDR_LEB:
     case R_WASM_TABLE_NUMBER_LEB:
-      encodeULEB128(value, loc, 5);
+      encodeULEB128(static_cast<uint32_t>(value), loc, 5);
       break;
     case R_WASM_MEMORY_ADDR_LEB64:
       encodeULEB128(value, loc, 10);

diff  --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp
index 0758bb922a3bc..1e69f16cc5f97 100644
--- a/lld/wasm/InputFiles.cpp
+++ b/lld/wasm/InputFiles.cpp
@@ -106,7 +106,7 @@ uint32_t ObjFile::calcNewIndex(const WasmRelocation &reloc) const {
 
 // Relocations can contain addend for combined sections. This function takes a
 // relocation and returns updated addend by offset in the output section.
-uint64_t ObjFile::calcNewAddend(const WasmRelocation &reloc) const {
+int64_t ObjFile::calcNewAddend(const WasmRelocation &reloc) const {
   switch (reloc.Type) {
   case R_WASM_MEMORY_ADDR_LEB:
   case R_WASM_MEMORY_ADDR_LEB64:

diff  --git a/lld/wasm/InputFiles.h b/lld/wasm/InputFiles.h
index cf2c1739e3220..c14d763ff30cd 100644
--- a/lld/wasm/InputFiles.h
+++ b/lld/wasm/InputFiles.h
@@ -119,7 +119,7 @@ class ObjFile : public InputFile {
   uint32_t calcNewIndex(const WasmRelocation &reloc) const;
   uint64_t calcNewValue(const WasmRelocation &reloc, uint64_t tombstone,
                         const InputChunk *chunk) const;
-  uint64_t calcNewAddend(const WasmRelocation &reloc) const;
+  int64_t calcNewAddend(const WasmRelocation &reloc) const;
   Symbol *getSymbol(const WasmRelocation &reloc) const {
     return symbols[reloc.Index];
   };

diff  --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp
index 636c1d238932f..a016b7085a000 100644
--- a/llvm/lib/MC/WasmObjectWriter.cpp
+++ b/llvm/lib/MC/WasmObjectWriter.cpp
@@ -140,36 +140,58 @@ raw_ostream &operator<<(raw_ostream &OS, const WasmRelocationEntry &Rel) {
 }
 #endif
 
-// Write X as an (unsigned) LEB value at offset Offset in Stream, padded
+// Write Value as an (unsigned) LEB value at offset Offset in Stream, padded
 // to allow patching.
-template <int W>
-void writePatchableLEB(raw_pwrite_stream &Stream, uint64_t X, uint64_t Offset) {
+template <typename T, int W>
+void writePatchableULEB(raw_pwrite_stream &Stream, T Value, uint64_t Offset) {
   uint8_t Buffer[W];
-  unsigned SizeLen = encodeULEB128(X, Buffer, W);
+  unsigned SizeLen = encodeULEB128(Value, Buffer, W);
   assert(SizeLen == W);
   Stream.pwrite((char *)Buffer, SizeLen, Offset);
 }
 
-// Write X as an signed LEB value at offset Offset in Stream, padded
+// Write Value as an signed LEB value at offset Offset in Stream, padded
 // to allow patching.
-template <int W>
-void writePatchableSLEB(raw_pwrite_stream &Stream, int64_t X, uint64_t Offset) {
+template <typename T, int W>
+void writePatchableSLEB(raw_pwrite_stream &Stream, T Value, uint64_t Offset) {
   uint8_t Buffer[W];
-  unsigned SizeLen = encodeSLEB128(X, Buffer, W);
+  unsigned SizeLen = encodeSLEB128(Value, Buffer, W);
   assert(SizeLen == W);
   Stream.pwrite((char *)Buffer, SizeLen, Offset);
 }
 
-// Write X as a plain integer value at offset Offset in Stream.
-static void patchI32(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) {
+static void writePatchableU32(raw_pwrite_stream &Stream, uint32_t Value,
+                              uint64_t Offset) {
+  writePatchableULEB<uint32_t, 5>(Stream, Value, Offset);
+}
+
+static void writePatchableS32(raw_pwrite_stream &Stream, int32_t Value,
+                              uint64_t Offset) {
+  writePatchableSLEB<int32_t, 5>(Stream, Value, Offset);
+}
+
+static void writePatchableU64(raw_pwrite_stream &Stream, uint64_t Value,
+                              uint64_t Offset) {
+  writePatchableSLEB<uint64_t, 10>(Stream, Value, Offset);
+}
+
+static void writePatchableS64(raw_pwrite_stream &Stream, int64_t Value,
+                              uint64_t Offset) {
+  writePatchableSLEB<int64_t, 10>(Stream, Value, Offset);
+}
+
+// Write Value as a plain integer value at offset Offset in Stream.
+static void patchI32(raw_pwrite_stream &Stream, uint32_t Value,
+                     uint64_t Offset) {
   uint8_t Buffer[4];
-  support::endian::write32le(Buffer, X);
+  support::endian::write32le(Buffer, Value);
   Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset);
 }
 
-static void patchI64(raw_pwrite_stream &Stream, uint64_t X, uint64_t Offset) {
+static void patchI64(raw_pwrite_stream &Stream, uint64_t Value,
+                     uint64_t Offset) {
   uint8_t Buffer[8];
-  support::endian::write64le(Buffer, X);
+  support::endian::write64le(Buffer, Value);
   Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset);
 }
 
@@ -423,8 +445,8 @@ void WasmObjectWriter::endSection(SectionBookkeeping &Section) {
 
   // Write the final section size to the payload_len field, which follows
   // the section id byte.
-  writePatchableLEB<5>(static_cast<raw_pwrite_stream &>(W->OS), Size,
-                       Section.SizeOffset);
+  writePatchableU32(static_cast<raw_pwrite_stream &>(W->OS), Size,
+                    Section.SizeOffset);
 }
 
 // Emit the Wasm header.
@@ -755,7 +777,7 @@ void WasmObjectWriter::applyRelocations(
                       RelEntry.Offset;
 
     LLVM_DEBUG(dbgs() << "applyRelocation: " << RelEntry << "\n");
-    auto Value = getProvisionalValue(RelEntry, Layout);
+    uint64_t Value = getProvisionalValue(RelEntry, Layout);
 
     switch (RelEntry.Type) {
     case wasm::R_WASM_FUNCTION_INDEX_LEB:
@@ -764,10 +786,10 @@ void WasmObjectWriter::applyRelocations(
     case wasm::R_WASM_MEMORY_ADDR_LEB:
     case wasm::R_WASM_TAG_INDEX_LEB:
     case wasm::R_WASM_TABLE_NUMBER_LEB:
-      writePatchableLEB<5>(Stream, Value, Offset);
+      writePatchableU32(Stream, Value, Offset);
       break;
     case wasm::R_WASM_MEMORY_ADDR_LEB64:
-      writePatchableLEB<10>(Stream, Value, Offset);
+      writePatchableU64(Stream, Value, Offset);
       break;
     case wasm::R_WASM_TABLE_INDEX_I32:
     case wasm::R_WASM_MEMORY_ADDR_I32:
@@ -787,14 +809,14 @@ void WasmObjectWriter::applyRelocations(
     case wasm::R_WASM_MEMORY_ADDR_SLEB:
     case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
     case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB:
-      writePatchableSLEB<5>(Stream, Value, Offset);
+      writePatchableS32(Stream, Value, Offset);
       break;
     case wasm::R_WASM_TABLE_INDEX_SLEB64:
     case wasm::R_WASM_TABLE_INDEX_REL_SLEB64:
     case wasm::R_WASM_MEMORY_ADDR_SLEB64:
     case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64:
     case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB64:
-      writePatchableSLEB<10>(Stream, Value, Offset);
+      writePatchableS64(Stream, Value, Offset);
       break;
     default:
       llvm_unreachable("invalid relocation type");

diff  --git a/llvm/test/MC/WebAssembly/reloc-code.s b/llvm/test/MC/WebAssembly/reloc-code.s
index cd301098f9a8c..c7b05f81a7ff7 100644
--- a/llvm/test/MC/WebAssembly/reloc-code.s
+++ b/llvm/test/MC/WebAssembly/reloc-code.s
@@ -14,12 +14,12 @@ f1:
 
   # Call functions at `a` and `b` indirectly.
   i32.const 0
-  i32.load  a
+  i32.load  a - 10
   call_indirect  () -> (i64)
   drop
 
   i32.const 0
-  i32.load  b
+  i32.load  b + 20
   call_indirect  () -> (i32)
   drop
 
@@ -49,7 +49,7 @@ b:
 # CHECK-NEXT:       Type: R_WASM_MEMORY_ADDR_LEB (3)
 # CHECK-NEXT:       Offset: 0x7
 # CHECK-NEXT:       Symbol: a
-# CHECK-NEXT:       Addend: 0
+# CHECK-NEXT:       Addend: -10
 # CHECK-NEXT:     }
 # CHECK-NEXT:     Relocation {
 # CHECK-NEXT:       Type: R_WASM_TYPE_INDEX_LEB (6)
@@ -60,7 +60,7 @@ b:
 # CHECK-NEXT:       Type: R_WASM_MEMORY_ADDR_LEB (3)
 # CHECK-NEXT:       Offset: 0x18
 # CHECK-NEXT:       Symbol: b
-# CHECK-NEXT:       Addend: 0
+# CHECK-NEXT:       Addend: 20
 # CHECK-NEXT:     }
 # CHECK-NEXT:     Relocation {
 # CHECK-NEXT:       Type: R_WASM_TYPE_INDEX_LEB (6)
@@ -87,7 +87,7 @@ b:
 # REF-NEXT:       Type: R_WASM_MEMORY_ADDR_LEB (3)
 # REF-NEXT:       Offset: 0x7
 # REF-NEXT:       Symbol: a
-# REF-NEXT:       Addend: 0
+# REF-NEXT:       Addend: -10
 # REF-NEXT:     }
 # REF-NEXT:     Relocation {
 # REF-NEXT:       Type: R_WASM_TYPE_INDEX_LEB (6)
@@ -103,7 +103,7 @@ b:
 # REF-NEXT:       Type: R_WASM_MEMORY_ADDR_LEB (3)
 # REF-NEXT:       Offset: 0x1C
 # REF-NEXT:       Symbol: b
-# REF-NEXT:       Addend: 0
+# REF-NEXT:       Addend: 20
 # REF-NEXT:     }
 # REF-NEXT:     Relocation {
 # REF-NEXT:       Type: R_WASM_TYPE_INDEX_LEB (6)


        


More information about the llvm-branch-commits mailing list