1From 93adcb770b99351b18553089c164fe3ef2119699 Mon Sep 17 00:00:00 2001
2From: Sam Clegg <sbc@chromium.org>
3Date: Fri, 25 Aug 2023 13:56:16 -0700
4Subject: [PATCH] [lld][WebAssembly] Add `--table-base` setting
5
6This is similar to `--global-base` but determines where to place the
7table segments rather than that data segments.
8
9See https://github.com/emscripten-core/emscripten/issues/20097
10
11Differential Revision: https://reviews.llvm.org/D158892
12---
13 test/wasm/table-base.s | 72 ++++++++++++++++++++++++++++++++++++++
14 wasm/Driver.cpp | 19 ++++++++--
15 wasm/Options.td | 5 ++-
16 wasm/Writer.cpp | 8 -----
17 4 files changed, 93 insertions(+), 11 deletions(-)
18 create mode 100644 test/wasm/table-base.s
19
20diff --git a/test/wasm/table-base.s b/test/wasm/table-base.s
21new file mode 100644
22index 000000000000000..56fff414fd31d96
23--- /dev/null
24+++ b/test/wasm/table-base.s
25@@ -0,0 +1,72 @@
26+# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %s -o %t.o
27+
28+# RUN: wasm-ld --export=__table_base -o %t.wasm %t.o
29+# RUN: obj2yaml %t.wasm | FileCheck %s -check-prefix=CHECK-DEFAULT
30+
31+# RUN: wasm-ld --table-base=100 --export=__table_base -o %t.wasm %t.o
32+# RUN: obj2yaml %t.wasm | FileCheck %s -check-prefix=CHECK-100
33+
34+.globl _start
35+_start:
36+ .functype _start () -> ()
37+ i32.const _start
38+ drop
39+ end_function
40+
41+# CHECK-DEFAULT: - Type: TABLE
42+# CHECK-DEFAULT-NEXT: Tables:
43+# CHECK-DEFAULT-NEXT: - Index: 0
44+# CHECK-DEFAULT-NEXT: ElemType: FUNCREF
45+# CHECK-DEFAULT-NEXT: Limits:
46+# CHECK-DEFAULT-NEXT: Flags: [ HAS_MAX ]
47+# CHECK-DEFAULT-NEXT: Minimum: 0x2
48+# CHECK-DEFAULT-NEXT: Maximum: 0x2
49+
50+# CHECK-DEFAULT: - Type: GLOBAL
51+# CHECK-DEFAULT-NEXT: Globals:
52+# CHECK-DEFAULT-NEXT: - Index: 0
53+# CHECK-DEFAULT-NEXT: Type: I32
54+# CHECK-DEFAULT-NEXT: Mutable: true
55+# CHECK-DEFAULT-NEXT: InitExpr:
56+# CHECK-DEFAULT-NEXT: Opcode: I32_CONST
57+# CHECK-DEFAULT-NEXT: Value: 66560
58+# CHECK-DEFAULT-NEXT: - Index: 1
59+# CHECK-DEFAULT-NEXT: Type: I32
60+# CHECK-DEFAULT-NEXT: Mutable: false
61+# CHECK-DEFAULT-NEXT: InitExpr:
62+# CHECK-DEFAULT-NEXT: Opcode: I32_CONST
63+# CHECK-DEFAULT-NEXT: Value: 1
64+
65+# CHECK-DEFAULT: - Type: EXPORT
66+# CHECK-DEFAULT: - Name: __table_base
67+# CHECK-DEFAULT-NEXT: Kind: GLOBAL
68+# CHECK-DEFAULT-NEXT: Index: 1
69+
70+# CHECK-100: - Type: TABLE
71+# CHECK-100-NEXT: Tables:
72+# CHECK-100-NEXT: - Index: 0
73+# CHECK-100-NEXT: ElemType: FUNCREF
74+# CHECK-100-NEXT: Limits:
75+# CHECK-100-NEXT: Flags: [ HAS_MAX ]
76+# CHECK-100-NEXT: Minimum: 0x65
77+# CHECK-100-NEXT: Maximum: 0x65
78+
79+# CHECK-100: - Type: GLOBAL
80+# CHECK-100-NEXT: Globals:
81+# CHECK-100-NEXT: - Index: 0
82+# CHECK-100-NEXT: Type: I32
83+# CHECK-100-NEXT: Mutable: true
84+# CHECK-100-NEXT: InitExpr:
85+# CHECK-100-NEXT: Opcode: I32_CONST
86+# CHECK-100-NEXT: Value: 66560
87+# CHECK-100-NEXT: - Index: 1
88+# CHECK-100-NEXT: Type: I32
89+# CHECK-100-NEXT: Mutable: false
90+# CHECK-100-NEXT: InitExpr:
91+# CHECK-100-NEXT: Opcode: I32_CONST
92+# CHECK-100-NEXT: Value: 100
93+
94+# CHECK-100: - Type: EXPORT
95+# CHECK-100: - Name: __table_base
96+# CHECK-100-NEXT: Kind: GLOBAL
97+# CHECK-100-NEXT: Index: 1
98diff --git a/wasm/Driver.cpp b/wasm/Driver.cpp
99index 84304881f5ca34e..c2f5f0185781f36 100644
100--- a/wasm/Driver.cpp
101+++ b/wasm/Driver.cpp
102@@ -502,6 +502,7 @@ static void readConfigs(opt::InputArgList &args) {
103
104 config->initialMemory = args::getInteger(args, OPT_initial_memory, 0);
105 config->globalBase = args::getInteger(args, OPT_global_base, 0);
106+ config->tableBase = args::getInteger(args, OPT_table_base, 0);
107 config->maxMemory = args::getInteger(args, OPT_max_memory, 0);
108 config->zStackSize =
109 args::getZOptionValue(args, OPT_z, "stack-size", WasmPageSize);
110@@ -573,6 +574,17 @@ static void setConfigs() {
111 if (config->exportTable)
112 error("-shared/-pie is incompatible with --export-table");
113 config->importTable = true;
114+ } else {
115+ // Default table base. Defaults to 1, reserving 0 for the NULL function
116+ // pointer.
117+ if (!config->tableBase)
118+ config->tableBase = 1;
119+ // The default offset for static/global data, for when --global-base is
120+ // not specified on the command line. The precise value of 1024 is
121+ // somewhat arbitrary, and pre-dates wasm-ld (Its the value that
122+ // emscripten used prior to wasm-ld).
123+ if (!config->globalBase && !config->relocatable && !config->stackFirst)
124+ config->globalBase = 1024;
125 }
126
127 if (config->relocatable) {
128@@ -666,8 +678,11 @@ static void checkOptions(opt::InputArgList &args) {
129 warn("-Bsymbolic is only meaningful when combined with -shared");
130 }
131
132- if (config->globalBase && config->isPic) {
133- error("--global-base may not be used with -shared/-pie");
134+ if (config->isPic) {
135+ if (config->globalBase)
136+ error("--global-base may not be used with -shared/-pie");
137+ if (config->tableBase)
138+ error("--table-base may not be used with -shared/-pie");
139 }
140 }
141
142diff --git a/wasm/Options.td b/wasm/Options.td
143index 50417d2928e0a34..bb764396bf4df14 100644
144--- a/wasm/Options.td
145+++ b/wasm/Options.td
146@@ -191,7 +191,7 @@ def growable_table: FF<"growable-table">,
147 HelpText<"Remove maximum size from function table, allowing table to grow">;
148
149 def global_base: JJ<"global-base=">,
150- HelpText<"Where to start to place global data">;
151+ HelpText<"Memory offset at which to place global data (Defaults to 1024)">;
152
153 def import_memory: FF<"import-memory">,
154 HelpText<"Import the module's memory from the default module of \"env\" with the name \"memory\".">;
155@@ -224,6 +224,9 @@ def no_entry: FF<"no-entry">,
156 def stack_first: FF<"stack-first">,
157 HelpText<"Place stack at start of linear memory rather than after data">;
158
159+def table_base: JJ<"table-base=">,
160+ HelpText<"Table offset at which to place address taken functions (Defaults to 1)">;
161+
162 defm whole_archive: B<"whole-archive",
163 "Force load of all members in a static library",
164 "Do not force load of all members in a static library (default)">;
165diff --git a/wasm/Writer.cpp b/wasm/Writer.cpp
166index f25d358dc5bae6f..0576bf2907e49c4 100644
167--- a/wasm/Writer.cpp
168+++ b/wasm/Writer.cpp
169@@ -358,13 +358,6 @@ void Writer::layoutMemory() {
170 memoryPtr = config->globalBase;
171 }
172 } else {
173- if (!config->globalBase && !config->relocatable && !config->isPic) {
174- // The default offset for static/global data, for when --global-base is
175- // not specified on the command line. The precise value of 1024 is
176- // somewhat arbitrary, and pre-dates wasm-ld (Its the value that
177- // emscripten used prior to wasm-ld).
178- config->globalBase = 1024;
179- }
180 memoryPtr = config->globalBase;
181 }
182
183@@ -1685,7 +1678,6 @@ void Writer::run() {
184 // For PIC code the table base is assigned dynamically by the loader.
185 // For non-PIC, we start at 1 so that accessing table index 0 always traps.
186 if (!config->isPic) {
187- config->tableBase = 1;
188 if (WasmSym::definedTableBase)
189 WasmSym::definedTableBase->setVA(config->tableBase);
190 if (WasmSym::definedTableBase32)