Skip to content
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

Configure C function exports correctly for emscripten targets #39171

Closed
brson opened this issue Jan 19, 2017 · 15 comments
Closed

Configure C function exports correctly for emscripten targets #39171

brson opened this issue Jan 19, 2017 · 15 comments
Labels
A-linkage Area: linking into static, shared libraries and binaries O-asmjs Target: asm.js - http://asmjs.org/ O-wasm Target: WASM (WebAssembly), http://webassembly.org/

Comments

@brson
Copy link
Contributor

brson commented Jan 19, 2017

In order to call emscriptened functions from JS one must pass -s EXPORTED_FUNCTIONS=[...] to emcc, with each exported symbol. ISTM that it would be consistent for rustc to do this automatically for cdylib and staticlib targets.

cc @CryZe @alexcrichton

@brson brson added O-asmjs Target: asm.js - http://asmjs.org/ A-linkage Area: linking into static, shared libraries and binaries O-wasm Target: WASM (WebAssembly), http://webassembly.org/ labels Jan 19, 2017
@alexcrichton
Copy link
Member

We've already got lists of symbols that we explicitly pass to the linker to export, so this shouldn't be too hard to implement as well!

@RReverser
Copy link
Contributor

I'd like to try to implement this in a PR.

@RReverser
Copy link
Contributor

RReverser commented Jan 22, 2017

Kinda implemented this locally but there are two issues/caveats:

  1. Apparently JS is generated only for binary target, so to export functions you still need to compile with such target and have at least empty main function.

  2. To achieve this, I've patched export_symbols function in linker which seems like a proper place; however, it seems like symbols are collected from all dependent crates too, so the list of exported functions looks like:

[
    "_foo",
    "_main",
    "___udivmodti4",
    "___fixsfti",
    "___fixunsdfti",
    "___floattisf",
    "___muloti4",
    "___modti3",
    "___divti3",
    "___umodti3",
    "___udivti3",
    "___fixdfti",
    "___floatuntisf",
    "___multi3",
    "___floattidf",
    "___fixunssfti",
    "___floatuntidf",
    "___lshrti3",
    "___ashrti3",
    "___ashlti3",
    "___rust_reallocate",
    "___rust_reallocate_inplace",
    "___rust_deallocate",
    "___rust_allocate",
    "___rust_usable_size",
    "___rust_start_panic",
    "_rust_eh_personality",
    "___rust_maybe_catch_panic"
]

As you can see, apart from own exported _main (required) and _foo (explicitly exported), tons of others are added, and some of them are incompatible with Emscripten which makes it complain:

