Open7

WasmLinux: BusyBoxをコンパイルする

okuokuokuoku

さぁ面倒なやつだ。。

https://busybox.net/

https://git.busybox.net/busybox/

BusyBoxは様々なLinuxコマンドが1つになったプロジェクトで、これさえ動けばそのLinuxシステム上で生活することが可能になる。 ...というのは過言かもしれないが、とにかく大きなマイルストーンになるのは間違いない。

WasmLinuxにはいくつかの機能が欠けているのでまだビルドしても動かないが、そもそもビルドすらできなければ終りなので、ビルドを先に準備する。

okuokuokuoku

型が合わない

In file included from applets/applets.c:9:
In file included from include/busybox.h:8:
In file included from include/libbb.h:13:
In file included from include/platform.h:333:
In file included from /home/oku/repos/musl/prefix/include/unistd.h:37:
/home/oku/repos/musl/prefix/include/bits/alltypes.h:54:15: error: typedef redefinition with different types ('int' vs 'long')
   54 | typedef _Addr intptr_t;
      |               ^
/usr/lib/clang/18/include/stdint.h:291:25: note: previous definition is here
  291 | typedef __INTPTR_TYPE__ intptr_t;
      |                         ^
In file included from applets/applets.c:9:
In file included from include/busybox.h:8:
In file included from include/libbb.h:34:
In file included from /usr/lib/clang/18/include/stddef.h:77:
/usr/lib/clang/18/include/__stddef_size_t.h:13:23: error: typedef redefinition with different types ('unsigned long' vs 'unsigned int')
   13 | typedef __SIZE_TYPE__ size_t;
      |                       ^
/home/oku/repos/musl/prefix/include/bits/alltypes.h:34:24: note: previous definition is here
   34 | typedef unsigned _Addr size_t;
      |                        ^
In file included from applets/applets.c:9:
In file included from include/busybox.h:8:
In file included from include/libbb.h:34:
In file included from /usr/lib/clang/18/include/stddef.h:87:
/usr/lib/clang/18/include/__stddef_wchar_t.h:19:24: error: typedef redefinition with different types ('int' vs 'unsigned int')
   19 | typedef __WCHAR_TYPE__ wchar_t;
      |                        ^
/home/oku/repos/musl/prefix/include/bits/alltypes.h:10:18: note: previous definition is here
   10 | typedef unsigned wchar_t;
      |                  ^
3 errors generated.
make[1]: *** [scripts/Makefile.build:198: applets/applets.o] エラー 1
make: *** [Makefile:372: applets_dir] エラー 2

intptr_t については、 -ffreestanding が残ってたのでClang側の <stdint.h> が使われているのが敗因。というわけで -ffreestanding を削ればOK。

残り2つはclang側のpredefineにある。

#define __SIZE_TYPE__ long unsigned int
#define __WCHAR_TYPE__ int

うーん。。とりあえずコンパイラがそう言ってるんだからMUSLの方を合わせるか。。

https://github.com/okuoku/wasmlinux-musl/commit/aa52b6ff90d6290454f9a4be5c5f5a83d35acf86

okuokuokuoku

リンクしない

