We are more or less trying to solve this exact problem with Wasm Components [1]. If core WebAssembly is a portable instruction format, WebAssembly Components are a portable executable/linkable format.
Using them is unfortunately not yet quite as easy as using repr(wasm)/extern "wasm". But with wit-bindgen [2] and the wasm32-wasip2 target [3], it's not that hard either.
I love WASM and WASI, but it's not nearly the same, unfortunately. Performance takes a hit, you can't use async in a straightforward way, launching hundreds of thousands of tasks is problematic etc. WASM is great for allowing to extend your app, but I don't see it as a replacement for an ABI anytime soon