Skip to content

Commit c0cb513

Browse files
authored
[lld][WebAssembly] Use writePtrConst helper function (#166228)
This is especially important for writing i32 values larger than 2gb which need to be encoded as negative SLEB vales in the binary. Without this change offsets over 2gb are wrongly encoded and cause validation errors. Fixes: emscripten-core/emscripten#25706
1 parent 148a42b commit c0cb513

File tree

3 files changed

+66
-16
lines changed

3 files changed

+66
-16
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
## Verifies runtime relocation code for addresses over 2gb works correctly.
2+
## We have had issues with LEB encoding of address over 2gb in i32.const
3+
## instruction leading to invalid binaries.
4+
5+
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s
6+
# RUN: wasm-ld --global-base=2147483648 --experimental-pic --unresolved-symbols=import-dynamic -no-gc-sections --shared-memory --no-entry -o %t.wasm %t.o
7+
# XUN: obj2yaml %t.wasm | FileCheck %s
8+
# RUN: llvm-objdump -d --no-show-raw-insn --no-leading-addr %t.wasm | FileCheck %s --
9+
10+
.globl tls_sym
11+
.globl data_sym
12+
.globl _start
13+
.globaltype __tls_base, i32
14+
15+
_start:
16+
.functype _start () -> ()
17+
global.get __tls_base
18+
i32.const tls_sym@TLSREL
19+
i32.add
20+
drop
21+
i32.const data_sym
22+
drop
23+
end_function
24+
25+
.section tls_sec,"T",@
26+
.p2align 2
27+
tls_sym:
28+
.int32 0
29+
.int32 extern_sym
30+
.size tls_sym, 8
31+
32+
.section data_sec,"",@
33+
.p2align 2
34+
data_sym:
35+
.int32 0
36+
.int32 extern_sym
37+
.size data_sym, 8
38+
39+
.section .custom_section.target_features,"",@
40+
.int8 2
41+
.int8 43
42+
.int8 7
43+
.ascii "atomics"
44+
.int8 43
45+
.int8 11
46+
.ascii "bulk-memory"
47+
48+
# CHECK: <__wasm_apply_data_relocs>:
49+
# CHECK-EMPTY:
50+
# CHECK-NEXT: i32.const -2147483636
51+
# CHECK-NEXT: global.get 0
52+
# CHECK-NEXT: i32.store 0
53+
# CHECK-NEXT: end
54+
55+
# CHECK: <__wasm_apply_tls_relocs>:
56+
# CHECK-EMPTY:
57+
# CHECK-NEXT: i32.const -2147483644
58+
# CHECK-NEXT: global.get 0
59+
# CHECK-NEXT: i32.store 0
60+
# CHECK-NEXT: end

lld/wasm/InputChunks.cpp

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -423,8 +423,6 @@ bool InputChunk::generateRelocationCode(raw_ostream &os) const {
423423

424424
bool is64 = ctx.arg.is64.value_or(false);
425425
bool generated = false;
426-
unsigned opcode_ptr_const = is64 ? WASM_OPCODE_I64_CONST
427-
: WASM_OPCODE_I32_CONST;
428426
unsigned opcode_ptr_add = is64 ? WASM_OPCODE_I64_ADD
429427
: WASM_OPCODE_I32_ADD;
430428

@@ -451,8 +449,7 @@ bool InputChunk::generateRelocationCode(raw_ostream &os) const {
451449
<< " output offset=" << offset << "\n");
452450

453451
// Calculate the address at which to apply the relocation
454-
writeU8(os, opcode_ptr_const, "CONST");
455-
writeSleb128(os, offset, "offset");
452+
writePtrConst(os, offset, is64, "offset");
456453

457454
// In PIC mode we need to add the __memory_base
458455
if (ctx.isPic) {
@@ -466,8 +463,6 @@ bool InputChunk::generateRelocationCode(raw_ostream &os) const {
466463

467464
// Now figure out what we want to store at this location
468465
bool is64 = relocIs64(rel.Type);
469-
unsigned opcode_reloc_const =
470-
is64 ? WASM_OPCODE_I64_CONST : WASM_OPCODE_I32_CONST;
471466
unsigned opcode_reloc_add =
472467
is64 ? WASM_OPCODE_I64_ADD : WASM_OPCODE_I32_ADD;
473468
unsigned opcode_reloc_store =
@@ -477,8 +472,7 @@ bool InputChunk::generateRelocationCode(raw_ostream &os) const {
477472
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
478473
writeUleb128(os, sym->getGOTIndex(), "global index");
479474
if (rel.Addend) {
480-
writeU8(os, opcode_reloc_const, "CONST");
481-
writeSleb128(os, rel.Addend, "addend");
475+
writePtrConst(os, rel.Addend, is64, "addend");
482476
writeU8(os, opcode_reloc_add, "ADD");
483477
}
484478
} else {
@@ -491,8 +485,8 @@ bool InputChunk::generateRelocationCode(raw_ostream &os) const {
491485
baseSymbol = ctx.sym.tlsBase;
492486
writeU8(os, WASM_OPCODE_GLOBAL_GET, "GLOBAL_GET");
493487
writeUleb128(os, baseSymbol->getGlobalIndex(), "base");
494-
writeU8(os, opcode_reloc_const, "CONST");
495-
writeSleb128(os, file->calcNewValue(rel, tombstone, this), "offset");
488+
writePtrConst(os, file->calcNewValue(rel, tombstone, this), is64,
489+
"offset");
496490
writeU8(os, opcode_reloc_add, "ADD");
497491
}
498492

lld/wasm/SyntheticSections.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -434,8 +434,6 @@ void GlobalSection::addInternalGOTEntry(Symbol *sym) {
434434
void GlobalSection::generateRelocationCode(raw_ostream &os, bool TLS) const {
435435
assert(!ctx.arg.extendedConst);
436436
bool is64 = ctx.arg.is64.value_or(false);
437-
unsigned opcode_ptr_const = is64 ? WASM_OPCODE_I64_CONST
438-
: WASM_OPCODE_I32_CONST;
439437
unsigned opcode_ptr_add = is64 ? WASM_OPCODE_I64_ADD
440438
: WASM_OPCODE_I32_ADD;
441439

@@ -452,8 +450,7 @@ void GlobalSection::generateRelocationCode(raw_ostream &os, bool TLS) const {
452450
writeUleb128(os, ctx.sym.memoryBase->getGlobalIndex(), "__memory_base");
453451

454452
// Add the virtual address of the data symbol
455-
writeU8(os, opcode_ptr_const, "CONST");
456-
writeSleb128(os, d->getVA(), "offset");
453+
writePtrConst(os, d->getVA(), is64, "offset");
457454
} else if (auto *f = dyn_cast<FunctionSymbol>(sym)) {
458455
if (f->isStub)
459456
continue;
@@ -462,8 +459,7 @@ void GlobalSection::generateRelocationCode(raw_ostream &os, bool TLS) const {
462459
writeUleb128(os, ctx.sym.tableBase->getGlobalIndex(), "__table_base");
463460

464461
// Add the table index to __table_base
465-
writeU8(os, opcode_ptr_const, "CONST");
466-
writeSleb128(os, f->getTableIndex(), "offset");
462+
writePtrConst(os, f->getTableIndex(), is64, "offset");
467463
} else {
468464
assert(isa<UndefinedData>(sym) || isa<SharedData>(sym));
469465
continue;

0 commit comments

Comments
 (0)