Skip to content

Commit cd1b8ce

Browse files
committed
Don't build MAIN_MODULE as RELOCATABLE
The main advantage here is that main module no longer requires relocation entries for symbols defined locally. Fixes: #12682
1 parent 40261df commit cd1b8ce

22 files changed

+250
-257
lines changed

emcc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ def phase_setup(options, state):
413413
'unused-command-line-argument',
414414
"linker flag ignored during compilation: '%s'" % arg)
415415

416-
if settings.MAIN_MODULE or settings.SIDE_MODULE:
416+
if settings.SIDE_MODULE:
417417
settings.RELOCATABLE = 1
418418

419419
if 'USE_PTHREADS' in user_settings:

src/jsifier.mjs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ function isDefined(symName) {
121121
}
122122
// 'invoke_' symbols are created at runtime in library_dylink.py so can
123123
// always be considered as defined.
124-
if (RELOCATABLE && symName.startsWith('invoke_')) {
124+
if ((MAIN_MODULE || RELOCATABLE) && symName.startsWith('invoke_')) {
125125
return true;
126126
}
127127
return false;
@@ -572,7 +572,7 @@ function(${args}) {
572572
if (!LibraryManager.library.hasOwnProperty(symbol)) {
573573
const isWeakImport = WEAK_IMPORTS.has(symbol);
574574
if (!isDefined(symbol) && !isWeakImport) {
575-
if (PROXY_TO_PTHREAD && !MAIN_MODULE && symbol == '__main_argc_argv') {
575+
if (PROXY_TO_PTHREAD && !(MAIN_MODULE || RELOCATABLE) && symbol == '__main_argc_argv') {
576576
error('PROXY_TO_PTHREAD proxies main() for you, but no main exists');
577577
return;
578578
}
@@ -603,7 +603,7 @@ function(${args}) {
603603

604604
// emit a stub that will fail at runtime
605605
var stubFunctionBody = `abort('missing function: ${symbol}');`
606-
if (RELOCATABLE) {
606+
if (RELOCATABLE || MAIN_MODULE) {
607607
// Create a stub for this symbol which can later be replaced by the
608608
// dynamic linker. If this stub is called before the symbol is
609609
// resolved assert in debug builds or trap in release builds.
@@ -762,8 +762,8 @@ function(${args}) {
762762
contentText = 'export ' + contentText;
763763
}
764764

765-
// Relocatable code needs signatures to create proper wrappers.
766-
if (sig && RELOCATABLE) {
765+
// Dynamic linking needs signatures to create proper wrappers.
766+
if (sig && (MAIN_MODULE || RELOCATABLE)) {
767767
if (!WASM_BIGINT) {
768768
sig = sig[0].replace('j', 'i') + sig.slice(1).replace(/j/g, 'ii');
769769
}
@@ -774,7 +774,7 @@ function(${args}) {
774774
}
775775
if (isStub) {
776776
contentText += `\n${mangled}.stub = true;`;
777-
if (ASYNCIFY && MAIN_MODULE) {
777+
if (ASYNCIFY && (MAIN_MODULE || RELOCATABLE)) {
778778
contentText += `\nasyncifyStubs['${symbol}'] = undefined;`;
779779
}
780780
}

src/lib/libasync.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ addToLibrary({
2121

2222
#if ASYNCIFY
2323
$Asyncify__deps: ['$runAndAbortIfError', '$callUserCallback',
24+
#if ASSERTIONS
25+
'$createNamedFunction',
26+
#endif
2427
#if !MINIMAL_RUNTIME
2528
'$runtimeKeepalivePush', '$runtimeKeepalivePop',
2629
#endif
@@ -143,6 +146,9 @@ addToLibrary({
143146
#endif
144147
#if MAIN_MODULE
145148
wrapper.orig = original;
149+
#endif
150+
#if ASSERTIONS
151+
wrapper = createNamedFunction(`async_wrapper_${original.name}`, wrapper);
146152
#endif
147153
return wrapper;
148154
},

src/lib/libcore.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1775,6 +1775,9 @@ addToLibrary({
17751775
},
17761776

17771777
$dynCall: (sig, ptr, args = [], promising = false) => {
1778+
#if ASSERTIONS
1779+
assert(ptr, `null function pointer in dynCall`);
1780+
#endif
17781781
#if ASSERTIONS && (DYNCALLS || !WASM_BIGINT || !JSPI)
17791782
assert(!promising, 'async dynCall is not supported in this mode')
17801783
#endif
@@ -2187,6 +2190,17 @@ addToLibrary({
21872190
#endif
21882191
},
21892192

2193+
#if MAIN_MODULE || RELOCATABLE
2194+
#if WASM_EXCEPTIONS
2195+
// In dynamic linking we define tags here and feed them to each module
2196+
__cpp_exception: "new WebAssembly.Tag({'parameters': ['{{{ POINTER_WASM_TYPE }}}']})",
2197+
#endif
2198+
2199+
#if SUPPORT_LONGJMP == 'wasm'
2200+
__c_longjmp: "new WebAssembly.Tag({'parameters': ['{{{ POINTER_WASM_TYPE }}}']})",
2201+
#endif
2202+
#endif
2203+
21902204
#if RELOCATABLE
21912205
// Globals that are normally exported from the wasm module but in relocatable
21922206
// mode are created here and imported by the module.
@@ -2210,11 +2224,12 @@ addToLibrary({
22102224
__stack_high: '{{{ STACK_HIGH }}}',
22112225
__stack_low: '{{{ STACK_LOW }}}',
22122226
__global_base: '{{{ GLOBAL_BASE }}}',
2213-
#if ASYNCIFY == 1
2227+
#endif // RELOCATABLE
2228+
2229+
#if (MAIN_MODULE || RELOCATABLE) && ASYNCIFY == 1
22142230
__asyncify_state: "new WebAssembly.Global({'value': 'i32', 'mutable': true}, 0)",
22152231
__asyncify_data: "new WebAssembly.Global({'value': '{{{ POINTER_WASM_TYPE }}}', 'mutable': true}, {{{ to64(0) }}})",
22162232
#endif
2217-
#endif // RELOCATABLE
22182233

22192234
_emscripten_fs_load_embedded_files__deps: ['$FS', '$PATH'],
22202235
_emscripten_fs_load_embedded_files: (ptr) => {

src/lib/libdylink.js

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
* Dynamic library loading
77
*/
88

9-
#if !RELOCATABLE
10-
#error "library_dylink.js requires RELOCATABLE"
9+
#if !MAIN_MODULE && !RELOCATABLE
10+
#error "library_dylink.js requires MAIN_MODULE or RELOCATABLE"
1111
#endif
1212

1313
var LibraryDylink = {
@@ -170,10 +170,10 @@ var LibraryDylink = {
170170
get(obj, symName) {
171171
var rtn = GOT[symName];
172172
if (!rtn) {
173-
rtn = GOT[symName] = new WebAssembly.Global({'value': '{{{ POINTER_WASM_TYPE }}}', 'mutable': true});
174173
#if DYLINK_DEBUG == 2
175-
dbg("new GOT entry: " + symName);
174+
dbg(`new GOT entry: ${symName}`);
176175
#endif
176+
rtn = GOT[symName] = new WebAssembly.Global({'value': '{{{ POINTER_WASM_TYPE }}}', 'mutable': true}, {{{ to64(-1) }}});
177177
}
178178
if (!currentModuleWeakSymbols.has(symName)) {
179179
// Any non-weak reference to a symbol marks it as `required`, which
@@ -189,6 +189,11 @@ var LibraryDylink = {
189189
$isInternalSym: (symName) => {
190190
// TODO: find a way to mark these in the binary or avoid exporting them.
191191
return [
192+
'memory',
193+
'__memory_base',
194+
'__table_base',
195+
'__stack_pointer',
196+
'__indirect_function_table',
192197
'__cpp_exception',
193198
'__c_longjmp',
194199
'__wasm_apply_data_relocs',
@@ -213,6 +218,7 @@ var LibraryDylink = {
213218

214219
$updateGOT__internal: true,
215220
$updateGOT__deps: ['$GOT', '$isInternalSym', '$addFunction'],
221+
$updateGOT__docs: '/** @param {boolean=} replace */',
216222
$updateGOT: (exports, replace) => {
217223
#if DYLINK_DEBUG
218224
dbg(`updateGOT: adding ${Object.keys(exports).length} symbols`);
@@ -230,18 +236,14 @@ var LibraryDylink = {
230236
}
231237
#endif
232238

233-
234-
var existingEntry = GOT[symName] && GOT[symName].value != 0;
239+
var existingEntry = GOT[symName] && GOT[symName].value != {{{ to64(-1) }}};
235240
if (replace || !existingEntry) {
236241
#if DYLINK_DEBUG == 2
237-
dbg(`updateGOT: before: ${symName} : ${GOT[symName].value}`);
242+
dbg(`updateGOT: before: ${symName} : ${GOT[symName]?.value}`);
238243
#endif
239244
var newValue;
240245
if (typeof value == 'function') {
241246
newValue = {{{ to64('addFunction(value)') }}};
242-
#if DYLINK_DEBUG == 2
243-
dbg(`updateGOT: FUNC: ${symName} : ${GOT[symName].value}`);
244-
#endif
245247
} else if (typeof value == {{{ POINTER_JS_TYPE }}}) {
246248
newValue = value;
247249
} else {
@@ -255,7 +257,7 @@ var LibraryDylink = {
255257
#if DYLINK_DEBUG == 2
256258
dbg(`updateGOT: after: ${symName} : ${newValue} (${value})`);
257259
#endif
258-
GOT[symName] ||= new WebAssembly.Global({'value': '{{{ POINTER_WASM_TYPE }}}', 'mutable': true});
260+
GOT[symName] ??= new WebAssembly.Global({'value': '{{{ POINTER_WASM_TYPE }}}', 'mutable': true});
259261
GOT[symName].value = newValue;
260262
}
261263
#if DYLINK_DEBUG
@@ -283,9 +285,12 @@ var LibraryDylink = {
283285

284286
// Applies relocations to exported things.
285287
$relocateExports__internal: true,
286-
$relocateExports__deps: ['$updateGOT', '$isImmutableGlobal'],
287-
$relocateExports__docs: '/** @param {boolean=} replace */',
288-
$relocateExports: (exports, memoryBase, replace) => {
288+
$relocateExports__deps: ['$isImmutableGlobal'],
289+
$relocateExports: (exports, memoryBase = 0) => {
290+
#if DYLINK_DEBUG
291+
dbg(`relocateExports memoryBase=${memoryBase} count=${Object.keys(exports).length}`);
292+
#endif
293+
289294
function relocateExport(name, value) {
290295
#if SPLIT_MODULE
291296
// Do not modify exports synthesized by wasm-split
@@ -307,7 +312,6 @@ var LibraryDylink = {
307312
for (var e in exports) {
308313
relocated[e] = relocateExport(e, exports[e])
309314
}
310-
updateGOT(relocated, replace);
311315
return relocated;
312316
},
313317

@@ -318,13 +322,17 @@ var LibraryDylink = {
318322
dbg('reportUndefinedSymbols');
319323
#endif
320324
for (var [symName, entry] of Object.entries(GOT)) {
321-
if (entry.value == 0) {
325+
if (entry.value == {{{ to64(-1) }}}) {
326+
#if DYLINK_DEBUG
327+
dbg(`undef GOT entry: ${symName}`);
328+
#endif
322329
var value = resolveGlobalSymbol(symName, true).sym;
323330
if (!value && !entry.required) {
324331
// Ignore undefined symbols that are imported as weak.
325332
#if DYLINK_DEBUG
326333
dbg('ignoring undefined weak symbol:', symName);
327334
#endif
335+
entry.value = 0;
328336
continue;
329337
}
330338
#if ASSERTIONS
@@ -346,7 +354,7 @@ var LibraryDylink = {
346354
entry.value = value;
347355
#endif
348356
} else {
349-
throw new Error(`bad export type for '${symName}': ${typeof value}`);
357+
throw new Error(`bad export type for '${symName}': ${typeof value} (${value})`);
350358
}
351359
}
352360
}
@@ -393,7 +401,7 @@ var LibraryDylink = {
393401
// Allocate memory even if malloc isn't ready yet. The allocated memory here
394402
// must be zero initialized since its used for all static data, including bss.
395403
$getMemory__noleakcheck: true,
396-
$getMemory__deps: ['$GOT', '__heap_base', '$alignMemory', 'calloc'],
404+
$getMemory__deps: ['$GOT', 'emscripten_get_sbrk_ptr', '__heap_base', '$alignMemory', 'calloc'],
397405
$getMemory: (size) => {
398406
// After the runtime is initialized, we must only use sbrk() normally.
399407
#if DYLINK_DEBUG
@@ -411,8 +419,15 @@ var LibraryDylink = {
411419
#if ASSERTIONS
412420
assert(end <= HEAP8.length, 'failure to getMemory - memory growth etc. is not supported there, call malloc/sbrk directly or increase INITIAL_MEMORY');
413421
#endif
414-
___heap_base = end;
415-
GOT['__heap_base'].value = {{{ to64('end') }}};
422+
___heap_base = {{{ to64('end') }}};
423+
#if PTHREADS
424+
if (!ENVIRONMENT_IS_PTHREAD) {
425+
#endif
426+
var sbrk_ptr = _emscripten_get_sbrk_ptr();
427+
{{{ makeSetValue('sbrk_ptr', 0, 'end', '*') }}}
428+
#if PTHREADS
429+
}
430+
#endif
416431
return ret;
417432
},
418433

@@ -625,7 +640,7 @@ var LibraryDylink = {
625640
* @param {number=} handle
626641
*/`,
627642
$loadWebAssemblyModule__deps: [
628-
'$loadDynamicLibrary', '$getMemory',
643+
'$loadDynamicLibrary', '$getMemory', '$updateGOT',
629644
'$relocateExports', '$resolveGlobalSymbol', '$GOTHandler',
630645
'$getDylinkMetadata', '$alignMemory',
631646
'$currentModuleWeakSymbols',
@@ -635,7 +650,7 @@ var LibraryDylink = {
635650
],
636651
$loadWebAssemblyModule: (binary, flags, libName, localScope, handle) => {
637652
#if DYLINK_DEBUG
638-
dbg('loadWebAssemblyModule:', libName);
653+
dbg('loadWebAssemblyModule:', libName, handle);
639654
#endif
640655
var metadata = getDylinkMetadata(binary);
641656

@@ -654,6 +669,9 @@ var LibraryDylink = {
654669
// exclusive access to it for the duration of this function. See the
655670
// locking in `dynlink.c`.
656671
var firstLoad = !handle || !{{{ makeGetValue('handle', C_STRUCTS.dso.mem_allocated, 'i8') }}};
672+
#if DYLINK_DEBUG
673+
dbg('firstLoad:', firstLoad);
674+
#endif
657675
if (firstLoad) {
658676
#endif
659677
// alignments are powers of 2
@@ -790,6 +808,7 @@ var LibraryDylink = {
790808
// add new entries to functionsInTableMap
791809
updateTableMap(tableBase, metadata.tableSize);
792810
moduleExports = relocateExports(instance.exports, memoryBase);
811+
updateGOT(moduleExports);
793812
#if ASYNCIFY
794813
moduleExports = Asyncify.instrumentWasmExports(moduleExports);
795814
#endif
@@ -881,18 +900,27 @@ var LibraryDylink = {
881900
if (applyRelocs) {
882901
if (runtimeInitialized) {
883902
#if DYLINK_DEBUG
884-
dbg('applyRelocs');
903+
dbg('running __wasm_apply_data_relocs');
885904
#endif
886905
applyRelocs();
887906
} else {
907+
#if DYLINK_DEBUG
908+
dbg('delaying __wasm_apply_data_relocs');
909+
#endif
888910
__RELOC_FUNCS__.push(applyRelocs);
889911
}
890912
}
891913
var init = moduleExports['__wasm_call_ctors'];
892914
if (init) {
893915
if (runtimeInitialized) {
916+
#if DYLINK_DEBUG
917+
dbg('running __wasm_call_ctors');
918+
#endif
894919
init();
895920
} else {
921+
#if DYLINK_DEBUG
922+
dbg('delaying __wasm_call_ctors');
923+
#endif
896924
// we aren't ready to run compiled code yet
897925
addOnPostCtor(init);
898926
}

src/lib/libglemu.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ assert(!FULL_ES3, 'cannot emulate both ES3 and legacy GL');
1010

1111
{{{
1212
const copySigs = (func) => {
13-
if (!RELOCATABLE) return '';
13+
if (!MAIN_MODULE) return '';
1414
return ` _${func}.sig = _emscripten_${func}.sig = orig_${func}.sig;`;
1515
};
1616
const fromPtr = (arg) => {

src/lib/libpthread.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,7 @@ var LibraryPThread = {
594594
#if MAIN_MODULE
595595
$registerTLSInit: (tlsInitFunc, moduleExports, metadata) => {
596596
#if DYLINK_DEBUG
597-
dbg("registerTLSInit: " + tlsInitFunc);
597+
dbg('registerTLSInit:', tlsInitFunc, metadata?.tlsExports);
598598
#endif
599599
// In relocatable builds, we use the result of calling tlsInitFunc
600600
// (`_emscripten_tls_init`) to relocate the TLS exports of the module
@@ -613,7 +613,7 @@ var LibraryPThread = {
613613
}
614614
var tlsExports = {};
615615
metadata.tlsExports.forEach((s) => tlsExports[s] = moduleExports[s]);
616-
relocateExports(tlsExports, __tls_base, /*replace=*/true);
616+
updateGOT(relocateExports(tlsExports, __tls_base), /*replace=*/true);
617617
}
618618

619619
// Register this function so that its gets called for each thread on

src/modules.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ function calculateLibraries() {
9393
libraries.push('libsyscall.js');
9494
}
9595

96-
if (RELOCATABLE) {
96+
if (MAIN_MODULE || RELOCATABLE) {
9797
libraries.push('libdylink.js');
9898
}
9999

0 commit comments

Comments
 (0)