removing "-s ONLY_MY_CODE=1" compilation argument causes WebAssembly program to break

Viewed 821

I have a small WebAssembly program that works correctly when compiled via the following bash script:

source_list="../../src/cpp/main/main.cc"
emcc -std=c++11 $source_list -o out/index.html -O1 -s WASM=1  -s ONLY_MY_CODE=1  -s EXPORTED_FUNCTIONS="['_go']"
cp ../../src/html/index.html out/

When I load the program in my browser I see hi there printed to the JS console.

However, in preparation to use fancier code, I change my compile script by removing the -s ONLY_MY_CODE=1 entry.

Without any further changes to any files, when I then compile and run the program I see the following error message in the browser:

index.html:1 Uncaught (in promise) LinkError: WebAssembly Instantiation: Import #0 module="env" function="DYNAMICTOP_PTR" error: global import must be a number at <anonymous> Promise rejected (async) (anonymous) @ index.html:35

How can I resolve this issue?

main.cc

extern "C"
{
    extern void print(char *message);

    void go()
    {
        print("hi there");
    }
}

index.html

<script>

  var webSocket;
  const memory = new WebAssembly.Memory({ initial: 256, maximum: 256 });
  const buffer = new Uint8Array(memory.buffer);
  var exports;

  function toJsStr(offset){
      var s="";
      for(;;){
          var b = buffer[offset++];
          if( b == 0 )
              return s;
      s += String.fromCharCode(b);  
    }
  } 

  function print(offset){
    console.log(toJsStr(offset));
  }

  fetch('index.wasm').then(response => 
    response.arrayBuffer()
  ).then(bytes => {
      var imports = {};
      imports.env = {};
      imports.env.memory = memory;
      imports.env.memoryBase = 0;
      imports.env.table = new WebAssembly.Table({ initial: 0, maximum: 0, element: 'anyfunc' });
      imports.env.tableBase = 0;
      imports.env._print = print;

      return WebAssembly.instantiate(bytes, imports);
    }
  ).then(module => {
        exports = module.instance.exports; 

        exports._go();
      }
  );
  </script>
1 Answers

Emscripten includes a runtime within the generated WASM code. This generated runtime allows it to support a wide range of C / C++ features, making it much easier to port complex codebases. This runtime also has a JavaScript counterpart, so when you compile a C / C++ codebase you will see it output a wasm file, a JavaScript file and a HTML file also. The HTML file is a templated test harness for your code.

When compiling with ONLY_MY_CODE you are eliminating most of this runtime, and as a result the JavaScript and HTML files are also no longer generated. When using ONLY_MY_CODE the features you can use are really quite limited, for example you cannot use strings, or return anything other than numeric types from exported functions.

As a result, in your example, when removing ONLY_MY_CODE you need to load your wasm file via the generated JavaScript file. This will load the wasm code and also handle the exports / imports / memory in order to 'marry up' the generated runtime code. The function DYNAMICTOP_PTR that appears in your error message is one of the component parts of this runtime.

Related