emscripten-core / emscripten

Emscripten: An LLVM-to-WebAssembly Compiler
Other
25.89k stars 3.32k forks source link

Emscripten & WASI & POSIX #9479

Closed syrusakbary closed 3 years ago

syrusakbary commented 5 years ago

After compiling this simple example with emscripten (using tot-upstream, with em++ issue_577.cpp -s WASM=1 -o issue_577.wasm):

#include <iostream>

int main(int argc, char* argv[]) {
  std::cout << "Does this work?" << std::endl;
  return 0;
}

The WebAssembly file has the following imports:

  (import "env" "__cxa_uncaught_exceptions" (func $env.__cxa_uncaught_exceptions (type $t16)))
  (import "env" "__cxa_atexit" (func $env.__cxa_atexit (type $t1)))
  (import "env" "__syscall6" (func $env.__syscall6 (type $t2)))
  (import "env" "__syscall145" (func $env.__syscall145 (type $t2)))
  (import "env" "__syscall140" (func $env.__syscall140 (type $t2)))
  (import "wasi_unstable" "fd_write" (func $wasi_unstable.fd_write (type $t11)))
  (import "env" "getenv" (func $env.getenv (type $t0)))
  (import "env" "__map_file" (func $env.__map_file (type $t2)))
  (import "env" "__syscall91" (func $env.__syscall91 (type $t2)))
  (import "env" "strftime_l" (func $env.strftime_l (type $t7)))
  (import "env" "__cxa_pure_virtual" (func $env.__cxa_pure_virtual (type $t12)))
  (import "env" "pthread_cond_broadcast" (func $env.pthread_cond_broadcast (type $t0)))
  (import "env" "pthread_cond_wait" (func $env.pthread_cond_wait (type $t2)))
  (import "wasi_unstable" "proc_exit" (func $wasi_unstable.proc_exit (type $t10)))

Note that there wasi_unstable imports are mixed with the emscripten env ones.

(See attached generated wasm: issue_577.wasm.zip)

This makes a bit hard for standalone-wasm implementors, as now we have to mix two different ABIs (WASI and Emscripten POSIX-like) and make sure they both run properly. This is quite challenging as both WASI and Emscripten have a different data structure in the VM context (in Wasmer, the struct holding the the VM WASI data is different than the Emscripten data)

I think Emscripten should adopt only WASI when all the imports are WASI-like, otherwise use the already existing ABI.

Thoughts @kripken?

sbc100 commented 5 years ago

We are trying to move emscripten in the direction of WASI where possible to avoid supporting two different ABIs. This means emscripten's wasm files will start to look more WASI compatible over time. @kripken even recently added a -s STANDALONE_WASM flag which more of this.

Its sounds like you are saying that it would be hard for you integrate part of the WASI implementing into you emscripten ABI support? But in the long run, if you could do this, wouldn't it actually reduce your code complexity? I admit I didn't look at your source yet, so I don't fully understand why this would be a problem.

sbc100 commented 5 years ago

Also, what do you think this -s STANDALONE_WASM option? Would wasmer want to limit its support for emscripeten binaries such that it only supports binaries built with this flag? Another way of putting it, do you want to continue to support arbitrary emscripten binaries found on the web, or can you control the compiler flags of the binaries you want to run?

Supporting only STANDALONE_WASM would simplify your code I imagine.

kripken commented 5 years ago

Thanks for raising the issue @syrusakbary !

There are multiple things happening here. One is that, regardless of STANDALONE_WASM, emscripten wants to to use wasi APIs as much as possible. Just so that we're as standards-compliant as we can be, and not have arbitrary odd things. As a result, even without that flag, a hello world program will have some wasi imports like fd_write alongside the env ones.

Over time we hope to remove the other env imports where possible. However, I don't think we'll ever get to zero, since there are things that just only make sense on the Web, that I doubt wasi will support. For example a memory growth API that is JS-friendly seems to have no support.

But another issue is that we don't think it's practical to have two modes, 100% wasi and 100% non-wasi, because wasi is still a work in progress, as is our support for it. In the meantime, custom embedders may use wasi support but also add extra support for non-wasi stuff. I don't see a way around that (even if we assume wasi will eventually have graphics and audio etc., it will take many years).

We do have the EMSCRIPTEN_METADATA option which indicates which ABI the wasm binary uses - as we support more wasi, the ABI will be changing gradually, and we'll update the version there.

That's the big picture from our perspective. I'd like to understand more what specifically is inconvenient for wasmer, and work to find a solution.

syrusakbary commented 5 years ago

Wasmer Emscripten implementation and WASI implementation don't share the same context data. The reason why we are doing this is:

Because of that, it's hard to use Emscripten and WASI together for the same underlying filesystem.

