Skip to content

Commit

Permalink
unix: take address in assembly for Darwin syscall wrappers
Browse files Browse the repository at this point in the history
In Go 1.17 we will introduce a register-based ABI on some
platforms, as well as ABI wrappers to bridge the ABIs. For Darwin
syscall wrappers, it needs to be called directly, instead of
through wrappers. Currently, it is written as that the syscall
functions are defined in assembly and their addresses are taken
from Go using funcPC. In Go 1.17 this will result in the address
of the ABI wrapper, which is undesired.

In the syscall package in the standard library we changed to use
a compiler intrinsic internal/abi.FuncPCABI0 to take the address
of the syscall function. But that is not available to this repo
and not available in older versions of Go. Here we take a
different approach: taking the address directly from assembly.
This also ensures we get the address of the defined syscall
function, not the ABI wrapper.

Updates golang/go#45702.

Change-Id: Ia7480d0fb0ca4fb9bf2f36d2deb1e3e5e4eb8284
Reviewed-on: https://go-review.googlesource.com/c/sys/+/317894
Trust: Cherry Mui <cherryyz@google.com>
Run-TryBot: Cherry Mui <cherryyz@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
  • Loading branch information
cherrymui committed May 7, 2021
1 parent 30e306a commit a76c4d0
Show file tree
Hide file tree
Showing 13 changed files with 2,183 additions and 1,024 deletions.
274 changes: 137 additions & 137 deletions unix/darwin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (

type darwinTest struct {
name string
f func()
f uintptr
}

// TODO(khr): decide whether to keep this test enabled permanently or
Expand Down Expand Up @@ -62,7 +62,7 @@ func init() {
if len(os.Args) >= 3 && os.Args[1] == "testDarwinLoader" {
for _, test := range darwinTests {
if test.name == os.Args[2] {
test.f()
syscall_syscall(test.f, ^uintptr(0), ^uintptr(0), ^uintptr(0))
}
}
// Panic with a "success" label, so the parent process can check it.
Expand All @@ -72,139 +72,139 @@ func init() {

// All the _trampoline functions in zsyscall_darwin_$ARCH.s
var darwinTests = [...]darwinTest{
{"getgroups", libc_getgroups_trampoline},
{"setgroups", libc_setgroups_trampoline},
{"wait4", libc_wait4_trampoline},
{"accept", libc_accept_trampoline},
{"bind", libc_bind_trampoline},
{"connect", libc_connect_trampoline},
{"socket", libc_socket_trampoline},
{"getsockopt", libc_getsockopt_trampoline},
{"setsockopt", libc_setsockopt_trampoline},
{"getpeername", libc_getpeername_trampoline},
{"getsockname", libc_getsockname_trampoline},
{"shutdown", libc_shutdown_trampoline},
{"socketpair", libc_socketpair_trampoline},
{"recvfrom", libc_recvfrom_trampoline},
{"sendto", libc_sendto_trampoline},
{"recvmsg", libc_recvmsg_trampoline},
{"sendmsg", libc_sendmsg_trampoline},
{"kevent", libc_kevent_trampoline},
{"sysctl", libc_sysctl_trampoline},
{"utimes", libc_utimes_trampoline},
{"futimes", libc_futimes_trampoline},
{"fcntl", libc_fcntl_trampoline},
{"poll", libc_poll_trampoline},
{"madvise", libc_madvise_trampoline},
{"mlock", libc_mlock_trampoline},
{"mlockall", libc_mlockall_trampoline},
{"mprotect", libc_mprotect_trampoline},
{"msync", libc_msync_trampoline},
{"munlock", libc_munlock_trampoline},
{"munlockall", libc_munlockall_trampoline},
{"ptrace", libc_ptrace_trampoline},
{"pipe", libc_pipe_trampoline},
{"getxattr", libc_getxattr_trampoline},
{"fgetxattr", libc_fgetxattr_trampoline},
{"setxattr", libc_setxattr_trampoline},
{"fsetxattr", libc_fsetxattr_trampoline},
{"removexattr", libc_removexattr_trampoline},
{"fremovexattr", libc_fremovexattr_trampoline},
{"listxattr", libc_listxattr_trampoline},
{"flistxattr", libc_flistxattr_trampoline},
{"kill", libc_kill_trampoline},
{"ioctl", libc_ioctl_trampoline},
{"access", libc_access_trampoline},
{"adjtime", libc_adjtime_trampoline},
{"chdir", libc_chdir_trampoline},
{"chflags", libc_chflags_trampoline},
{"chmod", libc_chmod_trampoline},
{"chown", libc_chown_trampoline},
{"chroot", libc_chroot_trampoline},
{"close", libc_close_trampoline},
{"dup", libc_dup_trampoline},
{"dup2", libc_dup2_trampoline},
{"exchangedata", libc_exchangedata_trampoline},
{"exit", libc_exit_trampoline},
{"faccessat", libc_faccessat_trampoline},
{"fchdir", libc_fchdir_trampoline},
{"fchflags", libc_fchflags_trampoline},
{"fchmod", libc_fchmod_trampoline},
{"fchmodat", libc_fchmodat_trampoline},
{"fchown", libc_fchown_trampoline},
{"fchownat", libc_fchownat_trampoline},
{"flock", libc_flock_trampoline},
{"fpathconf", libc_fpathconf_trampoline},
{"fstat64", libc_fstat64_trampoline},
{"fstatat64", libc_fstatat64_trampoline},
{"fstatfs64", libc_fstatfs64_trampoline},
{"fsync", libc_fsync_trampoline},
{"ftruncate", libc_ftruncate_trampoline},
{"getdtablesize", libc_getdtablesize_trampoline},
{"getegid", libc_getegid_trampoline},
{"geteuid", libc_geteuid_trampoline},
{"getgid", libc_getgid_trampoline},
{"getpgid", libc_getpgid_trampoline},
{"getpgrp", libc_getpgrp_trampoline},
{"getpid", libc_getpid_trampoline},
{"getppid", libc_getppid_trampoline},
{"getpriority", libc_getpriority_trampoline},
{"getrlimit", libc_getrlimit_trampoline},
{"getrusage", libc_getrusage_trampoline},
{"getsid", libc_getsid_trampoline},
{"getuid", libc_getuid_trampoline},
{"issetugid", libc_issetugid_trampoline},
{"kqueue", libc_kqueue_trampoline},
{"lchown", libc_lchown_trampoline},
{"link", libc_link_trampoline},
{"linkat", libc_linkat_trampoline},
{"listen", libc_listen_trampoline},
{"lstat64", libc_lstat64_trampoline},
{"mkdir", libc_mkdir_trampoline},
{"mkdirat", libc_mkdirat_trampoline},
{"mkfifo", libc_mkfifo_trampoline},
{"mknod", libc_mknod_trampoline},
{"open", libc_open_trampoline},
{"openat", libc_openat_trampoline},
{"pathconf", libc_pathconf_trampoline},
{"pread", libc_pread_trampoline},
{"pwrite", libc_pwrite_trampoline},
{"read", libc_read_trampoline},
{"readlink", libc_readlink_trampoline},
{"readlinkat", libc_readlinkat_trampoline},
{"rename", libc_rename_trampoline},
{"renameat", libc_renameat_trampoline},
{"revoke", libc_revoke_trampoline},
{"rmdir", libc_rmdir_trampoline},
{"lseek", libc_lseek_trampoline},
{"select", libc_select_trampoline},
{"setegid", libc_setegid_trampoline},
{"seteuid", libc_seteuid_trampoline},
{"setgid", libc_setgid_trampoline},
{"setlogin", libc_setlogin_trampoline},
{"setpgid", libc_setpgid_trampoline},
{"setpriority", libc_setpriority_trampoline},
{"setprivexec", libc_setprivexec_trampoline},
{"setregid", libc_setregid_trampoline},
{"setreuid", libc_setreuid_trampoline},
{"setrlimit", libc_setrlimit_trampoline},
{"setsid", libc_setsid_trampoline},
{"settimeofday", libc_settimeofday_trampoline},
{"setuid", libc_setuid_trampoline},
{"stat64", libc_stat64_trampoline},
{"statfs64", libc_statfs64_trampoline},
{"symlink", libc_symlink_trampoline},
{"symlinkat", libc_symlinkat_trampoline},
{"sync", libc_sync_trampoline},
{"truncate", libc_truncate_trampoline},
{"umask", libc_umask_trampoline},
{"undelete", libc_undelete_trampoline},
{"unlink", libc_unlink_trampoline},
{"unlinkat", libc_unlinkat_trampoline},
{"unmount", libc_unmount_trampoline},
{"write", libc_write_trampoline},
{"mmap", libc_mmap_trampoline},
{"munmap", libc_munmap_trampoline},
{"gettimeofday", libc_gettimeofday_trampoline},
{"getfsstat64", libc_getfsstat64_trampoline},
{"getgroups", libc_getgroups_trampoline_addr},
{"setgroups", libc_setgroups_trampoline_addr},
{"wait4", libc_wait4_trampoline_addr},
{"accept", libc_accept_trampoline_addr},
{"bind", libc_bind_trampoline_addr},
{"connect", libc_connect_trampoline_addr},
{"socket", libc_socket_trampoline_addr},
{"getsockopt", libc_getsockopt_trampoline_addr},
{"setsockopt", libc_setsockopt_trampoline_addr},
{"getpeername", libc_getpeername_trampoline_addr},
{"getsockname", libc_getsockname_trampoline_addr},
{"shutdown", libc_shutdown_trampoline_addr},
{"socketpair", libc_socketpair_trampoline_addr},
{"recvfrom", libc_recvfrom_trampoline_addr},
{"sendto", libc_sendto_trampoline_addr},
{"recvmsg", libc_recvmsg_trampoline_addr},
{"sendmsg", libc_sendmsg_trampoline_addr},
{"kevent", libc_kevent_trampoline_addr},
{"sysctl", libc_sysctl_trampoline_addr},
{"utimes", libc_utimes_trampoline_addr},
{"futimes", libc_futimes_trampoline_addr},
{"fcntl", libc_fcntl_trampoline_addr},
{"poll", libc_poll_trampoline_addr},
{"madvise", libc_madvise_trampoline_addr},
{"mlock", libc_mlock_trampoline_addr},
{"mlockall", libc_mlockall_trampoline_addr},
{"mprotect", libc_mprotect_trampoline_addr},
{"msync", libc_msync_trampoline_addr},
{"munlock", libc_munlock_trampoline_addr},
{"munlockall", libc_munlockall_trampoline_addr},
{"ptrace", libc_ptrace_trampoline_addr},
{"pipe", libc_pipe_trampoline_addr},
{"getxattr", libc_getxattr_trampoline_addr},
{"fgetxattr", libc_fgetxattr_trampoline_addr},
{"setxattr", libc_setxattr_trampoline_addr},
{"fsetxattr", libc_fsetxattr_trampoline_addr},
{"removexattr", libc_removexattr_trampoline_addr},
{"fremovexattr", libc_fremovexattr_trampoline_addr},
{"listxattr", libc_listxattr_trampoline_addr},
{"flistxattr", libc_flistxattr_trampoline_addr},
{"kill", libc_kill_trampoline_addr},
{"ioctl", libc_ioctl_trampoline_addr},
{"access", libc_access_trampoline_addr},
{"adjtime", libc_adjtime_trampoline_addr},
{"chdir", libc_chdir_trampoline_addr},
{"chflags", libc_chflags_trampoline_addr},
{"chmod", libc_chmod_trampoline_addr},
{"chown", libc_chown_trampoline_addr},
{"chroot", libc_chroot_trampoline_addr},
{"close", libc_close_trampoline_addr},
{"dup", libc_dup_trampoline_addr},
{"dup2", libc_dup2_trampoline_addr},
{"exchangedata", libc_exchangedata_trampoline_addr},
{"exit", libc_exit_trampoline_addr},
{"faccessat", libc_faccessat_trampoline_addr},
{"fchdir", libc_fchdir_trampoline_addr},
{"fchflags", libc_fchflags_trampoline_addr},
{"fchmod", libc_fchmod_trampoline_addr},
{"fchmodat", libc_fchmodat_trampoline_addr},
{"fchown", libc_fchown_trampoline_addr},
{"fchownat", libc_fchownat_trampoline_addr},
{"flock", libc_flock_trampoline_addr},
{"fpathconf", libc_fpathconf_trampoline_addr},
{"fstat64", libc_fstat64_trampoline_addr},
{"fstatat64", libc_fstatat64_trampoline_addr},
{"fstatfs64", libc_fstatfs64_trampoline_addr},
{"fsync", libc_fsync_trampoline_addr},
{"ftruncate", libc_ftruncate_trampoline_addr},
{"getdtablesize", libc_getdtablesize_trampoline_addr},
{"getegid", libc_getegid_trampoline_addr},
{"geteuid", libc_geteuid_trampoline_addr},
{"getgid", libc_getgid_trampoline_addr},
{"getpgid", libc_getpgid_trampoline_addr},
{"getpgrp", libc_getpgrp_trampoline_addr},
{"getpid", libc_getpid_trampoline_addr},
{"getppid", libc_getppid_trampoline_addr},
{"getpriority", libc_getpriority_trampoline_addr},
{"getrlimit", libc_getrlimit_trampoline_addr},
{"getrusage", libc_getrusage_trampoline_addr},
{"getsid", libc_getsid_trampoline_addr},
{"getuid", libc_getuid_trampoline_addr},
{"issetugid", libc_issetugid_trampoline_addr},
{"kqueue", libc_kqueue_trampoline_addr},
{"lchown", libc_lchown_trampoline_addr},
{"link", libc_link_trampoline_addr},
{"linkat", libc_linkat_trampoline_addr},
{"listen", libc_listen_trampoline_addr},
{"lstat64", libc_lstat64_trampoline_addr},
{"mkdir", libc_mkdir_trampoline_addr},
{"mkdirat", libc_mkdirat_trampoline_addr},
{"mkfifo", libc_mkfifo_trampoline_addr},
{"mknod", libc_mknod_trampoline_addr},
{"open", libc_open_trampoline_addr},
{"openat", libc_openat_trampoline_addr},
{"pathconf", libc_pathconf_trampoline_addr},
{"pread", libc_pread_trampoline_addr},
{"pwrite", libc_pwrite_trampoline_addr},
{"read", libc_read_trampoline_addr},
{"readlink", libc_readlink_trampoline_addr},
{"readlinkat", libc_readlinkat_trampoline_addr},
{"rename", libc_rename_trampoline_addr},
{"renameat", libc_renameat_trampoline_addr},
{"revoke", libc_revoke_trampoline_addr},
{"rmdir", libc_rmdir_trampoline_addr},
{"lseek", libc_lseek_trampoline_addr},
{"select", libc_select_trampoline_addr},
{"setegid", libc_setegid_trampoline_addr},
{"seteuid", libc_seteuid_trampoline_addr},
{"setgid", libc_setgid_trampoline_addr},
{"setlogin", libc_setlogin_trampoline_addr},
{"setpgid", libc_setpgid_trampoline_addr},
{"setpriority", libc_setpriority_trampoline_addr},
{"setprivexec", libc_setprivexec_trampoline_addr},
{"setregid", libc_setregid_trampoline_addr},
{"setreuid", libc_setreuid_trampoline_addr},
{"setrlimit", libc_setrlimit_trampoline_addr},
{"setsid", libc_setsid_trampoline_addr},
{"settimeofday", libc_settimeofday_trampoline_addr},
{"setuid", libc_setuid_trampoline_addr},
{"stat64", libc_stat64_trampoline_addr},
{"statfs64", libc_statfs64_trampoline_addr},
{"symlink", libc_symlink_trampoline_addr},
{"symlinkat", libc_symlinkat_trampoline_addr},
{"sync", libc_sync_trampoline_addr},
{"truncate", libc_truncate_trampoline_addr},
{"umask", libc_umask_trampoline_addr},
{"undelete", libc_undelete_trampoline_addr},
{"unlink", libc_unlink_trampoline_addr},
{"unlinkat", libc_unlinkat_trampoline_addr},
{"unmount", libc_unmount_trampoline_addr},
{"write", libc_write_trampoline_addr},
{"mmap", libc_mmap_trampoline_addr},
{"munmap", libc_munmap_trampoline_addr},
{"gettimeofday", libc_gettimeofday_trampoline_addr},
{"getfsstat64", libc_getfsstat64_trampoline_addr},
}
14 changes: 10 additions & 4 deletions unix/mkasm_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import (
"strings"
)

const ptrsize = 8 // Pointer size. All supported platforms are 64-bit.

func writeASMFile(in string, fileName string, buildTags string) {
trampolines := map[string]bool{}

Expand All @@ -31,14 +33,18 @@ func writeASMFile(in string, fileName string, buildTags string) {
fmt.Fprintf(&out, "\n")
fmt.Fprintf(&out, "#include \"textflag.h\"\n")
for _, line := range strings.Split(in, "\n") {
if !strings.HasPrefix(line, "func ") || !strings.HasSuffix(line, "_trampoline()") {
const prefix = "var "
const suffix = "_trampoline_addr uintptr"
if !strings.HasPrefix(line, prefix) || !strings.HasSuffix(line, suffix) {
continue
}
fn := line[5 : len(line)-13]
fn := strings.TrimSuffix(strings.TrimPrefix(line, prefix), suffix)
if !trampolines[fn] {
trampolines[fn] = true
fmt.Fprintf(&out, "TEXT ·%s_trampoline(SB),NOSPLIT,$0-0\n", fn)
fmt.Fprintf(&out, "\tJMP\t%s(SB)\n", fn)
fmt.Fprintf(&out, "\nTEXT %s_trampoline<>(SB),NOSPLIT,$0-0\n", fn)
fmt.Fprintf(&out, "\tJMP\t%s(SB)\n\n", fn)
fmt.Fprintf(&out, "GLOBL\t·%s_trampoline_addr(SB), RODATA, $%d\n", fn, ptrsize)
fmt.Fprintf(&out, "DATA\t·%s_trampoline_addr(SB)/%d, $%s_trampoline<>(SB)\n", fn, ptrsize, fn)
}
}
err := ioutil.WriteFile(fileName, out.Bytes(), 0644)
Expand Down
6 changes: 3 additions & 3 deletions unix/mksyscall.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ func main() {
sysname = strings.TrimPrefix(sysname, "SYS_") // remove SYS_
sysname = strings.ToLower(sysname) // lowercase
libcFn = sysname
sysname = "funcPC(libc_" + sysname + "_trampoline)"
sysname = "libc_" + sysname + "_trampoline_addr"
}

// Actual call.
Expand Down Expand Up @@ -363,8 +363,8 @@ func main() {
if libc && !trampolines[libcFn] {
// some system calls share a trampoline, like read and readlen.
trampolines[libcFn] = true
// Declare assembly trampoline.
text += fmt.Sprintf("func libc_%s_trampoline()\n", libcFn)
// Declare assembly trampoline address.
text += fmt.Sprintf("var libc_%s_trampoline_addr uintptr\n\n", libcFn)
// Assembly trampoline calls the libc_* function, which this magic
// redirects to use the function from libSystem.
text += fmt.Sprintf("//go:cgo_import_dynamic libc_%s %s \"/usr/lib/libSystem.B.dylib\"\n", libcFn, libcFn)
Expand Down
4 changes: 2 additions & 2 deletions unix/syscall_darwin.1_13.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ import (
//sys readdir_r(dir uintptr, entry *Dirent, result **Dirent) (res Errno)

func fdopendir(fd int) (dir uintptr, err error) {
r0, _, e1 := syscall_syscallPtr(funcPC(libc_fdopendir_trampoline), uintptr(fd), 0, 0)
r0, _, e1 := syscall_syscallPtr(libc_fdopendir_trampoline_addr, uintptr(fd), 0, 0)
dir = uintptr(r0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}

func libc_fdopendir_trampoline()
var libc_fdopendir_trampoline_addr uintptr

//go:cgo_import_dynamic libc_fdopendir fdopendir "/usr/lib/libSystem.B.dylib"

Expand Down
9 changes: 1 addition & 8 deletions unix/syscall_darwin_libSystem.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

package unix

import "unsafe"
import _ "unsafe"

// Implemented in the runtime package (runtime/sys_darwin.go)
func syscall_syscall(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
Expand All @@ -25,10 +25,3 @@ func syscall_syscallPtr(fn, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
//go:linkname syscall_rawSyscall syscall.rawSyscall
//go:linkname syscall_rawSyscall6 syscall.rawSyscall6
//go:linkname syscall_syscallPtr syscall.syscallPtr

// Find the entry point for f. See comments in runtime/proc.go for the
// function of the same name.
//go:nosplit
func funcPC(f func()) uintptr {
return **(**uintptr)(unsafe.Pointer(&f))
}
Loading

0 comments on commit a76c4d0

Please sign in to comment.