Skip to content
This repository has been archived by the owner on Mar 24, 2022. It is now read-only.

Does compiler attribute also work in wasm32-wasi-gcc? #259

Closed
posutsai opened this issue Jul 30, 2019 · 8 comments
Closed

Does compiler attribute also work in wasm32-wasi-gcc? #259

posutsai opened this issue Jul 30, 2019 · 8 comments

Comments

@posutsai
Copy link

I try to use used attribute in gcc to force my enterFunc appears in the wasm name section. However, it seems doesn't work. I wonder could I use all features in original clang or gcc and if not, how can I force my function to be compiled?

#include <stdio.h>

void __attribute__((used)) enterFunc() {
    printf("entering Function !");
}

int addTwo(int a, int b) {
    return a + b;
}

int main(int argc, char *argv[]) {
    addTwo(1, 1);
    return 0;
}
@pchickey
Copy link
Contributor

We haven't tried using gcc to emit wasm at all. In theory, the wasm it emits should work. I'm not sure how to ensure that gcc will emit an export for a given function. I'm not able to find docs on gcc's support of wasm on the gnu site, where did you get this gcc toolchain from?

@posutsai
Copy link
Author

posutsai commented Aug 2, 2019

Isn't wasm32-wasi-gcc part of toolchain provided by lucet? I thought it was installed with lucet. Anyway, it's just a demonstration that I try to compile from c to wasm using wasm as backend and execute on wasi environment. If wasm32-wasi-clang can do the same thing just like the demo on wiki page, it is totally fine to use it as the compiler.

I believe I have to elaborate on my issue. All I want to do is to let a function foo which is called in a.wasm but defined in another b.wasm. I find out it is possible to integrate multiple WebAssembly modules in Javascript host by dynamic linking. I wonder whether I can do the same thing in wasi or not

// a.c -> a.wasm
extern void foo();
int main() {
    foo();
}

// b.c -> b.wasm
#include <stdio.h>
void foo() {
    printf("this is foo function");
}

Specifically, I already know if I use extern keyword and compiled by emcc, a.wasm will attempt to import foo function from env. The foo function will be exported by adding EMSCRIPTEN_KEEPALIVE macro. I would like to do the same thing in wasi.

Sorry for not describing my issue clearly.

@tyler
Copy link
Member

tyler commented Aug 2, 2019

Solving your immediate issue should be as simple as defining a macro like:

#define export __attribute__( ( visibility( "default" ) ) )

And then prepend your function definitions with the macro in the same way as the EMSCRIPTEN_KEEPALIVE macro.

The larger thing you’re trying to do with dynamic linking is a little trickier. Lucet provides a lower level interface to working with wasm modules and instances. In principle, there’s no reason you can’t do it. But it won’t be quite as straight-forward as in javascript.

@posutsai
Copy link
Author

posutsai commented Aug 8, 2019

