Open5

WasmLinux: initcallへの対応

okuokuokuoku

WebAssemblyのリンカはリンカスクリプトに対応していないので、通常のELFなLinuxがやっているような、特定のセクションに関数ポインタを集めておいて配列に変換する というテクニックは使えない。

先駆者

先駆者はマップファイルから関数名を取り出してハードコードにしている。

https://retrage01.hateblo.jp/entry/2018/07/21/153000

https://github.com/retrage/linux/blob/e4ce7a5ff6bb6f084b486fd5712f1bf59ccfaf44/init/main.c#L917-L927

これでも動くが、できれば2passでビルドするのは避けたい。。(マップファイルはリンク後にできるものなので、一度はリンクする必要がある)

okuokuokuoku

抽出

定義されたinitcall類は llvm-nm で抽出できる。

$ llvm-nm --defined-only --format=just-symbols vmlinux.a | grep __initcall__
__initcall__kmod_nommu__257_1855_init_admin_reserve4
__initcall__kmod_page_alloc__419_8863_init_per_zone_wmark_min2
__initcall__kmod_slub__278_6058_slab_sysfs_init6
...

例えば __initcall__kmod_clocksource__186_1439_init_clocksource_sysfs6 のような名称は、 __initcall_id とか __initcall_stub マクロで生成されている。

https://github.com/lkl/linux/blob/3023e6f25fbf6d5f95b4e7ebd011fa688434ce5f/include/linux/init.h#L187-L201

このシンボルの末尾には 1 とか rootfs といったソート順を表わす文字(列)が入る。

https://github.com/lkl/linux/blob/3023e6f25fbf6d5f95b4e7ebd011fa688434ce5f/include/linux/init.h#L271-L294

あとは、これらのシンボルへのポインタが詰まった配列を生成してやり、 __initcall0_start みたいな名前で生成すれば良い。

https://github.com/lkl/linux/blob/3023e6f25fbf6d5f95b4e7ebd011fa688434ce5f/init/main.c#L1375-L1376

ただし、 このロジックは配列が単一であり、 _start シンボルがそれぞれのレベルの始端を指す ことを前提としている。

static const int arr[] = {
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9
};

const int* const ptr_0 = &arr[0];
const int* const ptr_5 = &arr[5];

こういう感じで数を数えて出すくらいしか思いつかないな。。とりあえずコレで。。

okuokuokuoku

undefinedが増えた

wasm-ld: error: ../vmlinux.a(kernel/params.o): undefined symbol: __start___modver
wasm-ld: error: ../vmlinux.a(kernel/params.o): undefined symbol: __start___modver
wasm-ld: error: ../vmlinux.a(kernel/params.o): undefined symbol: __stop___modver
wasm-ld: error: ../vmlinux.a(kernel/params.o): undefined symbol: __stop___modver
wasm-ld: error: ../vmlinux.a(drivers/pci/quirks.o): undefined symbol: __end_pci_fixups_early
wasm-ld: error: ../vmlinux.a(drivers/pci/quirks.o): undefined symbol: __start_pci_fixups_early
wasm-ld: error: ../vmlinux.a(drivers/pci/quirks.o): undefined symbol: __end_pci_fixups_header
wasm-ld: error: ../vmlinux.a(drivers/pci/quirks.o): undefined symbol: __start_pci_fixups_header
wasm-ld: error: ../vmlinux.a(drivers/pci/quirks.o): undefined symbol: __end_pci_fixups_final
wasm-ld: error: ../vmlinux.a(drivers/pci/quirks.o): undefined symbol: __start_pci_fixups_final
wasm-ld: error: ../vmlinux.a(drivers/pci/quirks.o): undefined symbol: __end_pci_fixups_enable
wasm-ld: error: ../vmlinux.a(drivers/pci/quirks.o): undefined symbol: __start_pci_fixups_enable
wasm-ld: error: ../vmlinux.a(drivers/pci/quirks.o): undefined symbol: __end_pci_fixups_resume
wasm-ld: error: ../vmlinux.a(drivers/pci/quirks.o): undefined symbol: __start_pci_fixups_resume
wasm-ld: error: ../vmlinux.a(drivers/pci/quirks.o): undefined symbol: __end_pci_fixups_resume_early
wasm-ld: error: ../vmlinux.a(drivers/pci/quirks.o): undefined symbol: __start_pci_fixups_resume_early
wasm-ld: error: ../vmlinux.a(drivers/pci/quirks.o): undefined symbol: __end_pci_fixups_suspend
wasm-ld: error: ../vmlinux.a(drivers/pci/quirks.o): undefined symbol: __start_pci_fixups_suspend
wasm-ld: error: ../vmlinux.a(drivers/pci/quirks.o): undefined symbol: __end_pci_fixups_suspend_late
wasm-ld: error: ../vmlinux.a(drivers/pci/quirks.o): undefined symbol: __start_pci_fixups_suspend_late

wasm-ldってdead code stripしてんの。。!? EDIT: そもそもLinuxは標準でO2だった。