Why is hard?

Based on the example that I provided before, the set of imports are:

  (import "env" "__cxa_uncaught_exceptions" (func $env.__cxa_uncaught_exceptions (type $t16)))
  (import "env" "__cxa_atexit" (func $env.__cxa_atexit (type $t1)))
  (import "env" "__syscall6" (func $env.__syscall6 (type $t2)))
  (import "env" "__syscall145" (func $env.__syscall145 (type $t2)))
  (import "env" "__syscall140" (func $env.__syscall140 (type $t2)))
  (import "wasi_unstable" "fd_write" (func $wasi_unstable.fd_write (type $t11)))
  (import "env" "getenv" (func $env.getenv (type $t0)))
  (import "env" "__map_file" (func $env.__map_file (type $t2)))
  (import "env" "__syscall91" (func $env.__syscall91 (type $t2)))
  (import "env" "strftime_l" (func $env.strftime_l (type $t7)))
  (import "env" "__cxa_pure_virtual" (func $env.__cxa_pure_virtual (type $t12)))
  (import "env" "pthread_cond_broadcast" (func $env.pthread_cond_broadcast (type $t0)))
  (import "env" "pthread_cond_wait" (func $env.pthread_cond_wait (type $t2)))
  (import "wasi_unstable" "proc_exit" (func $wasi_unstable.proc_exit (type $t10)))

But let's get analyze them more detailed:

Cpp calls (are separated from fs) 👍:

  # This is a Cpp method 👍
  (import "env" "__cxa_uncaught_exceptions" (func $env.__cxa_uncaught_exceptions (type $t16)))
  # This is a Cpp method 👍
  (import "env" "__cxa_atexit" (func $env.__cxa_atexit (type $t1)))
  # This is a Cpp method 👍
  (import "env" "__cxa_pure_virtual" (func $env.__cxa_pure_virtual (type $t12)))

Filesystem calls (non-wasi) ❗️

  # This is a call to close a file ❗️(it should be WASI fd_close)
  (import "env" "__syscall6" (func $env.__syscall6 (type $t2)))
  # This is a call to read a file descriptor ❗️(it should be WASI fd_readv)
  (import "env" "__syscall145" (func $env.__syscall145 (type $t2)))
  # This is a call to seek a file descriptor ❗️(it should be WASI fd_seek)
  (import "env" "__syscall140" (func $env.__syscall140 (type $t2)))

WASI filesystem calls

  # This is a WASI call  👍
  (import "wasi_unstable" "fd_write" (func $wasi_unstable.fd_write (type $t11)))

Other calls:

  # This could be a WASI call, but doesn't interact with the fs so it's also ok to not use WASI  👍
  (import "env" "getenv" (func $env.getenv (type $t0)))
  # This map_file can be a bit challenging
  (import "env" "__map_file" (func $env.__map_file (type $t2)))
  # This map_file can be a bit challenging
  (import "env" "__syscall91" (func $env.__syscall91 (type $t2)))
  # This could be a WASI call, but doesn't interact with the fs so it's also ok to not use WASI  👍
  (import "env" "strftime_l" (func $env.strftime_l (type $t7)))
  # This is a non-filesystem method 👍
  (import "env" "pthread_cond_broadcast" (func $env.pthread_cond_broadcast (type $t0)))
  # This is a non-filesystem method 👍
  (import "env" "pthread_cond_wait" (func $env.pthread_cond_wait (type $t2)))
  # This is a WASI call 👍
  (import "wasi_unstable" "proc_exit" (func $wasi_unstable.proc_exit (type $t10)))

Ideal solution

Right now, the filesystem calls are intermixed between WASI (wasi_unstable.fd_write) and Emscripten (env.__syscall6, env.__syscall145, env.__syscall140) ... and this makes the implementation very coupled from both.

Our WASI implementation relies on different sandboxed filesystem descriptors that can't be reused in the normal Emscripten context.

It would be awesome, if for the filesystem we can relay completely in WASI (so it can be easily decoupled from the other Emscripten syscalls). Perhaps it would be easier to either use all or none, as an incremental approach will be much more challenging on the standalone WASM runtimes side.

Adding also @AndrewScheidecker to the thread as he might have some extra input / ideas

sbc100 commented 5 years ago

The plan is to move as many of the emscripten syscalls as possible to WASI syscalls. So the ones you mention will be moving to WASI very soon I imagine. fd_write was chosen as the first one to transition since its what you need for hello world.

However there will inevitably be syscall in emscripten that don't map to WASI syscalls. This might well include filesystem syscalls that take the same file descriptors as the WASI syscalls. I imagine we will get to a place where the emscripten syscalls represent a super of the WASI syscalls.

