Open3

WasmLinux: syscallの発行を目指す会

okuokuokuoku

とりあえず空の init の動作まで進んだので、前のLKL内で直接syscallを発行する手法の再現を目指す。

https://qiita.com/okuoku/items/c8ca95983c6873d0f872

実用的なLinuxシステムを目指すなら、

  1. シングルプロセス、NOMMUでカーネルとメモリ空間共有( mmap とかは使えない )
  2. マルチプロセス -- clone を呼んでpidを分ける
  3. Wasmモジュールを分離
  4. libc(たぶんMUSL)を移植
  5. hard-mmuで mmap を再現 -- ホストシステム(Win32とかLinux)のmmapを流用 ← ここまでwasm2c専用
  6. Wasmのバイナリトランスレータを書いてsoft-mmu化、他のWasmランタイムやブラウザで実行

のようなステップだろうか。。

okuokuokuoku

Clang16はまだrelocatableなWasmを出力できない

https://reviews.llvm.org/D153293

https://github.com/llvm/llvm-project/commit/55e199a2c9f4

ダメじゃん。。 手元でツールチェインをビルドする必要がある。(Clang17はまだFedoraのパッケージにも来てないので) いやSnapshotがあった。。

https://copr.fedorainfracloud.org/coprs/g/fedora-llvm-team/llvm-snapshots/

(この手順に加えて、 dnf update しておく必要がある。)

okuokuokuoku

RelocatableなExecutableの生成

基本的には https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md に従ったバイナリが出力される。

int the_global = 1234;

int
main(int ac, char** av){
    the_global = ac;
    return (int)&the_global;
}

を、

cc --verbose -nostdlib -Wl,-pie -Wl,--no-entry -fPIC -Wl,--export=main -Wl,--Map=out.map -o out.wasm check.c

のようにコンパイルして wasm2c すると、

struct w2c_env;
extern u32* w2c_env_0x5F_memory_base(struct w2c_env*);
extern u32* w2c_env_0x5F_stack_pointer(struct w2c_env*);
extern u32* w2c_env_0x5F_table_base(struct w2c_env*);

typedef struct w2c_0x24out0x2Ewasm {
  /* import: 'env' '__memory_base' */
  u32 *w2c_env_0x5F_memory_base;
  /* import: 'env' '__stack_pointer' */
  u32 *w2c_env_0x5F_stack_pointer;
  /* import: 'env' '__table_base' */
  u32 *w2c_env_0x5F_table_base;
  wasm_rt_memory_t w2c_memory;
} w2c_0x24out0x2Ewasm;

void wasm2c_0x24out0x2Ewasm_instantiate(w2c_0x24out0x2Ewasm*, struct w2c_env*);
void wasm2c_0x24out0x2Ewasm_free(w2c_0x24out0x2Ewasm*);
wasm_rt_func_type_t wasm2c_0x24out0x2Ewasm_get_func_type(uint32_t param_count, uint32_t result_count, ...);

/* export: 'memory' */
wasm_rt_memory_t* w2c_0x24out0x2Ewasm_memory(w2c_0x24out0x2Ewasm* instance);

/* export: '__wasm_apply_data_relocs' */
void w2c_0x24out0x2Ewasm_0x5F_wasm_apply_data_relocs(w2c_0x24out0x2Ewasm*);

/* export: 'main' */
u32 w2c_0x24out0x2Ewasm_main(w2c_0x24out0x2Ewasm*, u32, u32);

のようなインターフェース入りで出力される。

アプリ側は、 w2c_env_0x5F_memory_base といったリロケーション情報提供用の関数を用意した上でモジュールをinstanciateすると、使用メモリをオフセットした形でモジュールを使用できるが、 新しくメモリを確保してしまう のでこの辺は今のところwasm2cの出力を使うのではなく自前で実装する必要がある。

必要になるメモリサイズは、 wasm-objdump で調べられる:

$ wasm-objdump -x -j dylink.0 out.wasm

out.wasm:       file format wasm 0x1
module name: <out.wasm>

Section Details:

Custom:
 - name: "dylink.0"
 - mem_size     : 4
 - mem_p2align  : 2
 - table_size   : 0
 - table_p2align: 0