How to access WebAssembly linear memory from C/C++

不羁岁月 提交于 2019-11-27 01:12:07

问题


I'm writing a small C program intended to be compiled to wasm w/ emcc and run in a web browser. Because wasm exported functions can only accept simple number values as parameter inputs and return values, I need to share memory between the JavaScript API and the compiled WebAssembly code in order to access more complex data types like strings or char arrays. The problem is that I can't for the life of me figure out how to access WebAssembly linear memory from inside of my C program.

My ultimate goal is to be able to read strings initialized in JavaScript inside of my C program, and then also read strings that are modified/initialized in my C program back in the web browser's JavaScript code.

Here is a basic example of what I'm trying to do:

main.js

const importObject = {
  'env': {
    'memoryBase': 0,
    'tableBase': 0,
    'memory': new WebAssembly.Memory({initial: 256}),
    'table': new WebAssembly.Table({initial: 0, element: 'anyfunc'})
  }
}

// using the fetchAndInstantiate util function from
// https://github.com/mdn/webassembly-examples/blob/master/wasm-utils.js
fetchAndInstantiate('example.wasm', importObject).then(instance => {

      // call the compiled webassembly main function
      instance.exports._main()
      console.log(importObject.env.memory)
})

example.c

int main() {
    // somehow access importObject.env.memory 
    // so that I can write a string to it
    return 0;
}

This question gets me part of the way there, however, I still don't understand how to read/write from the WebAssembly memory buffer in my C code.


回答1:


What you need to do is communicate a location within the WebAssembly module that both the C and JavaScript code read / write to.

Here's a simple example that adds a number to each element in array. This is the C code:

const int SIZE = 10;
int data[SIZE];

void add(int value) { 
  for (int i=0; i<SIZE; i++) {
    data[i] = data[i] + value;
  }
}

int* getData() {
  return &data[0];
}

The important thing in the above code is the int* getData() function, which returns a reference to the start of the data array. When compiled to WebAssembly, this will return an integer which is the location of the data array within the modules linear memory.

Here's an example of how to use it:

var wasmModule = new WebAssembly.Module(wasmCode);
var wasmInstance = new WebAssembly.Instance(wasmModule, wasmImports);

// obtain the offset to the array
var offset = wasmInstance.exports.getData();

// create a view on the memory that points to this array
var linearMemory = new Uint32Array(wasmInstance.exports.memory.buffer, offset, 10);

// populate with some data
for (var i = 0; i < linearMemory.length; i++) {
  linearMemory[i] = i;
}

// mutate the array within the WebAssembly module
wasmInstance.exports.add(10);

// log the results
for (var i = 0; i < linearMemory.length; i++) {
  log(linearMemory[i]);
}

You can see the complete example in this WASM fiddle.




回答2:


There are 2 opposite approaches:

  1. Declare all your data elements as globals and add helper functions to return begining address for each.
  2. Don't use globals, allocate desired Memory in JS, calculate offsets and pass those offsets to called functions. In this case available memory will start from 0 (zero).

(1) is ok for simple things. (2) is suitable when your data size is unknown.



来源:https://stackoverflow.com/questions/46748572/how-to-access-webassembly-linear-memory-from-c-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!