From a2fb5cd823f5223070c3cce741dd5b3879bac21b Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Thu, 27 Jun 2019 18:14:03 -0400 Subject: [PATCH] cmd/cgo: accept weak dynamic imports cgo produces dynamic imports for Go binaries by scanning the dynamic imports table of a binary produced by the system C compiler and linker. Currently, since it uses elf.File.ImportedSymbols, it only reads global symbols. Unfortunately, recent versions of lld emit weak symbol imports for several pthread symbols, which means the cgo tool doesn't emit dynamic imports for them, which ultimately causes linking of cgo binaries to fail. Fix this by using elf.File.DynamicSymbols instead and filtering down to both global and weak symbols. Fixes #31912. Change-Id: If346a7eca6733e3bfa2cccf74a9cda02a3e81d38 Reviewed-on: https://go-review.googlesource.com/c/go/+/184100 Run-TryBot: Austin Clements TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/cmd/cgo/out.go | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index 488db52c2e..1fddbb6b54 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -268,6 +268,35 @@ func (p *Package) writeDefs() { } } +// elfImportedSymbols is like elf.File.ImportedSymbols, but it +// includes weak symbols. +// +// A bug in some versions of LLD (at least LLD 8) cause it to emit +// several pthreads symbols as weak, but we need to import those. See +// issue #31912 or https://bugs.llvm.org/show_bug.cgi?id=42442. +// +// When doing external linking, we hand everything off to the external +// linker, which will create its own dynamic symbol tables. For +// internal linking, this may turn weak imports into strong imports, +// which could cause dynamic linking to fail if a symbol really isn't +// defined. However, the standard library depends on everything it +// imports, and this is the primary use of dynamic symbol tables with +// internal linking. +func elfImportedSymbols(f *elf.File) []elf.ImportedSymbol { + syms, _ := f.DynamicSymbols() + var imports []elf.ImportedSymbol + for _, s := range syms { + if (elf.ST_BIND(s.Info) == elf.STB_GLOBAL || elf.ST_BIND(s.Info) == elf.STB_WEAK) && s.Section == elf.SHN_UNDEF { + imports = append(imports, elf.ImportedSymbol{ + Name: s.Name, + Library: s.Library, + Version: s.Version, + }) + } + } + return imports +} + func dynimport(obj string) { stdout := os.Stdout if *dynout != "" { @@ -290,7 +319,7 @@ func dynimport(obj string) { } } } - sym, _ := f.ImportedSymbols() + sym := elfImportedSymbols(f) for _, s := range sym { targ := s.Name if s.Version != "" { -- 2.48.1