For the time being since you have two different sandbox models I imagine you will need to continue to maintain two different version of the WASI syscalls (i.e. fd_write for emscripten will not be the same function as fd_write for WASI). However in the long term I would hope that both WASI and emscripten runtimes would use the same sandboxed implementation. Is there any reason you wouldn't want the same filesystem sandbox when running emscripten-built binaries?

kripken commented 5 years ago

Yes, as @sbc100 said, we intend to fix many of those soon. E.g. __cxa_uncaught_exceptions is a trivial fix to just move some JS into C. Full filesystem support may take a while, though, I'm not sure offhand how easy that will be.

I do understand that the intermediate state may be harder to support for your embedding. But we have to move incrementally in Emscripten. One option might be to say that wasmer doesn't support Emscripten versions in that intermediate state - so wasmer would support older versions, and eventually new-enough versions once that work is done, but not versions X-Y in the middle.

But also as @sbc100 said, I expect we'll always be a superset of wasi in some form or other. Hopefully not for filesystem I/O, but definitely for other stuff (graphics, audio, etc.).

syrusakbary commented 5 years ago

Is there any reason you wouldn't want the same filesystem sandbox when running emscripten-built binaries?

We would love to have the same sandbox in Emscripten. But it's just quite hard if the filesystem calls are intermixed between emscripten and WASI (meaning: it's hard if we use wasi_unstable.fd_write, env.__syscall6, env.__syscall145, env.__syscall140 all at the same time) It will be easier if all the filesystem calls are handled with WASI (as opposed to only fd_write).

I imagine we will get to a place where the emscripten syscalls represent a super of the WASI syscalls.

I think that would be awesome ❤️

But also as @sbc100 said, I expect we'll always be a superset of wasi in some form or other. Hopefully not for filesystem I/O, but definitely for other stuff (graphics, audio, etc.).

Yeah, I think that's the good approach. I just wished all WASI (regarding the fs) was implemented at once so we could reuse the WASI sandboxed code that we have :)

sbc100 commented 5 years ago

@syrusakbary what do you think about the STANDALONE_WASM mode? Do you want to be able to run arbitrary emscripten binaries or would you be ok requiring they be built with STANDALONE_WASM ? (i.e. do you build all your binaries yourself or do you want to run emscripten binaries from the web?)

AndrewScheidecker commented 5 years ago

I think it's a good move to use the WASI ABI for as much of the Emscripten functionality as possible. The ABI changes are a short-term burden for WAVM, but in the long-term it will be much less of a burden if the WASI and Emscripten environments can share code.

But also as @sbc100 said, I expect we'll always be a superset of wasi in some form or other. Hopefully not for filesystem I/O, but definitely for other stuff (graphics, audio, etc.).

Don't rule out adding graphics and audio APIs to WASI! I would implement them in WAVM if they existed.

@syrusakbary what do you think about the STANDALONE_WASM mode? Do you want to be able to run arbitrary emscripten binaries or would you be ok requiring they be built with STANDALONE_WASM ? (i.e. do you build all your binaries yourself or do you want to run emscripten binaries from the web?)

I think it's ok to have a flag to produce binaries that work in non-browser environments. It needs to be possible to unambiguously detect a binary compiled without it and produce a nice error message, though.

MarkMcCaskey commented 5 years ago

Don't rule out adding graphics and audio APIs to WASI! I would implement them in WAVM if they existed.

That's true, I'm also very excited about these in WASI, but I think/hope WASI won't have the same graphics APIs that Emscripten has. I spent some time experimenting with the SDL and OpenGL stuff and got it kind of working in Wasmer, but it had some serious issues. The two most prominent are the main loop and the security. The main loop is inverted and works with callbacks which isn't that natural outside the web or JS. Securely executing OpenGL is really tricky and we have to care about and handle the differences between OpenGL, OpenGL ES, and WebGL. There's been some discussion about using WebGPU in WASI, which apparently solves some or all of these problems.

To the general topic: it's tricky. Being able to execute Wasm from the web directly is really neat. However there are already some issues with this because of versioning and how often Emscripten changes. Emscripten compiles to a complete working solution because it can generate the relevant JS and Wasm that work together, the issue is that this means that supporting arbitrary Emscripten Wasm from the web is non-trivial because it's a moving target. I'm not sure if Emscripten stores its version info in the Wasm anywhere, but we're currently not detecting it or using it at Wasmer, we just vaguely target the latest version.

If Emscripten can move all its FS calls into WASI eventually, that would be a good change in my opinion. However, if it can't then things may start to get really complex. In the future WASI fds will be opaque references so Emscripten's will have to be too, or you'll need extra layers of abstraction to keep track of the relationship between Emscripten file handles and WASi file handles and you'll have to sync metadata between them. Any calls outside the WASI ones need to interact with the sandbox appropriately.

