-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Description
I find that when using O3 optimization, this global necessary for dynamic linking to work is eliminated. I can not find a way to keep this export. I tried passing __stack_pointer to EXPORTED_FUNCTIONS and EXPORTED_RUNTIME_METHODS, both of which create an error as it does not recognize that symbol. I also tried passing -Wl,--export=__stack_pointer or -Wl,--export,__stack_pointer to emcc, both of which do nothing. Even then, I feel like this is unintended behavior.
I presume that CMake uses O3 optimization by default when compiling release builds; this is how I found the issue. Perhaps there is a way to change that, but I would prefer for me to be able to use dlopen even with O3 optimization.
emcc version
> emcc -v
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 4.0.19 (08e2de1031913e4ba7963b1c56f35f036a7d4d56)
clang version 22.0.0git (https:/github.com/llvm/llvm-project 12f392cff10fcc70b4ec4f01ab386922742e9136)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: C:\dev\emsdk\upstream\bin
emcc compile command
> emcc -o out/main.js -O3 -sMAIN_MODULE=2 "-Wl,-lnodefs.js" main.c -v
"C:/dev/emsdk/upstream/bin\clang.exe" -target wasm32-unknown-emscripten -fignore-exceptions -fPIC -fvisibility=default -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr '--sysroot=C:\dev\emsdk\upstream\emscripten\cache\sysroot' -DEMSCRIPTEN -Xclang '-iwithsysroot/include\fakesdl' -Xclang '-iwithsysroot/include\compat' -O3 -v -c main.c -o 'C:\Users\nabca\AppData\Local\Temp\emscripten_temp_fnr2y61r\main.o'
clang version 22.0.0git (https:/github.com/llvm/llvm-project 12f392cff10fcc70b4ec4f01ab386922742e9136)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: C:\dev\emsdk\upstream\bin
(in-process)
"C:\\dev\\emsdk\\upstream\\bin\\clang.exe" -cc1 -triple wasm32-unknown-emscripten -O3 -emit-obj -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name main.c -mrelocation-model pic -pic-level 2 -mframe-pointer=none -ffp-contract=on -fno-rounding-math -mconstructor-aliases -target-feature +mutable-globals -target-cpu generic -debugger-tuning=gdb "-fdebug-compilation-dir=C:\\Users\\nabca\\Documents\\src\\misc\\wasmldtest" -v "-fcoverage-compilation-dir=C:\\Users\\nabca\\Documents\\src\\misc\\wasmldtest" -resource-dir "C:\\dev\\emsdk\\upstream\\lib\\clang\\22" -D EMSCRIPTEN -isysroot "C:\\dev\\emsdk\\upstream\\emscripten\\cache\\sysroot" -internal-isystem "C:\\dev\\emsdk\\upstream\\lib\\clang\\22\\include" -internal-isystem "C:\\dev\\emsdk\\upstream\\emscripten\\cache\\sysroot/include/wasm32-emscripten" -internal-isystem "C:\\dev\\emsdk\\upstream\\emscripten\\cache\\sysroot/include" -ferror-limit 19 -fmessage-length=120 -fvisibility=default -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fignore-exceptions -fcolor-diagnostics -vectorize-loops -vectorize-slp "-iwithsysroot/include\\fakesdl" "-iwithsysroot/include\\compat" -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr -o "C:\\Users\\nabca\\AppData\\Local\\Temp\\emscripten_temp_fnr2y61r\\main.o" -x c main.c
clang -cc1 version 22.0.0git based upon LLVM 22.0.0git default target x86_64-pc-windows-msvc
ignoring nonexistent directory "C:\dev\emsdk\upstream\emscripten\cache\sysroot/include/wasm32-emscripten"
#include "..." search starts here:
#include <...> search starts here:
C:\dev\emsdk\upstream\emscripten\cache\sysroot/include\fakesdl
C:\dev\emsdk\upstream\emscripten\cache\sysroot/include\compat
C:\dev\emsdk\upstream\lib\clang\22\include
C:\dev\emsdk\upstream\emscripten\cache\sysroot/include
End of search list.
"C:/dev/emsdk/upstream/bin\clang.exe" --version
"C:/dev/emsdk/upstream/bin\wasm-ld.exe" -o out/main.wasm -Bdynamic 'C:\Users\nabca\AppData\Local\Temp\emscripten_temp_fnr2y61r\main.o' '-LC:\dev\emsdk\upstream\emscripten\cache\sysroot\lib\wasm32-emscripten\pic' '-LC:\dev\emsdk\upstream\emscripten\src\lib' -lGL-getprocaddr -lal -lhtml5 -lstubs -lnoexit -lc -ldlmalloc -lcompiler_rt -lc++-noexcept -lc++abi-noexcept -lsockets -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr 'C:\Users\nabca\AppData\Local\Temp\tmpu410uy5glibemscripten_js_symbols.so' --strip-debug --export=__stack_pointer --export=_emscripten_stack_alloc --export=__wasm_call_ctors --export=setThrew --export=_emscripten_stack_restore --export=emscripten_stack_get_current --export=_emscripten_find_dylib --export=emscripten_get_sbrk_ptr --export=__heap_base --export=calloc --export-if-defined=__start_em_asm --export-if-defined=__stop_em_asm --export-if-defined=__start_em_lib_deps --export-if-defined=__stop_em_lib_deps --export-if-defined=__start_em_js --export-if-defined=__stop_em_js --export-if-defined=main --export-if-defined=__main_argc_argv --experimental-pic --unresolved-symbols=import-dynamic --export-table --growable-table -z stack-size=65536 --no-growable-memory --initial-heap=16777216 --no-entry --table-base=1 --global-base=1024
"C:/dev/emsdk/upstream/bin\llvm-objcopy.exe" out/main.wasm out/main.wasm '--remove-section=.debug*' --remove-section=producers --remove-section=name
"C:/dev/emsdk/node/22.16.0_64bit/bin/node.exe" 'C:\dev\emsdk\upstream\emscripten\tools\compiler.mjs' -
"C:/dev/emsdk/upstream\bin\wasm-opt" --strip-target-features --post-emscripten -O3 --low-memory-unused --zero-filled-memory --pass-arg=directize-initial-contents-immutable --no-stack-ir out/main.wasm -o out/main.wasm --mvp-features --enable-bulk-memory --enable-bulk-memory-opt --enable-call-indirect-overlong --enable-multivalue --enable-mutable-globals --enable-nontrapping-float-to-int --enable-reference-types --enable-sign-ext
"C:/dev/emsdk/node/22.16.0_64bit/bin/node.exe" 'C:\dev\emsdk\upstream\emscripten\tools\acorn-optimizer.mjs' 'C:\Users\nabca\AppData\Local\Temp\emscripten_temp_fnr2y61r\main.js' AJSDCE --minify-whitespace -o 'C:\Users\nabca\AppData\Local\Temp\emscripten_temp_fnr2y61r\main.jso1.js'
"C:/dev/emsdk/node/22.16.0_64bit/bin/node.exe" 'C:\dev\emsdk\upstream\emscripten\tools\acorn-optimizer.mjs' 'C:\Users\nabca\AppData\Local\Temp\emcc_acorn_info_18nw1eiu.js' emitDCEGraph --no-print
"C:/dev/emsdk/upstream\bin\wasm-metadce" '--graph-file=C:\Users\nabca\AppData\Local\Temp\emcc_dce_graph_yiq193w4.json' --optimize-level=3 --shrink-level=0 --optimize-stack-ir out/main.wasm -o out/main.wasm --mvp-features --enable-bulk-memory --enable-bulk-memory-opt --enable-call-indirect-overlong --enable-multivalue --enable-mutable-globals --enable-nontrapping-float-to-int --enable-reference-types --enable-sign-ext
"C:/dev/emsdk/node/22.16.0_64bit/bin/node.exe" 'C:\dev\emsdk\upstream\emscripten\tools\acorn-optimizer.mjs' 'C:\Users\nabca\AppData\Local\Temp\emcc_acorn_info_in7iw816.js' applyDCEGraphRemovals --minify-whitespace -o 'C:\Users\nabca\AppData\Local\Temp\emscripten_temp_fnr2y61r\main.jso2.js'
"C:/dev/emsdk/node/22.16.0_64bit/bin/node.exe" 'C:\dev\emsdk\upstream\emscripten\tools\acorn-optimizer.mjs' 'C:\Users\nabca\AppData\Local\Temp\emscripten_temp_fnr2y61r\main.jso2.js' AJSDCE --minify-whitespace -o 'C:\Users\nabca\AppData\Local\Temp\emscripten_temp_fnr2y61r\main.jso3.js'
wasm-objdump output
> wasm-objdump -x -j Export out/main.wasm
main.wasm: file format wasm 0x1
Section Details:
Export[13]:
- memory[0] -> "memory"
- func[53] <__wasm_call_ctors> -> "__wasm_call_ctors"
- table[0] -> "__indirect_function_table"
- func[52] <main> -> "main"
- func[38] <__dl_seterr> -> "__dl_seterr"
- func[28] <_emscripten_find_dylib> -> "_emscripten_find_dylib"
- func[20] <calloc> -> "calloc"
- func[45] <emscripten_get_sbrk_ptr> -> "emscripten_get_sbrk_ptr"
- global[1] -> "__heap_base"
- func[41] <setThrew> -> "setThrew"
- func[44] <_emscripten_stack_restore> -> "_emscripten_stack_restore"
- func[43] <_emscripten_stack_alloc> -> "_emscripten_stack_alloc"
- func[42] <emscripten_stack_get_current> -> "emscripten_stack_get_current"
main.c -- works perfectly fine with O2 or -sMAIN_MODULE=1
#include <stdio.h>
#include <dlfcn.h>
typedef void (*testfunc_f)(int*);
int main(void) {
printf("Main module loaded.\n");
void *mod = dlopen("./side.so", RTLD_NOW);
if (mod == NULL) {
printf("Could not load side module.\n");
return 1;
}
printf("Resolve test_func...\n");
testfunc_f f = dlsym(mod, "test_func");
if (f == NULL) {
printf("Could not get exported function.\n");
return 1;
}
printf("Run test_func...\n");
int a = 10;
f(&a);
printf("value: %i\n", a);
printf("Done.\n");
dlclose(mod);
return 0;
}and side.c, just to be thorough
#include <emscripten.h>
EMSCRIPTEN_KEEPALIVE
void test_func(int *a) {
int v = *a;
for (int i = 0; i < v; ++i) {
*a += i;
}
}