Open4

WasmLinux: MUSL libcユーザランドの事前調査

okuokuokuoku

とりあえずHello, worldに必要なものだけ先に用意して、あとはprintfデバッグしつつpthreadやTLS、シグナルを用意するのが良いかな。いわゆるPOSIXのsingle process環境に近いところを目指す。

okuokuokuoku

純粋なHello, worldで呼ばれるsyscallを列挙する

#include <stdio.h>

int
__original_main(int ac, char** av){
    printf("Hello, world!\n");
    return 0;
}

をコンパイルして wasm-decompile に掛ける:

$ wasm-decompile --enable-threads user.wasm | grep syscall
import function wasmlinux_syscall32(a:int, b:int, c:int):int;
  f = wasmlinux_syscall32(222, 6, b);
  c = wasmlinux_syscall32(96, 1, b);
    if (wasmlinux_syscall32(73, 5, c + 208) > -1) goto B_k;
    if (wasmlinux_syscall32(56, 3, c + 208) > -1) goto B_l;
    if (wasmlinux_syscall32(56, 3, c + 208) > -1) goto B_m;
    if (wasmlinux_syscall32(56, 3, c + 208) > -1) goto B_n;
  wasmlinux_syscall32(94, 1, b);
    wasmlinux_syscall32(93, 1, b);
function syscall_ret(a:int):int {
  a = syscall_ret(wasmlinux_syscall32(57, 1, b));
  b = syscall_ret(wasmlinux_syscall32(66, 3, d + 16));
      f != (b = syscall_ret(wasmlinux_syscall32(66, 3, d + 16)))) continue L_c;
  if (eqz(wasmlinux_syscall32(29, 3, d + 16))) goto B_a;
    if (wasmlinux_syscall32(98, 4, b) != -38) goto B_c;
    wasmlinux_syscall32(98, 4, b);
  if (wasmlinux_syscall32(98, 3, b) != -38) goto B_b;
  wasmlinux_syscall32(98, 3, b);
    if (wasmlinux_syscall32(98, 4, b) != -38) goto B_g;
    wasmlinux_syscall32(98, 4, b);
  c = syscall_ret(wasmlinux_syscall32(62, 3, d));
#define __NR3264_mmap 222
#define __NR_set_tid_address 96
#define __NR_ppoll 73
#define __NR_openat 56
#define __NR_exit 93
#define __NR_exit_group 94
#define __NR_close 57
#define __NR_writev 66
#define __NR_ioctl 29
#define __NR_futex 98
#define __NR3264_lseek 62

なかなかキツそうなのが揃ってんな。。一旦libcじゃなくて直接syscallを発行するスタイルに戻して動作確認するのが良いかな。

futexとmmapはエミュレーションしないといけないかもしれない。NOMMUのドキュメントにはかなり複雑な実装状況が書かれている。

https://github.com/lkl/linux/blob/3023e6f25fbf6d5f95b4e7ebd011fa688434ce5f/Documentation/admin-guide/mm/nommu-mmap.rst

okuokuokuoku

Hello, World 直後にクラッシュする

... 最初 dup したfdを閉じたら pid = 1 の方でも閉じた判定になってて焦ったけど、cloneに余計なフラグを渡してたのが問題だった。

https://github.com/okuoku/lkl-wasm/commit/2f4e4d3db7a3df38f672f9ecfad073b04c29b964

とりあえず、ここまででMUSLをリンクしたWasm moduleから printf("Hello, world!\n"); できるようになったが、直後でクラッシュする:

* thread #28, name = 'runner', stop reason = signal SIGABRT
  * frame #0: 0x00007ffff7ab0884 libc.so.6`__pthread_kill_implementation + 276
    frame #1: 0x00007ffff7a5fafe libc.so.6`raise + 30
    frame #2: 0x00007ffff7a4887f libc.so.6`abort + 223
    frame #3: 0x00000000004024e5 runner`wasm_rt_trap(code=WASM_RT_TRAP_CALL_INDIRECT) at wasm-rt-impl.c:75:3
    frame #4: 0x0000000001350e15 runner`w2c_kernel_lkl_syscall(instance=0x00007ffd78000b70, var_p0=98, var_p1=4, var_p2=1042546656) at lin.c:1692154
    frame #5: 0x0000000001373388 runner`w2c_kernel_syscall_0(instance=0x00007ffd78000b70, var_p0=98, var_p1=4, var_p2=1042546656) at lin.c:1704131
    frame #6: 0x0000000000403f29 runner`w2c_kernel_syscall(instance=0x00007ffd78000b70, var_p0=98, var_p1=4, var_p2=1042546656) at lin.c:191102:10
    frame #7: 0x000000000269be71 runner`runsyscall32(no=98, nargs=4, in=1042546656) at runner.cpp:201:30
    frame #8: 0x000000000269c00e runner`w2c_env_wasmlinux_syscall32(env=0x0000000000000000, argc=4, no=98, args=1042546656) at runner.cpp:274:24
    frame #9: 0x00000000026844f2 runner`w2c_user_0x5F_lockfile(instance=0x00000000029a5260, var_p0=1868963937) at user.c:3136:14
    frame #10: 0x00000000026852a8 runner`w2c_user_0x5F_stdio_exit(instance=0x00000000029a5260) at user.c:3378:12
    frame #11: 0x000000000268336f runner`w2c_user_exit(instance=0x00000000029a5260, var_p0=0) at user.c:2679:3
    frame #12: 0x0000000002682f83 runner`w2c_user_libc_start_main_stage2(instance=0x00000000029a5260, var_p0=2, var_p1=1, var_p2=1059577860) at user.c:2588:3
    frame #13: 0x0000000002682e14 runner`w2c_user_0x5F_libc_start_main(instance=0x00000000029a5260, var_p0=2, var_p1=1, var_p2=1059577860, var_p3=1, var_p4=0, var_p5=0) at user.c:2568:12
    frame #14: 0x0000000002680a5e runner`w2c_user_0x5Fstart_c_0(instance=0x00000000029a5260, var_p0=1059577856) at user.c:1723:12
    frame #15: 0x000000000267eec3 runner`w2c_user_0x5Fstart_c(instance=0x00000000029a5260, var_p0=1059577856) at user.c:1361:3
    frame #16: 0x000000000269c34e runner`thr_user(procctx=948439040) at runner.cpp:359:25
    frame #17: 0x00000000026a0516 runner`void std::__invoke_impl<void, void (*)(unsigned int), unsigned int>((null)=__invoke_other @ 0x00007ffd94ff8b10, __f=0x0000000002a00cd0, (null)=0x0000000002a00cc8) at invoke.h:61:36
    frame #18: 0x00000000026a02f5 runner`std::__invoke_result<void (*)(unsigned int), unsigned int>::type std::__invoke<void (*)(unsigned int), unsigned int>(__fn=0x0000000002a00cd0, (null)=0x0000000002a00cc8) at invoke.h:96:40
    frame #19: 0x00000000026a0079 runner`void std::thread::_Invoker<std::tuple<void (*)(unsigned int), unsigned int>>::_M_invoke<0ul, 1ul>(this=0x0000000002a00cc8, (null)=_Index_tuple<0, 1> @ 0x00007ffd94ff8b70) at std_thread.h:292:26
    frame #20: 0x000000000269ff34 runner`std::thread::_Invoker<std::tuple<void (*)(unsigned int), unsigned int>>::operator()(this=0x0000000002a00cc8) at std_thread.h:299:20
    frame #21: 0x000000000269fec6 runner`std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)(unsigned int), unsigned int>>>::_M_run(this=0x0000000002a00cc0) at std_thread.h:244:20
    frame #22: 0x00007ffff7ce31b3 libstdc++.so.6`execute_native_thread_routine + 19
    frame #23: 0x00007ffff7aae947 libc.so.6`start_thread + 759
    frame #24: 0x00007ffff7b34860 libc.so.6`__clone3 + 48

呼ぼうとしているsyscallは、 w2c_kernel_0x5F_se_sys_futex_time32

(lldb) p instance->w2c_T0.data[var_i4]
(wasm_rt_funcref_t) $0 = {
  func_type = 0x00000000026a1470 "\xe3\xe1\xd3u_A\x96\xa4\xe0\xe2P\x997O\xf5^\xe1\x88\xd0X\xd13۳\xac\xd6\U0000001a#\xbf\xd4\xc01"
  func = 0x00000000010e9606 (runner`w2c_kernel_0x5F_se_sys_futex_time32 at lin.c:1450451)
  module_instance = 0x00007ffd78000b70
}

https://github.com/lkl/linux/blob/3023e6f25fbf6d5f95b4e7ebd011fa688434ce5f/include/linux/syscalls.h#L620-L622

args = 4 は明かに少い。。

https://github.com/okuoku/wasmlinux-musl/blob/46a5460c07d177948c5ede526fbd31278f209738/src/internal/pthread_impl.h#L175-L180

MUSL側の __futexwaitSYS_futex で確かにこれを 98 番にアサインしている。

https://github.com/okuoku/wasmlinux-musl/blob/46a5460c07d177948c5ede526fbd31278f209738/arch/wasm32/bits/syscall.h.in#L100

この引数の違いがどこから来たのか調査する必要があるな。。