I think this bad-case scenario of partial migration will introduce the complexity primarily on the Emscripten compiler side, which will need to be reimplemented on the host side.

sbc100 commented 5 years ago

Specifically regarding WASI using reference types. If/when that happens both emscripten libc and wasi-libc will need to convert between ref types and integer fds anyway. Because libc is based on file descriptors. I don't see problem doing this. If anything I see an opportunity to one day share libc code between wasi-libc and emscripten's libc.

kripken commented 5 years ago

@MarkMcCaskey

I'm not sure if Emscripten stores its version info in the Wasm anywhere, but we're currently not detecting it or using it at Wasmer, we just vaguely target the latest version.

We do have an option (EMIT_EMSCRIPTEN_METADATA) to emit such metadata, but it's not on by default. But maybe wasmer could say that it only runs ones with the metadata?

I think this bad-case scenario of partial migration will introduce the complexity primarily on the Emscripten compiler side, which will need to be reimplemented on the host side.

Yeah, we definitely don't plan to do a partial migration - the goal is to have something simple at the end, hopefully just using wasi for filesystem stuff. However, there is some chance of encountering problems with using the wasi API.

kripken commented 5 years ago

After doing more work here, I realized that Emscripten switching to 100% wasi for our ABI would preclude full POSIX support.

One example: In NODERAWFS mode we literally propagate file operations to node's FS API directly. For example, if we ask to create a file with mode 0644 then node will do that for us. However, the wasi API doesn't have a POSIX-like owner/group/world levels of permissions. So this just wouldn't work, and would be a regression for us, unless I'm missing something.

Likewise, there are plenty of open() etc. flags that POSIX supports which wasi doesn't, so this is probably not limited to the file mode.

I don't think we want to regress this, as it's useful to compile to js+wasm and run in node with full POSIX powers!

As a result, I think we may want to think about something like this:

In practice, I think the majority of programs doing pure computation, and maybe some printf logging, would not need PURE_WASI. The flag would only be needed when doing more general operations on files, where wasi and POSIX diverge.

Maybe there's a better solution that I'm missing, though?

sbc100 commented 5 years ago

Your approach sounds reasonable.

My only question would be what is the value in the PURE_WASI mode? It seems that any reasonable sized app that targets that web would not be able to use it anyway. And small or non-web codebases might as well use wasi-sdk instread. It seems like the PURE_WASI mode, while kind of cool, might not be very useful since most of the customers for that would probably be better off with wasi-sdk.

kripken commented 5 years ago

One advantage would be that users with a web port don't need a new toolchain to get a wasi build, they can just flip a flag. Another advantage is that Emscripten could support wasi + other stuff, like say OpenGL, which is not in the wasi SDK. That might make sense in say a game engine plugin, if their runtime already has wasi support for printing and files.

But, yeah, I wish we could do better here - there would be more value for users if Emscripten emitted wasi by default. But abandoning POSIX support doesn't seem worth that. Curious if others feel otherwise though!

sbc100 commented 5 years ago

I'm not totally against a PURE_WASI option if there are user out there who would want it.

In terms of giving up POSIX compatibility and/to accepting regressions in size and/or performance, and agree that we should not sacrifice those things for WASI compatibility. We could make compromised here and there of course if the loss is negligible, and we can continue to push the WASI standard in places where we think it makes sense (as you have started to do already).

syrusakbary commented 5 years ago

Thanks for the updates and for keeping us in the loop!

And small or non-web codebases might as well use wasi-sdk instread. It seems like the PURE_WASI mode, while kind of cool, might not be very useful since most of the customers for that would probably be better off with wasi-sdk.

Agreed, we are now investigating into more ways to compile project easily into WASI. Perhaps it will be tricky for Emscripten to adopt WASI fully regarding possible regressions in size/performance. You probably have much more context than I do on the feasibility of this :)

kripken commented 5 years ago

@syrusakbary

What do you think about the POSIX issue mentioned earlier? I'm curious if wasmer is interested to run applications that use more POSIX than WASI can support.

As a concrete example, you can't implement the commandline tool ls in WASI, AFAIK, because WASI can't represent the owner/group/world permission levels (it has a simpler system). That is, the rwx etc. stuff here;

$ ls -al foo
-rwxrwxr-x 1 alon alon 117312 Oct 17 19:10 foo

Similarly, you can't port something like Python 100% in WASI, because people can use it to look at those permissions.

That stuff does work in Emscripten's POSIX support currently. How important do you think it is?

kripken commented 5 years ago

@AndrewScheidecker

I'd be curious to hear your thoughts on how important POSIX support is in WAVM, specifically POSIX stuff that doesn't fit into WASI, see the above example.

AndrewScheidecker commented 5 years ago

