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

Export Table from standalone wasm modules #9907

Closed
kripken opened this issue Nov 27, 2019 · 14 comments
Closed

Export Table from standalone wasm modules #9907

kripken opened this issue Nov 27, 2019 · 14 comments
Labels

Comments

@kripken
Copy link
Member

kripken commented Nov 27, 2019

In standalone wasm modules we don't import the memory or the table. We do export the memory by default, but not the table.

Should we always export it, or optionally perhaps?

@sbc100
Copy link
Collaborator

sbc100 commented Nov 27, 2019

We already have a linker flag for that: -Wl,--export-table. However we currently have whitelist of supported linker flags, we should probably switch the balcklist instead.

@kripken
Copy link
Member Author

kripken commented Nov 27, 2019

We went back and forth on the blacklist/whitelist issue I think, and I don't remember the details... maybe it's simplest to just add that to the current whitelist?

@cggallant
Copy link

On my side the --export-table flag worked because it was part of the SUPPORTED_LLD_LINKER_FLAG_PREFIXES list in emcc.py. I needed to adjust the SUPPORTED_LLD_LINKER_FLAGS list locally to allow the --growable-table flag to work too.

@Rochet2
Copy link

Rochet2 commented Aug 13, 2020

Seems I am still unable to use --export-table. Using 2.0.0 (d81f400).
Without this, the table must always be imported from host with -Wl,--import-table in dynamic linking case as far as I see.

Have not seen --growable-table flag anywhere (even google), but seems emscripten enforces a fixed size by default and allows using -s ALLOW_MEMORY_GROWTH=1 to allow growing up to a point, which is nice.

@ggallant-dovico
Copy link

Just an FYI, with the latest version of Emscripten (1.40.1), I don't need to adjust the emcc.py file anymore.

@sbc100
Copy link
Collaborator

sbc100 commented Aug 14, 2020

Yes -Wl,--export-table now works with standalone mode.

@Rochet2 is your issue something different? Does -Wl,--export-table -s STANDALONE_WASM not work as expected for you?

For normal mode (non-standalone) we always create the table in JS and import it into the wasm module. We don't support anyother mode that I know of.

@Rochet2
Copy link

Rochet2 commented Aug 14, 2020

@sbc100 Here is a full example.

The C file:

#include <stdlib.h>

int foo() {
    return 42;
}

int bar() {
    return 9001;
}

__attribute__((used))
int main() {
    int (*indirectly_called)() = rand()%2 == 0 ? &foo : &bar;
    indirectly_called();
    return 0;
}

Command used to build:

docker run   --rm   -v $(pwd):/src   -u $(id -u):$(id -g)   emscripten/emsdk   emcc example.c -o example.wasm -Os -Wl,--export-table,--no-entry,--export,malloc -s ALLOW_MEMORY_GROWTH=1 -s STANDALONE_WASM

The generated .wasm converted to wat looks like this:

(module
  (type $t0 (func (result i32)))
  (type $t1 (func (param i32) (result i32)))
  (type $t2 (func (param i32)))
  (import "env" "emscripten_notify_memory_growth" (func $env.emscripten_notify_memory_growth (type $t2)))

  ;;;; <A bunch of functions here>

  (table $T0 3 3 funcref)
  (memory $memory 256 32768)
  (global $g0 (mut i32) (i32.const 5244592))
  (export "memory" (memory 0))
  (export "__original_main" (func $__original_main))
  (export "malloc" (func $malloc))
  (elem $e0 (i32.const 1) $f6 $f2)
  (data $d0 (i32.const 1552) "\b0\06P"))

As you may see, both flags were used and the table is not exported even if one exists.
I would expect a table to be exported even if one isn't used though.

Here is the version output:

docker run   --rm   -v $(pwd):/src   -u $(id -u):$(id -g)   emscripten/emsdk   emcc --version
emcc (Emscripten gcc/clang-like replacement) 2.0.0 (d81f400831a22f04901ab149f29d3caf77979bf6)
Copyright (C) 2014 the Emscripten authors (see AUTHORS.txt)
This is free and open source software under the MIT license.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

@ggallant-dovico
Copy link

ggallant-dovico commented Aug 14, 2020

I tested your code on my side and the optimization flag seems to be the issue. If I change it from -Os to -O1 I see the following:

(module
  (type $type0 (func (result i32)))
  (type $type1 (func (param i32) (result i32)))
  (type $type2 (func (param i32)))
  (import "env" "emscripten_notify_memory_growth" (func $env.emscripten_notify_memory_growth (;0;) (param i32)))
  (table $__indirect_function_table (;0;) 3 3 anyfunc)
  (memory $memory (;0;) 256 32768)
  (global $global0 (mut i32) (i32.const 5244576))
  (global $__data_end (;1;) i32 (i32.const 1532))
  (export "memory" (memory $memory))
  (export "__indirect_function_table" (table $__indirect_function_table))
  (export "__original_main" (func $__original_main))
  (export "__errno_location" (func $__errno_location))
  (export "stackSave" (func $stackSave))
  (export "stackRestore" (func $stackRestore))
  (export "stackAlloc" (func $stackAlloc))
  (export "malloc" (func $malloc))
  (export "__data_end" (global $__data_end))
  (export "__growWasmMemory" (func $__growWasmMemory))
  (elem (i32.const 1) $func3 $func2)
...

It now has an export for __indirect_function_table.

@Rochet2
Copy link

Rochet2 commented Aug 14, 2020

Great :)
Without the optimization flags the table is exported, but it seems that the table is fixed size with min 3 and max 3 length.

Trying to append -s ALLOW_TABLE_GROWTH=1 -s RESERVED_FUNCTION_POINTERS=100 or only one of these to the compilation command does nothing.

If --import-table is used, the code imports a table with (import "env" "table" (table $env.table 3 funcref)) allowing the creator of the table to define the limits nicely even if no flags are provided in addition to --import-table.

I feel like there are a few issues bundled in here.
For now, I will keep on importing the table as a workaround.
Doing so allows use of any optimization flags and growing of the table.

@ggallant-dovico
Copy link

To tell it that you want the table to be allowed to grow, include the --growable-table flag as part of the -Wl list:
-Wl,--export-table,--growable-table

@Rochet2
Copy link

Rochet2 commented Aug 14, 2020

Thanks for clarifying.

@sbc100
Copy link
Collaborator

sbc100 commented Aug 14, 2020

OK, so I see two issues here we could fix.

  1. -s ALLOW_TABLE_GROWTH=1 should probably set --growable-table at least in standalone mode (although passing --growable-table directly seems ok since one already need to set explict wasm-ld flags to get the table exported at all).
  2. More importantly, we need to look into why the table export is being removed in -Os.

@kripken
Copy link
Member Author

kripken commented Aug 14, 2020

It looks like metadce removes the table export, as it sees it isn't used.

We should probably rethink how metadce works with standalone mode, as this has come up before. As a workaround for now, though, building with -O2 (less than -O3 or -Os) will avoid metadce, and preserve that export.

@stale
Copy link

stale bot commented Aug 18, 2021

This issue has been automatically marked as stale because there has been no activity in the past year. It will be closed automatically if no further activity occurs in the next 30 days. Feel free to re-open at any time if this issue is still relevant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants