Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/src/lib/libdylink.js
4150 views
1
/**
2
* @license
3
* Copyright 2020 The Emscripten Authors
4
* SPDX-License-Identifier: MIT
5
*
6
* Dynamic library loading
7
*/
8
9
#if !RELOCATABLE
10
#error "library_dylink.js requires RELOCATABLE"
11
#endif
12
13
var LibraryDylink = {
14
#if FILESYSTEM
15
$registerWasmPlugin__deps: ['$preloadPlugins'],
16
$registerWasmPlugin: () => {
17
// Use string keys here for public methods to avoid minification since the
18
// plugin consumer also uses string keys.
19
var wasmPlugin = {
20
promiseChainEnd: Promise.resolve(),
21
'canHandle': (name) => {
22
return !Module['noWasmDecoding'] && name.endsWith('.so')
23
},
24
'handle': async (byteArray, name) =>
25
// loadWebAssemblyModule can not load modules out-of-order, so rather
26
// than just running the promises in parallel, this makes a chain of
27
// promises to run in series.
28
wasmPlugin.promiseChainEnd = wasmPlugin.promiseChainEnd.then(async () => {
29
try {
30
var exports = await loadWebAssemblyModule(byteArray, {loadAsync: true, nodelete: true}, name, {});
31
} catch (error) {
32
throw new Error(`failed to instantiate wasm: ${name}: ${error}`);
33
}
34
#if DYLINK_DEBUG
35
dbg('registering preloadedWasm:', name);
36
#endif
37
preloadedWasm[name] = exports;
38
return byteArray;
39
})
40
};
41
preloadPlugins.push(wasmPlugin);
42
},
43
44
$preloadedWasm__deps: ['$registerWasmPlugin'],
45
$preloadedWasm__postset: `
46
registerWasmPlugin();
47
`,
48
$preloadedWasm: {},
49
50
$replaceORIGIN__deps: ['$PATH'],
51
$replaceORIGIN: (parentLibName, rpath) => {
52
if (rpath.startsWith('$ORIGIN')) {
53
// TODO: what to do if we only know the relative path of the file? It will return "." here.
54
var origin = PATH.dirname(parentLibName);
55
return rpath.replace('$ORIGIN', origin);
56
}
57
58
return rpath;
59
},
60
#endif // FILESYSTEM
61
62
$isSymbolDefined: (symName) => {
63
// Ignore 'stub' symbols that are auto-generated as part of the original
64
// `wasmImports` used to instantiate the main module.
65
var existing = wasmImports[symName];
66
if (!existing || existing.stub) {
67
return false;
68
}
69
#if ASYNCIFY
70
// Even if a symbol exists in wasmImports, and is not itself a stub, it
71
// could be an ASYNCIFY wrapper function that wraps a stub function.
72
if (symName in asyncifyStubs && !asyncifyStubs[symName]) {
73
return false;
74
}
75
#endif
76
return true;
77
},
78
79
// Dynamic version of shared.py:make_invoke. This is needed for invokes
80
// that originate from side modules since these are not known at JS
81
// generation time.
82
#if !DISABLE_EXCEPTION_CATCHING || SUPPORT_LONGJMP == 'emscripten'
83
$createInvokeFunction__internal: true,
84
$createInvokeFunction__deps: ['$dynCall', 'setThrew', '$stackSave', '$stackRestore'],
85
$createInvokeFunction: (sig) => (ptr, ...args) => {
86
var sp = stackSave();
87
try {
88
return dynCall(sig, ptr, args);
89
} catch(e) {
90
stackRestore(sp);
91
// Create a try-catch guard that rethrows the Emscripten EH exception.
92
#if EXCEPTION_STACK_TRACES
93
// Exceptions thrown from C++ and longjmps will be an instance of
94
// EmscriptenEH.
95
if (!(e instanceof EmscriptenEH)) throw e;
96
#else
97
// Exceptions thrown from C++ will be a pointer (number) and longjmp
98
// will throw the number Infinity. Use the compact and fast "e !== e+0"
99
// test to check if e was not a Number.
100
if (e !== e+0) throw e;
101
#endif
102
_setThrew(1, 0);
103
#if WASM_BIGINT
104
// In theory this if statement could be done on
105
// creating the function, but I just added this to
106
// save wasting code space as it only happens on exception.
107
if (sig[0] == "j") return 0n;
108
#endif
109
}
110
},
111
#endif
112
113
// Resolve a global symbol by name. This is used during module loading to
114
// resolve imports, and by `dlsym` when used with `RTLD_DEFAULT`.
115
// Returns both the resolved symbol (i.e. a function or a global) along with
116
// the canonical name of the symbol (in some cases is modify the symbol as
117
// part of the loop process, so that actual symbol looked up has a different
118
// name).
119
$resolveGlobalSymbol__deps: ['$isSymbolDefined',
120
#if !DISABLE_EXCEPTION_CATCHING || SUPPORT_LONGJMP == 'emscripten'
121
'$createInvokeFunction',
122
#endif
123
],
124
$resolveGlobalSymbol__internal: true,
125
$resolveGlobalSymbol: (symName, direct = false) => {
126
var sym;
127
#if !WASM_BIGINT
128
// First look for the orig$ symbol which is the symbol without i64
129
// legalization performed.
130
if (direct && ('orig$' + symName in wasmImports)) {
131
symName = 'orig$' + symName;
132
}
133
#endif
134
if (isSymbolDefined(symName)) {
135
sym = wasmImports[symName];
136
}
137
#if !DISABLE_EXCEPTION_CATCHING || SUPPORT_LONGJMP == 'emscripten'
138
// Asm.js-style exception handling: invoke wrapper generation
139
else if (symName.startsWith('invoke_')) {
140
// Create (and cache) new invoke_ functions on demand.
141
sym = wasmImports[symName] = createInvokeFunction(symName.split('_')[1]);
142
}
143
#endif
144
#if !DISABLE_EXCEPTION_CATCHING
145
else if (symName.startsWith('__cxa_find_matching_catch_')) {
146
// When the main module is linked we create whichever variants of
147
// `__cxa_find_matching_catch_` (see jsifier.js) that we know are needed,
148
// but a side module loaded at runtime might need different/additional
149
// variants so we create those dynamically.
150
sym = wasmImports[symName] = (...args) => {
151
#if MEMORY64
152
args = args.map(Number);
153
#endif
154
var rtn = findMatchingCatch(args);
155
return {{{ to64('rtn') }}};
156
}
157
}
158
#endif
159
return {sym, name: symName};
160
},
161
162
$GOT: {},
163
$currentModuleWeakSymbols: '=new Set({{{ JSON.stringify(Array.from(WEAK_IMPORTS)) }}})',
164
165
// Create globals to each imported symbol. These are all initialized to zero
166
// and get assigned later in `updateGOT`
167
$GOTHandler__internal: true,
168
$GOTHandler__deps: ['$GOT', '$currentModuleWeakSymbols'],
169
$GOTHandler: {
170
get(obj, symName) {
171
var rtn = GOT[symName];
172
if (!rtn) {
173
rtn = GOT[symName] = new WebAssembly.Global({'value': '{{{ POINTER_WASM_TYPE }}}', 'mutable': true});
174
#if DYLINK_DEBUG == 2
175
dbg("new GOT entry: " + symName);
176
#endif
177
}
178
if (!currentModuleWeakSymbols.has(symName)) {
179
// Any non-weak reference to a symbol marks it as `required`, which
180
// enabled `reportUndefinedSymbols` to report undefined symbol errors
181
// correctly.
182
rtn.required = true;
183
}
184
return rtn;
185
}
186
},
187
188
$isInternalSym__internal: true,
189
$isInternalSym: (symName) => {
190
// TODO: find a way to mark these in the binary or avoid exporting them.
191
return [
192
'__cpp_exception',
193
'__c_longjmp',
194
'__wasm_apply_data_relocs',
195
'__dso_handle',
196
'__tls_size',
197
'__tls_align',
198
'__set_stack_limits',
199
'_emscripten_tls_init',
200
'__wasm_init_tls',
201
'__wasm_call_ctors',
202
'__start_em_asm',
203
'__stop_em_asm',
204
'__start_em_js',
205
'__stop_em_js',
206
].includes(symName) || symName.startsWith('__em_js__')
207
#if SPLIT_MODULE
208
// Exports synthesized by wasm-split should be prefixed with '%'
209
|| symName[0] == '%'
210
#endif
211
;
212
},
213
214
$updateGOT__internal: true,
215
$updateGOT__deps: ['$GOT', '$isInternalSym', '$addFunction'],
216
$updateGOT: (exports, replace) => {
217
#if DYLINK_DEBUG
218
dbg(`updateGOT: adding ${Object.keys(exports).length} symbols`);
219
#endif
220
for (var symName in exports) {
221
if (isInternalSym(symName)) {
222
continue;
223
}
224
225
var value = exports[symName];
226
#if !WASM_BIGINT
227
if (symName.startsWith('orig$')) {
228
symName = symName.split('$')[1];
229
replace = true;
230
}
231
#endif
232
233
GOT[symName] ||= new WebAssembly.Global({'value': '{{{ POINTER_WASM_TYPE }}}', 'mutable': true});
234
if (replace || GOT[symName].value == 0) {
235
#if DYLINK_DEBUG == 2
236
dbg(`updateGOT: before: ${symName} : ${GOT[symName].value}`);
237
#endif
238
if (typeof value == 'function') {
239
GOT[symName].value = {{{ to64('addFunction(value)') }}};
240
#if DYLINK_DEBUG == 2
241
dbg(`updateGOT: FUNC: ${symName} : ${GOT[symName].value}`);
242
#endif
243
} else if (typeof value == {{{ POINTER_JS_TYPE }}}) {
244
GOT[symName].value = value;
245
} else {
246
err(`unhandled export type for '${symName}': ${typeof value}`);
247
}
248
#if DYLINK_DEBUG == 2
249
dbg(`updateGOT: after: ${symName} : ${GOT[symName].value} (${value})`);
250
#endif
251
}
252
#if DYLINK_DEBUG
253
else if (GOT[symName].value != value) {
254
dbg(`updateGOT: EXISTING SYMBOL: ${symName} : ${GOT[symName].value} (${value})`);
255
}
256
#endif
257
}
258
#if DYLINK_DEBUG
259
dbg("done updateGOT");
260
#endif
261
},
262
263
// Applies relocations to exported things.
264
$relocateExports__internal: true,
265
$relocateExports__deps: ['$updateGOT'],
266
$relocateExports__docs: '/** @param {boolean=} replace */',
267
$relocateExports: (exports, memoryBase, replace) => {
268
var relocated = {};
269
270
for (var e in exports) {
271
var value = exports[e];
272
#if SPLIT_MODULE
273
// Do not modify exports synthesized by wasm-split
274
if (e.startsWith('%')) {
275
relocated[e] = value
276
continue;
277
}
278
#endif
279
if (typeof value == 'object') {
280
// a breaking change in the wasm spec, globals are now objects
281
// https://github.com/WebAssembly/mutable-global/issues/1
282
value = value.value;
283
}
284
if (typeof value == {{{ POINTER_JS_TYPE }}}) {
285
value += {{{ to64('memoryBase') }}};
286
}
287
relocated[e] = value;
288
}
289
updateGOT(relocated, replace);
290
return relocated;
291
},
292
293
$reportUndefinedSymbols__internal: true,
294
$reportUndefinedSymbols__deps: ['$GOT', '$resolveGlobalSymbol'],
295
$reportUndefinedSymbols: () => {
296
#if DYLINK_DEBUG
297
dbg('reportUndefinedSymbols');
298
#endif
299
for (var [symName, entry] of Object.entries(GOT)) {
300
if (entry.value == 0) {
301
var value = resolveGlobalSymbol(symName, true).sym;
302
if (!value && !entry.required) {
303
// Ignore undefined symbols that are imported as weak.
304
#if DYLINK_DEBUG
305
dbg('ignoring undefined weak symbol:', symName);
306
#endif
307
continue;
308
}
309
#if ASSERTIONS
310
assert(value, `undefined symbol '${symName}'. perhaps a side module was not linked in? if this global was expected to arrive from a system library, try to build the MAIN_MODULE with EMCC_FORCE_STDLIBS=1 in the environment`);
311
#endif
312
#if DYLINK_DEBUG == 2
313
dbg(`assigning dynamic symbol from main module: ${symName} -> ${prettyPrint(value)}`);
314
#endif
315
if (typeof value == 'function') {
316
/** @suppress {checkTypes} */
317
entry.value = {{{ to64('addFunction(value, value.sig)') }}};
318
#if DYLINK_DEBUG == 2
319
dbg(`assigning table entry for : ${symName} -> ${entry.value}`);
320
#endif
321
} else if (typeof value == 'number') {
322
entry.value = {{{ to64('value') }}};
323
#if MEMORY64
324
} else if (typeof value == 'bigint') {
325
entry.value = value;
326
#endif
327
} else {
328
throw new Error(`bad export type for '${symName}': ${typeof value}`);
329
}
330
}
331
}
332
#if DYLINK_DEBUG
333
dbg('done reportUndefinedSymbols');
334
#endif
335
},
336
337
// dynamic linker/loader (a-la ld.so on ELF systems)
338
$LDSO__deps: ['$newDSO'],
339
$LDSO: {
340
// name -> dso [refcount, name, module, global]; Used by dlopen
341
loadedLibsByName: {},
342
// handle -> dso; Used by dlsym
343
loadedLibsByHandle: {},
344
init() {
345
#if ASSERTIONS
346
// This function needs to run after the initial wasmImports object
347
// as been created.
348
assert(wasmImports);
349
#endif
350
newDSO('__main__', {{{ cDefs.RTLD_DEFAULT }}}, wasmImports);
351
},
352
},
353
354
$dlSetError__internal: true,
355
$dlSetError__deps: ['__dl_seterr', '$stringToUTF8OnStack', '$stackSave', '$stackRestore'],
356
$dlSetError: (msg) => {
357
#if DYLINK_DEBUG
358
dbg('dlSetError:', msg);
359
#endif
360
var sp = stackSave();
361
var cmsg = stringToUTF8OnStack(msg);
362
___dl_seterr(cmsg, 0);
363
stackRestore(sp);
364
},
365
366
// We support some amount of allocation during startup in the case of
367
// dynamic linking, which needs to allocate memory for dynamic libraries that
368
// are loaded. That has to happen before the main program can start to run,
369
// because the main program needs those linked in before it runs (so we can't
370
// use normally malloc from the main program to do these allocations).
371
//
372
// Allocate memory even if malloc isn't ready yet. The allocated memory here
373
// must be zero initialized since its used for all static data, including bss.
374
$getMemory__noleakcheck: true,
375
$getMemory__deps: ['$GOT', '__heap_base', '$alignMemory', 'calloc'],
376
$getMemory: (size) => {
377
// After the runtime is initialized, we must only use sbrk() normally.
378
#if DYLINK_DEBUG
379
dbg("getMemory: " + size + " runtimeInitialized=" + runtimeInitialized);
380
#endif
381
if (runtimeInitialized) {
382
// Currently we don't support freeing of static data when modules are
383
// unloaded via dlclose. This function is tagged as `noleakcheck` to
384
// avoid having this reported as leak.
385
return _calloc(size, 1);
386
}
387
var ret = ___heap_base;
388
// Keep __heap_base stack aligned.
389
var end = ret + alignMemory(size, {{{ STACK_ALIGN }}});
390
#if ASSERTIONS
391
assert(end <= HEAP8.length, 'failure to getMemory - memory growth etc. is not supported there, call malloc/sbrk directly or increase INITIAL_MEMORY');
392
#endif
393
___heap_base = end;
394
GOT['__heap_base'].value = {{{ to64('end') }}};
395
return ret;
396
},
397
398
// returns the side module metadata as an object
399
// { memorySize, memoryAlign, tableSize, tableAlign, neededDynlibs}
400
$getDylinkMetadata__deps: ['$UTF8ArrayToString'],
401
$getDylinkMetadata__internal: true,
402
$getDylinkMetadata: (binary) => {
403
var offset = 0;
404
var end = 0;
405
406
function getU8() {
407
return binary[offset++];
408
}
409
410
function getLEB() {
411
var ret = 0;
412
var mul = 1;
413
while (1) {
414
var byte = binary[offset++];
415
ret += ((byte & 0x7f) * mul);
416
mul *= 0x80;
417
if (!(byte & 0x80)) break;
418
}
419
return ret;
420
}
421
422
function getString() {
423
var len = getLEB();
424
offset += len;
425
return UTF8ArrayToString(binary, offset - len, len);
426
}
427
428
function getStringList() {
429
var count = getLEB();
430
var rtn = []
431
while (count--) rtn.push(getString());
432
return rtn;
433
}
434
435
/** @param {string=} message */
436
function failIf(condition, message) {
437
if (condition) throw new Error(message);
438
}
439
440
if (binary instanceof WebAssembly.Module) {
441
var dylinkSection = WebAssembly.Module.customSections(binary, 'dylink.0');
442
failIf(dylinkSection.length === 0, 'need dylink section');
443
binary = new Uint8Array(dylinkSection[0]);
444
end = binary.length
445
} else {
446
var int32View = new Uint32Array(new Uint8Array(binary.subarray(0, 24)).buffer);
447
#if SUPPORT_BIG_ENDIAN
448
var magicNumberFound = int32View[0] == 0x6d736100 || int32View[0] == 0x0061736d;
449
#else
450
var magicNumberFound = int32View[0] == 0x6d736100;
451
#endif
452
failIf(!magicNumberFound, 'need to see wasm magic number'); // \0asm
453
// we should see the dylink custom section right after the magic number and wasm version
454
failIf(binary[8] !== 0, 'need the dylink section to be first')
455
offset = 9;
456
var section_size = getLEB(); //section size
457
end = offset + section_size;
458
var name = getString();
459
failIf(name !== 'dylink.0');
460
}
461
462
var customSection = { neededDynlibs: [], tlsExports: new Set(), weakImports: new Set(), runtimePaths: [] };
463
var WASM_DYLINK_MEM_INFO = 0x1;
464
var WASM_DYLINK_NEEDED = 0x2;
465
var WASM_DYLINK_EXPORT_INFO = 0x3;
466
var WASM_DYLINK_IMPORT_INFO = 0x4;
467
var WASM_DYLINK_RUNTIME_PATH = 0x5;
468
var WASM_SYMBOL_TLS = 0x100;
469
var WASM_SYMBOL_BINDING_MASK = 0x3;
470
var WASM_SYMBOL_BINDING_WEAK = 0x1;
471
while (offset < end) {
472
var subsectionType = getU8();
473
var subsectionSize = getLEB();
474
if (subsectionType === WASM_DYLINK_MEM_INFO) {
475
customSection.memorySize = getLEB();
476
customSection.memoryAlign = getLEB();
477
customSection.tableSize = getLEB();
478
customSection.tableAlign = getLEB();
479
} else if (subsectionType === WASM_DYLINK_NEEDED) {
480
customSection.neededDynlibs = getStringList();
481
} else if (subsectionType === WASM_DYLINK_EXPORT_INFO) {
482
var count = getLEB();
483
while (count--) {
484
var symname = getString();
485
var flags = getLEB();
486
if (flags & WASM_SYMBOL_TLS) {
487
customSection.tlsExports.add(symname);
488
}
489
}
490
} else if (subsectionType === WASM_DYLINK_IMPORT_INFO) {
491
var count = getLEB();
492
while (count--) {
493
var modname = getString();
494
var symname = getString();
495
var flags = getLEB();
496
if ((flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
497
customSection.weakImports.add(symname);
498
}
499
}
500
} else if (subsectionType === WASM_DYLINK_RUNTIME_PATH) {
501
customSection.runtimePaths = getStringList();
502
} else {
503
#if ASSERTIONS
504
err('unknown dylink.0 subsection:', subsectionType)
505
#endif
506
// unknown subsection
507
offset += subsectionSize;
508
}
509
}
510
511
#if ASSERTIONS
512
var tableAlign = Math.pow(2, customSection.tableAlign);
513
assert(tableAlign === 1, `invalid tableAlign ${tableAlign}`);
514
assert(offset == end);
515
#endif
516
517
#if DYLINK_DEBUG
518
dbg('dylink needed:', customSection.neededDynlibs);
519
#endif
520
521
return customSection;
522
},
523
524
#if DYNCALLS || !WASM_BIGINT
525
$registerDynCallSymbols: (exports) => {
526
for (var [sym, exp] of Object.entries(exports)) {
527
if (sym.startsWith('dynCall_')) {
528
var sig = sym.substring(8);
529
if (!dynCalls.hasOwnProperty(sig)) {
530
dynCalls[sig] = exp;
531
}
532
}
533
}
534
},
535
#endif
536
537
// Module.symbols <- libModule.symbols (flags.global handler)
538
$mergeLibSymbols__deps: ['$isSymbolDefined'],
539
$mergeLibSymbols: (exports, libName) => {
540
#if DYNCALLS || !WASM_BIGINT
541
registerDynCallSymbols(exports);
542
#endif
543
// add symbols into global namespace TODO: weak linking etc.
544
for (var [sym, exp] of Object.entries(exports)) {
545
#if ASSERTIONS == 2
546
if (isSymbolDefined(sym)) {
547
var curr = wasmImports[sym], next = exp;
548
// don't warn on functions - might be odr, linkonce_odr, etc.
549
if (!(typeof curr == 'function' && typeof next == 'function')) {
550
err(`warning: symbol '${sym}' from '${libName}' already exists (duplicate symbol? or weak linking, which isn't supported yet?)`); // + [curr, ' vs ', next]);
551
}
552
}
553
#endif
554
555
// When RTLD_GLOBAL is enabled, the symbols defined by this shared object
556
// will be made available for symbol resolution of subsequently loaded
557
// shared objects.
558
//
559
// We should copy the symbols (which include methods and variables) from
560
// SIDE_MODULE to MAIN_MODULE.
561
const setImport = (target) => {
562
#if ASYNCIFY
563
if (target in asyncifyStubs) {
564
asyncifyStubs[target] = exp;
565
}
566
#endif
567
if (!isSymbolDefined(target)) {
568
wasmImports[target] = exp;
569
}
570
}
571
setImport(sym);
572
573
#if !hasExportedSymbol('main')
574
// Special case for handling of main symbol: If a side module exports
575
// `main` that also acts a definition for `__main_argc_argv` and vice
576
// versa.
577
const main_alias = '__main_argc_argv';
578
if (sym == 'main') {
579
setImport(main_alias)
580
}
581
if (sym == main_alias) {
582
setImport('main')
583
}
584
#endif
585
}
586
},
587
588
#if DYLINK_DEBUG
589
$dumpTable__deps: ['$wasmTable'],
590
$dumpTable: () => {
591
var len = wasmTable.length;
592
for (var i = {{{ toIndexType(0) }}} ; i < len; i++) {
593
dbg(`table: ${i} : ${wasmTable.get(i)}`);
594
}
595
},
596
#endif
597
598
// Loads a side module from binary data or compiled Module. Returns the module's exports or a
599
// promise that resolves to its exports if the loadAsync flag is set.
600
$loadWebAssemblyModule__docs: `
601
/**
602
* @param {string=} libName
603
* @param {Object=} localScope
604
* @param {number=} handle
605
*/`,
606
$loadWebAssemblyModule__deps: [
607
'$loadDynamicLibrary', '$getMemory',
608
'$relocateExports', '$resolveGlobalSymbol', '$GOTHandler',
609
'$getDylinkMetadata', '$alignMemory',
610
'$currentModuleWeakSymbols',
611
'$updateTableMap',
612
'$wasmTable',
613
'$addOnPostCtor',
614
],
615
$loadWebAssemblyModule: (binary, flags, libName, localScope, handle) => {
616
#if DYLINK_DEBUG
617
dbg('loadWebAssemblyModule:', libName);
618
#endif
619
var metadata = getDylinkMetadata(binary);
620
currentModuleWeakSymbols = metadata.weakImports;
621
#if ASSERTIONS
622
var originalTable = wasmTable;
623
#endif
624
625
// loadModule loads the wasm module after all its dependencies have been loaded.
626
// can be called both sync/async.
627
function loadModule() {
628
#if PTHREADS
629
// The first thread to load a given module needs to allocate the static
630
// table and memory regions. Later threads re-use the same table region
631
// and can ignore the memory region (since memory is shared between
632
// threads already).
633
// If `handle` is specified than it is assumed that the calling thread has
634
// exclusive access to it for the duration of this function. See the
635
// locking in `dynlink.c`.
636
var firstLoad = !handle || !{{{ makeGetValue('handle', C_STRUCTS.dso.mem_allocated, 'i8') }}};
637
if (firstLoad) {
638
#endif
639
// alignments are powers of 2
640
var memAlign = Math.pow(2, metadata.memoryAlign);
641
// prepare memory
642
var memoryBase = metadata.memorySize ? alignMemory(getMemory(metadata.memorySize + memAlign), memAlign) : 0; // TODO: add to cleanups
643
var tableBase = metadata.tableSize ? {{{ from64Expr('wasmTable.length') }}} : 0;
644
if (handle) {
645
{{{ makeSetValue('handle', C_STRUCTS.dso.mem_allocated, '1', 'i8') }}};
646
{{{ makeSetValue('handle', C_STRUCTS.dso.mem_addr, 'memoryBase', '*') }}};
647
{{{ makeSetValue('handle', C_STRUCTS.dso.mem_size, 'metadata.memorySize', 'i32') }}};
648
{{{ makeSetValue('handle', C_STRUCTS.dso.table_addr, 'tableBase', '*') }}};
649
{{{ makeSetValue('handle', C_STRUCTS.dso.table_size, 'metadata.tableSize', 'i32') }}};
650
}
651
#if PTHREADS
652
} else {
653
// Read the values for tableBase and memoryBase from shared memory. The
654
// thread that first loaded the DLL already set these values.
655
memoryBase = {{{ makeGetValue('handle', C_STRUCTS.dso.mem_addr, '*') }}};
656
tableBase = {{{ makeGetValue('handle', C_STRUCTS.dso.table_addr, '*') }}};
657
}
658
#endif
659
660
if (metadata.tableSize) {
661
#if ASSERTIONS
662
assert({{{ from64Expr('wasmTable.length') }}} == tableBase, `unexpected table size while loading ${libName}: ${wasmTable.length}`);
663
#endif
664
#if DYLINK_DEBUG
665
dbg("loadModule: growing table by: " + metadata.tableSize);
666
#endif
667
wasmTable.grow({{{ toIndexType('metadata.tableSize') }}});
668
}
669
#if DYLINK_DEBUG
670
dbg(`loadModule: memory[${memoryBase}:${memoryBase + metadata.memorySize}]` +
671
` table[${tableBase}:${tableBase + metadata.tableSize}]`);
672
#endif
673
674
// This is the export map that we ultimately return. We declare it here
675
// so it can be used within resolveSymbol. We resolve symbols against
676
// this local symbol map in the case there they are not present on the
677
// global Module object. We need this fallback because Modules sometime
678
// need to import their own symbols
679
var moduleExports;
680
681
function resolveSymbol(sym) {
682
var resolved = resolveGlobalSymbol(sym).sym;
683
if (!resolved && localScope) {
684
resolved = localScope[sym];
685
}
686
if (!resolved) {
687
resolved = moduleExports[sym];
688
}
689
#if ASSERTIONS
690
assert(resolved, `undefined symbol '${sym}'. perhaps a side module was not linked in? if this global was expected to arrive from a system library, try to build the MAIN_MODULE with EMCC_FORCE_STDLIBS=1 in the environment`);
691
#endif
692
return resolved;
693
}
694
695
// TODO kill ↓↓↓ (except "symbols local to this module", it will likely be
696
// not needed if we require that if A wants symbols from B it has to link
697
// to B explicitly: similarly to -Wl,--no-undefined)
698
//
699
// wasm dynamic libraries are pure wasm, so they cannot assist in
700
// their own loading. When side module A wants to import something
701
// provided by a side module B that is loaded later, we need to
702
// add a layer of indirection, but worse, we can't even tell what
703
// to add the indirection for, without inspecting what A's imports
704
// are. To do that here, we use a JS proxy (another option would
705
// be to inspect the binary directly).
706
var proxyHandler = {
707
get(stubs, prop) {
708
// symbols that should be local to this module
709
switch (prop) {
710
case '__memory_base':
711
return {{{ to64('memoryBase') }}};
712
case '__table_base':
713
return {{{ to64('tableBase') }}};
714
#if MEMORY64
715
#if MEMORY64 == 2
716
case '__memory_base32':
717
return memoryBase;
718
#endif
719
case '__table_base32':
720
return tableBase;
721
#endif
722
}
723
if (prop in wasmImports && !wasmImports[prop].stub) {
724
// No stub needed, symbol already exists in symbol table
725
var res = wasmImports[prop];
726
#if ASYNCIFY
727
// Asyncify wraps exports, and we need to look through those wrappers.
728
if (res.orig) {
729
res = res.orig;
730
}
731
#endif
732
return res;
733
}
734
// Return a stub function that will resolve the symbol
735
// when first called.
736
if (!(prop in stubs)) {
737
var resolved;
738
stubs[prop] = (...args) => {
739
resolved ||= resolveSymbol(prop);
740
return resolved(...args);
741
};
742
}
743
return stubs[prop];
744
}
745
};
746
var proxy = new Proxy({}, proxyHandler);
747
var info = {
748
'GOT.mem': new Proxy({}, GOTHandler),
749
'GOT.func': new Proxy({}, GOTHandler),
750
'env': proxy,
751
'{{{ WASI_MODULE_NAME }}}': proxy,
752
};
753
754
function postInstantiation(module, instance) {
755
#if ASSERTIONS
756
// the table should be unchanged
757
assert(wasmTable === originalTable);
758
#endif
759
#if PTHREADS
760
if (!ENVIRONMENT_IS_PTHREAD && libName) {
761
#if DYLINK_DEBUG
762
dbg('registering sharedModules:', libName)
763
#endif
764
// cache all loaded modules in `sharedModules`, which gets passed
765
// to new workers when they are created.
766
sharedModules[libName] = module;
767
}
768
#endif
769
// add new entries to functionsInTableMap
770
updateTableMap(tableBase, metadata.tableSize);
771
moduleExports = relocateExports(instance.exports, memoryBase);
772
#if ASYNCIFY
773
moduleExports = Asyncify.instrumentWasmExports(moduleExports);
774
#endif
775
if (!flags.allowUndefined) {
776
reportUndefinedSymbols();
777
}
778
#if STACK_OVERFLOW_CHECK >= 2
779
// If the runtime has already been initialized we set the stack limits
780
// now. Otherwise this is delayed until `setDylinkStackLimits` is
781
// called after initialization.
782
if (moduleExports['__set_stack_limits'] && runtimeInitialized) {
783
moduleExports['__set_stack_limits']({{{ to64('_emscripten_stack_get_base()') }}}, {{{ to64('_emscripten_stack_get_end()') }}});
784
}
785
#endif
786
787
#if MAIN_MODULE
788
function addEmAsm(addr, body) {
789
var args = [];
790
var arity = 0;
791
for (; arity < 16; arity++) {
792
if (body.indexOf('$' + arity) != -1) {
793
args.push('$' + arity);
794
} else {
795
break;
796
}
797
}
798
args = args.join(',');
799
var func = `(${args}) => { ${body} };`;
800
#if DYLINK_DEBUG
801
dbg('adding new EM_ASM constant at:', ptrToString(start));
802
#endif
803
{{{ makeEval('ASM_CONSTS[start] = eval(func)') }}};
804
}
805
806
// Add any EM_ASM function that exist in the side module
807
if ('__start_em_asm' in moduleExports) {
808
var start = moduleExports['__start_em_asm'];
809
var stop = moduleExports['__stop_em_asm'];
810
{{{ from64('start') }}}
811
{{{ from64('stop') }}}
812
while (start < stop) {
813
var jsString = UTF8ToString(start);
814
addEmAsm(start, jsString);
815
start = HEAPU8.indexOf(0, start) + 1;
816
}
817
}
818
819
function addEmJs(name, cSig, body) {
820
// The signature here is a C signature (e.g. "(int foo, char* bar)").
821
// See `create_em_js` in emcc.py` for the build-time version of this
822
// code.
823
var jsArgs = [];
824
cSig = cSig.slice(1, -1)
825
if (cSig != 'void') {
826
cSig = cSig.split(',');
827
for (var i in cSig) {
828
var jsArg = cSig[i].split(' ').pop();
829
jsArgs.push(jsArg.replace('*', ''));
830
}
831
}
832
var func = `(${jsArgs}) => ${body};`;
833
#if DYLINK_DEBUG
834
dbg(`adding new EM_JS function: ${jsArgs} = ${func}`);
835
#endif
836
{{{ makeEval('moduleExports[name] = eval(func)') }}};
837
}
838
839
for (var name in moduleExports) {
840
if (name.startsWith('__em_js__')) {
841
var start = moduleExports[name]
842
var jsString = UTF8ToString({{{ from64Expr('start') }}});
843
// EM_JS strings are stored in the data section in the form
844
// SIG<::>BODY.
845
var parts = jsString.split('<::>');
846
addEmJs(name.replace('__em_js__', ''), parts[0], parts[1]);
847
delete moduleExports[name];
848
}
849
}
850
#endif
851
852
// initialize the module
853
#if PTHREADS
854
// Only one thread should call __wasm_call_ctors, but all threads need
855
// to call _emscripten_tls_init
856
registerTLSInit(moduleExports['_emscripten_tls_init'], instance.exports, metadata)
857
if (firstLoad) {
858
#endif
859
var applyRelocs = moduleExports['__wasm_apply_data_relocs'];
860
if (applyRelocs) {
861
if (runtimeInitialized) {
862
#if DYLINK_DEBUG
863
dbg('applyRelocs');
864
#endif
865
applyRelocs();
866
} else {
867
__RELOC_FUNCS__.push(applyRelocs);
868
}
869
}
870
var init = moduleExports['__wasm_call_ctors'];
871
if (init) {
872
if (runtimeInitialized) {
873
init();
874
} else {
875
// we aren't ready to run compiled code yet
876
addOnPostCtor(init);
877
}
878
}
879
#if PTHREADS
880
}
881
#endif
882
return moduleExports;
883
}
884
885
if (flags.loadAsync) {
886
return (async () => {
887
var instance;
888
if (binary instanceof WebAssembly.Module) {
889
instance = new WebAssembly.Instance(binary, info);
890
} else {
891
// Destructuring assignment without declaration has to be wrapped
892
// with parens or parser will treat the l-value as an object
893
// literal instead.
894
({ module: binary, instance } = await WebAssembly.instantiate(binary, info));
895
}
896
return postInstantiation(binary, instance);
897
})();
898
}
899
900
var module = binary instanceof WebAssembly.Module ? binary : new WebAssembly.Module(binary);
901
var instance = new WebAssembly.Instance(module, info);
902
return postInstantiation(module, instance);
903
}
904
905
// We need to set rpath in flags based on the current library's rpath.
906
// We can't mutate flags or else if a depends on b and c and b depends on d,
907
// then c will be loaded with b's rpath instead of a's.
908
flags = {...flags, rpath: { parentLibPath: libName, paths: metadata.runtimePaths }}
909
// now load needed libraries and the module itself.
910
if (flags.loadAsync) {
911
return metadata.neededDynlibs
912
.reduce((chain, dynNeeded) => chain.then(() =>
913
loadDynamicLibrary(dynNeeded, flags, localScope)
914
), Promise.resolve())
915
.then(loadModule);
916
}
917
918
metadata.neededDynlibs.forEach((needed) => loadDynamicLibrary(needed, flags, localScope));
919
return loadModule();
920
},
921
922
#if STACK_OVERFLOW_CHECK >= 2
923
// Sometimes we load libraries before runtime initialization. In this case
924
// we delay calling __set_stack_limits (which must be called for each
925
// module).
926
$setDylinkStackLimits: (stackTop, stackMax) => {
927
for (var name in LDSO.loadedLibsByName) {
928
#if DYLINK_DEBUG
929
dbg(`setDylinkStackLimits for '${name}'`);
930
#endif
931
var lib = LDSO.loadedLibsByName[name];
932
lib.exports['__set_stack_limits']?.({{{ to64("stackTop") }}}, {{{ to64("stackMax") }}});
933
}
934
},
935
#endif
936
937
$newDSO: (name, handle, syms) => {
938
var dso = {
939
refcount: Infinity,
940
name,
941
exports: syms,
942
global: true,
943
};
944
LDSO.loadedLibsByName[name] = dso;
945
if (handle != undefined) {
946
LDSO.loadedLibsByHandle[handle] = dso;
947
}
948
return dso;
949
},
950
951
#if FILESYSTEM
952
$findLibraryFS__deps: [
953
'$replaceORIGIN',
954
'_emscripten_find_dylib',
955
'$withStackSave',
956
'$stackAlloc',
957
'$lengthBytesUTF8',
958
'$stringToUTF8OnStack',
959
'$stringToUTF8',
960
'$FS',
961
'$PATH',
962
#if WASMFS
963
'_wasmfs_identify',
964
'_wasmfs_read_file',
965
#endif
966
],
967
$findLibraryFS: (libName, rpath) => {
968
// If we're preloading a dynamic library, the runtime is not ready to call
969
// __wasmfs_identify or __emscripten_find_dylib. So just quit out.
970
//
971
// This means that DT_NEEDED for the main module and transitive dependencies
972
// of it won't work with this code path. Similarly, it means that calling
973
// loadDynamicLibrary in a preRun hook can't use this code path.
974
if (!runtimeInitialized) {
975
return undefined;
976
}
977
if (PATH.isAbs(libName)) {
978
#if WASMFS
979
var result = withStackSave(() => __wasmfs_identify(stringToUTF8OnStack(libName)));
980
return result === {{{ cDefs.EEXIST }}} ? libName : undefined;
981
#else
982
try {
983
FS.lookupPath(libName);
984
return libName;
985
} catch (e) {
986
return undefined;
987
}
988
#endif
989
}
990
var rpathResolved = (rpath?.paths || []).map((p) => replaceORIGIN(rpath?.parentLibPath, p));
991
return withStackSave(() => {
992
// In dylink.c we use: `char buf[2*NAME_MAX+2];` and NAME_MAX is 255.
993
// So we use the same size here.
994
var bufSize = 2*255 + 2;
995
var buf = stackAlloc(bufSize);
996
var rpathC = stringToUTF8OnStack(rpathResolved.join(':'));
997
var libNameC = stringToUTF8OnStack(libName);
998
var resLibNameC = __emscripten_find_dylib(buf, rpathC, libNameC, bufSize);
999
return resLibNameC ? UTF8ToString(resLibNameC) : undefined;
1000
});
1001
},
1002
#endif // FILESYSTEM
1003
1004
// loadDynamicLibrary loads dynamic library @ lib URL / path and returns
1005
// handle for loaded DSO.
1006
//
1007
// Several flags affect the loading:
1008
//
1009
// - if flags.global=true, symbols from the loaded library are merged into global
1010
// process namespace. Flags.global is thus similar to RTLD_GLOBAL in ELF.
1011
//
1012
// - if flags.nodelete=true, the library will be never unloaded. Flags.nodelete
1013
// is thus similar to RTLD_NODELETE in ELF.
1014
//
1015
// - if flags.loadAsync=true, the loading is performed asynchronously and
1016
// loadDynamicLibrary returns corresponding promise.
1017
//
1018
// If a library was already loaded, it is not loaded a second time. However
1019
// flags.global and flags.nodelete are handled every time a load request is made.
1020
// Once a library becomes "global" or "nodelete", it cannot be removed or unloaded.
1021
$loadDynamicLibrary__deps: ['$LDSO', '$loadWebAssemblyModule',
1022
'$mergeLibSymbols', '$newDSO',
1023
'$asyncLoad',
1024
#if FILESYSTEM
1025
'$preloadedWasm',
1026
'$findLibraryFS',
1027
#endif
1028
#if DYNCALLS || !WASM_BIGINT
1029
'$registerDynCallSymbols',
1030
#endif
1031
],
1032
$loadDynamicLibrary__docs: `
1033
/**
1034
* @param {number=} handle
1035
* @param {Object=} localScope
1036
*/`,
1037
$loadDynamicLibrary: function(libName, flags = {global: true, nodelete: true}, localScope, handle) {
1038
#if DYLINK_DEBUG
1039
dbg(`loadDynamicLibrary: ${libName} handle: ${handle}`);
1040
dbg('existing:', Object.keys(LDSO.loadedLibsByName));
1041
#endif
1042
// when loadDynamicLibrary did not have flags, libraries were loaded
1043
// globally & permanently
1044
1045
var dso = LDSO.loadedLibsByName[libName];
1046
if (dso) {
1047
// the library is being loaded or has been loaded already.
1048
#if ASSERTIONS
1049
assert(dso.exports !== 'loading', `Attempt to load '${libName}' twice before the first load completed`);
1050
#endif
1051
if (!flags.global) {
1052
if (localScope) {
1053
Object.assign(localScope, dso.exports);
1054
}
1055
#if DYNCALLS || !WASM_BIGINT
1056
registerDynCallSymbols(dso.exports);
1057
#endif
1058
} else if (!dso.global) {
1059
// The library was previously loaded only locally but not
1060
// we have a request with global=true.
1061
dso.global = true;
1062
mergeLibSymbols(dso.exports, libName)
1063
}
1064
// same for "nodelete"
1065
if (flags.nodelete && dso.refcount !== Infinity) {
1066
dso.refcount = Infinity;
1067
}
1068
dso.refcount++
1069
if (handle) {
1070
LDSO.loadedLibsByHandle[handle] = dso;
1071
}
1072
return flags.loadAsync ? Promise.resolve(true) : true;
1073
}
1074
1075
// allocate new DSO
1076
dso = newDSO(libName, handle, 'loading');
1077
dso.refcount = flags.nodelete ? Infinity : 1;
1078
dso.global = flags.global;
1079
1080
// libName -> libData
1081
function loadLibData() {
1082
#if PTHREADS
1083
var sharedMod = sharedModules[libName];
1084
#if DYLINK_DEBUG
1085
dbg(`checking sharedModules: ${libName}: ${sharedMod ? 'found' : 'not found'}`);
1086
#endif
1087
if (sharedMod) {
1088
return flags.loadAsync ? Promise.resolve(sharedMod) : sharedMod;
1089
}
1090
#endif
1091
1092
// for wasm, we can use fetch for async, but for fs mode we can only imitate it
1093
if (handle) {
1094
var data = {{{ makeGetValue('handle', C_STRUCTS.dso.file_data, '*') }}};
1095
var dataSize = {{{ makeGetValue('handle', C_STRUCTS.dso.file_data_size, '*') }}};
1096
if (data && dataSize) {
1097
var libData = HEAP8.slice(data, data + dataSize);
1098
return flags.loadAsync ? Promise.resolve(libData) : libData;
1099
}
1100
}
1101
1102
#if FILESYSTEM
1103
var f = findLibraryFS(libName, flags.rpath);
1104
#if DYLINK_DEBUG
1105
dbg(`checking filesystem: ${libName}: ${f ? 'found' : 'not found'}`);
1106
#endif
1107
if (f) {
1108
var libData = FS.readFile(f, {encoding: 'binary'});
1109
return flags.loadAsync ? Promise.resolve(libData) : libData;
1110
}
1111
#endif
1112
1113
var libFile = locateFile(libName);
1114
if (flags.loadAsync) {
1115
return asyncLoad(libFile);
1116
}
1117
1118
// load the binary synchronously
1119
if (!readBinary) {
1120
throw new Error(`${libFile}: file not found, and synchronous loading of external files is not available`);
1121
}
1122
return readBinary(libFile);
1123
}
1124
1125
// libName -> exports
1126
function getExports() {
1127
#if FILESYSTEM
1128
// lookup preloaded cache first
1129
var preloaded = preloadedWasm[libName];
1130
#if DYLINK_DEBUG
1131
dbg(`checking preloadedWasm: ${libName}: ${preloaded ? 'found' : 'not found'}`);
1132
#endif
1133
if (preloaded) {
1134
return flags.loadAsync ? Promise.resolve(preloaded) : preloaded;
1135
}
1136
#endif
1137
1138
// module not preloaded - load lib data and create new module from it
1139
if (flags.loadAsync) {
1140
return loadLibData().then((libData) => loadWebAssemblyModule(libData, flags, libName, localScope, handle));
1141
}
1142
1143
return loadWebAssemblyModule(loadLibData(), flags, libName, localScope, handle);
1144
}
1145
1146
// module for lib is loaded - update the dso & global namespace
1147
function moduleLoaded(exports) {
1148
if (dso.global) {
1149
mergeLibSymbols(exports, libName);
1150
} else if (localScope) {
1151
Object.assign(localScope, exports);
1152
#if DYNCALLS || !WASM_BIGINT
1153
registerDynCallSymbols(exports);
1154
#endif
1155
}
1156
dso.exports = exports;
1157
}
1158
1159
if (flags.loadAsync) {
1160
#if DYLINK_DEBUG
1161
dbg("loadDynamicLibrary: done (async)");
1162
#endif
1163
return getExports().then((exports) => {
1164
moduleLoaded(exports);
1165
return true;
1166
});
1167
}
1168
1169
moduleLoaded(getExports());
1170
#if DYLINK_DEBUG
1171
dbg("loadDynamicLibrary: done");
1172
#endif
1173
return true;
1174
},
1175
1176
$loadDylibs__internal: true,
1177
$loadDylibs__deps: ['$loadDynamicLibrary', '$reportUndefinedSymbols', '$addRunDependency', '$removeRunDependency'],
1178
$loadDylibs: async () => {
1179
if (!dynamicLibraries.length) {
1180
#if DYLINK_DEBUG
1181
dbg('loadDylibs: no libraries to preload');
1182
#endif
1183
reportUndefinedSymbols();
1184
return;
1185
}
1186
1187
#if DYLINK_DEBUG
1188
dbg('loadDylibs:', dynamicLibraries);
1189
#endif
1190
addRunDependency('loadDylibs');
1191
1192
// Load binaries asynchronously
1193
for (var lib of dynamicLibraries) {
1194
await loadDynamicLibrary(lib, {loadAsync: true, global: true, nodelete: true, allowUndefined: true})
1195
}
1196
// we got them all, wonderful
1197
reportUndefinedSymbols();
1198
1199
#if DYLINK_DEBUG
1200
dbg('loadDylibs done!');
1201
#endif
1202
removeRunDependency('loadDylibs');
1203
},
1204
1205
// void* dlopen(const char* filename, int flags);
1206
$dlopenInternal__deps: ['$dlSetError', '$PATH'],
1207
$dlopenInternal: (handle, jsflags) => {
1208
// void *dlopen(const char *file, int mode);
1209
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dlopen.html
1210
var filename = UTF8ToString(handle + {{{ C_STRUCTS.dso.name }}});
1211
var flags = {{{ makeGetValue('handle', C_STRUCTS.dso.flags, 'i32') }}};
1212
#if DYLINK_DEBUG
1213
dbg('dlopenInternal:', filename);
1214
#endif
1215
filename = PATH.normalize(filename);
1216
var searchpaths = [];
1217
1218
var global = Boolean(flags & {{{ cDefs.RTLD_GLOBAL }}});
1219
var localScope = global ? null : {};
1220
1221
// We don't care about RTLD_NOW and RTLD_LAZY.
1222
var combinedFlags = {
1223
global,
1224
nodelete: Boolean(flags & {{{ cDefs.RTLD_NODELETE }}}),
1225
loadAsync: jsflags.loadAsync,
1226
}
1227
1228
if (jsflags.loadAsync) {
1229
return loadDynamicLibrary(filename, combinedFlags, localScope, handle);
1230
}
1231
1232
try {
1233
return loadDynamicLibrary(filename, combinedFlags, localScope, handle)
1234
} catch (e) {
1235
#if ASSERTIONS
1236
err(`Error in loading dynamic library ${filename}: ${e}`);
1237
#endif
1238
dlSetError(`Could not load dynamic lib: ${filename}\n${e}`);
1239
return 0;
1240
}
1241
},
1242
1243
_dlopen_js__deps: ['$dlopenInternal'],
1244
#if ASYNCIFY
1245
_dlopen_js__async: true,
1246
#endif
1247
_dlopen_js: {{{ asyncIf(ASYNCIFY == 2) }}} (handle) =>
1248
#if ASYNCIFY
1249
Asyncify.handleSleep((wakeUp) =>
1250
dlopenInternal(handle, { loadAsync: true })
1251
.then(wakeUp)
1252
// Note: this currently relies on being able to catch errors even from `wakeUp` callback itself.
1253
// That's why we can't refactor it to `handleAsync` at the moment.
1254
.catch(() => wakeUp(0))
1255
)
1256
#else
1257
dlopenInternal(handle, { loadAsync: false })
1258
#endif
1259
,
1260
1261
// Async version of dlopen.
1262
_emscripten_dlopen_js__deps: ['$dlopenInternal', '$callUserCallback', '$dlSetError'],
1263
_emscripten_dlopen_js: (handle, onsuccess, onerror, user_data) => {
1264
/** @param {Object=} e */
1265
function errorCallback(e) {
1266
var filename = UTF8ToString(handle + {{{ C_STRUCTS.dso.name }}});
1267
dlSetError(`'Could not load dynamic lib: ${filename}\n${e}`);
1268
{{{ runtimeKeepalivePop() }}}
1269
callUserCallback(() => {{{ makeDynCall('vpp', 'onerror') }}}(handle, user_data));
1270
}
1271
function successCallback() {
1272
{{{ runtimeKeepalivePop() }}}
1273
callUserCallback(() => {{{ makeDynCall('vpp', 'onsuccess') }}}(handle, user_data));
1274
}
1275
1276
{{{ runtimeKeepalivePush() }}}
1277
var promise = dlopenInternal(handle, { loadAsync: true });
1278
if (promise) {
1279
promise.then(successCallback, errorCallback);
1280
} else {
1281
errorCallback();
1282
}
1283
},
1284
1285
_dlsym_catchup_js: (handle, symbolIndex) => {
1286
#if DYLINK_DEBUG
1287
dbg("_dlsym_catchup: handle=" + ptrToString(handle) + " symbolIndex=" + symbolIndex);
1288
#endif
1289
var lib = LDSO.loadedLibsByHandle[handle];
1290
var symDict = lib.exports;
1291
var symName = Object.keys(symDict)[symbolIndex];
1292
var sym = symDict[symName];
1293
var result = addFunction(sym, sym.sig);
1294
#if DYLINK_DEBUG
1295
dbg(`_dlsym_catchup: result=${result}`);
1296
#endif
1297
return result;
1298
},
1299
1300
// void* dlsym(void* handle, const char* symbol);
1301
_dlsym_js__deps: ['$dlSetError', '$getFunctionAddress', '$addFunction'],
1302
_dlsym_js: (handle, symbol, symbolIndex) => {
1303
// void *dlsym(void *restrict handle, const char *restrict name);
1304
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html
1305
symbol = UTF8ToString(symbol);
1306
#if DYLINK_DEBUG
1307
dbg('dlsym_js:', symbol);
1308
#endif
1309
var result;
1310
var newSymIndex;
1311
1312
var lib = LDSO.loadedLibsByHandle[handle];
1313
#if ASSERTIONS
1314
assert(lib, `Tried to dlsym() from an unopened handle: ${handle}`);
1315
#endif
1316
if (!lib.exports.hasOwnProperty(symbol) || lib.exports[symbol].stub) {
1317
dlSetError(`Tried to lookup unknown symbol "${symbol}" in dynamic lib: ${lib.name}`)
1318
return 0;
1319
}
1320
newSymIndex = Object.keys(lib.exports).indexOf(symbol);
1321
#if !WASM_BIGINT
1322
var origSym = 'orig$' + symbol;
1323
result = lib.exports[origSym];
1324
if (result) {
1325
newSymIndex = Object.keys(lib.exports).indexOf(origSym);
1326
}
1327
else
1328
#endif
1329
result = lib.exports[symbol];
1330
1331
if (typeof result == 'function') {
1332
#if DYLINK_DEBUG
1333
dbg(`dlsym_js: ${symbol} getting table slot for: ${result}`);
1334
#endif
1335
1336
#if ASYNCIFY
1337
// Asyncify wraps exports, and we need to look through those wrappers.
1338
if (result.orig) {
1339
result = result.orig;
1340
}
1341
#endif
1342
var addr = getFunctionAddress(result);
1343
if (addr) {
1344
#if DYLINK_DEBUG
1345
dbg('symbol already exists in table:', symbol);
1346
#endif
1347
result = addr;
1348
} else {
1349
// Insert the function into the wasm table. If its a direct wasm
1350
// function the second argument will not be needed. If its a JS
1351
// function we rely on the `sig` attribute being set based on the
1352
// `<func>__sig` specified in library JS file.
1353
result = addFunction(result, result.sig);
1354
#if DYLINK_DEBUG
1355
dbg('adding symbol to table:', symbol);
1356
#endif
1357
{{{ makeSetValue('symbolIndex', 0, 'newSymIndex', '*') }}};
1358
}
1359
}
1360
#if DYLINK_DEBUG
1361
dbg(`dlsym_js: ${symbol} -> ${result}`);
1362
#endif
1363
return result;
1364
},
1365
};
1366
1367
addToLibrary(LibraryDylink);
1368
1369