I do want to support as much of POSIX as I can in WAVM, one way or another. That would ideally be through some standardized ABI like WASI. I don't see why WASI wouldn't eventually support all of POSIX.

kripken commented 5 years ago

Thanks @AndrewScheidecker! Good to know.

syrusakbary commented 5 years ago

What do you think about the POSIX issue mentioned earlier? I'm curious if wasmer is interested to run applications that use more POSIX than WASI can support.

Yeah, I think WASI would eventually support all of POSIX. Or, at least, that's where we would like to move towards :)

As a concrete example, you can't implement the commandline tool ls in WASI

We actually got ls working perfectly with WASI (you can install coreutils from wapm ). It's true that the concept of groups/owner doesn't exist... but it's easy to alleviate!

kripken commented 5 years ago

It's true that the concept of groups/owner doesn't exist... but it's easy to alleviate!

Oh, interesting! How did you do it?

syrusakbary commented 5 years ago

Here are the commits into Rust's coreutils:

https://github.com/wapm-packages/coreutils/commit/b76e18d1eae1881ecc0d7e7b86d34603c17416a3#diff-e0d0d10a53bd466a68dc6509c9057367R209

kripken commented 5 years ago

Oh, but doesn't that commit just skip the POSIX stuff that WASI can't do? Or did I misunderstand it?

appcypher commented 5 years ago

Add a PURE_WASI (or some other name) flag which uses WASI even for things with downsides.

I think this would be a preferable approach IMHO.

yowl commented 4 years ago

Is there a way to run emscripten produced wasm with wasmer today, I get ImportNotFound(s) for with and without -s STANDALONE_WASM=1 ?

sbc100 commented 4 years ago

Most non-trivial programs that build with emscripten contain a lot of non-wasi imports. Only programs with extremely minimal requirements will end up depending on wasi alone.

For warmer I believe the maintain some amount of support for emscripten custom syscall layer so you might have some success there.

Are are the list of imports that are missing?

yowl commented 4 years ago

List is shorter for STANDALONE_WASM=0:

LinkError([ImportNotFound { namespace: "wasi_unstable", name: "fd_write" }, ImportNotFound { namespace: "env", name: "lock" }, ImportNotFound { namespace: "env", name: "unlock" }, ImportNotFound { namespace: "env", name: "abort" }, ImportNotFound { namespace: "env", name: "emscripten_resize_heap" }, ImportNotFound { namespace: "env", name: "setTempRet0" }, ImportNotFound { namespace: "env", name: "memory" }, ImportNotFound { namespace: "env", name: "table" }])
yowl commented 4 years ago

This is CoreRT BTW (a .Net compiler/runtime) so it's going to fit in the "non-trivial" category.

sbc100 commented 4 years ago

I would have thought the list would be shorter for STANDALONE_WASM=1. That is the intention of that flag anyway.

Depending on your programs dependencies will most likely need to implement a lot of extra stuff on the embedder side to support using emscripten-generated wasm files in such environments.

yowl commented 4 years ago

I wonder what people are doing for CI environments for emscripten built wasm. Running firefox --headless was not totally reliable for us.

sbc100 commented 4 years ago

Node works pretty good. The emscripten generated JS works find there, and it even supports threads these days.

kripken commented 4 years ago

It would be good to see the list for STANDALONE_WASM=0 - as @sbc100 said it should be shorter, and we definitely want to improve it (hopefully to 0).

yowl commented 4 years ago

@kripken I guess you meam =1. =0 is posted above. The list for =1 is

