📜  WebAssembly-动态链接

📅  最后修改于: 2020-11-02 05:14:07             🧑  作者: Mango


动态链接是在运行期间将两个或多个模块链接在一起的过程。

为了演示动态链接的工作原理,我们将使用C程序,并使用Ecmascript sdk将其编译为wasm。

所以这里我们有-

test1.c

int test1(){ 
   return 100; 
}

test2.c

int test2(){ 
   return 200; 
}

main.c

#include 

int test1(); 
int test2();
int main() { 
   int result = test1() + test2(); 
   return result; 
}

在main.c代码中,它使用在test1.c和test2.c内部定义的test1()和test2()。让我们检查如何在WebAssembly中链接这些模块。

编译以上代码的命令如下:如命令所示,使用SIDE_MODULE = 1进行动态链接。

emcc test1.c test2.c main.c -s SIDE_MODULE=1 -o maintest.wasm

使用WasmtoWat(可在https://webassembly.github.io/wabt/demo/wasm2wat/上获得)将获得maintest.wasm的WebAssembly文本格式。

(module 
   (type $t0 (func (result i32))) (type $t1 (func)) 
   (type $t2 (func (param i32))) (type $t3 (func (param i32 i32) (result i32))) 
   (import "env" "stackSave" (func $env.stackSave (type $t0))) 
   (import "env" "stackRestore" (func $env.stackRestore (type $t2))) 
   (import "env" "__memory_base" (global $env.__memory_base i32)) 
   (import "env" "__table_base" (global $env.__table_base i32)) 
   (import "env" "memory" (memory $env.memory 0)) 
   (import "env" "table" (table $env.table 0 funcref)) 
   (func $f2 (type $t1) 
      (call $__wasm_apply_relocs)
   )
   (func $__wasm_apply_relocs (export "__wasm_apply_relocs") (type $t1)) 
   (func $test1 (export "test1") (type $t0) (result i32) 
      (local $l0 i32) 
      (local.set $l0 
         (i32.const 100)
      )
      (return 
         (local.get $l0)
      )
   )
   (func $test2 (export "test2") (type $t0) (result i32) 
      (local $l0 i32) 
      (local.set $l0 
         (i32.const 200)) 
      (return 
         (local.get $l0)
      )
   ) 
   (func $__original_main 
      (export "__original_main") 
      (type $t0) 
      (result i32) 
      (local $l0 i32) 
      (local $l1 i32) 
      (local $l2 i32) 
      (local $l3 i32) 
      (local $l4 i32) 
      (local $l5 i32) 
      (local $l6 i32) 
      (local $l7 i32) 
      (local $l8 i32) 
      (local $l9 i32) 
      (local.set $l0(call $env.stackSave))
      (local.set $l1 (i32.const 16))
      (local.set $l2 (i32.sub (local.get $l0) (local.get $l1)))
      (call $env.stackRestore (local.get $l2) ) (local.set $l3(i32.const 0)) 
      (i32.store offset=12 (local.get $l2) (local.get $l3)) 
      (local.set $l4 (call $test1)) 
      (local.set $l5 (call $test2)) 
      (local.set $l6 (i32.add (local.get $l4) (local.get $l5))) 
      (i32.store offset=8 (local.get $l2) (local.get $l6)) 
      (local.set $l7 (i32.load offset=8 (local.get $l2))) 
      (local.set $l8 (i32.const 16)) 
      (local.set $l9 (i32.add (local.get $l2) (local.get $l8))) 
      (call $env.stackRestore (local.get $l9)) (return(local.get $l7))
   )
   (func $main 
      (export "main") 
      (type $t3) 
      (param $p0 i32) 
      (param $p1 i32) 
      (result i32) 
      (local $l2 i32) 
      (local.set $l2 
      (call $__original_main)) 
      (return (local.get $l2))
   ) 
   (func $__post_instantiate (export "__post_instantiate") (type $t1) (call $f2)) 
   (global $__dso_handle (export "__dso_handle") i32 (i32.const 0))
)

WebAssembly文本格式具有一些定义的导入,如下所示-

(import "env" "stackSave" (func $env.stackSave (type $t0)))       
(import "env" "stackRestore" (func $env.stackRestore (type $t2))) 
(import "env" "__memory_base" (global $env.__memory_base i32)) 
(import "env" "__table_base" (global $env.__table_base i32)) 
(import "env" "memory" (memory $env.memory 0)) 
(import "env" "table" (table $env.table 0 funcref))

这是在emcc(emscripten sdk)编译代码时添加的,它处理WebAssembly中的内存管理。

进行进出口

现在要查看输出,我们将必须定义在.wat代码中可以看到的导入-

(import "env" "stackSave" (func $env.stackSave (type $t0)))       
(import "env" "stackRestore" (func $env.stackRestore (type $t2))) 
(import "env" "__memory_base" (global $env.__memory_base i32)) 
(import "env" "__table_base" (global $env.__table_base i32)) 
(import "env" "memory" (memory $env.memory 0)) 
(import "env" "table" (table $env.table 0 funcref))

上面的术语解释如下-

  • env.stackSave-用于堆栈管理,这是脚本编译代码提供的功能。

  • env.stackRestore-用于堆栈管理,此功能由脚本编译代码提供。

  • env .__ memory_base-这是一个不可更改的i32全局偏移量,用于env.memory中并为wasm模块保留。模块可以在其数据段的初始化程序中使用此全局变量,以便将它们加载到正确的地址。

  • env .__ table_base-这是一个不变的i32全局偏移量,在env.table中使用并保留给wasm模块。模块可以在其表元素段的初始化程序中使用此全局变量,以便以正确的偏移量加载它们。

  • env.memory-这将具有wasm模块之间需要共享的内存详细信息。

  • env.table-这将包含wasm模块之间需要共享的表详细信息。

导入必须在javascript中定义如下:

var wasmMemory = new WebAssembly.Memory({'initial': 256,'maximum': 65536}); 
const importObj = { 
   env: {
      stackSave: n => 2, stackRestore: n => 3, //abortStackOverflow: () => {
         throw new Error('overflow'); 
      }, 
      table: new WebAssembly.Table({ 
         initial: 0, maximum: 65536, element: 'anyfunc' 
      }), __table_base: 0,
      memory: wasmMemory, __memory_base: 256 
   } 
};

以下是在WebAssembly.instantiate中利用importObj的javascript代码。


   
   
      
   

输出

输出如下-

进口货