指向本地结构的指针如何转换为 webassembly?

Posted

技术标签:

【中文标题】指向本地结构的指针如何转换为 webassembly?【英文标题】:How do pointer to local structures get translated to webassembly? 【发布时间】:2017-04-26 19:14:58 【问题描述】:

不幸的是,我无法获得一个可以将 C/C++ 编译为 wasm 文件的工作工具链,但我希望有好心人能帮助我。给定程序片段:

struct foo 
    int a;
    float b;
;

void function(foo * p);

void my_program() 
    struct foo my_foo;
    my_foo.a = 1;
    my_foo.b = -3.0F;
    foo(&my_foo);

my_program 的 wasm 代码是什么样的?

【问题讨论】:

【参考方案1】:

我假设你的意思是废文本格式是什么样的?

我在你的代码中调整了一些东西,以便它可以编译:

struct foo 
    int a;
    float b;
;

extern void bar(struct foo * p);

void my_program() 
    struct foo my_foo;
    my_foo.a = 1;
    my_foo.b = -3.0F;
    bar(&my_foo);
 

使用 emscripten/binaryen 编译,然后使用 wasm2wast:

emcc -s WASM=1 -s SIDE_MODULE=1 -O2 str.c -o str.js
wasm-dis str.wasm -o str.wast

请注意,如果没有-s SIDE_MODULE=1 -O2,emscripten 会引入一堆标准库(malloc 等),并且 wast 文件有 10,000 行长。我假设您可能只想要相当简单的 wasm/wast 结果,没有所有的链接/包含。

这会产生以下废品文件:

(module
 (type $0 (func (param i32)))
 (type $1 (func))
 (import "env" "memoryBase" (global $import$0 i32))
 (import "env" "_bar" (func $import$1 (param i32)))
 (import "env" "memory" (memory $0 256))
 (import "env" "table" (table 0 anyfunc))
 (import "env" "tableBase" (global $import$4 i32))
 (global $global$0 (mut i32) (i32.const 0))
 (global $global$1 (mut i32) (i32.const 0))
 (export "_my_program" (func $0))
 (export "__post_instantiate" (func $2))
 (export "runPostSets" (func $1))
 (func $0 (type $1)
  (local $var$0 i32)
  (local $var$1 i32)
  (block $label$0
   (set_local $var$0
    (get_global $global$0)
   )
   (set_global $global$0
    (i32.add
     (get_global $global$0)
     (i32.const 16)
    )
   )
   (i32.store
    (tee_local $var$1
     (get_local $var$0)
    )
    (i32.const 1)
   )
   (f32.store offset=4
    (get_local $var$1)
    (f32.const -3)
   )
   (call $import$1
    (get_local $var$1)
   )
   (set_global $global$0
    (get_local $var$0)
   )
  )
 )
 (func $1 (type $1)
  (nop)
 )
 (func $2 (type $1)
  (block $label$0
   (set_global $global$0
    (get_global $import$0)
   )
   (set_global $global$1
    (i32.add
     (get_global $global$0)
     (i32.const 5242880)
    )
   )
   (call $1)
  )
 )
 ;; custom section "dylink", size 5
)

请注意,memoryBasetableBase__post_instantiaterunPostSets 是用于平台内存集成/初始化的附加脚本。 memoryBase 基本上是 C 堆栈的开始,其值由 __post_instantiate 复制到 $global$0(对于该模块中的所有函数都是全局的)。当my_program 被调用时,首先发生的事情是我们将堆栈指针调整16 以指向编译器在堆栈上为my_foo 结构“分配”空间的位置。我们现在使用offset=X 执行几个i32.store 操作来更新foo 中的字段。当函数返回时,我们将堆栈指针 ($global$0) 恢复到我们进入函数时的位置。

【讨论】:

我想了解的是如何分配本地存储来为结构提供空间。似乎 global 2 的行为就像某种显式堆栈指针;它被复制到本地 0,增加 16 (sizeof foo) 并在过程退出时,它被重置回本地 0 中的值。假设环境提供“堆栈指针”作为全局指针是否正确? @JohnKällén 是的,这就是我的理解。我使用 binaryen 的 wasm-dis 更新了废物,因为它具有更智能的反汇编和更多注释。我还为解释这一点的代码添加了一些解释性文本。

以上是关于指向本地结构的指针如何转换为 webassembly?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 CFFI 中找到指向结构的指针的地址并将其转换为 void**

返回指向本地结构的指针

Swig:将成员变量(指向值的指针)转换为 python 列表

数组强制转换成结构体指针,结构体内部指针的指向问题

如何将指向c数组的指针转换为python数组

指向函数本地结构的指针的范围和生存期