E:\GitHub\corert>"c:\Program Files (x86)\Wasmer\bin\wasmer.exe" tests\src\Simple\HelloWasm\bin\Debug\wasm\native\HelloWasm.wasm
Error: Can't instantiate module: LinkError([ImportNotFound { namespace: "env", name: "GlobalizationNative_CompareStringOrdinalIgnoreCase" }, ImportNotFound { namespace: "env", name: "GlobalizationNative_GetDefaultLocaleName" }, ImportNotFound { namespace: "env", name: "GlobalizationNative_CompareString" }, ImportNotFound { namespace: "env", name: "SystemNative_SysLog" }, ImportNotFound { namespace: "env", name: "SystemNative_Write" }, ImportNotFound { namespace: "env", name: "GlobalizationNative_GetSortHandle" }, ImportNotFound { namespace: "env", name: "GlobalizationNative_GetLocaleInfoInt" }, ImportNotFound { namespace: "env", name: "GlobalizationNative_GetCalendars" }, ImportNotFound { namespace: "env", name: "GetStdHandle" }, ImportNotFound { namespace: "env", name: "GlobalizationNative_StartsWith" }, ImportNotFound { namespace: "env", name: "GlobalizationNative_EndsWith" }, ImportNotFound { namespace: "env", name: "GetConsoleOutputCP" }, ImportNotFound { namespace: "env", name: "WriteFile" }, ImportNotFound { namespace: "env", name: "GetFileType" }, ImportNotFound { namespace: "env", name: "GlobalizationNative_GetLocaleInfoString" }, ImportNotFound { namespace: "env", name: "GlobalizationNative_GetLocaleInfoGroupingSizes" }, ImportNotFound { namespace: "env", name: "GlobalizationNative_GetLocaleName" }, ImportNotFound { namespace: "env", name: "WriteConsoleW" }, ImportNotFound { namespace: "env", name: "GlobalizationNative_GetLocaleTimeFormat" }, ImportNotFound { namespace: "env", name: "GlobalizationNative_GetLatestJapaneseEra" }, ImportNotFound { namespace: "env", name: "GetConsoleMode" }, ImportNotFound { namespace: "env", name: "WideCharToMultiByte" }, ImportNotFound { namespace: "env", name: "ReadConsoleW" }, ImportNotFound { namespace: "env", name: "ReadFile" }, ImportNotFound { namespace: "env", name: "GlobalizationNative_GetSortKey" }, ImportNotFound { namespace: "env", name: "MultiByteToWideChar" }, ImportNotFound { namespace: "env", name: "SystemNative_GetSystemTimeAsTicks" }, ImportNotFound { namespace: "env", name: "FormatMessageW" }, ImportNotFound { namespace: "env", name: "GlobalizationNative_GetJapaneseEraStartDate" }, ImportNotFound { namespace: "env", name: "GlobalizationNative_IndexOfOrdinalIgnoreCase" }, ImportNotFound { namespace: "env", name: "GlobalizationNative_LastIndexOf" }, ImportNotFound { namespace: "env", name: "GlobalizationNative_IndexOf" }, ImportNotFound { namespace: "env", name: "GlobalizationNative_GetCalendarInfo" }, ImportNotFound { namespace: "env", name: "SystemNative_GetPid" }, ImportNotFound { namespace: "env", name: "GetCPInfoExW" }, ImportNotFound { namespace: "env", name: "GlobalizationNative_GetTimeZoneDisplayName" }, ImportNotFound { namespace: "env", name: "SystemNative_CloseDir" }, ImportNotFound { namespace: "env", name: "SystemNative_ReadDirR" }, ImportNotFound { namespace: "env", name: "SystemNative_OpenDir" }, ImportNotFound { namespace: "env", name: "SystemNative_GetReadDirRBufferSize" }, ImportNotFound { namespace: "env", name: "SystemNative_ReadLink" }, ImportNotFound { namespace: "env", name: "SystemNative_Unlink" }, ImportNotFound { namespace: "env", name: "SystemNative_LStat" }, ImportNotFound { namespace: "env", name: "SystemNative_Stat" }, ImportNotFound { namespace: "env", name: "GlobalizationNative_ChangeCase" }, ImportNotFound { namespace: "env", name: "GlobalizationNative_ChangeCaseTurkish" }, ImportNotFound { namespace: "env", name: "GlobalizationNative_ChangeCaseInvariant" }, ImportNotFound { namespace: "env", name: "SystemNative_LSeek" }, ImportNotFound { namespace: "env", name: "SystemNative_FStat" }, ImportNotFound { namespace: "env", name: "SystemNative_ConvertErrorPalToPlatform" }, ImportNotFound { namespace: "env", name: "SystemNative_ConvertErrorPlatformToPal" }, ImportNotFound { namespace: "env", name: "SystemNative_Read" }, ImportNotFound { namespace: "env", name: "SystemNative_FSync" }, ImportNotFound { namespace: "env", name: "SystemNative_GetCwd" }, ImportNotFound { namespace: "env", name: "SystemNative_FTruncate" }, ImportNotFound { namespace: "env", name: "SystemNative_PosixFAdvise" }, ImportNotFound { namespace: "env", name: "SystemNative_FLock" }, ImportNotFound { namespace: "env", name: "SystemNative_StrErrorR" }, ImportNotFound { namespace: "env", name: "SystemNative_Open" }, ImportNotFound { namespace: "env", name: "SystemNative_Close" }, ImportNotFound { namespace: "env", name: "SystemNative_GetTimestampResolution" }, ImportNotFound { namespace: "env", name: "SystemNative_GetTimestamp" }, ImportNotFound { namespace: "env", name: "SystemNative_GetCpuUtilization" }, ImportNotFound { namespace: "env", name: "pthread_equal" }, ImportNotFound { namespace: "env", name: "pthread_condattr_destroy" }, ImportNotFound { namespace: "env", name: "signal" }, ImportNotFound { namespace: "env", name: "sysconf" }, ImportNotFound { namespace: "env", name: "__cxa_thread_atexit" }, ImportNotFound { namespace: "env", name: "nanosleep" }, ImportNotFound { namespace: "env", name: "sched_yield" }, ImportNotFound { namespace: "env", name: "pthread_condattr_init" }, ImportNotFound { namespace: "env", name: "pthread_condattr_setclock" }, ImportNotFound { namespace: "env", name: "pthread_cond_init" }, ImportNotFound { namespace: "env", name: "pthread_attr_init" }, ImportNotFound { namespace: "env", name: "pthread_attr_setdetachstate" }, ImportNotFound { namespace: "env", name: "pthread_create" }, ImportNotFound { namespace: "env", name: "pthread_attr_destroy" }, ImportNotFound { namespace: "env", name: "clock_gettime" }, ImportNotFound { namespace: "env", name: "pthread_cond_timedwait" }, ImportNotFound { namespace: "env", name: "pthread_getattr_np" }, ImportNotFound { namespace: "env", name: "pthread_attr_getstack" }, ImportNotFound { namespace: "env", name: "getpagesize" }, ImportNotFound { namespace: "env", name: "gettimeofday" }, ImportNotFound { namespace: "env", name: "pthread_cond_destroy" }, ImportNotFound { namespace: "env", name: "pthread_attr_setstacksize" }, ImportNotFound { namespace: "wasi_unstable", name: "args_sizes_get" }, ImportNotFound { namespace: "wasi_unstable", name: "args_get" }, ImportNotFound { namespace: "wasi_unstable", name: "proc_exit" }, ImportNotFound { namespace: "env", name: "__syscall5" }, ImportNotFound { namespace: "env", name: "__syscall340" }, ImportNotFound { namespace: "env", name: "__syscall191" }, ImportNotFound { namespace: "env", name: "__syscall219" }, ImportNotFound { namespace: "env", name: "__syscall150" }, ImportNotFound { namespace: "env", name: "__syscall192" }, ImportNotFound { namespace: "env", name: "__syscall125" }, ImportNotFound { namespace: "env", name: "__syscall151" }, ImportNotFound { namespace: "env", name: "__syscall197" }, ImportNotFound { namespace: "env", name: "__syscall195" }, ImportNotFound { namespace: "wasi_unstable", name: "fd_close" }, ImportNotFound { namespace: "env", name: "__syscall221" }, ImportNotFound { namespace: "env", name: "__syscall54" }, ImportNotFound { namespace: "wasi_unstable", name: "fd_read" }, ImportNotFound { namespace: "wasi_unstable", name: "fd_seek" }, ImportNotFound { namespace: "wasi_unstable", name: "fd_write" }, ImportNotFound { namespace: "env", name: "__syscall20" }, ImportNotFound { namespace: "env", name: "__syscall3" }, ImportNotFound { namespace: "wasi_unstable", name: "environ_sizes_get" }, ImportNotFound { namespace: "wasi_unstable", name: "environ_get" }, ImportNotFound { namespace: "wasi_unstable", name: "fd_fdstat_get" }, ImportNotFound { namespace: "env", name: "emscripten_notify_memory_growth" }])