$ make V=1 CC=/home/oku/repos/linux/_warp/bin/warp-hosted-cc CROSS_COMPILE=/home/oku/repos/linux/_warp/bin/warp-
rm -f .kernelrelease
echo 1.37.0.git > .kernelrelease
/home/oku/repos/busybox/scripts/gen_build_files.sh /home/oku/repos/busybox /home/oku/repos/busybox
make -f scripts/Makefile.build obj=scripts/basic
mkdir -p .tmp_versions
rm -f .tmp_versions/*
make -f scripts/Makefile.build obj=applets
wasm-ld: error: entry point specified for relocatable output file
wasm-ld: warning: creating shared libraries, with -shared, is not yet stable
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[1]: *** [scripts/Makefile.build:264: applets/built-in.o] エラー 1
make: *** [Makefile:372: applets_dir] エラー 2

... もしかして -r でリンクしてるのか。。? というか、 V=1 でコマンドラインが出ない理由もわからん。。GNU Makeには --trace があるのでそれで代用。

https://github.com/llvm/llvm-project/blob/8569465adf5e6c792e88be56b0e6b24f1c74e633/lld/wasm/Driver.cpp#L640-L642

とりあえず -Wl,--no-entry で無理矢理通しておく。

diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 5eac45f91..4d5e9ae87 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -252,12 +252,14 @@ $(sort $(subdir-obj-y)): $(subdir-ym) ;
 #
 # Rule to compile a set of .o files into one .o file
 #
+WASMLINUX_NOENTRY=-Wl,--no-entry
+
 ifdef builtin-target
 quiet_cmd_link_o_target = LD      $@
 # If the list of objects to link is empty, just create an empty built-in.o
 # -nostdlib is added to make "make LD=gcc ..." work (some people use that)
 cmd_link_o_target = $(if $(strip $(obj-y)),\
-               $(LD) -nostdlib $(ld_flags) -r -o $@ $(filter $(obj-y), $^),\
+               $(LD) -nostdlib $(ld_flags) -r $(WASMLINUX_NOENTRY) -o $@ $(filter $(obj-y), $^),\
                rm -f $@; $(AR) rcs $@)

 $(builtin-target): $(obj-y) FORCE
@@ -292,10 +294,10 @@ $($(subst $(obj)/,,$(@:.o=-objs)))    \
 $($(subst $(obj)/,,$(@:.o=-y)))), $^)

 quiet_cmd_link_multi-y = LD      $@
-cmd_link_multi-y = $(LD) $(ld_flags) -r -o $@ $(link_multi_deps)
+cmd_link_multi-y = $(LD) $(ld_flags) -r -Wl,--no-entry -o $@ $(link_multi_deps)

 quiet_cmd_link_multi-m = LD [M]  $@
-cmd_link_multi-m = $(LD) $(ld_flags) $(LDFLAGS_MODULE) -o $@ $(link_multi_deps)
+cmd_link_multi-m = $(LD) $(ld_flags) $(LDFLAGS_MODULE) -Wl,--no-entry -o $@ $(link_multi_deps)

 # We would rather have a list of rules like
 #      foo.o: $(foo-objs)
okuokuokuoku

<linux/kd.h> が無い

... カーネルヘッダの作り方忘れた。。とりあえず作りおきがあったのでそれを指定。

okuokuokuoku

<sys/sysinfo.h> が無い

これはMuslとglibcの非互換だよね多分。というわけで依存している freeuptime は一旦ビルドから外した。

okuokuokuoku

start-group end-group が無い

とりあえず scripts/trylink を適当に調整。これが必要って事は完全にforkする必要があるな。。

diff --git a/scripts/trylink b/scripts/trylink
index 2255deee7..577ab7e96 100755
--- a/scripts/trylink
+++ b/scripts/trylink
@@ -93,10 +93,10 @@ if ! check_cc "-Wl,--sort-section,alignment"; then
     SORT_SECTION=""
 fi

-START_GROUP="-Wl,--start-group"
-END_GROUP="-Wl,--end-group"
+START_GROUP=
+END_GROUP=
 INFO_OPTS() {
-       echo "-Wl,--warn-common -Wl,-Map,$EXE.map -Wl,--verbose"
+       echo "-Wl,-Map,$EXE.map -Wl,--verbose"
 }

 # gold may not support --sort-common (yet)
@@ -129,6 +129,8 @@ fi
 # Sanitize lib list (dups, extra spaces etc)
 LDLIBS=`echo "$LDLIBS" | xargs -n1 | sort | uniq | xargs`

+WASMLINUX_OPTS="-Wl,--no-entry -Wl,--export=_start_c /home/oku/repos/musl/prefix/lib/crt1.o /home/oku/repos/musl/prefix/lib/libc.a"
+
 # First link with all libs. If it fails, bail out
 echo "Trying libraries: $LDLIBS"
 # "lib1 lib2 lib3" -> "-llib1 -llib2 -llib3"
@@ -140,6 +142,7 @@ try $CC $CFLAGS $LDFLAGS \
        $SORT_SECTION \
        $GC_SECTIONS \
        $START_GROUP $O_FILES $A_FILES $END_GROUP \
+        $WASMLINUX_OPTS \
        $l_list \
 || {
     echo "Failed: $l_list"
@@ -167,6 +170,7 @@ while test "$LDLIBS"; do
                $SORT_SECTION \
                $GC_SECTIONS \
                $START_GROUP $O_FILES $A_FILES $END_GROUP \
+                $WASMLINUX_OPTS \
                $l_list
        if test $? = 0; then
            echo " Library $one is not needed, excluding it"
@@ -196,6 +200,7 @@ if ! test -f busybox_ldscript; then
            $SORT_SECTION \
            $GC_SECTIONS \
            $START_GROUP $O_FILES $A_FILES $END_GROUP \
+            $WASMLINUX_OPTS \
            $l_list \
            `INFO_OPTS` \
     || {

https://github.com/okuoku/wasmlinux-busybox/commit/d1b50d73a2ddd5d6834ba6177dfbff31b7015535

okuokuokuoku

空っぽのexecutableができる

... まぁ main のABI問題(mainの引数が2引数と3引数の両方あるのをどうすんのか問題)を解決していないからね。。 __main_argc_argv ができるので、一旦 __original_main に置き換える。

diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index d9cc48423..d7a9d780f 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -1029,8 +1029,12 @@ get_script_content(unsigned n UNUSED_PARAM)
 #if ENABLE_BUILD_LIBBUSYBOX
 int lbb_main(char **argv)
 #else
+#ifdef __wasm__
+int __original_main(int argc UNUSED_PARAM, char **argv, char **envp UNUSED_PARAM)
+#else
 int main(int argc UNUSED_PARAM, char **argv)
 #endif
+#endif
 {
 #if 0
        /* TODO: find a use for a block of memory between end of .bss

https://github.com/okuoku/wasmlinux-busybox/commit/84402e422b147f099b671da819b1f3d618a59ff6

これでwasm2cを掛けると46MiB。結構でかいね。。

-rw-r--r--. 1 oku oku  46M 11月 13 01:19 user.c
-rw-r--r--. 1 oku oku 6.6K 11月 13 01:19 user.h