-
Notifications
You must be signed in to change notification settings - Fork 190
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LTO failing to prune WASI fd_* imports #401
Comments
The term LTO normally refers to a specific thing which I believe what you are talking about here is normal linker DCE (dead code elimination) that we support via
Note: (2) only happens if One limitation that we currently have is that (1) is performed first. This is when we pull any needed object files from archives. Once we decide we need and object file its not possible to fully undo this decision, if we find out later (in 2) that we didn't need it after all. @sunfishcode has tried to work around this limitation in some cases: https://reviews.llvm.org/D85062 |
Thanks for taking a look. There's a good chance I'm using the wrong terms everywhere! I'm not familiar with this whole toolchain at all. I used lto only because that was the term in the I think the reference (or at least one of them) that is preventing the (func $__wasm_call_dtors (;630;) (type 72)
call $#func629<dummy>
call $__stdio_exit
)
(func $_initialize.command_export (;631;) (type 31) (result i32)
call $_initialize
call $__wasm_call_dtors
) I think I can use a tool like Having spent some time looking the |
The I would hope that the kind of DCE you are trying achieve here would work with or without LTO enabled.
Indeed any time you have function pointer floating around (such as vtables, or in this case I believe musl using a kind of vtable type thing for std file handles) then DCE becomes hard since the linker cannot easily reason about the dependency graph. This is one reason why de-virtualization in C++ is useful when it works.
I think one of the problem is that stdio in musl is using dyanmic dispatch. See https://github.com/bminor/musl/blob/7ada6dde6f9dc6a2836c3d92c2f762d35fd229e0/src/internal/stdio_impl.h#L28-L30 The dispatch tables then include pointer to the function you want to avoid including: https://github.com/bminor/musl/blob/7ada6dde6f9dc6a2836c3d92c2f762d35fd229e0/src/stdio/stdin.c#L11-L13 |
For The problem is that I imagine what is happening is that |
@sbc100 as I noted, I'm a bit over my head here but that matches my intuition. Here's what I think is happening, again from intuition only: I've got a dummy c library that has a strong reference to Even though the consuming rust project only consumes a symbol from the library that has no references, they are statefully baked in and obfuscated through that dynamic dispatch mechanism. |
I wonder if there's some trick that might allow us to avoid the virtualization of these Does that sound plausible? |
If you can find a way to do what you describe that would be great. I am not aware of any way to achieve that though. |
I am not sure whether what I have found is relevant for you, as it is for C++ and not Rust, but I was struggling with something similar (undesired I haven't dug into productising this solution for various configurations and it's possibly not an ideal default, but I'd argue it should be taken under consideration, as as of now there is no way to natively run stdlib containers in simple bare metal applications in the browser without relying on a WASI runtime or recompiling the whole SDK (which takes a while as you surely are aware of). I have pushed a PR with more details here: #418 |
I saw that WebAssembly/wasi-libc#505 landed and wonder if that might be a tool to help address the issues brought up here. If that's the case, is a custom build of the sdk required to take advantage of it? |
In this repo, I've shown two scenarios where code that is functionally identical produces very different WASM binaries.
Setup
The two scenarios I'm testing are for a rust
cdylib
whose code looks like this:Importantly, the
print
function is guarded by theprint
feature that is off by default.The c code we're binding looks like this:
If we run the
cargo build
withNO_PRINTF=1
, then the c code instead looks like this:Scenario 1:
WASM binary size: 2.4K
Scenario 2:
NO_PRINTF=1
WASM binary size: 459B
Conclusion
This might be totally expected given the rust compilation pipeline and the way
wasi-libc
is authored and structured, but is quite surprising to me.I was expecting that link-time optimizations would be 'smart' enough to notice that
printf
was not referenced by any exported functions in the rust library and recursively pruned. I've put together the minimal repro in hopes that it helps illustrate the observations in a reproducible way and could be helpful if this behaviour is not as intended.The text was updated successfully, but these errors were encountered: