builder, runtime: fix duplicate symbol error with Go 1.26+ on Windows

Go 1.26 changed syscall.loadlibrary, syscall.loadsystemlibrary, and
syscall.getprocaddress from declarations to definitions in
syscall/dll_windows.go. TinyGo's runtime also defines these via
//go:linkname, causing "symbol multiply defined!" during LLVM module
linking.

Resolve this by detecting duplicate function definitions before calling
llvm.LinkModules and turning the incoming duplicate into a declaration,
so the runtime's version wins. TinyGo's implementations must take
precedence because Go 1.26's versions depend on //go:cgo_import_dynamic,
which TinyGo does not support.

Also fix the signature of syscall_loadsystemlibrary to match the
standard library (remove unused absoluteFilepath parameter).

Signed-off-by: deadprogram <ron@hybridgroup.com>
This commit is contained in:
deadprogram
2026-04-10 09:47:47 +02:00
committed by Ron Evans
parent ed1a56785a
commit 2d477e069d
2 changed files with 19 additions and 1 deletions
+18
View File
@@ -546,6 +546,24 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
if err != nil {
return fmt.Errorf("failed to load bitcode file: %w", err)
}
// Resolve duplicate function definitions before linking.
// This can happen when a newer Go version adds a function
// body in a standard library package that was previously
// just a declaration provided by //go:linkname from the
// runtime. In that case, keep the existing (runtime)
// definition and turn the new one into a declaration.
for fn := pkgMod.FirstFunction(); !fn.IsNil(); fn = llvm.NextFunction(fn) {
if fn.IsDeclaration() {
continue
}
existing := mod.NamedFunction(fn.Name())
if existing.IsNil() || existing.IsDeclaration() {
continue
}
for _, bb := range fn.BasicBlocks() {
bb.EraseFromParent()
}
}
err = llvm.LinkModules(mod, pkgMod)
if err != nil {
return fmt.Errorf("failed to link module: %w", err)