LLVM ERROR: Function __ashlti3 has illegal integer argument
Traceback (most recent call last):
  File "/Users/rreverser/cf-repos/rust/emsdk_portable/emscripten/incoming/emcc", line 13, in <module>
    emcc.run()
  File "/Users/rreverser/cf-repos/rust/emsdk_portable/emscripten/incoming/emcc.py", line 1647, in run
    final = shared.Building.emscripten(final, append_ext=False, extra_args=extra_args)
  File "/Users/rreverser/cf-repos/rust/emsdk_portable/emscripten/incoming/tools/shared.py", line 1745, in emscripten
    call_emscripten(cmdline)
  File "/Users/rreverser/cf-repos/rust/emsdk_portable/emscripten/incoming/emscripten.py", line 1836, in _main
    temp_files.run_and_clean(lambda: main(
  File "/Users/rreverser/cf-repos/rust/emsdk_portable/emscripten/incoming/tools/tempfiles.py", line 78, in run_and_clean
    return func()
  File "/Users/rreverser/cf-repos/rust/emsdk_portable/emscripten/incoming/emscripten.py", line 1841, in <lambda>
    DEBUG=DEBUG,
  File "/Users/rreverser/cf-repos/rust/emsdk_portable/emscripten/incoming/emscripten.py", line 1742, in main
    temp_files=temp_files, DEBUG=DEBUG)
  File "/Users/rreverser/cf-repos/rust/emsdk_portable/emscripten/incoming/emscripten.py", line 91, in emscript
    funcs, metadata, mem_init = get_and_parse_backend(infile, settings, temp_files, DEBUG)
  File "/Users/rreverser/cf-repos/rust/emsdk_portable/emscripten/incoming/emscripten.py", line 160, in get_and_parse_backend
    backend_output = open(temp_js).read()

Should we somehow filter those or even allow only top-level exports?

@CryZe
Copy link
Contributor

CryZe commented Jan 22, 2017 via email

@RReverser
Copy link
Contributor

@CryZe I guess; anyway, that wasn't my main point, just wanted to clarify "for rustc to do this automatically for cdylib and staticlib targets" from the first comment.

@alexcrichton
Copy link
Member

@RReverser some of those are existing bugs in the compiler (such as ___rust_reallocate) but others like ___umodti3 are news to me! They shouldn't be in that symbol list at all in theory...

@RReverser
Copy link
Contributor

@alexcrichton Apparently they're coming from libcompiler_builtins which does export them explicitly:

        #[export_name="__umodti3"]
        pub extern "C" fn u128_mod_(a: u128_, b: u128_) -> $cret {
            unsafe {
                let mut r = ::core::mem::zeroed();
                u128_div_mod(a, b, &mut r);
                ($conv)(r)
            }
        }

@alexcrichton
Copy link
Member

@RReverser indeed! I'm working on a patch (alexcrichton@9048de6) to fix this but it'll take a moment to finish testing.

@RReverser
Copy link
Contributor

RReverser commented Jan 22, 2017

@alexcrichton No problem, just let me know when I should send a PR.

In the meanwhile, instead of condition in GnuLinker's export_symbols, I defined a separate Linker for Emscripten with support for passing optimization levels, debug levels, and now playing to see whether I can add dynamic linking support.

@alexcrichton
Copy link
Member

@RReverser I've posted a PR for that change.

@brson
Copy link
Contributor Author

brson commented Jan 27, 2017

Apparently JS is generated only for binary target

I wonder if this is the correct behavior. Perhaps asmjs staticlibs and/or cdylibs should be .js?

@brson
Copy link
Contributor Author

brson commented Jan 27, 2017

I honestly don't know what extensions we emit for all the output types for asmjs.

@brson
Copy link
Contributor Author

brson commented Jan 27, 2017

It looks to me like asm.js uses the default extension types for dylibs and staticlibs, .so, and .a.

I'd say that staticlibs being .a is correct for something you are going to run through emcc, but maybe .so should be .js. Are we really emitting .so files?

@RReverser
Copy link
Contributor

RReverser commented Jan 28, 2017

@brson We are not - we simply prohibit dynamically linked libs altogether AFAIK. I think what we really should do is generate them via Emscripten's SIDE_MODULE / MAIN_MODULE mechanism, but that requires a little bit more investigation.

Btw, I've left my laptop with changes at the office, will rebase & submit PR for this issue on Monday if that works for you. Would be nice to finally get some first PR into Rust :)

@brson
Copy link
Contributor Author

brson commented Feb 1, 2017

Sounds good @RReverser !

RReverser added a commit to RReverser/rust that referenced this issue Feb 7, 2017
It claims to accept most GNU linker options, but in fact most of them
have no effect and instead it requires some special options which are
easier to handle in a separate trait.

Currently added:
 - `export_symbols`: works on executables as special Emscripten case
since staticlibs/dylibs aren't compiled to JS, while exports are
required to be accessible from JS.
Fixes rust-lang#39171.
 - `optimize` - translates Rust's optimization level to Emscripten
optimization level (whether passed via `-C opt-level=...` or `-O...`).
Fixes rust-lang#36899.
 - `debuginfo` - translates debug info; Emscripten has 5 debug levels
while Rust has 3, so chose to translate `-C debuginfo=1` to `-g3`
(preserves whitespace, variable and function names for easy debugging).
Fixes rust-lang#36901.
 - `no_default_libraries` - tells Emscripten to exlude `memcpy` and co.
frewsxcv added a commit to frewsxcv/rust that referenced this issue Feb 8, 2017
Add Emscripten-specific linker

Emscripten claims to accept most GNU linker options, but in fact most of `-Wl,...` are useless for it and instead it requires some additional special options which are easier to handle in a separate trait.

Currently added:
 - `export_symbols`: works on executables as special Emscripten case since staticlibs/dylibs aren't compiled to JS, while exports are required to be accessible from JS.
Fixes rust-lang#39171.
 - `optimize` - translates Rust's optimization level to Emscripten optimization level (whether passed via `-C opt-level=...` or `-O...`).
Fixes rust-lang#36899.
 - `debuginfo` - translates debug info; Emscripten has 5 debug levels while Rust has 3, so chose to translate `-C debuginfo=1` to `-g3` (preserves whitespace, variable and function names for easy debugging).
Fixes rust-lang#36901.
 - `no_default_libraries` - tells Emscripten to exclude `memcpy` and co.

TODO (in future PR): dynamic linking via `SIDE_MODULE` / `MAIN_MODULE` mechanism.
frewsxcv added a commit to frewsxcv/rust that referenced this issue Feb 8, 2017
Add Emscripten-specific linker

Emscripten claims to accept most GNU linker options, but in fact most of `-Wl,...` are useless for it and instead it requires some additional special options which are easier to handle in a separate trait.

Currently added:
 - `export_symbols`: works on executables as special Emscripten case since staticlibs/dylibs aren't compiled to JS, while exports are required to be accessible from JS.
Fixes rust-lang#39171.
 - `optimize` - translates Rust's optimization level to Emscripten optimization level (whether passed via `-C opt-level=...` or `-O...`).
Fixes rust-lang#36899.
 - `debuginfo` - translates debug info; Emscripten has 5 debug levels while Rust has 3, so chose to translate `-C debuginfo=1` to `-g3` (preserves whitespace, variable and function names for easy debugging).
Fixes rust-lang#36901.
 - `no_default_libraries` - tells Emscripten to exclude `memcpy` and co.

TODO (in future PR): dynamic linking via `SIDE_MODULE` / `MAIN_MODULE` mechanism.
RReverser added a commit to RReverser/rust that referenced this issue Feb 10, 2017
It claims to accept most GNU linker options, but in fact most of them
have no effect and instead it requires some special options which are
easier to handle in a separate trait.

Currently added:
 - `export_symbols`: works on executables as special Emscripten case
since staticlibs/dylibs aren't compiled to JS, while exports are
required to be accessible from JS.
Fixes rust-lang#39171.
 - `optimize` - translates Rust's optimization level to Emscripten
optimization level (whether passed via `-C opt-level=...` or `-O...`).
Fixes rust-lang#36899.
 - `debuginfo` - translates debug info; Emscripten has 5 debug levels
while Rust has 3, so chose to translate `-C debuginfo=1` to `-g3`
(preserves whitespace, variable and function names for easy debugging).
Fixes rust-lang#36901.
 - `no_default_libraries` - tells Emscripten to exlude `memcpy` and co.
bors added a commit that referenced this issue Feb 10, 2017
Add Emscripten-specific linker

Emscripten claims to accept most GNU linker options, but in fact most of `-Wl,...` are useless for it and instead it requires some additional special options which are easier to handle in a separate trait.

Currently added:
 - `export_symbols`: works on executables as special Emscripten case since staticlibs/dylibs aren't compiled to JS, while exports are required to be accessible from JS.
Fixes #39171.
 - `optimize` - translates Rust's optimization level to Emscripten optimization level (whether passed via `-C opt-level=...` or `-O...`).
Fixes #36899.
 - `debuginfo` - translates debug info; Emscripten has 5 debug levels while Rust has 3, so chose to translate `-C debuginfo=1` to `-g3` (preserves whitespace, variable and function names for easy debugging).
Fixes #36901.
 - `no_default_libraries` - tells Emscripten to exclude `memcpy` and co.

TODO (in future PR): dynamic linking via `SIDE_MODULE` / `MAIN_MODULE` mechanism.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-linkage Area: linking into static, shared libraries and binaries O-asmjs Target: asm.js - http://asmjs.org/ O-wasm Target: WASM (WebAssembly), http://webassembly.org/
Projects
None yet
Development

No branches or pull requests

4 participants