]> Cypherpunks repositories - gostls13.git/commitdiff
net: use libc (not cgo) for DNS on macOS
authorRuss Cox <rsc@golang.org>
Fri, 28 Oct 2022 14:54:37 +0000 (10:54 -0400)
committerRuss Cox <rsc@golang.org>
Tue, 1 Nov 2022 14:05:39 +0000 (14:05 +0000)
Change the macOS implementation to use libc calls.
Using libc calls directly is what we do for all the runtime and os syscalls.
Doing so here as well improves consistency and also makes it possible
to cross-compile (from non-Mac systems) macOS binaries that use the
native name resolver.

Fixes #12524.

Change-Id: I011f4fcc5c50fbb5396e494889765dcbb9342336
Reviewed-on: https://go-review.googlesource.com/c/go/+/446178
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
src/internal/syscall/unix/asm_darwin.s
src/internal/syscall/unix/getentropy_darwin.go
src/internal/syscall/unix/net_darwin.go [new file with mode: 0644]
src/net/cgo_resnew.go
src/net/cgo_sockold.go
src/net/cgo_unix.go
src/net/cgo_unix_cgo.go [new file with mode: 0644]
src/net/cgo_unix_syscall.go [new file with mode: 0644]
src/runtime/sys_darwin.go
src/runtime/sys_darwin_amd64.s
src/runtime/sys_darwin_arm64.s

index 8fbdc1d866d262f861eb30aade13c6d0b116090f..02c9a3e7f3e2eb0e77ca2b733dfe0f4d3edaedaa 100644 (file)
@@ -6,3 +6,15 @@
 
 TEXT ·libc_getentropy_trampoline(SB),NOSPLIT,$0-0
        JMP     libc_getentropy(SB)
+
+TEXT ·libc_getaddrinfo_trampoline(SB),NOSPLIT,$0-0
+       JMP     libc_getaddrinfo(SB)
+
+TEXT ·libc_freeaddrinfo_trampoline(SB),NOSPLIT,$0-0
+       JMP     libc_freeaddrinfo(SB)
+
+TEXT ·libc_getnameinfo_trampoline(SB),NOSPLIT,$0-0
+       JMP     libc_getnameinfo(SB)
+
+TEXT ·libc_gai_strerror_trampoline(SB),NOSPLIT,$0-0
+       JMP     libc_gai_strerror(SB)
index 7bab1f27b0c89695debed55061e21f38c686c0bf..834099ffed645fd6c743a27fae6476305f8624d2 100644 (file)
@@ -8,7 +8,6 @@ package unix
 
 import (
        "internal/abi"
-       "syscall"
        "unsafe"
 )
 
@@ -27,6 +26,3 @@ func GetEntropy(p []byte) error {
        }
        return nil
 }
