WebAssembly / WebAssembly/tool-conventions
Referencing symbols accross the DLL boundary
Nobody has claimed this yet.
- Dominant language
- WebAssembly
- Stars
- 372
- Forks
- 75
- PR merge metrics
- No merged PRs in 30d
Description
The current state of dynamic linking is described https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md.
However this doesn't detail how imported symbols can referenced. Looking at the current implementation in emscripten it seems that all references to external symbols current go through JS functions:
Function Imports
Imported functions point JS thunks, which start empty and get updates as that various DLL are loaded. This works a little bit like PLT written in JS. Because all the complexity is moved JS all such functions are called with the regular call instruction and codegen doesn't need to know if a function is internal or external to the DLL.
Address Imports
For address that are external the current module, getters are used to retrieve the absolute symbol address. These are JS functions of the form g$<symbol_name> which return the absolute address of the given dynamic symbol. This means the codegen for -fPIC code needs to treat internal at external symbols very differently.
- internal:
get_global $memory_base + add known offset of <symbol_name>. - external
call g$<symbol_name>.
The circular nature of imports and exports between shared libraries means that we can't directly import functions from other modules. However, I think we can do better than forcing all references to external functions and address to go via JS.
I'm proposing the following scheme:
Function Imports
All functions imported from other DLLs go via call_indirect. The loader is responsible for allocating table slots for every function. This makes the table act as out PLT. Functions are imported as immutable globals that represent the table offset so each external call would looks like:
get_global $foo
call_indirect
Address Imports
We can use mutable globals for this. The loader can allocate one mutable global for each data address. A load from external address would then look like:
get_global $bar
i32.load
Mutable globals are needed because the addresses all global won't be known until all DLLs have been loaded, and which point the loader and update the mutable globals.
Its possible that only code compiled with -fPIC would need this extra indirection. We could treat the main executable as unique and always load it last, at which point all data address and wasm function will be available to the loader and external functions can be imported directly, avoiding the call_indirect.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading DynamicLinking.md and comparing its description with the current Emscripten implementation outlined in the issue. Evaluate the proposed call_indirect and mutable-global schemes for function and address imports, including the -fPIC and main-executable cases. Done requires an agreed convention that resolves how imported symbols are represented and loaded across DLLs.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- wasm
- Domain
- compilers
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100