wasi-sdk
wasi-sdk copied to clipboard
`__main_argc_argv` is not retained in main module linked with `libc.so`
I'm trying to add shared-everything support in WebAssembly port of CRuby, and found an issue.
Dependencies
- wasm-tools: with my patch to fix
_start
issue- https://github.com/bytecodealliance/wasm-tools/pull/1339
- wasi-sdk: The latest main https://github.com/WebAssembly/wasi-sdk/commit/317548590b402d622194416094fe0e392b725fe2
-
gh run download 7227946508 --repo WebAssembly/wasi-sdk --name dist-ubuntu-bionic
-
Repro
$ curl -LO https://github.com/bytecodealliance/wasmtime/releases/download/v15.0.0/wasi_snapshot_preview1.command.wasm
$ cat main.c
int main(int argc, char **argv) {
return 0;
}
$ $WASI_SDK_PATH/bin/clang main.c -fPIC -Xlinker -pie -Xlinker --import-memory -Xlinker --experimental-pic -o a.out
$ wasm-tools component link a.out $WASI_SDK_PATH/share/wasi-sysroot/lib/wasm32-wasi/libc.so --adapt wasi_snapshot_preview1.command.wasm -o a.out.wasm
$ wasmtime run --wasm component-model a.out.wasm
Error: failed to run main module `a.out.wasm`
Caused by:
0: failed to invoke `run` function
1: error while executing at wasm backtrace:
0: 0x1417c - wit-component:stubs!<wasm function 0>
1: 0x1f43a - libc.so!__main_void
2: 0xae76c - a.out!_start
3: 0xb05df - wit-component:shim!adapt-a.out-_start
4: 0x5220 - wit-component:adapter:wasi_snapshot_preview1!wasi:cli/[email protected]#run
note: using the `WASMTIME_BACKTRACE_DETAILS=1` environment variable may show more debugging information
2: wasm trap: wasm `unreachable` instruction executed
The main problem here is:
-
__main_argc_argv
is defined with hidden visibility
$ wasm-objdump -x main.o | grep "F <__main_argc_argv>"
- 0: F <__main_argc_argv> func=1 [ binding=global vis=hidden ]
-
__main_argc_argv
is referenced fromlibc.so
's__main_void
(which is referenced fromcrt1-command.o
's_start
) but the use of__main_argc_argv
inlibc.so
doesn't mark it live. With static-link,libc.a
,crt1-command.o
, andmain.o
are linked together into a single image, so symbols are fully resolved.
Options
There are several ways to resolve the issue. I prefer option 3 as an ideal solution, but I'd like to hear @dicej opinion before tackling it.
Option 1. Adding -Xlinker -export-if-defined=__main_argc_argv
to clang
command.
This is a tentative workaround without toolchain modification.
Option 2. Set __main_argc_argv
's visibility as default in clang
- Need to update other compilers that use wasi-libc like Swift
- The symbol will be leaked to other images
Option 3. Move __main_void
to crt1-command.o
- Linking
__main_void
into the main module cleanly solves the liveness issue. - According to the comment, something wrong happens with
--no-gc-sections
.
I think option 3 makes the most sense.
Option 3 sounds good to me, too, but see also https://github.com/WebAssembly/wasi-libc/pull/429#discussion_r1295544604 for the discussion regarding --no-gc-sections
. @yamt may have opinions about this.
Yes, we would have to find a way to not break --no-gc-sections
of course.
i have been using Option 1 if it matters. https://github.com/yamt/garbage/blob/fbc9f79d77243940251a8826f0eba67cf986bf76/c/shlib/wasi.sh#L64-L72
as you can see in the above url, i needed many non-default linker options to build a reasonable pie executable. --export-if-defined=__main_argc_argv
was merely one of them. isn't it the case for you?
Option 2. Set
__main_argc_argv
's visibility as default in clang* Need to update other compilers that use wasi-libc like Swift
does swift use llvm wasm-ld?
* The symbol will be leaked to other images
can you explain a bit?
@yamt
i have been using Option 1 if it matters.
https://github.com/yamt/garbage/blob/fbc9f79d77243940251a8826f0eba67cf986bf76/c/shlib/wasi.sh#L64-L72
That's good to know, thanks for sharing.
as you can see in the above url, i needed many non-default linker options to build a reasonable pie executable.
--export-if-defined=__main_argc_argv
was merely one of them. isn't it the case for you?
Right, it's one of tweaks but I think it would be better if we can reduce the number of such tweaks that is needed due to toolchain internal implementation.
Also we actually don't need to "export" the entry point but just need to include it in the final linked module. I don't think it causes any real problem at this moment but would be better to keep exported stuff minimal.
Option 2. Set
__main_argc_argv
's visibility as default in clang* Need to update other compilers that use wasi-libc like Swift
does swift use llvm wasm-ld?
Yes, we are using LLVM and wasm-ld, and doing main entry point codegen like what clang does. https://github.com/apple/swift/blob/a6c98879abefd42d67aeeb3394784281061d1647/lib/AST/ASTContext.cpp#L5989
* The symbol will be leaked to other images
can you explain a bit?
If we made __main_argc_argv
's visibility as __attribute__((visibility(default)))
, the entry point would be visible from other shared libraries. As I said for Option 1, I don't think it will be a problem soon, but exposing a symbol is not an ideal side-effect just for retaining the symbol.
Anyway, I will trace the problem of --no-gc-section
to see if Option 3 is a realistic option
as you can see in the above url, i needed many non-default linker options to build a reasonable pie executable.
my memory was a bit wrong. actually, flags for pie executable: https://github.com/yamt/garbage/blob/6c69da7068c4f61d95b38a7642693c646985f550/c/shlib/wasi.sh#L59-L68 flags for non-pie executable: https://github.com/yamt/garbage/blob/6c69da7068c4f61d95b38a7642693c646985f550/c/shlib/wasi.sh#L75-L91