Which includes a bunch of symbols that are undefined in my code base e.g. SystemNative_Close. We can ignore those for the purpose of this discussion I think as they are not pertinent to the discussion of generally using wasmer for emscripten wasms.

@sbc100 Thanks for node tip!

sbc100 commented 4 years ago

As you say that list contains mostly symbols related to your project. It would be useful if you could filter out all those symbols so we could see the resulting list of emscripten-internal symbol.

From first glance it doesn't look that big. A few syscall functions and a few pthread functions.

Out of interest how do you plan in injecting symbols like SystemNative_Close into the wasmer runtime?

yowl commented 4 years ago

Tried to format the list better, removing my stuff

 namespace: "env" name: "pthread_equal" }
  namespace: "env" name: "pthread_condattr_destroy" }
  namespace: "env" name: "signal" }
  namespace: "env" name: "sysconf" }
  namespace: "env" name: "__cxa_thread_atexit" }
  namespace: "env" name: "nanosleep" }
  namespace: "env" name: "sched_yield" }
  namespace: "env" name: "pthread_condattr_init" }
  namespace: "env" name: "pthread_condattr_setclock" }
  namespace: "env" name: "pthread_cond_init" }
  namespace: "env" name: "pthread_attr_init" }
  namespace: "env" name: "pthread_attr_setdetachstate" }
  namespace: "env" name: "pthread_create" }
  namespace: "env" name: "pthread_attr_destroy" }
  namespace: "env" name: "clock_gettime" }
  namespace: "env" name: "pthread_cond_timedwait" }
  namespace: "env" name: "pthread_getattr_np" }
  namespace: "env" name: "pthread_attr_getstack" }
  namespace: "env" name: "getpagesize" }
  namespace: "env" name: "gettimeofday" }
  namespace: "env" name: "pthread_cond_destroy" }
  namespace: "env" name: "pthread_attr_setstacksize" }
  namespace: "wasi_unstable" name: "args_sizes_get" }
  namespace: "wasi_unstable" name: "args_get" }
  namespace: "wasi_unstable" name: "proc_exit" }
  namespace: "env" name: "__syscall5" }
  namespace: "env" name: "__syscall340" }
  namespace: "env" name: "__syscall191" }
  namespace: "env" name: "__syscall219" }
  namespace: "env" name: "__syscall150" }
  namespace: "env" name: "__syscall192" }
  namespace: "env" name: "__syscall125" }
  namespace: "env" name: "__syscall151" }
  namespace: "env" name: "__syscall197" }
  namespace: "env" name: "__syscall195" }
  namespace: "wasi_unstable" name: "fd_close" }
  namespace: "env" name: "__syscall221" }
  namespace: "env" name: "__syscall54" }
  namespace: "wasi_unstable" name: "fd_read" }
  namespace: "wasi_unstable" name: "fd_seek" }
  namespace: "wasi_unstable" name: "fd_write" }
  namespace: "env" name: "__syscall20" }
  namespace: "env" name: "__syscall3" }
  namespace: "wasi_unstable" name: "environ_sizes_get" }
  namespace: "wasi_unstable" name: "environ_get" }
  namespace: "wasi_unstable" name: "fd_fdstat_get" }
  namespace: "env" name: "emscripten_notify_memory_growth" }]) 

Things SystemNative_Close are not used at present so dont' cause a runtime problem with emscripten/firefox, but eventually they will get a wasm implementation in the .Net framework,

sbc100 commented 4 years ago

Much better. Thanks.

So all the things that start with "wasi_unstable" should be implement by the wasi runtime already (so I don't know why they are showing up in that list.

All the pthread symbols I guess are there because you program depends on threads? We should probably be stubbing those out inside the wasm binary when you are not building with -pthreads (are you building with -pthreads or -s USE_THREADS?). So we can deal with those, or you can stub them out somehow since there is no way they are going to work in wamer or wasmtime today (right).

So that leaves:

  namespace: "env" name: "signal" }
  namespace: "env" name: "sysconf" }
  namespace: "env" name: "__cxa_thread_atexit" }
  namespace: "env" name: "nanosleep" }
  namespace: "env" name: "sched_yield" }
  namespace: "env" name: "clock_gettime" }
  namespace: "env" name: "getpagesize" }
  namespace: "env" name: "gettimeofday" }
  namespace: "env" name: "__syscall5" }
  namespace: "env" name: "__syscall340" }
  namespace: "env" name: "__syscall191" }
  namespace: "env" name: "__syscall219" }
  namespace: "env" name: "__syscall150" }
  namespace: "env" name: "__syscall192" }
  namespace: "env" name: "__syscall125" }
  namespace: "env" name: "__syscall151" }
  namespace: "env" name: "__syscall197" }
  namespace: "env" name: "__syscall195" }
  namespace: "env" name: "__syscall221" }
  namespace: "env" name: "__syscall54" }
  namespace: "env" name: "__syscall20" }
  namespace: "env" name: "__syscall3" }
  namespace: "env" name: "emscripten_notify_memory_growth" }]) 

For some of those you will probably want to modify you code to remove the dependency. For others we can work on removing the dependency in the WASM_STANDALONE builds. We would need to look at them on a case by case bases.

BTW, I'm working on change that will make the syscall symbols appear as names rather than number to make that a little more readable.

syrusakbary commented 4 years ago

Sorry for the delay replying @sbc100 , I just read your message.

It's awesome that Emscripten supports all WASI syscalls. This will unblock Wasmer Emscripten integration, which we paused because of security concerns. But now that Emscripten is using the bulk of WASI we should be able to revisit it!

Edit: perhaps I misread the message. Just to make sure: does Emscripten uses WASI syscalls everywhere where is possible? (excluding things that are not supported by WASI, of course)

stale[bot] commented 3 years ago

This issue has been automatically marked as stale because there has been no activity in the past year. It will be closed automatically if no further activity occurs in the next 30 days. Feel free to re-open at any time if this issue is still relevant.

syrusakbary commented 1 year ago

A follow up on this issue. At Wasmer we have worked hard to make WASI as closest as possible to POSIX.

We have created https://wasix.org/ as a way to accomplish this: it currently supports threads, sockets, signals, longjmp/setjmp, and many more.... hope this makes easier to compile to Wasm in the future!