Webassembly - попытка скомпилировать буфер кода и выполнить его через EM_ JS - C - PullRequest
1 голос
/ 19 марта 2020

Я экспериментирую с веб-сборкой, и я создал игрушечный модуль, который использует грубые числа в C

extern "C" {
bool isPrime(int n) {
    for (int i = 2; i <= n; i++) {
        if (n % i == 0) return false;
    }

    return true;
}

int getPrimes() {
    int primesFound = 0;

    for (int i = 2; i < 4206969; i++) {
        if (isPrime(i)) {
            primesFound++;
        }
    }

    return primesFound;
}

}

Компиляция с помощью em cc / O3 в windows дает мне следующий поток байтов:

    0x0, 0x61, 0x73, 0x6d, 0x1, 0x0, 0x0, 0x0, 0x1, 0x8, 0x2, 0x60, 
    0x0, 0x0, 0x60, 0x0, 0x1, 0x7f, 0x3, 0x3, 0x2, 0x0, 0x1, 0x5, 0x6, 0x1, 0x1, 0x80, 0x2,
    0x80, 0x2, 0x7, 0x1f, 0x3, 0x6, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x2, 0x0, 0x9, 0x67,
    0x65, 0x74, 0x50, 0x72, 0x69, 0x6d, 0x65, 0x73, 0x0, 0x1, 0x6, 0x5f, 0x73, 0x74, 0x61,
    0x72, 0x74, 0x0, 0x0, 0xa, 0x4e, 0x2, 0x3, 0x0, 0x1, 0xb, 0x48, 0x1, 0x4, 0x7f, 0x41,
    0x2, 0x21, 0x0, 0x3, 0x40, 0x41, 0x2, 0x21, 0x1, 0x2, 0x40, 0x3, 0x40, 0x20, 0x0, 0x20, 
    0x1, 0x70, 0x45, 0xd, 0x1, 0x20, 0x0, 0x20, 0x1, 0x46, 0x21, 0x3, 0x20, 0x1, 0x41, 0x1,
    0x6a, 0x21, 0x1, 0x20, 0x3, 0x45, 0xd, 0x0, 0xb, 0x20, 0x2, 0x41, 0x1, 0x6a, 0x21, 0x2,
    0xb, 0x20, 0x0, 0x41, 0x1, 0x6a, 0x22, 0x0, 0x41, 0xf9, 0xe2, 0x80, 0x2, 0x47, 0xd, 0x0,
    0xb, 0x20, 0x2, 0xb, 0xb, 0xa, 0x1, 0x0, 0x41, 0x80, 0xc, 0xb, 0x3, 0xa0, 0x6, 0x50

Что, вероятно, непонятно большинству, но инструмент WASM to WAT VS C предполагает, что это представляет следующий WASM:

(module
 (type $t0 (func))
 (type $t1 (func (result i32)))
 (func $_start (type $t0)
   nop)
 (func $getPrimes (type $t1) (result i32)
   (local $l0 i32) (local $l1 i32) (local $l2 i32) (local $l3 i32)
   i32.const 2
   local.set $l0
   loop $L0
     i32.const 2
     local.set $l1
     block $B1
       loop $L2
         local.get $l0
         local.get $l1
         i32.rem_u
         i32.eqz
         br_if $B1
         local.get $l0
         local.get $l1
         i32.eq
         local.set $l3
         local.get $l1
         i32.const 1
         i32.add
         local.set $l1
         local.get $l3
         i32.eqz
         br_if $L2
       end
       local.get $l2
       i32.const 1
       i32.add
       local.set $l2
     end
     local.get $l0
     i32.const 1
     i32.add
     local.tee $l0
     i32.const 4206969
     i32.ne
     br_if $L0
   end
   local.get $l2)
 (memory $memory 256 256)
 (export "memory" (memory 0))
 (export "getPrimes" (func $getPrimes))
 (export "_start" (func $_start))
 (data $d0 (i32.const 1536) "\a0\06P"))

Из другой программы вызывается следующая EM_ JS, предназначенная для WASM, она сообщает механизму javascript скомпилировать WASM и затем выполнить его.

EM_JS(int, call_wasmBlock, (const uint8_t* wasmBlock, uint32_t length), {
    let wasmBuf = new Uint8Array(Module.HEAPU8.buffer, wasmBlock, length);
    WebAssembly.instantiate(wasmBuf)
        .then(
            obj => console.log(obj.instance.exports.getPrimes())
        );
});

