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

wasm output contains compiler_rt exports #2910

Closed
daurnimator opened this issue Jul 17, 2019 · 23 comments · Fixed by #10517
Closed

wasm output contains compiler_rt exports #2910

daurnimator opened this issue Jul 17, 2019 · 23 comments · Fixed by #10517
Labels
arch-wasm 32-bit and 64-bit WebAssembly
Milestone

Comments

@daurnimator
Copy link
Contributor

foo.c:

int foo(void) {
    return 42;
}
$ zig build-lib -target wasm32-freestanding --c-source foo.c
$ wasm-dis foo.wasm  | grep '(func' | tail
 (func $__udivmodti4 (; 265 ;) (type $50) (param $0 i32) (param $1 i64) (param $2 i64) (param $3 i64) (param $4 i64) (param $5 i32)
 (func $__umodti3 (; 266 ;) (type $28) (param $0 i32) (param $1 i64) (param $2 i64) (param $3 i64) (param $4 i64)
 (func $__muloti4 (; 267 ;) (type $50) (param $0 i32) (param $1 i64) (param $2 i64) (param $3 i64) (param $4 i64) (param $5 i32)
 (func $__mulodi4 (; 268 ;) (type $23) (param $0 i64) (param $1 i64) (param $2 i32) (result i64)
 (func $compiler_rt.mulXf3.S.loWord (; 269 ;) (type $35) (param $0 i64) (result i64)
 (func $compiler_rt.mulXf3.S.hiWord (; 270 ;) (type $35) (param $0 i64) (result i64)
 (func $compiler_rt.mulXf3.S.Word_1 (; 271 ;) (type $48) (param $0 i64) (param $1 i64) (result i64)
 (func $compiler_rt.mulXf3.S.Word_2 (; 272 ;) (type $48) (param $0 i64) (param $1 i64) (result i64)
 (func $compiler_rt.mulXf3.S.Word_3 (; 273 ;) (type $48) (param $0 i64) (param $1 i64) (result i64)
 (func $compiler_rt.mulXf3.S.Word_4 (; 274 ;) (type $48) (param $0 i64) (param $1 i64) (result i64)

Related #2062 #2290 #2369

@andrewrk
Copy link
Member

That's correct. Unused functions are not garbage collected until linking. Linking happens with build_exe.

@daurnimator
Copy link
Contributor Author

That's correct. Unused functions are not garbage collected until linking. Linking happens with build_exe.

Ah! so I should be using build-exe instead?
That results in an output file foo (rather than foo.wasm), but it seems to have the right exports:

$ wasm-dis foo | grep '(func'
 (type $0 (func))
 (type $1 (func (result i32)))
 (export "__wasm_call_ctors" (func $__wasm_call_ctors))
 (export "foo" (func $foo))
 (func $__wasm_call_ctors (; 0 ;) (type $0)
 (func $foo (; 1 ;) (type $1) (result i32)

I guess that __wasm_call_ctors function is there because https://reviews.llvm.org/D58806 isn't in LLVM 8?

@andrewrk andrewrk added this to the 0.6.0 milestone Jul 19, 2019
@andrewrk
Copy link
Member

I'm going to leave this open to investigate because my memory is fuzzy about how this is supposed to work.

@daurnimator daurnimator added the arch-wasm 32-bit and 64-bit WebAssembly label Aug 2, 2019
@daurnimator
Copy link
Contributor Author

From #2499 (thanks @fengb)

WebAssembly: build-exe is for executables which have a main(). build-lib is for building libraries of functions to use from, for example, a web browser environment.

I think this conflicts with your statement above?

@andrewrk andrewrk modified the milestones: 0.6.0, 0.7.0 Feb 10, 2020
@andrewrk andrewrk modified the milestones: 0.7.0, 0.8.0 Oct 30, 2020
@s-ol
Copy link
Contributor

s-ol commented Nov 10, 2020

The documentation also suggests to compoile as follows:

$ zig build-lib math.zig -target wasm32-freestanding

https://ziglang.org/documentation/master/#Freestanding

As of 0.7.0, compiling the example with -o ReleaseSmall results in a 51kb .wasm file containing a lot of seemingly useless symbols, not only from compiler_rt:

% wasm-objdump -d math.wasm | grep func
000db7 func[1] <__wasm_call_ctors>:
000dba func[2] <add>:
000dc8 func[3] <memset>:
000df3 func[4] <__memset>:
000e1e func[5] <memcpy>:
000e4f func[6] <memmove>:
000ebf func[7] <memcmp>:
000f0b func[8] <bcmp>:
000f4a func[9] <fmodf>:
001123 func[10] <fmod>:
001328 func[11] <floorf>:
0013a8 func[12] <ceilf>:
00142a func[13] <floor>:
0014e5 func[14] <ceil>:
0015a0 func[15] <fma>:
001b44 func[16] <std.math.frexp.frexp64>:
001c85 func[17] <fmaf>:
001c95 func[18] <sin>:
001f32 func[19] <sinf>:
002126 func[20] <cos>:
00239f func[21] <cosf>:
00257b func[22] <exp>:
0027f6 func[23] <expf>:
0029fb func[24] <exp2>:
002be6 func[25] <exp2f>:
002cff func[26] <log>:
002e86 func[27] <logf>:
002f96 func[28] <log2>:
003160 func[29] <log2f>:
00328a func[30] <log10>:
00346d func[31] <log10f>:
0035a7 func[32] <fabs>:
0035ba func[33] <fabsf>:
0035c8 func[34] <trunc>:
003625 func[35] <truncf>:
00367b func[36] <round>:
00373c func[37] <roundf>:
0037e1 func[38] <sqrt>:
003a07 func[39] <sqrtf>:
003f00 func[40] <__clzsi2>:
003f6e func[41] <__letf2>:
00404f func[42] <__gesf2>:
0040c0 func[43] <__gedf2>:
004149 func[44] <__getf2>:
004222 func[45] <__eqsf2>:
00429b func[46] <__eqdf2>:
00432c func[47] <__gnu_h2f_ieee>:
0043c5 func[48] <__gnu_f2h_ieee>:
0044d7 func[49] <__unordsf2>:
0044fd func[50] <__unorddf2>:
004537 func[51] <__unordtf2>:
00459b func[52] <__addsf3>:
0045a9 func[53] <compiler_rt.addXf3.addXf3>:
004826 func[54] <__adddf3>:
004834 func[55] <compiler_rt.addXf3.addXf3.26>:
004b3c func[56] <__addtf3>:
004b82 func[57] <compiler_rt.addXf3.addXf3.27>:
005129 func[58] <__ashlti3>:
005180 func[59] <__lshrti3>:
0051d7 func[60] <__subsf3>:
0051ed func[61] <__subdf3>:
005208 func[62] <__subtf3>:
00525a func[63] <__mulsf3>:
0054ba func[64] <__muldf3>:
0057f7 func[65] <__multf3>:
005e0b func[66] <__divsf3>:
0060ad func[67] <__divdf3>:
006459 func[68] <__divtf3>:
006e62 func[69] <__multi3>:
006ed8 func[70] <__ashldi3>:
006f38 func[71] <__ashrdi3>:
006f9b func[72] <__ashrti3>:
006ff5 func[73] <__lshrdi3>:
007056 func[74] <__floatsidf>:
007107 func[75] <__floatsisf>:
00719a func[76] <__floatdidf>:
0071e4 func[77] <__floatsitf>:
007292 func[78] <__floatunsisf>:
007308 func[79] <__floatundisf>:
0073ca func[80] <__floatunsidf>:
00740c func[81] <__floatundidf>:
007457 func[82] <__floatditf>:
007510 func[83] <__floattitf>:
0076e2 func[84] <__floattidf>:
0078c2 func[85] <__floattisf>:
007a31 func[86] <__floatdisf>:
007b0e func[87] <__floatunditf>:
007ba4 func[88] <__floatunsitf>:
007c3a func[89] <__floatuntitf>:
007ddd func[90] <__floatuntidf>:
007f87 func[91] <__floatuntisf>:
0080c6 func[92] <__extenddftf2>:
0081db func[93] <__extendsftf2>:
0082d7 func[94] <__truncdfhf2>:
008432 func[95] <__trunctfdf2>:
008631 func[96] <__trunctfsf2>:
00880e func[97] <__truncdfsf2>:
00896a func[98] <__extendsfdf2>:
008a17 func[99] <__fixunssfsi>:
008a85 func[100] <__fixunssfdi>:
008af9 func[101] <__fixunssfti>:
008bd1 func[102] <__fixunsdfsi>:
008c32 func[103] <__fixunsdfdi>:
008cac func[104] <__fixunsdfti>:
008d8a func[105] <__fixunstfsi>:
008e12 func[106] <__fixunstfdi>:
008e9e func[107] <__fixunstfti>:
008f84 func[108] <__fixdfdi>:
009059 func[109] <__fixdfsi>:
0090fb func[110] <__fixdfti>:
00927b func[111] <__fixsfdi>:
00934a func[112] <__fixsfsi>:
0093fa func[113] <__fixsfti>:
009573 func[114] <__fixtfdi>:
009676 func[115] <__fixtfsi>:
009763 func[116] <__fixtfti>:
0098e1 func[117] <__udivmoddi4>:
009bef func[118] <__popcountdi2>:
009c56 func[119] <__mulsi3>:
009c8c func[120] <__muldi3>:
009d05 func[121] <__divmoddi4>:
009d49 func[122] <__divdi3>:
009d7e func[123] <__divsi3>:
009dad func[124] <__udivsi3>:
009e55 func[125] <__udivdi3>:
009e64 func[126] <__modsi3>:
009e98 func[127] <__moddi3>:
009ef1 func[128] <__umodsi3>:
009f9d func[129] <__umoddi3>:
009fd7 func[130] <__divmodsi4>:
00a015 func[131] <__udivmodsi4>:
00a0c8 func[132] <__negsf2>:
00a0d6 func[133] <__negdf2>:
00a0ea func[134] <__divti3>:
00a189 func[135] <compiler_rt.udivmod.udivmod.64>:
00a501 func[136] <__modti3>:
00a59a func[137] <__udivti3>:
00a5e8 func[138] <__udivmodti4>:
00a636 func[139] <__umodti3>:
00a681 func[140] <__muloti4>:
00a831 func[141] <__mulodi4>:
00a907 func[142] <__atomic_load>:
00a947 func[143] <__atomic_store>:
00a987 func[144] <__atomic_exchange>:
00a9d5 func[145] <__atomic_compare_exchange>:
00aa61 func[146] <__atomic_load_1>:
00aa69 func[147] <__atomic_load_2>:
00aa71 func[148] <__atomic_load_4>:
00aa79 func[149] <__atomic_load_8>:
00aab7 func[150] <__atomic_store_1>:
00aac1 func[151] <__atomic_store_2>:
00aacb func[152] <__atomic_store_4>:
00aad5 func[153] <__atomic_store_8>:
00ab0f func[154] <__atomic_exchange_1>:
00ab24 func[155] <__atomic_exchange_2>:
00ab39 func[156] <__atomic_exchange_4>:
00ab4e func[157] <__atomic_exchange_8>:
00ab93 func[158] <__atomic_compare_exchange_1>:
00abc4 func[159] <__atomic_compare_exchange_2>:
00abf5 func[160] <__atomic_compare_exchange_4>:
00ac26 func[161] <__atomic_compare_exchange_8>:
00ac87 func[162] <__atomic_fetch_add_1>:
00ac9d func[163] <__atomic_fetch_add_2>:
00acb3 func[164] <__atomic_fetch_add_4>:
00acc9 func[165] <__atomic_fetch_add_8>:
00ad0f func[166] <__atomic_fetch_sub_1>:
00ad25 func[167] <__atomic_fetch_sub_2>:
00ad3b func[168] <__atomic_fetch_sub_4>:
00ad51 func[169] <__atomic_fetch_sub_8>:
00ad97 func[170] <__atomic_fetch_and_1>:
00adad func[171] <__atomic_fetch_and_2>:
00adc3 func[172] <__atomic_fetch_and_4>:
00add9 func[173] <__atomic_fetch_and_8>:
00ae1f func[174] <__atomic_fetch_or_1>:
00ae35 func[175] <__atomic_fetch_or_2>:
00ae4b func[176] <__atomic_fetch_or_4>:
00ae61 func[177] <__atomic_fetch_or_8>:
00aea7 func[178] <__atomic_fetch_xor_1>:
00aebd func[179] <__atomic_fetch_xor_2>:
00aed3 func[180] <__atomic_fetch_xor_4>:
00aee9 func[181] <__atomic_fetch_xor_8>:
00af2f func[182] <__atomic_fetch_nand_1>:
00af48 func[183] <__atomic_fetch_nand_2>:
00af61 func[184] <__atomic_fetch_nand_4>:
00af7a func[185] <__atomic_fetch_nand_8>:
00afc3 func[186] <__lesf2>:
00afd0 func[187] <__ledf2>:
00afdd func[188] <__ltsf2>:
00afea func[189] <__ltdf2>:
00aff7 func[190] <__nesf2>:
00b004 func[191] <__nedf2>:
00b011 func[192] <__gtsf2>:
00b01e func[193] <__gtdf2>:

@FireFox317
Copy link
Contributor

FireFox317 commented Nov 10, 2020

This suggest we are not passing the --gc-sections flag to the linker anymore. Well actually that only happends when linking as pointed out above (with build-exe)

@s-ol
Copy link
Contributor

s-ol commented Nov 10, 2020

I'm not sure what --gc-sections does exactly, but if it is the equivalent of wabt's wasm-strip then that's not all thats wrong; running the example math.wasm through wasm-strip reduces the filesize from 51k to 48k only.

By adding a dummy pub fn main() that calls add and using build-exe, the filesize goes down to just 150 bytes, but the add function is inlined and no longer exported as a symbol, so this is not a viable workaround for compiling wasm libraries.

@jedisct1
Copy link
Contributor

Build an executable instead.

If you are building a reactor, still add a main() function, containing only references to your entry points:

std.mem.doNotOptimizeAway(entrypoint1);
std.mem.doNotOptimizeAway(entrypoint2);
...

Unused functions will not be present in your module.

@s-ol
Copy link
Contributor

s-ol commented Nov 11, 2020

thanks @jedisct1 for the workaround, this brings the binary size down to 300 bytes, but it is clearly neither comfortable nor how things are intended to be used.

That's correct. Unused functions are not garbage collected until linking. Linking happens with build_exe.

This does not appear to be fully correct, compiling the WASM example without an added main entrypoint or any other workarounds for a native target (in this case x86_64-macos.10.15.3...10.15.3-gnu) and with build-lib, only the symbols marked extern or export are exported:

% objdump -t libmath.a 

libmath.a(zig-cache/o/7b9f6554b15377ff30a5ec8eb751292c/math.o):	file format Mach-O 64-bit x86-64

SYMBOL TABLE:
0000000000000008 gw    O __DATA,__data __mh_execute_header
0000000000000000 g     F __TEXT,__text _add
0000000000000000         *UND* _print

I would expect an equivalent result once the wasm target is added - a very small wasm file that contains only the symbols that are marked as exported, and whichever symbols these require to operate correctly.

@matthewp
Copy link

matthewp commented Feb 5, 2021

@s-ol where you able to get this to work? For me it still results in the exported function not being available.

const std = @import("std");

export fn add(a: i32, b: i32) i32 {
    return a + b;
}

pub fn main() void {
    std.mem.doNotOptimizeAway(add);
}

@andrewrk andrewrk modified the milestones: 0.8.0, 0.9.0 Jun 4, 2021
@12Boti
Copy link

12Boti commented Jun 9, 2021

I am experiencing the same issue. Nothing I export is actually available, the only exported function is _start, which runs main when called from javascript. I don't even want a main function, but zig build-exe requires it.

@jedisct1
Copy link
Contributor

jedisct1 commented Jun 9, 2021

A _start function is not required, and you can export anything else:

pub export fn myfunction() void {
    ...
}

Then compile with:

zig build-lib -OReleaseSmall -target wasm32-wasi -dynamic src.zig

Resulting Wasm code:

export memory memory(initial: 2, max: 0);

global g_a:int = 66560;
export global dso_handle:int = 1024;
export global data_end:int = 1024;
export global global_base:int = 1024;
export global heap_base:int = 66560;
export global memory_base:int = 0;
export global table_base:int = 1;

export function wasm_call_ctors() {
}

export function myfunction() {
}

This is with Zig 0.8.0.

@matthewp
Copy link

matthewp commented Jun 9, 2021

@jedisct1 build-lib includes all of libc (see: #7133) which is the reason people are trying to use build-exe as a workaround. The file size of build-lib is too large for use on the web.

@s-ol
Copy link
Contributor

s-ol commented Jun 9, 2021

I think this issue can be closed now. I just did the following testing with zig 0.8.0:

$ cat test.zig
pub export fn add(a: u32, b: u32) u32 {
    return a + b;
}
$ zig build-lib -OReleaseSmall -target wasm32-wasi -dynamic test.zig
$ ls -l test.wasm
-rwxr-xr-x 1 s-ol s-ol 298 Jun  9 13:59 test.wasm
$ wasm-dis test.wasm
(module
 (type $none_=>_none (func))
 (type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
 (global $__stack_pointer (mut i32) (i32.const 66560))
 (global $global$1 i32 (i32.const 1024))
 (global $global$2 i32 (i32.const 1024))
 (global $global$3 i32 (i32.const 1024))
 (global $global$4 i32 (i32.const 66560))
 (global $global$5 i32 (i32.const 0))
 (global $global$6 i32 (i32.const 1))
 (memory $0 2)
 (export "memory" (memory $0))
 (export "__wasm_call_ctors" (func $__wasm_call_ctors))
 (export "add" (func $add))
 (export "__dso_handle" (global $global$1))
 (export "__data_end" (global $global$2))
 (export "__global_base" (global $global$3))
 (export "__heap_base" (global $global$4))
 (export "__memory_base" (global $global$5))
 (export "__table_base" (global $global$6))
 (func $__wasm_call_ctors
 )
 (func $add (param $0 i32) (param $1 i32) (result i32)
  (i32.add
   (local.get $1)
   (local.get $0)
  )
 )
 ;; custom section "producers", size 16
)

328 bytes doesn't sound excessive to me, and while I'm not sure whether all of the symbols present are needed, I don't see the compiler_rt exports anymore.

@12Boti
Copy link

12Boti commented Jun 9, 2021

I see! I was missing -dynamic! Shouldn't that be documented somewhere? Well, maybe I just missed it.

@jedisct1
Copy link
Contributor

jedisct1 commented Jun 9, 2021

Nod, we should definitely document this!

Maybe keep the issue open until this is done.

@paulevans
Copy link

paulevans commented Dec 17, 2021

When this is documented it would be really useful to have a build.zig version

I tried something along the lines of this but it failed after the second build (on Windows) by deleting the .wasm file and leaving unresolvable sym links in the zig-out directory instead of the wasm. It output .a and .o instead too - only after the first build though.
const wasmLib = b.addSharedLibrary("weblib", "src/main_web.zig", builder.version(1,0,0));

.unversioned worked.
const wasmLib = b.addSharedLibrary("weblib", "src/main_web.zig", .unversioned);

Adding what @matthewp suggested kept the add function being available
std.mem.doNotOptimizeAway(add);

More of the build.zig

    wasmLib.setBuildMode(mode);
    wasmLib.setTarget(std.zig.CrossTarget { 
        .cpu_arch = .wasm32,
        .os_tag = .freestanding,
        .abi = .musl,
    });
    //wasmLib.install();    // Where did it go?
    wasmLib.setOutputDir(b.install_prefix); // Goes to zig-out

install() did not seem to put the .wasm file anywhere. Setting the output directory worked though.

@s-ol
Copy link
Contributor

s-ol commented Dec 17, 2021

@daurnimator maybe we could close this issue, or perhaps rename it to clarify that at this point what's lacking is mostly just documentation that suggests using -dynamic for building wasm library code?

@sporksmith
Copy link

sporksmith commented Dec 31, 2021

I'm running into this as well. In particular if the compiler ends up using memcpy then a bunch of other symbols (presumably from compiler_rt) get dragged in and exported, resulting in a much larger wasm file.

I ran into this while building for the wasm4 fantasy console, but stripped it down to a minimal example.

Somewhat silly code, but returning the array results in a generated call to memcpy, which appears to drag in and export a bunch of other symbols. Most of these aren't actually called anywhere, but since they're exported they are left in here and by other post-processing tools like wasm-opt.

const std = @import("std");

export var global_array: [100]u8 = undefined;

fn create_array() [100]u8 {
    return [_]u8{0} ** 100;
}

export fn myapi() void {
    global_array = create_array();
}
$ zig build-lib -target wasm32-freestanding -dynamic -OReleaseSmall main.zig
$ ls -sh main.wasm 
24K main.wasm
$ wasm-objdump -x ./main.wasm
...
Export[53]:
 - memory[0] -> "memory"
 - func[0] <__wasm_call_ctors> -> "__wasm_call_ctors"
 - func[1] <myapi> -> "myapi"
 - global[1] -> "global_array"
 - func[7] <memset> -> "memset"
 - func[8] <__memset> -> "__memset"
 - func[9] <memcpy> -> "memcpy"
 - func[10] <memmove> -> "memmove"
 - func[11] <memcmp> -> "memcmp"
 - func[12] <bcmp> -> "bcmp"
 - func[13] <fmodf> -> "fmodf"
 - func[14] <fmod> -> "fmod"
 - func[15] <ceilf> -> "ceilf"
 - func[16] <ceil> -> "ceil"
 - func[17] <ceill> -> "ceill"
 - func[18] <fmaf> -> "fmaf"
 - func[19] <fma> -> "fma"
 - func[21] <fmal> -> "fmal"
 - func[22] <sin> -> "sin"
 - func[26] <sinf> -> "sinf"
 - func[30] <cos> -> "cos"
 - func[32] <cosf> -> "cosf"
 - func[34] <sincos> -> "sincos"
 - func[35] <sincosf> -> "sincosf"
 - func[36] <exp> -> "exp"
 - func[37] <expf> -> "expf"
 - func[38] <exp2> -> "exp2"
 - func[39] <exp2f> -> "exp2f"
 - func[40] <log> -> "log"
 - func[41] <logf> -> "logf"
 - func[42] <log2> -> "log2"
 - func[43] <log2f> -> "log2f"
 - func[44] <log10> -> "log10"
 - func[45] <log10f> -> "log10f"
 - func[46] <fabs> -> "fabs"
 - func[47] <fabsf> -> "fabsf"
 - func[48] <trunc> -> "trunc"
 - func[49] <truncf> -> "truncf"
 - func[50] <round> -> "round"
 - func[51] <roundf> -> "roundf"
 - func[52] <fminf> -> "fminf"
 - func[53] <fmin> -> "fmin"
 - func[54] <fmaxf> -> "fmaxf"
 - func[55] <fmax> -> "fmax"
 - func[56] <sqrt> -> "sqrt"
 - func[57] <sqrtf> -> "sqrtf"
 - func[58] <truncl> -> "truncl"
 - global[2] -> "__dso_handle"
 - global[3] -> "__data_end"
 - global[4] -> "__global_base"
 - global[5] -> "__heap_base"
 - global[6] -> "__memory_base"
 - global[7] -> "__table_base"
...

If I tweak the code such that no call to memcpy is generated, we end up with something closer to the expected result. A much smaller wasm file and only the explicitly exported symbols plus a few other "special" symbols.

$ zig build-lib -dynamic -OReleaseSmall main.zig
$ ls -sh main.wasm 
4.0K main.wasm
$ wasm-objdump -x ./main.wasm
main.wasm:      file format wasm 0x1

Section Details:

Type[1]:
 - type[0] () -> nil
Function[2]:
 - func[0] sig=0 <__wasm_call_ctors>
 - func[1] sig=0 <myapi>
Memory[1]:
 - memory[0] pages: initial=2
Global[8]:
 - global[0] i32 mutable=1 - init i32=66672
 - global[1] i32 mutable=0 <global_array> - init i32=1024
 - global[2] i32 mutable=0 <__dso_handle> - init i32=1024
 - global[3] i32 mutable=0 <__data_end> - init i32=1124
 - global[4] i32 mutable=0 <__global_base> - init i32=1024
 - global[5] i32 mutable=0 <__heap_base> - init i32=66672
 - global[6] i32 mutable=0 <__memory_base> - init i32=0
 - global[7] i32 mutable=0 <__table_base> - init i32=1
Export[10]:
 - memory[0] -> "memory"
 - func[0] <__wasm_call_ctors> -> "__wasm_call_ctors"
 - func[1] <myapi> -> "myapi"
 - global[1] -> "global_array"
 - global[2] -> "__dso_handle"
 - global[3] -> "__data_end"
 - global[4] -> "__global_base"
 - global[5] -> "__heap_base"
 - global[6] -> "__memory_base"
 - global[7] -> "__table_base"
Code[2]:
 - func[0] size=2 <__wasm_call_ctors>
 - func[1] size=43 <myapi>
Custom:
 - name: "name"
 - func[0] <__wasm_call_ctors>
 - func[1] <myapi>
Custom:
 - name: "producers"

@paulevans
Copy link

@sporksmith I've been looking at that kind of thing too. This is an interesting discussion mentioning memory and wasm4
#8633

@sporksmith
Copy link

One workaround I've found is to use a build.zig file together with setting export_symbol_names. e.g. using the same example:

const std = @import("std");

pub fn build(b: *std.build.Builder) void {
    const mode = b.standardReleaseOptions();
    const lib = b.addSharedLibrary("zigbloat", "src/main.zig", .unversioned);
    lib.export_symbol_names = &[_][]const u8{"myapi"};
    lib.setTarget(.{ .cpu_arch = .wasm32, .os_tag = .freestanding });
    lib.setBuildMode(mode);
    lib.install();
}
$ zig build -Drelease-small=true
$ ls -hs zig-out/lib/zigbloat.wasm
4.0K zig-out/lib/zigbloat.wasm

And the same but without the export_symbol_names line:

$ ls -hs zig-out/lib/zigbloat.wasm
24K zig-out/lib/zigbloat.wasm

@sporksmith
Copy link

@paulevans

@sporksmith I've been looking at that kind of thing too. This is an interesting discussion mentioning memory and wasm4 #8633

Thanks! Yeah in my real code I'm using the wasm4 template, which uses the import_memory option, which prevents exporting the memory symbol. For but reporting purposes I started with a fresh zig init-lib to remove anything wasm4-specific

@Luukdegram
Copy link
Sponsor Member

One workaround I've found is to use a build.zig file together with setting export_symbol_names. e.g. using the same example:

In case you're wondering: When we switched to having the linker frontend in stage2 we did no longer have access to exported symbols from stage1, so we export all public symbols by default. export_symbol_names overrides that with names the user provided, therefore you no longer see compiler_rt symbols in your binary (because --export-all is no longer appended).

In the upcoming week, I'll implement a fix for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
arch-wasm 32-bit and 64-bit WebAssembly
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants