Skip to content
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

How to make C++ global compile to Wasm global? #11035

Closed
GirkovArpa opened this issue Apr 29, 2020 · 4 comments
Closed

How to make C++ global compile to Wasm global? #11035

GirkovArpa opened this issue Apr 29, 2020 · 4 comments

Comments

@GirkovArpa
Copy link

GirkovArpa commented Apr 29, 2020

This code:

typedef long int i32;

i32 myGlobal = 1337;

extern "C" {
  i32 myFunc() {
    return myGlobal;
  }
}
emcc -O3 -Wl,--no-entry -s INITIAL_MEMORY=64kb -s MAXIMUM_MEMORY=64kb -s ALLOW_MEMORY_GROWTH=0 -s TOTAL_STACK=0kb -s STANDALONE_WASM -s EXPORTED_FUNCTIONS="['_myFunc']" "index.cpp" -o "index.wasm" -s GLOBAL_BASE=0

Compiles to this:

(module
  (type $t0 (func (result i32)))
  (func $myFunc (type $t0) (result i32)
    i32.const 0
    i32.load)
  (memory $memory 1 1)
  (export "memory" (memory 0))
  (export "myFunc" (func $myFunc))
  (data $d0 (i32.const 0) "9\05") ;; 9\05 I guess is 1337 in some base?
  (data $d1 (i32.const 512) "\a0\02")) ;; bug, separate issue

It appears that the value of myGlobal is stored in linear memory, as opposed to an actual WebAssembly global. I would like to make it compile to an actual Wasm global, maybe like this:

  (global $g0 (mut i32) (i32.const 1337))

I know that Emscripten supports this because a separate project I have had variables compiled to globals, but it's a lot of code and I figured I'd ask here first before trying to go Sherlock-Holmes on that. 😄

@sbc100
Copy link
Collaborator

sbc100 commented Apr 29, 2020

Clang doesn't currently support wasm globals in C/C++. Global variables in C/C++ live in linear memory and have address. This is fairly fundamental to the language. If you want mess with actual wasm globals would have use assembly in some way. I'll come back to you with an example of this if I can.

Having said that, with the wasm backend you can export the address of the global directly:

For example:

$ cat test.c 
#include <emscripten.h>

EMSCRIPTEN_KEEPALIVE int foo = 3;

EMSCRIPTEN_KEEPALIVE int bar() {
  return foo;
}

int main() {
  return 0;
}
$ ./emcc -O2 test.c
$ wasm-objdump -x a.out.wasm
...
Global[3]:
 - global[0] i32 mutable=1 - init i32=5244416
 - global[1] i32 mutable=0 <foo> - init i32=1024
 - global[2] i32 mutable=0 <__data_end> - init i32=1528
Export[12]:
 - func[1] <__wasm_call_ctors> -> "__wasm_call_ctors"
 - func[2] <bar> -> "bar"
 - global[1] -> "foo"
 - func[3] <main> -> "main"
...

So here you can see that its possible export the address of foo, which is 1024 (that start the static data section). You can then gets its value in JS by doing HEAPU32[Module['_foo']>>2].

Note that this did not work in the old fastcomp backend. Exporting a data symbol never worked there. Its also not yet a well known, used, or tested feature.

@sbc100
Copy link
Collaborator

sbc100 commented Apr 29, 2020

It looks like we currently can't define new wasm globals, even in the assembly format. I opened a bug for that: https://bugs.llvm.org/show_bug.cgi?id=45742

@sbc100
Copy link
Collaborator

sbc100 commented May 28, 2020

You can now define new wasm globals using the assembly format if you need to.

See: https://github.com/emscripten-core/emscripten/blob/master/system/lib/compiler-rt/stack_ops.s

@TerrorJack
Copy link

Late to the party, but the URL above is outdated, now it's https://github.com/emscripten-core/emscripten/blob/main/system/lib/compiler-rt/stack_ops.S

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants