[lld] [lld][WebAssembly] Fix relocation of Wasm table index with GOT access (PR #104043)
Luc Blaeser via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 14 08:37:37 PDT 2024
https://github.com/luc-blaeser created https://github.com/llvm/llvm-project/pull/104043
Fix `wasm-ld` to handle the relocation of table indices for __shared functions__ in the __code segment__. The table element was not created for the corresponding table index. Moreover, `GOT.func` was missing for the corresponding function.
>From d40eb7c4e4b5b123abc6a0789f2b9d465c0ca1a9 Mon Sep 17 00:00:00 2001
From: luc-blaeser <luc.blaeser at dfinity.org>
Date: Mon, 12 Aug 2024 11:18:41 +0200
Subject: [PATCH] Fix relocation of Wasm table index with GOT access
---
lld/test/wasm/call-indirect-external.s | 27 +++++
lld/test/wasm/shared-call-indirect.s | 126 +++++++++++++++++++++++
lld/test/wasm/shared-call-indirect64.s | 135 +++++++++++++++++++++++++
lld/wasm/Relocations.cpp | 29 +++++-
4 files changed, 314 insertions(+), 3 deletions(-)
create mode 100644 lld/test/wasm/call-indirect-external.s
create mode 100644 lld/test/wasm/shared-call-indirect.s
create mode 100644 lld/test/wasm/shared-call-indirect64.s
diff --git a/lld/test/wasm/call-indirect-external.s b/lld/test/wasm/call-indirect-external.s
new file mode 100644
index 00000000000000..e226b891442485
--- /dev/null
+++ b/lld/test/wasm/call-indirect-external.s
@@ -0,0 +1,27 @@
+# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s
+
+# RUN: not wasm-ld --experimental-pic -shared %t.o -o /dev/null 2>&1 | \
+# RUN: FileCheck -check-prefix=ERRUND %s
+# ERRUND: error: {{.*}}.o: relocation R_WASM_TABLE_INDEX_REL_SLEB cannot be used against an undefined symbol `external_func`
+
+# RUN: not wasm-ld --experimental-pic -shared %t.o -o /dev/null --unresolved-symbols=report-all 2>&1 | \
+# RUN: FileCheck -check-prefix=ERRUND %s
+
+# RUN: not wasm-ld --experimental-pic -shared %t.o -o /dev/null --warn-unresolved-symbols 2>&1 | \
+# RUN: FileCheck -check-prefix=ERRUND %s
+
+# RUN: not wasm-ld --experimental-pic -shared %t.o -o /dev/null --unresolved-symbols=ignore-all 2>&1 | \
+# RUN: FileCheck -check-prefix=ERRUND %s
+
+.globaltype __table_base, i32, immutable
+
+.functype external_func () -> ()
+
+.globl _start
+_start:
+ .functype _start () -> ()
+ global.get __table_base
+ i32.const external_func at TBREL
+ i32.add
+ call_indirect () -> ()
+ end_function
diff --git a/lld/test/wasm/shared-call-indirect.s b/lld/test/wasm/shared-call-indirect.s
new file mode 100644
index 00000000000000..d805670b8513c7
--- /dev/null
+++ b/lld/test/wasm/shared-call-indirect.s
@@ -0,0 +1,126 @@
+# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s
+# RUN: wasm-ld --experimental-pic -shared -o %t.wasm %t.o
+# RUN: obj2yaml %t.wasm | FileCheck %s
+# RUN: llvm-objdump --disassemble-symbols=test_indirect_local_func_call,test_indirect_shared_func_call --no-show-raw-insn --no-leading-addr %t.wasm | FileCheck %s --check-prefixes DIS
+
+.globaltype __table_base, i32, immutable
+
+test_indirect_local_func_call:
+ .functype test_indirect_local_func_call () -> ()
+ global.get __table_base
+ i32.const local_func at TBREL
+ i32.add
+ call_indirect () -> ()
+ end_function
+
+# Test table index relocation in code section for shared functions
+
+test_indirect_shared_func_call:
+ .functype test_indirect_shared_func_call () -> ()
+ i64.const 12345
+ global.get __table_base
+ i32.const shared_func at TBREL
+ i32.add
+ call_indirect (i64) -> (i32)
+ drop
+ end_function
+
+local_func:
+ .functype local_func () -> ()
+ end_function
+
+.globl shared_func
+shared_func:
+ .functype shared_func (i64) -> (i32)
+ local.get 0
+ i32.wrap_i64
+ end_function
+
+.globl _start
+_start:
+ .functype _start () -> ()
+ call test_indirect_local_func_call
+ call test_indirect_shared_func_call
+ end_function
+
+# CHECK: Sections:
+# CHECK-NEXT: - Type: CUSTOM
+# CHECK-NEXT: Name: dylink.0
+# CHECK-NEXT: MemorySize: 0
+# CHECK-NEXT: MemoryAlignment: 0
+# CHECK-NEXT: TableSize: 2
+# CHECK-NEXT: TableAlignment: 0
+# CHECK-NEXT: Needed: []
+# CHECK-NEXT: - Type: TYPE
+
+# CHECK: - Type: IMPORT
+# CHECK-NEXT: Imports:
+# CHECK-NEXT: - Module: env
+# CHECK-NEXT: Field: memory
+# CHECK-NEXT: Kind: MEMORY
+# CHECK-NEXT: Memory:
+# CHECK-NEXT: Minimum: 0x0
+# CHECK-NEXT: - Module: env
+# CHECK-NEXT: Field: __indirect_function_table
+# CHECK-NEXT: Kind: TABLE
+# CHECK-NEXT: Table:
+# CHECK-NEXT: Index: 0
+# CHECK-NEXT: ElemType: FUNCREF
+# CHECK-NEXT: Limits:
+# CHECK-NEXT: Minimum: 0x2
+# CHECK-NEXT: - Module: env
+# CHECK-NEXT: Field: __memory_base
+# CHECK-NEXT: Kind: GLOBAL
+# CHECK-NEXT: GlobalType: I32
+# CHECK-NEXT: GlobalMutable: false
+# CHECK-NEXT: - Module: env
+# CHECK-NEXT: Field: __table_base
+# CHECK-NEXT: Kind: GLOBAL
+# CHECK-NEXT: GlobalType: I32
+# CHECK-NEXT: GlobalMutable: false
+# CHECK-NEXT: - Module: GOT.func
+# CHECK-NEXT: Field: shared_func
+# CHECK-NEXT: Kind: GLOBAL
+# CHECK-NEXT: GlobalType: I32
+# CHECK-NEXT: GlobalMutable: true
+# CHECK-NEXT: - Type: FUNCTION
+# CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 0, 0, 1, 0 ]
+# CHECK-NEXT: - Type: EXPORT
+# CHECK-NEXT: Exports:
+# CHECK-NEXT: - Name: __wasm_call_ctors
+# CHECK-NEXT: Kind: FUNCTION
+# CHECK-NEXT: Index: 0
+# CHECK-NEXT: - Name: __wasm_apply_data_relocs
+# CHECK-NEXT: Kind: FUNCTION
+# CHECK-NEXT: Index: 1
+# CHECK-NEXT: - Name: shared_func
+# CHECK-NEXT: Kind: FUNCTION
+# CHECK-NEXT: Index: 5
+# CHECK-NEXT: - Name: _start
+# CHECK-NEXT: Kind: FUNCTION
+# CHECK-NEXT: Index: 6
+# CHECK-NEXT: - Type: ELEM
+# CHECK-NEXT: Segments:
+# CHECK-NEXT: - Offset:
+# CHECK-NEXT: Opcode: GLOBAL_GET
+# CHECK-NEXT: Index: 1
+# CHECK-NEXT: Functions: [ 3, 5 ]
+
+
+# DIS: <test_indirect_local_func_call>:
+# DIS-EMPTY:
+# DIS-NEXT: global.get 1
+# DIS-NEXT: i32.const 0
+# DIS-NEXT: i32.add
+# DIS-NEXT: call_indirect 0
+# DIS-NEXT: end
+
+# DIS: <test_indirect_shared_func_call>:
+# DIS-EMPTY:
+# DIS-NEXT: i64.const 12345
+# DIS-NEXT: global.get 1
+# DIS-NEXT: i32.const 1
+# DIS-NEXT: i32.add
+# DIS-NEXT: call_indirect 1
+# DIS-NEXT: drop
+# DIS-NEXT: end
diff --git a/lld/test/wasm/shared-call-indirect64.s b/lld/test/wasm/shared-call-indirect64.s
new file mode 100644
index 00000000000000..b5e8a8de740802
--- /dev/null
+++ b/lld/test/wasm/shared-call-indirect64.s
@@ -0,0 +1,135 @@
+# RUN: llvm-mc -filetype=obj -triple=wasm64-unknown-unknown -o %t.o %s
+# RUN: wasm-ld -mwasm64 --experimental-pic -shared -o %t.wasm %t.o
+# RUN: obj2yaml %t.wasm | FileCheck %s
+# RUN: llvm-objdump --disassemble-symbols=test_indirect_local_func_call,test_indirect_shared_func_call --no-show-raw-insn --no-leading-addr %t.wasm | FileCheck %s --check-prefixes DIS
+
+.globaltype __table_base, i64, immutable
+
+test_indirect_local_func_call:
+ .functype test_indirect_local_func_call () -> ()
+ global.get __table_base
+ i64.const local_func at TBREL
+ i64.add
+ i32.wrap_i64 # Remove when table64 is supported
+ call_indirect () -> ()
+ end_function
+
+# Test table index relocation in code section for shared functions
+
+test_indirect_shared_func_call:
+ .functype test_indirect_shared_func_call () -> ()
+ i32.const 12345
+ global.get __table_base
+ i64.const shared_func at TBREL
+ i64.add
+ i32.wrap_i64 # Remove when table64 is supported
+ call_indirect (i32) -> (i32)
+ drop
+ end_function
+
+local_func:
+ .functype local_func () -> ()
+ end_function
+
+.globl shared_func
+shared_func:
+ .functype shared_func (i32) -> (i32)
+ local.get 0
+ end_function
+
+.globl _start
+_start:
+ .functype _start () -> ()
+ call test_indirect_local_func_call
+ call test_indirect_shared_func_call
+ end_function
+
+# CHECK: Sections:
+# CHECK-NEXT: - Type: CUSTOM
+# CHECK-NEXT: Name: dylink.0
+# CHECK-NEXT: MemorySize: 0
+# CHECK-NEXT: MemoryAlignment: 0
+# CHECK-NEXT: TableSize: 2
+# CHECK-NEXT: TableAlignment: 0
+# CHECK-NEXT: Needed: []
+# CHECK-NEXT: - Type: TYPE
+
+# CHECK: - Type: IMPORT
+# CHECK-NEXT: Imports:
+# CHECK-NEXT: - Module: env
+# CHECK-NEXT: Field: memory
+# CHECK-NEXT: Kind: MEMORY
+# CHECK-NEXT: Memory:
+# CHECK-NEXT: Flags: [ IS_64 ]
+# CHECK-NEXT: Minimum: 0x0
+# CHECK-NEXT: - Module: env
+# CHECK-NEXT: Field: __indirect_function_table
+# CHECK-NEXT: Kind: TABLE
+# CHECK-NEXT: Table:
+# CHECK-NEXT: Index: 0
+# CHECK-NEXT: ElemType: FUNCREF
+# CHECK-NEXT: Limits:
+# CHECK-NEXT: Minimum: 0x2
+# CHECK-NEXT: - Module: env
+# CHECK-NEXT: Field: __memory_base
+# CHECK-NEXT: Kind: GLOBAL
+# CHECK-NEXT: GlobalType: I64
+# CHECK-NEXT: GlobalMutable: false
+# CHECK-NEXT: - Module: env
+# CHECK-NEXT: Field: __table_base
+# CHECK-NEXT: Kind: GLOBAL
+# CHECK-NEXT: GlobalType: I64
+# CHECK-NEXT: GlobalMutable: false
+# CHECK-NEXT: - Module: env
+# CHECK-NEXT: Field: __table_base32
+# CHECK-NEXT: Kind: GLOBAL
+# CHECK-NEXT: GlobalType: I32
+# CHECK-NEXT: GlobalMutable: false
+# CHECK-NEXT: - Module: GOT.func
+# CHECK-NEXT: Field: shared_func
+# CHECK-NEXT: Kind: GLOBAL
+# CHECK-NEXT: GlobalType: I64
+# CHECK-NEXT: GlobalMutable: true
+# CHECK-NEXT: - Type: FUNCTION
+# CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 0, 0, 1, 0 ]
+# CHECK-NEXT: - Type: EXPORT
+# CHECK-NEXT: Exports:
+# CHECK-NEXT: - Name: __wasm_call_ctors
+# CHECK-NEXT: Kind: FUNCTION
+# CHECK-NEXT: Index: 0
+# CHECK-NEXT: - Name: __wasm_apply_data_relocs
+# CHECK-NEXT: Kind: FUNCTION
+# CHECK-NEXT: Index: 1
+# CHECK-NEXT: - Name: shared_func
+# CHECK-NEXT: Kind: FUNCTION
+# CHECK-NEXT: Index: 5
+# CHECK-NEXT: - Name: _start
+# CHECK-NEXT: Kind: FUNCTION
+# CHECK-NEXT: Index: 6
+# CHECK-NEXT: - Type: ELEM
+# CHECK-NEXT: Segments:
+# CHECK-NEXT: - Offset:
+# CHECK-NEXT: Opcode: GLOBAL_GET
+# CHECK-NEXT: Index: 2
+# CHECK-NEXT: Functions: [ 3, 5 ]
+
+
+# DIS: <test_indirect_local_func_call>:
+# DIS-EMPTY:
+# DIS-NEXT: global.get 1
+# DIS-NEXT: i64.const 0
+# DIS-NEXT: i64.add
+# DIS-NEXT: i32.wrap_i64
+# DIS-NEXT: call_indirect 0
+# DIS-NEXT: end
+
+# DIS: <test_indirect_shared_func_call>:
+# DIS-EMPTY:
+# DIS-NEXT: i32.const 12345
+# DIS-NEXT: global.get 1
+# DIS-NEXT: i64.const 1
+# DIS-NEXT: i64.add
+# DIS-NEXT: i32.wrap_i64
+# DIS-NEXT: call_indirect 1
+# DIS-NEXT: drop
+# DIS-NEXT: end
diff --git a/lld/wasm/Relocations.cpp b/lld/wasm/Relocations.cpp
index 6f33a4f28a9d09..bb9c53954d589d 100644
--- a/lld/wasm/Relocations.cpp
+++ b/lld/wasm/Relocations.cpp
@@ -102,13 +102,27 @@ void scanRelocations(InputChunk *chunk) {
switch (reloc.Type) {
case R_WASM_TABLE_INDEX_I32:
case R_WASM_TABLE_INDEX_I64:
+ // These relocations target the data section and are handled
+ // by `generateRelocationCode`. GOT accesses are handled below.
+ if (requiresGOTAccess(sym))
+ break;
+ out.elemSec->addEntry(cast<FunctionSymbol>(sym));
+ break;
case R_WASM_TABLE_INDEX_SLEB:
case R_WASM_TABLE_INDEX_SLEB64:
case R_WASM_TABLE_INDEX_REL_SLEB:
case R_WASM_TABLE_INDEX_REL_SLEB64:
- if (requiresGOTAccess(sym))
- break;
- out.elemSec->addEntry(cast<FunctionSymbol>(sym));
+ // These relocations target the code section and can only be resolved
+ // at linking time.
+ if (requiresGOTAccess(sym)) {
+ addGOTEntry(sym);
+ }
+ // The indirect call needs a table element that can only be added
+ // for defined functions.
+ if (sym->isDefined()) {
+ out.elemSec->addEntry(cast<FunctionSymbol>(sym));
+ }
+ // Unresolved symbols are handled below.
break;
case R_WASM_GLOBAL_INDEX_LEB:
case R_WASM_GLOBAL_INDEX_I32:
@@ -160,6 +174,15 @@ void scanRelocations(InputChunk *chunk) {
" cannot be used against symbol `" + toString(*sym) +
"`; recompile with -fPIC");
break;
+ case R_WASM_TABLE_INDEX_REL_SLEB:
+ case R_WASM_TABLE_INDEX_REL_SLEB64:
+ if (sym->isUndefined()) {
+ error(toString(file) + ": relocation " +
+ relocTypeToString(reloc.Type) +
+ " cannot be used against an undefined symbol `" +
+ toString(*sym) + "`");
+ }
+ break;
case R_WASM_TABLE_INDEX_I32:
case R_WASM_TABLE_INDEX_I64:
case R_WASM_MEMORY_ADDR_I32:
More information about the llvm-commits
mailing list