@tyler
Thank you for your answer. I have tried to add __attribute__(( visibility( "default" )) on my foo function. Here are the outputs of those files using wasm-objdump.

# a.wasm
b.wasm:	file format wasm 0x1

Section Details:

Type[2]:
 - type[0] (i32, i32) -> i32
 - type[1] () -> nil
Import[4]:
 - memory[0] pages: initial=0 <- env.__linear_memory
 - table[0] elem_type=funcref init=0 max=0 <- env.__indirect_function_table
 - global[0] i32 mutable=1 <- env.__stack_pointer
 - func[0] sig=1 <env.foo> <- env.foo
Function[1]:
 - func[1] sig=0 <main>
Code[1]:
 - func[1] size=84 <main>
Custom:
 - name: "linking"
  - symbol table [count=3]
   - 0: F <main> func=1 binding=global vis=hidden
   - 1: G <env.__stack_pointer> global=0 undefined binding=global vis=default
   - 2: F <env.foo> func=0 undefined binding=global vis=default
Custom:
 - name: "reloc.CODE"
  - relocations for section: 3 (Code) [4]
   - R_WASM_GLOBAL_INDEX_LEB offset=0x000006(file=0x00008d) symbol=1 <env.__stack_pointer>
   - R_WASM_GLOBAL_INDEX_LEB offset=0x00001b(file=0x0000a2) symbol=1 <env.__stack_pointer>
   - R_WASM_FUNCTION_INDEX_LEB offset=0x00003a(file=0x0000c1) symbol=2 <env.foo>
   - R_WASM_GLOBAL_INDEX_LEB offset=0x00004d(file=0x0000d4) symbol=1 <env.__stack_pointer>


# b.wasm
b.wasm:	file format wasm 0x1

Section Details:

Type[2]:
 - type[0] () -> nil
 - type[1] (i32, i32) -> i32
Import[3]:
 - memory[0] pages: initial=1 <- env.__linear_memory
 - table[0] elem_type=funcref init=0 max=0 <- env.__indirect_function_table
 - func[0] sig=1 <env.printf> <- env.printf
Function[1]:
 - func[1] sig=0 <foo>
Code[1]:
 - func[1] size=28 <foo>
Data[1]:
 - segment[0] <.rodata..L.str> size=12 - init i32=0
  - 0000000: 6865 6c6c 6f77 6f72 6c64 0a00            helloworld..
Custom:
 - name: "linking"
  - symbol table [count=3]
   - 0: F <foo> func=1 binding=global vis=default
   - 1: D <.L.str> segment=0 offset=0 size=12 binding=local vis=default
   - 2: F <env.printf> func=0 undefined binding=global vis=default
  - segment info [count=1]
   - 0: .rodata..L.str p2align=0 flags=0
Custom:
 - name: "reloc.CODE"
  - relocations for section: 3 (Code) [2]
   - R_WASM_MEMORY_ADDR_SLEB offset=0x000006(file=0x000079) symbol=1 <.L.str>
   - R_WASM_FUNCTION_INDEX_LEB offset=0x000016(file=0x000089) symbol=2 <env.printf>

As you can see, I failed to export foo function from b.wasm because it even doesn't have export section. Could you please describe more detail about those lower level interface in lucet. I guess to achieve my goal there are still several issues need to be solved.

  1. Export foo function from b.wasm
  2. Inject foo function into env module and make foo function importable.
  3. Find a way to let lucet runtime take instantiated a.wasm module as input and link to b.wasm when foo function is needed.

I wonder if those steps make sense and possible to do it. By the way, I use the attribute which is mentioned here. I am able to specify exactly which module to link the foo function. However, I don't know where to name the instantiated module. Thank you.

@pchickey
Copy link
Contributor

pchickey commented Aug 8, 2019

Are you using the clang compiler provided with wasi-sdk (e.g. typically installed at /opt/wasi-sdk/bin/clang? Those attributes work with clang's wasm compiler & linker.

If you are using wasm32-wasi-gcc, which I am not personally familiar with, that mechanism may not work. Could you share the command you used to compile the above module, and what your compiler says when passed the --version flag (or where you downloaded it from)? Was there some reason you chose this different compiler?

@pchickey
Copy link
Contributor

pchickey commented Aug 8, 2019

To answer the second part of the question - at this time, there is not a straightforward way to instantiate two webassembly modules and link them together using Lucet. You'd have to create rust functions in order to call the export function of one module from the import function of another. Even if you could do that, there's no way to share other imported/exported instance resources (memories, tables, globals) between instances in Lucet.

This isn't a restriction we intend to have forever, but at the moment, adding those capabilities isn't a high priority, because the applications we're using Lucet for does not require that sort of sophistication. If you absolutely need those capabilities, you could look into https://github.com/CraneStation/wasmtime/, which I believe does support that kind of thing. Lucet and Wasmtime share a bunch of code but I'm not super familiar with that aspect of their codebase.

@posutsai
Copy link
Author

posutsai commented Aug 8, 2019

@pchickey
Thank you for the comment. I use the same two wasm files and use preload option in wasmtime runtime. They successfully link to each other.
Here are the versions of the compilers I use. I have tried several ways to compile it.

# Version
$ wasm32-wasi-gcc --version
clang version 8.0.0 (tags/RELEASE_800/final)
Target: wasm32-unknown-wasi
Thread model: single
InstalledDir: /usr/local/opt/llvm/bin

# Compiling
# using gcc
$ wasm32-wasi-gcc -o foo.wasm foo.c -nostartfiles -Wl,--no-entry,--export=foo
# using clang
$ clang --sysroot=/opt/wasi-sysroot/ --target=wasm32-unknown-wasi -o foo.wasm foo.c -nostartfiles -Wl,--no-entry,--export=foo

After I manually add --export=foo flag, it appears in export section eventually but I still would like to know how to do it internally, without specifying each exported function explicitly.

@posutsai
Copy link
Author

posutsai commented Aug 9, 2019

I believe wasmtime really would be a better place to discuss my issue and I already create another issue in that repo.wasmtime's contributor offers some useful comments. I will close this issue. Feel free to ask me if someone is curious about how I solve the issue. Thank you both @pchickey and @tyler .

@posutsai posutsai closed this as completed Aug 9, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants