# 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
.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
# 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
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:
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);
}
#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);
}
// 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.
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:
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:
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");