I получить эту ошибку:

Uncaught (in promise) CompileError: WebAssembly.instantiate(): unexpected section <Export> @+158

Я не совсем уверен, где go с этим, и это в основном просто эксперименты с ограничениями веб-сборки.

1 Ответ

1 голос
/ 27 апреля 2020

index. js

'use strict';

import fs from 'fs';

const bin = fs.readFileSync('test.wasm');

// only checks for primes up to 100
const primeAppBin = new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 10, 2, 96, 0, 1, 127, 96, 1, 127, 1, 127, 3, 3, 2, 1, 0, 5, 4, 1, 1, 1, 1, 7, 32, 3, 6, 109, 101, 109, 111, 114, 121, 2, 0, 7, 105, 115, 80, 114, 105, 109, 101, 0, 0, 9, 103, 101, 116, 80, 114, 105, 109, 101, 115, 0, 1, 10, 142, 1, 2, 61, 1, 2, 127, 65, 1, 33, 1, 32, 0, 65, 4, 78, 4, 127, 32, 0, 65, 127, 106, 33, 2, 65, 2, 33, 1, 2, 64, 3, 64, 32, 0, 32, 1, 111, 69, 13, 1, 32, 1, 65, 1, 106, 34, 1, 32, 2, 71, 13, 0, 11, 65, 1, 15, 11, 65, 0, 5, 65, 1, 11, 11, 78, 1, 4, 127, 65, 2, 33, 0, 3, 64, 2, 64, 32, 0, 65, 4, 79, 4, 64, 32, 0, 65, 127, 106, 33, 3, 65, 2, 33, 2, 3, 64, 32, 0, 32, 2, 112, 69, 13, 2, 32, 2, 65, 1, 106, 34, 2, 32, 3, 71, 13, 0, 11, 11, 32, 1, 65, 1, 106, 33, 1, 11, 32, 0, 65, 1, 106, 34, 0, 65, 228, 0, 71, 13, 0, 11, 32, 1, 11, 11, 9, 1, 0, 65, 128, 12, 11, 2, 160, 6]);

(async () => {
  let buff;
  const imports = {
    env: {
      execWasm: (byteOffset, length) => {
        WebAssembly.instantiate(new Uint8Array(buff, byteOffset, length)).then(app => console.log(app.instance.exports.getPrimes() + ' primes found'));
      }
    }
  };
  const app = await WebAssembly.instantiate(bin, imports);
  const { memory, test } = app.instance.exports;
  const view = new Uint8Array(memory.buffer, 0, primeAppBin.length);
  for (let i in view) view[i] = primeAppBin[i];
  buff = memory.buffer;
  test(view.byteOffset, view.byteLength);
})();

test. cpp

// emcc -O3 "test.cpp" -o "test.wasm" -s STANDALONE_WASM -s EXPORTED_FUNCTIONS="['_test']" -s ERROR_ON_UNDEFINED_SYMBOLS=0 -Wl,--no-entry -msimd128 -s INITIAL_MEMORY=64kb -s ALLOW_MEMORY_GROWTH=0 -s TOTAL_STACK=0kb

#include <emscripten.h>

extern "C" {
  extern void execWasm(int byteOffset, int length);
  EMSCRIPTEN_KEEPALIVE
  void test (int byteOffset, int length) {
    execWasm(byteOffset, length);
  }
}

простых чисел. cpp

// emcc -O3 "primes.cpp" -o "primes.wasm" -s STANDALONE_WASM -s EXPORTED_FUNCTIONS="['_getPrimes']" -s ERROR_ON_UNDEFINED_SYMBOLS=0 -Wl,--no-entry -msimd128 -s INITIAL_MEMORY=64kb -s ALLOW_MEMORY_GROWTH=0 -s TOTAL_STACK=0kb

extern "C" {
    bool isPrime(int n) {
        for (int i = 2; i < n - 1; i++) {
            if (n % i == 0)
            return false;
        }
    return true;
    }

    int getPrimes() {
        int primesFound = 0;

        for (int i = 2; i < 4'206'969; i++) {
            if (isPrime(i)) {
                primesFound++;
            }
        }
        return primesFound;
    }
}
...