@@ -428,8 +428,18 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {
428428        //  compiler as we're telling LLVM (using 'wasm-import-name' and
429429        //  'wasm-import-name') what the real function name is and where to find
430430        //  it.
431-         const   bool  use_mangled_name = target_is_wasm (g->zig_target ) &&
431+         bool  use_mangled_name = target_is_wasm (g->zig_target ) &&
432432                fn_proto->is_extern  && fn_proto->lib_name  != nullptr ;
433+         //  This is subtle but important to match libc symbols at static link time correctly.
434+         //  We treat "c" lib_name as a special library indicating that it should be defined
435+         //  in libc. But if we mangle a libc symbol name here with "c" module name, then wasm-ld cannot resolve
436+         //  the symbol. This is because at the static link time with wasm-ld, the linker does not
437+         //  take module names into account, and instead looking for a pure symbol name (i.e. function name)
438+         //  written into the ".linking" custom section (i.e. it does not use import section).
439+         //  This is the intended behavior of wasm-ld, because Wasm has a concept of host functions,
440+         //  which are undefined functions supposed to be resolved by host runtimes *with module names*
441+         //  at load times even if it is "static linked" with the linker.
442+         use_mangled_name = use_mangled_name && (strcmp (buf_ptr (fn_proto->lib_name ), " c"  ) != 0 );
433443        //  Pick a weird name to avoid collisions...
434444        //  This whole function should be burned to the ground.
435445        Buf *mangled_symbol_buf = use_mangled_name ?
@@ -452,6 +462,13 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {
452462                llvm_fn = LLVMAddFunction (g->module , symbol_name, fn_llvm_type);
453463
454464                if  (use_mangled_name) {
465+                     //  Note that "wasm-import-module"ed symbols will not be resolved
466+                     //  in the future version of wasm-ld since the attribute basically means that
467+                     //  "the symbol should be resolved at load time by runtimes", though
468+                     //  the symbol is already mangled here and it is written into "linking" section
469+                     //  used by wasm-ld to match symbols, so it should not be expected by users.
470+                     //  tl;dr is that users should not put the lib_name specifier on extern statements
471+                     //  if they want to link symbols with wasm-ld.
455472                    addLLVMFnAttrStr (llvm_fn, " wasm-import-name"  , unmangled_name);
456473                    addLLVMFnAttrStr (llvm_fn, " wasm-import-module"  , buf_ptr (fn_proto->lib_name ));
457474                }
0 commit comments