Defaulting __attribute__((__weak__, __visibility__("hidden")))

1,211 views
Skip to first unread message

Rong Jie

unread,
Jun 5, 2017, 6:20:44 AM6/5/17
to emscripten-discuss
I am experimenting to generate WebAssembly code with wasm backend so that I don't need to rely on Emscripten's bulky JS library.

  1. Download artifacts from wasm-stat.us (currently all bots are red/yellow, I am using old artifacts).
  2. Write C code and compile with clang -S --target=wasm32-unknown-unknown -I lib\clang\5.0.0\include -I sysroot\include
  3. Compile .s to .wast with s2wasm --allocate-stack=1024 --import-memory --global-base=1024
  4. Optimize .wast and convert to .wasm with wasm-opt.
The result was pretty great, but the .wasm code includes all the unused functions because they are all exported. By adding __attribute__((__weak__, __visibility__("hidden"))) to potentially-unwanted functions and pass to wasm-opt, these functions can be stripped out.

My question is, can I do the inverse? Specifically, how to tell clang that I want all functions to default to __attribute__((__weak__, __visibility__("hidden"))), I will manually mark small number of functions I want to export with __attribute__((__weak__, __visibility__("default"))).

My code snippet in case you are interested.

#include <stdio.h>
#include <stdarg.h>

int hello[100];
int world[100];

int* __attribute__((__weak__, __visibility__("hidden"))) getHello() {
 
return hello;
}

int* __attribute__((__weak__, __visibility__("hidden"))) getWorld() {
 
return world;
}

long long __attribute__((__weak__, __visibility__("hidden"))) add64(long long a, long long b) {
 
return a + b;
}

int __attribute__((__weak__, __visibility__("hidden"))) vararg(int n, ...) {
 
int res = 0;
  va_list vl
;
  va_start
(vl, n);
 
for (int i = 0; i < n; i++)
    res
+= va_arg(vl, int);
  va_end
(vl);
 
return res;
}

char s[5];

int main() {
 
int a = vararg(5, 1, 2, 3, 4, 5);
  s
[0] = a/10+'0';
  s
[1] = a%10+'0';
  s
[2] = '\0';
  puts
(s);  
 
return 0;
}

weitjong

unread,
Jun 5, 2017, 8:10:30 AM6/5/17
to emscripten-discuss
https://gcc.gnu.org/wiki/Visibility

Clang is a drop-in replacement for GCC, so whatever explained in that page for symbol visibility is applicable for Clang as well.

Rong Jie

unread,
Jun 5, 2017, 7:48:10 PM6/5/17
to emscripten-discuss
-fvisibility=hidden, #pragma GCC visibility push(hidden), __attribute__((visibility("hidden"))), none of them work at all.

weitjong

unread,
Jun 5, 2017, 9:14:58 PM6/5/17
to emscripten-discuss
We have used the visibility attribute successfully in our project. The "-f" flags tell the linker to hide all the symbols, except those we have explicitly marked as having default visibility. We do that by using a preprocessor macro, quite similar to the one being outlined in the above link (though we have let CMake to auto-generate the macro for us so it is cross-platform). For our case it works for all the GCC/Clang compiler toolchains (both native and cross-compiling) that our project works with so far.

You didn't say exactly what didn't work for you.

Rong Jie

unread,
Jun 5, 2017, 11:03:01 PM6/5/17
to emscripten-discuss
Sorry for the confusion.

If I remove all __attribute__((__weak__, __visibility__("hidden"))) and:
  • Pass -fvisibility=hidden to clang
  • Or add #pragma GCC visibility push(hidden) at the beginning of C code.
  • Or add __attribute__((visibility("hidden"))) to all functions.
then in the .s file, I will see

        .hidden foo
       
.globl  foo
       
.type   foo,@function

instead of

        .hidden foo
       
.weak  foo
       
.type   foo,@function

So s2wasm still export all of them instead of those that are really used.

 (export "getHello" (func $0))
 
(export "getWorld" (func $1))
 
(export "add64" (func $2))
 
(export "vararg" (func $3))
 
(export "main" (func $4))

Which means wasm-opt can't eliminate them since they are exported.

Only adding __attribute__((__weak__, __visibility__("hidden"))) to all functions except those I want to export will make it works

Remember that I am doing clang -> s2wasm -> wasm-opt.

weitjong

unread,
Jun 6, 2017, 8:28:25 AM6/6/17
to emscripten-discuss
I see what you meant now. But it sounds like you want those symbols to get internalized. I think you should not use visibility attribute for that. May be try make your function static and compile with optimization level 1 or above.

Rong Jie

unread,
Jun 6, 2017, 9:49:10 AM6/6/17
to emscripten-discuss
I always use -O2. Your advice about using "static" works nicely, but that means I still need to update all functions.

I still can't determine how Emscripten does this without updating all function (only exported functions need "__attribute__((used))" and exported functions are always minority).

Alon Zakai

unread,
Jun 6, 2017, 1:54:59 PM6/6/17
to emscripten-discuss
> I am experimenting to generate WebAssembly code with wasm backend so that I don't need to rely on Emscripten's bulky JS library.

Those are separate issues. If you want to generate wasm without JS code, see


(you can do that with either backend, but the wasm backend isn't recommended yet for the same reasons it isn't recommended yet for non-standalone code, it's not stable or optimized yet).


--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsub...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages