如何从C / C ++访问WebAssembly线性内存

时间:2017-10-14 19:34:31

标签: emscripten webassembly

我正在编写一个小型C程序,旨在编译为wasm w / et=# select *,sum(product_count) over (partition by country_id,category_id) from products order by id; id | country_id | category_id | product_count | sum ----+------------+-------------+---------------+----- 1 | 12 | 1 | 2 | 6 2 | 12 | 1 | 4 | 6 3 | 12 | 2 | 1 | 1 4 | 45 | 5 | 2 | 3 5 | 45 | 5 | 1 | 3 6 | 45 | 8 | 5 | 5 7 | 3 | 1 | 3 | 6 8 | 3 | 1 | 3 | 6 (8 rows) 并在Web浏览器中运行。因为wasm导出的函数只能接受简单的数值作为参数输入和返回值,所以我需要在JavaScript API和编译的WebAssembly代码之间共享内存,以便访问更复杂的数据类型,如字符串或emcc数组。问题是,我不能为我的生活找出如何从我的C程序中访问WebAssembly linear memory

我的最终目标是能够在我的C程序中读取在JavaScript中初始化的字符串,然后在Web浏览器的JavaScript代码中读取在我的C程序中修改/初始化的字符串。

以下是我正在尝试做的一个基本示例:

main.js

char

example.c

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)
})

This question让我参与其中,然而,我仍然不明白如何从我的C代码中的WebAssembly内存缓冲区读取/写入。

3 个答案:

答案 0 :(得分:10)

您需要做的是在WebAssembly模块中传达C和JavaScript代码读/写的位置。

这是一个简单的例子,它为数组中的每个元素添加一个数字。这是C代码:

c("myclass", "numeric")

上面代码中重要的是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]; } 函数,它返回对int* getData()数组的开头的引用。当编译为WebAssembly时,这将返回一个整数,它是模块线性内存中data数组的位置。

以下是如何使用它的示例:

data

您可以在此WASM fiddle中看到完整示例。

答案 1 :(得分:1)

有两种相反的方法:

  1. 将所有数据元素声明为全局变量并添加辅助函数以返回每个元素的开始地址。
  2. 不要使用全局变量,在JS中分配所需的内存,计算偏移量并将这些偏移量传递给被调用的函数。在这种情况下,可用内存将从0(零)开始。
  3. (1)对于简单的事情是可以的。 (2)适用于您的数据大小未知的情况。

答案 2 :(得分:0)

WASM 对象有一个属性(我还没有看到记录),它存储一个指向每个变量和数组开头的指针。

鉴于此 C:

int myArray[100];

int main(){
    // Fill the array with data so we can see it
    for(int i = 0; i < 100; i ++){
        myArray[i] = 100 - i;
    }
    
    return 1;
}

您可以像这样访问数组的完整数据:

// Load WASM
fetch('script.wasm',{headers:{'Content-Type':'application/wasm'}})
.then(response => response.arrayBuffer())
.then(bits => WebAssembly.instantiate(bits))
.then(obj => {
    // We pull back 
    var sharedArray = new Int32Array(
        obj.instance.exports.memory.buffer, // WASM's memory
        obj.instance.exports.myArray.value, // myArray's pointer
        100                                 // The array's length
    );

    obj.instance.exports.main();

    console.log(sharedArray);
});

在 Chromium 和 Firefox 中测试。您不必使用 Emscripten 来实现这一点。