Open infinitesnow opened 6 months ago
Your JS code looks like it is setting the first 10 bytes of memory, which is almost certainly not what you want to be doing.
You need to find a region of memory that is available to write to. The easiest way to do that is to call the malloc
export and write into the resulting buffer.
Furthermost you cannot pass data
to to the edit functions since data
is a JS object (a typed array) and edit
takes a pointer (i.e. a Number).
Do you would want to do something like this:
var ptr = exports.malloc(MAX_SIZE);
for ( let i=0; i<MAX_SIZE; i++ ) {
data[ptr + i] = ...
}
exports.edit(ptr,5);
exports.free(ptr);
Right, I see. Yeah that was unreasonable.
However I’m still confused, I can’t seem to be able to understand what
—import-memory
is supposed to do. If that exists, why do I have to
malloc
from the browser? I have looked into the linker code, it defines
some imports in the Imports
section but doesn’t seem to do any symbol
resolution. Why can’t I link a char
pointer to the imported memory, have
the loader resolve it during module instantiation and use it in C++?
On Mon, 13 May 2024 at 18:11, Sam Clegg @.***> wrote:
Your JS code looks like it is setting the first 10 bytes of memory, which is almost certainly not what you want to be doing.
You need to find a region of memory that is available to write to. The easiest way to do that is to call the malloc export and write into the resulting buffer.
Furthermost you cannot pass data to to the edit functions since data is a JS object (a typed array) and edit takes a pointer (i.e. a Number).
Do you would want to do something like this:
var ptr = exports.malloc(MAX_SIZE); for ( let i=0; i<MAX_SIZE; i++ ) { data[ptr + i] = ... } edit(ptr,5); exports.free(ptr);
— Reply to this email directly, view it on GitHub https://github.com/WebAssembly/wasi-sdk/issues/419#issuecomment-2108119029, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACDKTYICQVVD4UC35K5UDQLZCDQ3BAVCNFSM6AAAAABHUJ6Z2OVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDCMBYGEYTSMBSHE . You are receiving this because you authored the thread.Message ID: @.***>
Yes, you should call malloc
to get your memory region. It doesn't matter if the memory is imported or exported, both sides (Wasm and JS) still need to agree on the memory layout.
I'm not quite sure what you mean by the second half of your question, but all static data needs to be resolved by the linker, so it can do that memory layout. You can't have static data that the linker does know about (at least not without using dyanmic linking which is probably not what you want).
It is possible to export a static char buffer is that works for you. e.g:
char myBuf[1024];
Then use -Wl,--export=myBuf
to export it and access that address from exports.myBuf
. That would avoid calling malloc.
You can't have static data that the linker does know about (at least not without using dyanmic linking which is probably not what you want).
If that's the case, then I don't understand how memory can be imported. My understanding is that an imported function is dynamically loaded. I was under the impression that -import-memory
would give me a relocatable symbol that I could access in code?
That sounded reasonable, I'd just create a few object of variable size in JS, pass them at instantiation time, then from C++ I could just treat those as normal .data
memory. Is that not what imported memory is?
You can't have static data that the linker does know about (at least not without using dyanmic linking which is probably not what you want).
If that's the case, then I don't understand how memory can be imported. My understanding is that an imported function is dynamically loaded. I was under the impression that
-import-memory
would give me a relocatable symbol that I could access in code?That sounded reasonable, I'd just create a few object of variable size in JS, pass them at instantiation time, then from C++ I could just treat those as normal
.data
memory. Is that not what imported memory is?
In the C/C++ there is just one memory. You can import it or export, but its layout will be determined statically at link time by wasm-ld. The layout of the memory is something like |zero page|static data|stack|heap...|
. With static linking you cannot alter this layout after linking except the grow the heap on the right hand side as the memory itself grows.
In C/C++ there is just one memory.
Yes, this would be my assumption. But if that's the case, I don't understand, what's the difference between exporting and importing memory in wasm? Wouldn't that effectively accomplish the same thing since it's one and the same block, regardless of which direction it is exchanged?
Maybe my use case is too simple, is there a use case where clearly one approach is better?
In C/C++ there is just one memory.
Yes, this would be my assumption. But if that's the case, I don't understand, what's the difference between exporting and importing memory in wasm? Wouldn't that effectively be the same thing?
Not a huge amount is different.
In one scenario, the memory (and its size limits) are statically baked into the wasm file. In the other scenario you must call new WebAssembly.Memory
from JS. This gives you a little more flexibility at the cost of an extra couple of lines of JS code. I recommend sticking with the exported memory to keep the JS code simpler/smaller.
Cool, thanks for the help.
I reckon importing would also allow you to save / restore the state of a module. I'll try the malloc
implementation.
I compile the following code:
From the browser:
Stack reported by Chrome:
I build with:
Changing
-O*
to-O0
fixes the issue.I built the SDK myself (on a WSL and a macOS host) with a small LLVM patch to allow baremetal code to run in the browser without runtime / imports:
Attaching reproducers (good
-O0
/bad-Oz
) reproducers.tar.gzMight be an LLVM issue, or I might be doing something wrong. Thought I'd start from reporting here.