forked from OSchip/llvm-project
[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
This commit is contained in:
parent
db7b1af8ef
commit
4c75521ce0
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -119,7 +119,7 @@ public:
|
|||
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];
|
||||
};
|
||||
|
|
|
@ -137,36 +137,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);
|
||||
}
|
||||
|
||||
|
@ -420,8 +442,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.
|
||||
|
@ -752,7 +774,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:
|
||||
|
@ -761,10 +783,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:
|
||||
|
@ -784,14 +806,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");
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue