-
-
Notifications
You must be signed in to change notification settings - Fork 222
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Porting to webassembly #8
Comments
Sounds awesome. I haven't tried it myself. I imagine the only major obstacle might be 32-bit. JavaScript only supports 32-bit integers. Blink runs on i386 and other 32-bit CPUs, and is regularly tested on them. However Blink was created in a 64-bit world, and as such, Blink has a 64-bit bias, therefore, you might not get optimal performance out of Blink in your 32-bit environments. |
This would be awesome!!! |
WebAssembly/tail-call#15 (comment) We're still waiting on tail calls for webassembly, lol. Wish there was another performant option. |
Someday we'll be able to use co_await in webassembly, hope I'm still around to see it happen, lol. |
Blink doesn't need tail calls. Also, good news! Blink is now stable on 32-bit platforms. I don't know if webassembly is multi-core, but the threading issues Blink was having earlier on 32-bit have been resolved. Your biggest obstacle is most likely going to be completely replacing everything in blink/syscall.c so it interfaces with WASI or something similar instead. |
@GorNishanov @tlively @madmongo1 @tomoliv30 any ideas on easiest way to implement linux syscall.c for webassembly? |
Dumb/crazy question, what sort of perf hit if blink runs nested within itself? I'm wondering if the outer vm could implement syscall.c for the inner vm? And handle threading etc. using co_await? Then outer vm could provide stupid simple interfaces for tunneling packets, etc.? |
It's possible to run Blink within Blink. There's noticeable slowdown, but it's not a showstopper. There's caveats, such as you can only have a single of the nested Blink instances make use of the linear memory optimization. The other nestings need to pass |
emscripten provides a surprisingly wide set of runtime APIs which might even be enough to "just work" already. |
With web workers and SharedArrayBuffers it's possibly to effectively have threads and emscripten even exposes those through pthreads as much as possible.
I gave it a quick try and it does almost build out-of-the-box with just |
I got it to compile too. When I tried to run Blink in Node, this happened, and I have no idea what it means.
I configured the Makefile to build an HTML file and ran it in the browser. I got the same thing. I'm going to push the fixes I made right now. Could you please help me figure out what's wrong? |
You might need newer LLVM or emscripten: emscripten-core/emscripten#12551 I'm using emscripten main with clang 15.0.6 (should be 16 mmeanwhile, but it works 🤷) |
Works!
The WASM page size is 64KiB, which means that #14 happens, but by doing the awful hack of just pretending that it's actually 4096 it can even run
It did require some hacks and workarounds though:
diff --git a/blink/blink.c b/blink/blink.c
index f6c0506..a241fd0 100644
--- a/blink/blink.c
+++ b/blink/blink.c
@@ -155,8 +155,10 @@ static void HandleSigs(void) {
unassert(!sigaction(SIGSEGV, &sa, 0));
#endif
}
-
+#include <emscripten.h>
int main(int argc, char *argv[], char **envp) {
+ EM_ASM({FS.mkdir('/cwd'); FS.mount(NODEFS, {root : '.'}, '/cwd');});
+ if(!envp) envp = environ;
g_blink_path = argc > 0 ? argv[0] : 0;
GetOpts(argc, argv);
if (optind_ == argc) PrintUsage(argc, argv, 48, 2);
diff --git a/blink/debug.h b/blink/debug.h
index a996413..5e64aa9 100644
--- a/blink/debug.h
+++ b/blink/debug.h
@@ -10,7 +10,7 @@
#define IB(x) \
__extension__({ \
__typeof__(x) x_ = (x); \
- unassert((intptr_t)x_ > 4096); \
+ unassert((intptr_t)x_ > 0); \
x_; \
})
#else
diff --git a/blink/memorymalloc.c b/blink/memorymalloc.c
index 3d0113b..b0b9266 100644
--- a/blink/memorymalloc.c
+++ b/blink/memorymalloc.c
@@ -64,6 +64,10 @@ void FreeBig(void *p, size_t n) {
void *AllocateBig(size_t n) {
void *p;
+#ifdef __EMSCRIPTEN__
+ p = Mmap(NULL, n, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0, "big");
+ return p != MAP_FAILED ? p : 0;
+#endif
u8 *brk;
if (!(brk = atomic_load_explicit(&g_allocator.brk, memory_order_relaxed))) {
// we're going to politely ask the kernel for addresses starting I built it with |
Wow. I'm still catching up. Quick question. Did you have any problems with |
I made a bunch more changes and I'm now blocked on this error.
I got a little further in the browser. Not sure what to do next. |
Yeah, I had to stub that out. FWICT that's a bug in emscripten in some way, as it's available in the system headers and there's also a stub for
Might just be the version of node, it might not support SharedArrayBuffer backed memory for WASM. I'm using v19.3.0 here.
That's where the "fun" part starts: Somehow making use of
function fileLoad(event, filename) {
var file = event.target.files[0];
var reader = new FileReader();
reader.onloadend = function(event) {
if(event.target.readyState == FileReader.DONE)
FS.writeFile(filename, new Uint8Array(event.target.result), {encoding: 'binary'});
};
reader.readAsArrayBuffer(file);
}
let fileInput = document.createElement("input");
fileInput.setAttribute("type", "file");
fileInput.onchange = () => { fileLoad(event, "executable"); };
document.body.appendChild(fileInput);
let button = document.createElement("button");
button.innerText = "Start";
button.onclick = () => { Module.callMain(["executable"]); };
document.body.appendChild(button); Build with At some point the best option is probably to expose some kind of API to JS, depending on what the actual use cases are. |
@Vogtinator @jart you guys are amazing. This is great! |
Well done guys! Very Cool! |
This is awesome, WILL hack with this :D |
please someone host their compiled blink.wasm ! |
Hmmmmm........ |
I pushed a github workflow for emscripten HTML builds: https://github.com/Vogtinator/blink/actions/workflows/emscripten.yml To build for node instead, uncomment the NODEFS mounting in |
@derekcollison I'm wondering if there could be implications/synergy here for nats? ie tunneling tcp syscalls, etc.? |
How so? Maybe running a nats-server in the browser? |
Yes, or the networking layer for many vm's running in browsers? |
You might want to try this, based on Vogtinator's workflow. |
Tweeted https://mobile.twitter.com/JustineTunney/status/1613895681038770182 @trungnt2910 @Vogtinator Would you both be interested in upstreaming your work? I've just added support for GitHub Actions today. We could add a WASM workflow for example. One thing I'd especially like to see, is some kind of ANSI code support, so we can render the Blinkenlights TUI in the browser so that people don't need to run it locally to use it. |
I think that's everything I can give you. If you need anything else, just let me know. |
Thank you for the readelf output. What will most likely get you working locally right away is building Blink using our musl-cross-make toolchain. You can do that by running:
That will build it exactly the same way it builds on my machine. In this case, at HEAD you should see:
As for these:
I've just pushed a few changes adding support for |
Might it be useful to add this to the existing |
With https://vogtinator.github.io/blink/blinkenlights.html By applying similar hacks to some syscalls (following commits on the master branch), interactive programs such as |
Just pulled the most recent changes and updated locally; I'm loving that the only error output I get is the 0x14e syscall. I think on linux that might be the compat_sendmmsg syscall? Either way, Thanks for the fast update. I reused the old client binaries with the new updated blink build, so nothing in terms of test input has changed outside of the upgrade.
|
Wow I'm really impressed to see Vi running in Blink in the browser. I'd love to be able to tweet that, once we get it up on https://jart.github.io/blink/blink.html Since you're using BusyBox, I'd like to give you something even better. Here's what I call the "Blink Software Pack" which contains Actually Portable Executables from the Cosmopolitan project that are known to work well under Blink (because Blink was designed primarily with Cosmopolitan in mind). The listing is:
You can download the software pack here: https://justine.lol/blinkenlights/blink-software-pack.tar.gz One issue you may encounter with WASM in the browser, is many Cosmopolitan binaries assume they have the ability to |
Wow, you guys are amazing! |
I suggest that a sub-project be made to allow such software packs but as a more formal release, perhaps something such as blinkOS? ;) |
I can't wait to see what happens w/ blinkOS, should be interesting! |
Not sure if it's applicable here, but I know the leaningtech guys are pretty excited about having tail calls for webvm. Looks like they will land soon in both chrome and safari. |
That's |
Yeah I was thinking an older version; https://thevivekpandey.github.io/posts/2017-09-25-linux-system-calls.html Good catch. |
Linux rseq link for Reference: https://github.com/torvalds/linux/blob/master/kernel/rseq.c I'm idling through code to see what I can find. So it seems https://www.gnu.org/software/libc/manual/html_node/Restartable-Sequences.html confirms "The GNU C Library sets the cpu_id field to RSEQ_CPU_ID_REGISTRATION_FAILED if registration failed or was explicitly disabled." so I'm looking and https://github.com/torvalds/linux/blob/master/include/uapi/linux/rseq.h says thats defaulted to -2 currently. This looks interesting: https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=e3e589829d16af9f7e73c7b70f74f3c5d5003e45 |
For future reference, a rseq search of the glibc code: https://sourceware.org/git/?p=glibc.git&a=search&h=HEAD&st=commit&s=rseq |
If its required is set by a value in the code as its checking ATTR_FLAG_DO_RSEQ, but of its needed and then doesn't init correctly, glibc calls __libc_fatal , |
"if" we'll soon have tail calls, which means emscripten will then support co_await and co_yield? Along with the compiler level optimizations they both provide? Does the need for emscripten "asyncify" go away? |
actually, maybe only co_await requires tail calls? and co_yield already works? @tlively |
Running |
There are images here too ... |
Curious if anyone has tried these lately. They all are erroring for me, albeit is slightly different ways. |
Due to certain bugs in the CI process, the WASM preview has not been updated for a long time. You might have better luck trying a local build. |
Hi. I'm trying to run a Linux binary in the browser. It's written in Golang. I can't compile for WASM because it has so many Linux dependencies. I tried to run it here: https://trungnt2910.com/blink/blink.html However, I got this error: Does this mean that emscripten must be compiled with -sALLOW_MEMORY_GROWTH? I can pay if someone wants to help. Thanks |
@RNRetailer If you can help fund further development on WASM integration, then please contact me by email. |
I'm one of the authors of the WASM port and the owner of the page you mentioned. The page on my fork is a bit outdated compared to the official one, which itself has also been abandoned for quite a long time. If you need my help updating the WASM version and fixing specific bugs, please reach out to |
No, just build blink with one of the options. However:
Depending on the dependencies you might have to spend more time getting those to work with blink wasm. With the additional layer in between you'll also significantly lose performance. |
Hey,
I'm thinking about trying to get blink running in the browser (via webassembly). My goal isn't just to run c code in the browser (could just use emscripten for that) but to actually run ape x64 executables in an interpreter where I can build a debugger and some visualization tools to see what's happening. (Similar to what blink already does).
I'm wondering if anybody has tried to compile blink for webassembly or what you think some of the challenges would be.
The text was updated successfully, but these errors were encountered: