]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link: support weak binding on darwin
authorqmuntal <quimmuntal@gmail.com>
Wed, 22 Oct 2025 14:33:18 +0000 (16:33 +0200)
committerQuim Muntal <quimmuntal@gmail.com>
Wed, 5 Nov 2025 20:38:57 +0000 (12:38 -0800)
Symbols loaded from host files can have the N_WEAK_REF bit set,
which is used to instruct the loader to not fail if that symbol
can't be resolved.

The Go internal linker should honor this information by setting the
BIND_SYMBOL_FLAGS_WEAK_IMPORT flag in the corresponding bind table
entry.

Fixes #76023

Cq-Include-Trybots: luci.golang.try:gotip-darwin-amd64-longtest,gotip-darwin-amd64_12,gotip-darwin-arm64_12,gotip-darwin-arm64_15,gotip-darwin-arm64-longtest,gotip-darwin-amd64_14
Change-Id: Id2cef247ec7a9cb08455844f3c30ff874772bb7b
Reviewed-on: https://go-review.googlesource.com/c/go/+/713760
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

src/cmd/cgo/internal/test/cgo_darwin_test.go [new file with mode: 0644]
src/cmd/cgo/internal/test/issue76023.go [new file with mode: 0644]
src/cmd/link/internal/ld/macho.go
src/cmd/link/internal/loader/loader.go
src/cmd/link/internal/loadmacho/ldmacho.go

diff --git a/src/cmd/cgo/internal/test/cgo_darwin_test.go b/src/cmd/cgo/internal/test/cgo_darwin_test.go
new file mode 100644 (file)
index 0000000..5d9d164
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2025 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build cgo && darwin
+
+package cgotest
+
+import "testing"
+
+func TestIssue76023(t *testing.T) { issue76023(t) }
diff --git a/src/cmd/cgo/internal/test/issue76023.go b/src/cmd/cgo/internal/test/issue76023.go
new file mode 100644 (file)
index 0000000..7fe8ae5
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2025 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build darwin
+
+package cgotest
+
+/*
+#cgo LDFLAGS: -Wl,-undefined,dynamic_lookup
+
+extern void __gotest_cgo_null_api(void) __attribute__((weak_import));
+
+int issue76023(void) {
+    if (__gotest_cgo_null_api) return 1;
+    return 0;
+}
+*/
+import "C"
+import "testing"
+
+func issue76023(t *testing.T) {
+       r := C.issue76023()
+       if r != 0 {
+               t.Error("found __gotest_cgo_null_api")
+       }
+}
index 6d3347ff2d4569ae43522202eceb6e082c311b33..65ae1268c31094b39d042b26e30aa89e6bf04b8f 100644 (file)
@@ -180,6 +180,8 @@ const (
        BIND_SPECIAL_DYLIB_FLAT_LOOKUP     = -2
        BIND_SPECIAL_DYLIB_WEAK_LOOKUP     = -3
 
+       BIND_SYMBOL_FLAGS_WEAK_IMPORT = 0x1
+
        BIND_OPCODE_MASK                                         = 0xF0
        BIND_IMMEDIATE_MASK                                      = 0x0F
        BIND_OPCODE_DONE                                         = 0x00
@@ -1429,7 +1431,11 @@ func machoDyldInfo(ctxt *Link) {
                        bind.AddUint8(BIND_OPCODE_SET_DYLIB_SPECIAL_IMM | uint8(d)&0xf)
                }
 
-               bind.AddUint8(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM)
+               flags := uint8(0)
+               if ldr.SymWeakBinding(r.targ) {
+                       flags |= BIND_SYMBOL_FLAGS_WEAK_IMPORT
+               }
+               bind.AddUint8(BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | flags)
                // target symbol name as a C string, with _ prefix
                bind.AddUint8('_')
                bind.Addstring(ldr.SymExtname(r.targ))
index 3fb2e86514a086aea2093a0d04564347fb98ad17..a612a1ac81587562f8a5d70660ed953cf58e9898 100644 (file)
@@ -241,6 +241,7 @@ type Loader struct {
        plt         map[Sym]int32       // stores dynimport for pe objects
        got         map[Sym]int32       // stores got for pe objects
        dynid       map[Sym]int32       // stores Dynid for symbol
+       weakBinding map[Sym]bool        // stores whether a symbol has a weak binding
 
        relocVariant map[relocId]sym.RelocVariant // stores variant relocs
 
@@ -326,6 +327,7 @@ func NewLoader(flags uint32, reporter *ErrorReporter) *Loader {
                plt:                  make(map[Sym]int32),
                got:                  make(map[Sym]int32),
                dynid:                make(map[Sym]int32),
+               weakBinding:          make(map[Sym]bool),
                attrCgoExportDynamic: make(map[Sym]struct{}),
                attrCgoExportStatic:  make(map[Sym]struct{}),
                deferReturnTramp:     make(map[Sym]bool),
@@ -1447,6 +1449,18 @@ func (l *Loader) SetSymExtname(i Sym, value string) {
        }
 }
 
+func (l *Loader) SymWeakBinding(i Sym) bool {
+       return l.weakBinding[i]
+}
+
+func (l *Loader) SetSymWeakBinding(i Sym, v bool) {
+       // reject bad symbols
+       if i >= Sym(len(l.objSyms)) || i == 0 {
+               panic("bad symbol index in SetSymWeakBinding")
+       }
+       l.weakBinding[i] = v
+}
+
 // SymElfType returns the previously recorded ELF type for a symbol
 // (used only for symbols read from shared libraries by ldshlibsyms).
 // It is not set for symbols defined by the packages being linked or
index 5e8022ce69bb36b40f7e960cce84299a1f00b64b..dcb0fd92c1f357109ded690a091eaa76d0f252d7 100644 (file)
@@ -613,6 +613,9 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, f *bio.Reader,
                }
                if machsym.desc&(N_WEAK_REF|N_WEAK_DEF) != 0 {
                        l.SetAttrDuplicateOK(s, true)
+                       if machsym.desc&N_WEAK_REF != 0 {
+                               l.SetSymWeakBinding(s, true)
+                       }
                }
                machsym.sym = s
                if machsym.sectnum == 0 { // undefined