-
-//go:linkname syscall_syscall syscall.syscall
-func syscall_syscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
diff --git a/src/internal/syscall/unix/net_darwin.go b/src/internal/syscall/unix/net_darwin.go
new file mode 100644 (file)
index 0000000..e5a879c
--- /dev/null
@@ -0,0 +1,116 @@
+// Copyright 2022 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.
+
+package unix
+
+import (
+       "internal/abi"
+       "syscall"
+       "unsafe"
+)
+
+const (
+       AI_CANONNAME = 0x2
+       AI_ALL       = 0x100
+       AI_V4MAPPED  = 0x800
+       AI_MASK      = 0x1407
+
+       EAI_AGAIN    = 2
+       EAI_NONAME   = 8
+       EAI_SYSTEM   = 11
+       EAI_OVERFLOW = 14
+
+       NI_NAMEREQD = 4
+)
+
+type Addrinfo struct {
+       Flags     int32
+       Family    int32
+       Socktype  int32
+       Protocol  int32
+       Addrlen   uint32
+       Canonname *byte
+       Addr      *syscall.RawSockaddr
+       Next      *Addrinfo
+}
+
+//go:cgo_import_dynamic libc_getaddrinfo getaddrinfo "/usr/lib/libSystem.B.dylib"
+func libc_getaddrinfo_trampoline()
+
+func Getaddrinfo(hostname, servname *byte, hints *Addrinfo, res **Addrinfo) (int, error) {
+       gerrno, _, errno := syscall_syscall6(abi.FuncPCABI0(libc_getaddrinfo_trampoline),
+               uintptr(unsafe.Pointer(hostname)),
+               uintptr(unsafe.Pointer(servname)),
+               uintptr(unsafe.Pointer(hints)),
+               uintptr(unsafe.Pointer(res)),
+               0,
+               0)
+       var err error
+       if errno != 0 {
+               err = errno
+       }
+       return int(gerrno), err
+}
+
+//go:cgo_import_dynamic libc_freeaddrinfo freeaddrinfo "/usr/lib/libSystem.B.dylib"
+func libc_freeaddrinfo_trampoline()
+
+func Freeaddrinfo(ai *Addrinfo) {
+       syscall_syscall6(abi.FuncPCABI0(libc_freeaddrinfo_trampoline),
+               uintptr(unsafe.Pointer(ai)),
+               0, 0, 0, 0, 0)
+}
+
+//go:cgo_import_dynamic libc_getnameinfo getnameinfo "/usr/lib/libSystem.B.dylib"
+func libc_getnameinfo_trampoline()
+
+func Getnameinfo(sa *syscall.RawSockaddr, salen int, host *byte, hostlen int, serv *byte, servlen int, flags int) (int, error) {
+       gerrno, _, errno := syscall_syscall9(abi.FuncPCABI0(libc_getnameinfo_trampoline),
+               uintptr(unsafe.Pointer(sa)),
+               uintptr(salen),
+               uintptr(unsafe.Pointer(host)),
+               uintptr(hostlen),
+               uintptr(unsafe.Pointer(serv)),
+               uintptr(servlen),
+               uintptr(flags),
+               0,
+               0)
+       var err error
+       if errno != 0 {
+               err = errno
+       }
+       return int(gerrno), err
+}
+
+//go:cgo_import_dynamic libc_gai_strerror gai_strerror "/usr/lib/libSystem.B.dylib"
+func libc_gai_strerror_trampoline()
+
+func GaiStrerror(ecode int) string {
+       r1, _, _ := syscall_syscall(abi.FuncPCABI0(libc_gai_strerror_trampoline),
+               uintptr(ecode),
+               0, 0)
+       return GoString((*byte)(unsafe.Pointer(r1)))
+}
+
+func GoString(p *byte) string {
+       if p == nil {
+               return ""
+       }
+       x := unsafe.Slice(p, 1e9)
+       for i, c := range x {
+               if c == 0 {
+                       return string(x[:i])
+               }
+       }
+       return ""
+}
+
+//go:linkname syscall_syscall syscall.syscall
+func syscall_syscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno)
+
+//go:linkname syscall_syscall6 syscall.syscall6
+func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno)
+
+//go:linkname syscall_syscall9 syscall.syscall9
+func syscall_syscall9(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
index fa6e68770ce35f16d1fc7d30e387948b0008815e..3f21c5c4c4fd5bb899cbe9a174b681c905f45c5a 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build cgo && !netgo && (darwin || (linux && !android) || netbsd || solaris)
+//go:build cgo && !netgo && ((linux && !android) || netbsd || solaris)
 
 package net
 
index 4d9869de04fabbf6f9dcf14375dfae035cfb1d5d..d0a99e073d82c2b98c812b01969cba08761a1350 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build cgo && !netgo && (aix || darwin || dragonfly || freebsd || netbsd || openbsd)
+//go:build cgo && !netgo && (aix || dragonfly || freebsd || netbsd || openbsd)
 
 package net
 
index 71d90560ac921fa1e0c50a07d79e643acaaacdb7..81f492f4eff3c58b855d09737c4f82ce40c6fb88 100644 (file)
@@ -2,25 +2,15 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// This file is called cgo_unix.go, but to allow syscalls-to-libc-based
+// implementations to share the code, it does not use cgo directly.
+// Instead of C.foo it uses _C_foo, which is defined in either
+// cgo_unix_cgo.go or cgo_unix_syscall.go
+
 //go:build cgo && !netgo && unix
 
 package net
 
-/*
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <unistd.h>
-#include <string.h>
-
-// If nothing else defined EAI_OVERFLOW, make sure it has a value.
-#ifndef EAI_OVERFLOW
-#define EAI_OVERFLOW -12
-#endif
-*/
-import "C"
-
 import (
        "context"
        "syscall"
@@ -32,8 +22,8 @@ import (
 // by convention.
 type addrinfoErrno int
 
-func (eai addrinfoErrno) Error() string   { return C.GoString(C.gai_strerror(C.int(eai))) }
-func (eai addrinfoErrno) Temporary() bool { return eai == C.EAI_AGAIN }
+func (eai addrinfoErrno) Error() string   { return _C_gai_strerror(_C_int(eai)) }
+func (eai addrinfoErrno) Temporary() bool { return eai == _C_EAI_AGAIN }
 func (eai addrinfoErrno) Timeout() bool   { return false }
 
 type portLookupResult struct {
@@ -61,23 +51,23 @@ func cgoLookupHost(ctx context.Context, name string) (hosts []string, err error,
 }
 
 func cgoLookupPort(ctx context.Context, network, service string) (port int, err error, completed bool) {
-       var hints C.struct_addrinfo
+       var hints _C_struct_addrinfo
        switch network {
        case "": // no hints
        case "tcp", "tcp4", "tcp6":
-               hints.ai_socktype = C.SOCK_STREAM
-               hints.ai_protocol = C.IPPROTO_TCP
+               *_C_ai_socktype(&hints) = _C_SOCK_STREAM
+               *_C_ai_protocol(&hints) = _C_IPPROTO_TCP
        case "udp", "udp4", "udp6":
-               hints.ai_socktype = C.SOCK_DGRAM
-               hints.ai_protocol = C.IPPROTO_UDP
+               *_C_ai_socktype(&hints) = _C_SOCK_DGRAM
+               *_C_ai_protocol(&hints) = _C_IPPROTO_UDP
        default:
                return 0, &DNSError{Err: "unknown network", Name: network + "/" + service}, true
        }
        switch ipVersion(network) {
        case '4':
-               hints.ai_family = C.AF_INET
+               *_C_ai_family(&hints) = _C_AF_INET
        case '6':
-               hints.ai_family = C.AF_INET6
+               *_C_ai_family(&hints) = _C_AF_INET6
        }
        if ctx.Done() == nil {
                port, err := cgoLookupServicePort(&hints, network, service)
@@ -95,19 +85,19 @@ func cgoLookupPort(ctx context.Context, network, service string) (port int, err
        }
 }
 
-func cgoLookupServicePort(hints *C.struct_addrinfo, network, service string) (port int, err error) {
+func cgoLookupServicePort(hints *_C_struct_addrinfo, network, service string) (port int, err error) {
        cservice := make([]byte, len(service)+1)
        copy(cservice, service)
        // Lowercase the C service name.
        for i, b := range cservice[:len(service)] {
                cservice[i] = lowerASCII(b)
        }
-       var res *C.struct_addrinfo
-       gerrno, err := C.getaddrinfo(nil, (*C.char)(unsafe.Pointer(&cservice[0])), hints, &res)
+       var res *_C_struct_addrinfo
+       gerrno, err := _C_getaddrinfo(nil, (*_C_char)(unsafe.Pointer(&cservice[0])), hints, &res)
        if gerrno != 0 {
                isTemporary := false
                switch gerrno {
-               case C.EAI_SYSTEM:
+               case _C_EAI_SYSTEM:
                        if err == nil { // see golang.org/issue/6232
                                err = syscall.EMFILE
                        }
@@ -117,16 +107,16 @@ func cgoLookupServicePort(hints *C.struct_addrinfo, network, service string) (po
                }
                return 0, &DNSError{Err: err.Error(), Name: network + "/" + service, IsTemporary: isTemporary}
        }
-       defer C.freeaddrinfo(res)
+       defer _C_freeaddrinfo(res)
 
-       for r := res; r != nil; r = r.ai_next {
-               switch r.ai_family {
-               case C.AF_INET:
-                       sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.ai_addr))
+       for r := res; r != nil; r = *_C_ai_next(r) {
+               switch *_C_ai_family(r) {
+               case _C_AF_INET:
+                       sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(*_C_ai_addr(r)))
                        p := (*[2]byte)(unsafe.Pointer(&sa.Port))
                        return int(p[0])<<8 | int(p[1]), nil
-               case C.AF_INET6:
-                       sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.ai_addr))
+               case _C_AF_INET6:
+                       sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(*_C_ai_addr(r)))
                        p := (*[2]byte)(unsafe.Pointer(&sa.Port))
                        return int(p[0])<<8 | int(p[1]), nil
                }
@@ -134,7 +124,7 @@ func cgoLookupServicePort(hints *C.struct_addrinfo, network, service string) (po
        return 0, &DNSError{Err: "unknown port", Name: network + "/" + service}
 }
 
-func cgoPortLookup(result chan<- portLookupResult, hints *C.struct_addrinfo, network, service string) {
+func cgoPortLookup(result chan<- portLookupResult, hints *_C_struct_addrinfo, network, service string) {
        port, err := cgoLookupServicePort(hints, network, service)
        result <- portLookupResult{port, err}
 }
@@ -143,29 +133,29 @@ func cgoLookupIPCNAME(network, name string) (addrs []IPAddr, cname string, err e
        acquireThread()
        defer releaseThread()
 
-       var hints C.struct_addrinfo
-       hints.ai_flags = cgoAddrInfoFlags
-       hints.ai_socktype = C.SOCK_STREAM
-       hints.ai_family = C.AF_UNSPEC
+       var hints _C_struct_addrinfo
+       *_C_ai_flags(&hints) = cgoAddrInfoFlags
+       *_C_ai_socktype(&hints) = _C_SOCK_STREAM
+       *_C_ai_family(&hints) = _C_AF_UNSPEC
        switch ipVersion(network) {
        case '4':
-               hints.ai_family = C.AF_INET
+               *_C_ai_family(&hints) = _C_AF_INET
        case '6':
-               hints.ai_family = C.AF_INET6
+               *_C_ai_family(&hints) = _C_AF_INET6
        }
 
        h := make([]byte, len(name)+1)
        copy(h, name)
-       var res *C.struct_addrinfo
-       gerrno, err := C.getaddrinfo((*C.char)(unsafe.Pointer(&h[0])), nil, &hints, &res)
+       var res *_C_struct_addrinfo
+       gerrno, err := _C_getaddrinfo((*_C_char)(unsafe.Pointer(&h[0])), nil, &hints, &res)
        if gerrno != 0 {
                isErrorNoSuchHost := false
                isTemporary := false
                switch gerrno {
-               case C.EAI_SYSTEM:
+               case _C_EAI_SYSTEM:
                        if err == nil {
                                // err should not be nil, but sometimes getaddrinfo returns
-                               // gerrno == C.EAI_SYSTEM with err == nil on Linux.
+                               // gerrno == _C_EAI_SYSTEM with err == nil on Linux.
                                // The report claims that it happens when we have too many
                                // open files, so use syscall.EMFILE (too many open files in system).
                                // Most system calls would return ENFILE (too many open files),
@@ -173,7 +163,7 @@ func cgoLookupIPCNAME(network, name string) (addrs []IPAddr, cname string, err e
                                // comes up again. golang.org/issue/6232.
                                err = syscall.EMFILE
                        }
-               case C.EAI_NONAME:
+               case _C_EAI_NONAME:
                        err = errNoSuchHost
                        isErrorNoSuchHost = true
                default:
@@ -183,10 +173,10 @@ func cgoLookupIPCNAME(network, name string) (addrs []IPAddr, cname string, err e
 
                return nil, "", &DNSError{Err: err.Error(), Name: name, IsNotFound: isErrorNoSuchHost, IsTemporary: isTemporary}
        }
-       defer C.freeaddrinfo(res)
+       defer _C_freeaddrinfo(res)
 
        if res != nil {
-               cname = C.GoString(res.ai_canonname)
+               cname = _C_GoString(*_C_ai_canonname(res))
                if cname == "" {
                        cname = name
                }
@@ -194,18 +184,18 @@ func cgoLookupIPCNAME(network, name string) (addrs []IPAddr, cname string, err e
                        cname += "."
                }
        }
-       for r := res; r != nil; r = r.ai_next {
+       for r := res; r != nil; r = *_C_ai_next(r) {
                // We only asked for SOCK_STREAM, but check anyhow.
-               if r.ai_socktype != C.SOCK_STREAM {
+               if *_C_ai_socktype(r) != _C_SOCK_STREAM {
                        continue
                }
-               switch r.ai_family {
-               case C.AF_INET:
-                       sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.ai_addr))
+               switch *_C_ai_family(r) {
+               case _C_AF_INET:
+                       sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(*_C_ai_addr(r)))
                        addr := IPAddr{IP: copyIP(sa.Addr[:])}
                        addrs = append(addrs, addr)
-               case C.AF_INET6:
-                       sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.ai_addr))
+               case _C_AF_INET6:
+                       sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(*_C_ai_addr(r)))
                        addr := IPAddr{IP: copyIP(sa.Addr[:]), Zone: zoneCache.name(int(sa.Scope_id))}
                        addrs = append(addrs, addr)
                }
@@ -288,7 +278,7 @@ func cgoLookupPTR(ctx context.Context, addr string) (names []string, err error,
        }
 }
 
-func cgoLookupAddrPTR(addr string, sa *C.struct_sockaddr, salen C.socklen_t) (names []string, err error) {
+func cgoLookupAddrPTR(addr string, sa *_C_struct_sockaddr, salen _C_socklen_t) (names []string, err error) {
        acquireThread()
        defer releaseThread()
 
@@ -297,14 +287,14 @@ func cgoLookupAddrPTR(addr string, sa *C.struct_sockaddr, salen C.socklen_t) (na
        for l := nameinfoLen; l <= maxNameinfoLen; l *= 2 {
                b = make([]byte, l)
                gerrno, err = cgoNameinfoPTR(b, sa, salen)
-               if gerrno == 0 || gerrno != C.EAI_OVERFLOW {
+               if gerrno == 0 || gerrno != _C_EAI_OVERFLOW {
                        break
                }
        }
        if gerrno != 0 {
                isTemporary := false
                switch gerrno {
-               case C.EAI_SYSTEM:
+               case _C_EAI_SYSTEM:
                        if err == nil { // see golang.org/issue/6232
                                err = syscall.EMFILE
                        }
@@ -323,17 +313,17 @@ func cgoLookupAddrPTR(addr string, sa *C.struct_sockaddr, salen C.socklen_t) (na
        return []string{absDomainName(string(b))}, nil
 }
 
-func cgoReverseLookup(result chan<- reverseLookupResult, addr string, sa *C.struct_sockaddr, salen C.socklen_t) {
+func cgoReverseLookup(result chan<- reverseLookupResult, addr string, sa *_C_struct_sockaddr, salen _C_socklen_t) {
        names, err := cgoLookupAddrPTR(addr, sa, salen)
        result <- reverseLookupResult{names, err}
 }
 
-func cgoSockaddr(ip IP, zone string) (*C.struct_sockaddr, C.socklen_t) {
+func cgoSockaddr(ip IP, zone string) (*_C_struct_sockaddr, _C_socklen_t) {
        if ip4 := ip.To4(); ip4 != nil {
-               return cgoSockaddrInet4(ip4), C.socklen_t(syscall.SizeofSockaddrInet4)
+               return cgoSockaddrInet4(ip4), _C_socklen_t(syscall.SizeofSockaddrInet4)
        }
        if ip6 := ip.To16(); ip6 != nil {
-               return cgoSockaddrInet6(ip6, zoneCache.index(zone)), C.socklen_t(syscall.SizeofSockaddrInet6)
+               return cgoSockaddrInet6(ip6, zoneCache.index(zone)), _C_socklen_t(syscall.SizeofSockaddrInet6)
        }
        return nil, 0
 }
diff --git a/src/net/cgo_unix_cgo.go b/src/net/cgo_unix_cgo.go
new file mode 100644 (file)
index 0000000..74e0406
--- /dev/null
@@ -0,0 +1,71 @@
+// Copyright 2022 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 && !netgo && unix && !darwin
+
+package net
+
+/*
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <string.h>
+
+// If nothing else defined EAI_OVERFLOW, make sure it has a value.
+#ifndef EAI_OVERFLOW
+#define EAI_OVERFLOW -12
+#endif
+*/
+import "C"
+
+const (
+       _C_AF_INET      = C.AF_INET
+       _C_AF_INET6     = C.AF_INET6
+       _C_AF_UNSPEC    = C.AF_UNSPEC
+       _C_EAI_AGAIN    = C.EAI_AGAIN
+       _C_EAI_NONAME   = C.EAI_NONAME
+       _C_EAI_OVERFLOW = C.EAI_OVERFLOW
+       _C_EAI_SYSTEM   = C.EAI_SYSTEM
+       _C_IPPROTO_TCP  = C.IPPROTO_TCP
+       _C_IPPROTO_UDP  = C.IPPROTO_UDP
+       _C_SOCK_DGRAM   = C.SOCK_DGRAM
+       _C_SOCK_STREAM  = C.SOCK_STREAM
+)
+
+type (
+       _C_char               = C.char
+       _C_uchar              = C.uchar
+       _C_int                = C.int
+       _C_uint               = C.uint
+       _C_socklen_t          = C.socklen_t
+       _C_struct_addrinfo    = C.struct_addrinfo
+       _C_struct_sockaddr    = C.struct_sockaddr
+)
+
+func _C_GoString(p *_C_char) string { return C.GoString(p) }
+func _C_CString(s string) *_C_char  { return C.CString(s) }
+
+func _C_ai_addr(ai *_C_struct_addrinfo) **_C_struct_sockaddr { return &ai.ai_addr }
+func _C_ai_addrlen(ai *_C_struct_addrinfo) *_C_uint          { return &ai.ai_addrlen }
+func _C_ai_canonname(ai *_C_struct_addrinfo) **_C_char       { return &ai.ai_canonname }
+func _C_ai_family(ai *_C_struct_addrinfo) *_C_int            { return &ai.ai_family }
+func _C_ai_flags(ai *_C_struct_addrinfo) *_C_int             { return &ai.ai_flags }
+func _C_ai_next(ai *_C_struct_addrinfo) **_C_struct_addrinfo { return &ai.ai_next }
+func _C_ai_protocol(ai *_C_struct_addrinfo) *_C_int          { return &ai.ai_protocol }
+func _C_ai_socktype(ai *_C_struct_addrinfo) *_C_int          { return &ai.ai_socktype }
+
+func _C_freeaddrinfo(ai *_C_struct_addrinfo) {
+       C.freeaddrinfo(ai)
+}
+
+func _C_gai_strerror(eai _C_int) string {
+       return C.GoString(C.gai_strerror(eai))
+}
+
+func _C_getaddrinfo(hostname, servname *_C_char, hints *_C_struct_addrinfo, res **_C_struct_addrinfo) (int, error) {
+       x, err := C.getaddrinfo(hostname, servname, hints, res)
+       return int(x), err
+}
diff --git a/src/net/cgo_unix_syscall.go b/src/net/cgo_unix_syscall.go
new file mode 100644 (file)
index 0000000..899654a
--- /dev/null
@@ -0,0 +1,85 @@
+// Copyright 2022 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 && !netgo && darwin
+
+package net
+
+import (
+       "internal/syscall/unix"
+       "syscall"
+       "unsafe"
+)
+
+const (
+       _C_AF_INET      = syscall.AF_INET
+       _C_AF_INET6     = syscall.AF_INET6
+       _C_AF_UNSPEC    = syscall.AF_UNSPEC
+       _C_EAI_AGAIN    = unix.EAI_AGAIN
+       _C_EAI_NONAME   = unix.EAI_NONAME
+       _C_EAI_OVERFLOW = unix.EAI_OVERFLOW
+       _C_EAI_SYSTEM   = unix.EAI_SYSTEM
+       _C_IPPROTO_TCP  = syscall.IPPROTO_TCP
+       _C_IPPROTO_UDP  = syscall.IPPROTO_UDP
+       _C_SOCK_DGRAM   = syscall.SOCK_DGRAM
+       _C_SOCK_STREAM  = syscall.SOCK_STREAM
+)
+
+type (
+       _C_char            = byte
+       _C_int             = int32
+       _C_uchar           = byte
+       _C_uint            = uint32
+       _C_socklen_t       = int
+       _C_struct_addrinfo = unix.Addrinfo
+       _C_struct_sockaddr = syscall.RawSockaddr
+)
+
+func _C_GoString(p *_C_char) string {
+       return unix.GoString(p)
+}
+
+func _C_CString(s string) *_C_char {
+       b := make([]byte, len(s)+1)
+       copy(b, s)
+       return &b[0]
+}
+
+func _C_ai_addr(ai *_C_struct_addrinfo) **_C_struct_sockaddr { return &ai.Addr }
+func _C_ai_addrlen(ai *_C_struct_addrinfo) *_C_uint          { return &ai.Addrlen }
+func _C_ai_canonname(ai *_C_struct_addrinfo) **_C_char       { return &ai.Canonname }
+func _C_ai_family(ai *_C_struct_addrinfo) *_C_int            { return &ai.Family }
+func _C_ai_flags(ai *_C_struct_addrinfo) *_C_int             { return &ai.Flags }
+func _C_ai_next(ai *_C_struct_addrinfo) **_C_struct_addrinfo { return &ai.Next }
+func _C_ai_protocol(ai *_C_struct_addrinfo) *_C_int          { return &ai.Protocol }
+func _C_ai_socktype(ai *_C_struct_addrinfo) *_C_int          { return &ai.Socktype }
+
+func _C_freeaddrinfo(ai *_C_struct_addrinfo) {
+       unix.Freeaddrinfo(ai)
+}
+
+func _C_gai_strerror(eai _C_int) string {
+       return unix.GaiStrerror(int(eai))
+}
+
+func _C_getaddrinfo(hostname, servname *byte, hints *_C_struct_addrinfo, res **_C_struct_addrinfo) (int, error) {
+       return unix.Getaddrinfo(hostname, servname, hints, res)
+}
+
+func cgoNameinfoPTR(b []byte, sa *syscall.RawSockaddr, salen int) (int, error) {
+       gerrno, err := unix.Getnameinfo(sa, salen, &b[0], len(b), nil, 0, unix.NI_NAMEREQD)
+       return int(gerrno), err
+}
+
+func cgoSockaddrInet4(ip IP) *syscall.RawSockaddr {
+       sa := syscall.RawSockaddrInet4{Len: syscall.SizeofSockaddrInet4, Family: syscall.AF_INET}
+       copy(sa.Addr[:], ip)
+       return (*syscall.RawSockaddr)(unsafe.Pointer(&sa))
+}
+
+func cgoSockaddrInet6(ip IP, zone int) *syscall.RawSockaddr {
+       sa := syscall.RawSockaddrInet6{Len: syscall.SizeofSockaddrInet6, Family: syscall.AF_INET6, Scope_id: uint32(zone)}
+       copy(sa.Addr[:], ip)
+       return (*syscall.RawSockaddr)(unsafe.Pointer(&sa))
+}
index 18b0490ebb41d91fe06528bc0bbac52abe259070..61b7f8c728ffab4197c9c60ed09a2303d654e7e2 100644 (file)
@@ -49,6 +49,17 @@ func syscall_syscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
 }
 func syscall6()
 
+//go:linkname syscall_syscall9 syscall.syscall9
+//go:nosplit
+//go:cgo_unsafe_args
+func syscall_syscall9(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) {
+       entersyscall()
+       libcCall(unsafe.Pointer(abi.FuncPCABI0(syscall9)), unsafe.Pointer(&fn))
+       exitsyscall()
+       return
+}
+func syscall9()
+
 //go:linkname syscall_syscall6X syscall.syscall6X
 //go:nosplit
 func syscall_syscall6X(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
@@ -87,7 +98,7 @@ func syscall_rawSyscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintpt
        return args.r1, args.r2, args.err
 }
 
-// syscallNoErr is used in crypto/x509 to call into Security.framework and CF.
+// crypto_x509_syscall is used in crypto/x509/internal/macos to call into Security.framework and CF.
 
 //go:linkname crypto_x509_syscall crypto/x509/internal/macos.syscall
 //go:nosplit
index ba81fcc35c4424b8ec3d6c07b30a6be8e0200817..369b12e8f9f86d86b3b9f63d432c5abaa01f9a11 100644 (file)
@@ -839,6 +839,65 @@ ok:
        POPQ    BP
        RET
 
+// syscall9 calls a function in libc on behalf of the syscall package.
+// syscall9 takes a pointer to a struct like:
+// struct {
+//     fn    uintptr
+//     a1    uintptr
+//     a2    uintptr
+//     a3    uintptr
+//     a4    uintptr
+//     a5    uintptr
+//     a6    uintptr
+//     a7    uintptr
+//     a8    uintptr
+//     a9    uintptr
+//     r1    uintptr
+//     r2    uintptr
+//     err   uintptr
+// }
+// syscall9 must be called on the g0 stack with the
+// C calling convention (use libcCall).
+//
+// syscall9 expects a 32-bit result and tests for 32-bit -1
+// to decide there was an error.
+TEXT runtime·syscall9(SB),NOSPLIT,$0
+       PUSHQ   BP
+       MOVQ    SP, BP
+       SUBQ    $16, SP
+       MOVQ    (0*8)(DI), R13// fn
+       MOVQ    (2*8)(DI), SI // a2
+       MOVQ    (3*8)(DI), DX // a3
+       MOVQ    (4*8)(DI), CX // a4
+       MOVQ    (5*8)(DI), R8 // a5
+       MOVQ    (6*8)(DI), R9 // a6
+       MOVQ    (7*8)(DI), R10 // a7
+       MOVQ    (8*8)(DI), R11 // a8
+       MOVQ    (9*8)(DI), R12 // a9
+       MOVQ    DI, (SP)
+       MOVQ    (1*8)(DI), DI // a1
+       XORL    AX, AX        // vararg: say "no float args"
+
+       CALL    R13
+
+       MOVQ    (SP), DI
+       MOVQ    AX, (10*8)(DI) // r1
+       MOVQ    DX, (11*8)(DI) // r2
+
+       CMPL    AX, $-1
+       JNE     ok
+
+       CALL    libc_error(SB)
+       MOVLQSX (AX), AX
+       MOVQ    (SP), DI
+       MOVQ    AX, (12*8)(DI) // err
+
+ok:
+       XORL    AX, AX        // no error (it's ignored anyway)
+       MOVQ    BP, SP
+       POPQ    BP
+       RET
+
 // syscall_x509 is for crypto/x509. It is like syscall6 but does not check for errors,
 // takes 5 uintptrs and 1 float64, and only returns one value,
 // for use with standard C ABI functions.
index bf0dc9d8ccb6ce7ba5f3c4d73bcf04935e188245..4fa99cc0f98cff8d8f02b9a8eb446239aeb67e47 100644 (file)
@@ -669,6 +669,63 @@ TEXT runtime·syscall6X(SB),NOSPLIT,$0
 ok:
        RET
 
+// syscall9 calls a function in libc on behalf of the syscall package.
+// syscall9 takes a pointer to a struct like:
+// struct {
+//     fn    uintptr
+//     a1    uintptr
+//     a2    uintptr
+//     a3    uintptr
+//     a4    uintptr
+//     a5    uintptr
+//     a6    uintptr
+//     a7    uintptr
+//     a8    uintptr
+//     a9    uintptr
+//     r1    uintptr
+//     r2    uintptr
+//     err   uintptr
+// }
+// syscall9 must be called on the g0 stack with the
+// C calling convention (use libcCall).
+TEXT runtime·syscall9(SB),NOSPLIT,$0
+       SUB     $16, RSP        // push structure pointer
+       MOVD    R0, 8(RSP)
+
+       MOVD    0(R0), R12      // fn
+       MOVD    16(R0), R1      // a2
+       MOVD    24(R0), R2      // a3
+       MOVD    32(R0), R3      // a4
+       MOVD    40(R0), R4      // a5
+       MOVD    48(R0), R5      // a6
+       MOVD    56(R0), R6      // a7
+       MOVD    64(R0), R7      // a8
+       MOVD    72(R0), R8      // a9
+       MOVD    8(R0), R0       // a1
+
+       // If fn is declared as vararg, we have to pass the vararg arguments on the stack.
+       // See syscall above. The only function this applies to is openat, for which the 4th
+       // arg must be on the stack.
+       MOVD    R3, (RSP)
+
+       BL      (R12)
+
+       MOVD    8(RSP), R2      // pop structure pointer
+       ADD     $16, RSP
+       MOVD    R0, 80(R2)      // save r1
+       MOVD    R1, 88(R2)      // save r2
+       CMPW    $-1, R0
+       BNE     ok
+       SUB     $16, RSP        // push structure pointer
+       MOVD    R2, 8(RSP)
+       BL      libc_error(SB)
+       MOVW    (R0), R0
+       MOVD    8(RSP), R2      // pop structure pointer
+       ADD     $16, RSP
+       MOVD    R0, 96(R2)      // save err
+ok:
+       RET
+
 // syscall_x509 is for crypto/x509. It is like syscall6 but does not check for errors,
 // takes 5 uintptrs and 1 float64, and only returns one value,
 // for use with standard C ABI functions.