libgo: handle linking to NetBSD's versioned symbols

On NetBSD, for backwards compatibility, various libc symbols are
renamed to a symbol with a version suffix. For example, this is the
(abbreviated) definition of sigaction:

    int sigaction(...) __asm__ ("__sigaction14")

This poses a challenge for libgo, which attempts to link sigaction by
way of an "//extern" comment:

    //extern sigaction
    func sigaction(...)

This results in a reference to the deprecated compatibility symbol
"sigaction", rather than the desired "__sigaction14" symbol.

This patch introduces a new "//extern-sysinfo" comment to handle this
situation. The new mklinknames.awk script scans a package for these
comments and outputs a "//go:linkname" directive that links the wrapper
to the correct versioned symbol, as determined by parsing the __asm__
annotation on the function's declaration in gen-sysinfo.go.

For now, only the following packages are scanned by mklinknames.awk:

    os
    os/user
    runtime
    syscall

Change-Id: I31b475098aecb9eb0579e8bb5952405e93ac960c
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/265125
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Trust: Emmanuel Odeke <emmanuel@orijtech.com>
diff --git a/libgo/Makefile.am b/libgo/Makefile.am
index 26e8385..f7a163e 100644
--- a/libgo/Makefile.am
+++ b/libgo/Makefile.am
@@ -574,6 +574,48 @@
 	$(SHELL) $(srcdir)/mvifdiff.sh gccgosizes.go.tmp gccgosizes.go
 	$(STAMP) $@
 
+os_linknames.go: s-os_linknames; @true
+s-os_linknames: os-list gen-sysinfo.go $(srcdir)/mklinknames.awk $(srcdir)/go/os/*.go
+	rm -f os_linknames.go.tmp
+	$(AWK) -f $(srcdir)/mklinknames.awk -v package=os `cat os-list` > os_linknames.go.tmp
+	$(SHELL) $(srcdir)/mvifdiff.sh os_linknames.go.tmp os_linknames.go
+	$(STAMP) $@
+
+os-list: s-os-list; @true
+s-os-list: Makefile $(srcdir)/go/os/*.go
+	rm -f os-list.tmp
+	$(SHELL) $(srcdir)/match.sh --goarch=$(GOARCH) --goos=$(GOOS) --srcdir=$(srcdir)/go/os > os-list.tmp
+	$(SHELL) $(srcdir)/mvifdiff.sh os-list.tmp os-list
+	$(STAMP) $@
+
+os_user_linknames.go: s-os_user_linknames; @true
+s-os_user_linknames: os-user-list gen-sysinfo.go $(srcdir)/mklinknames.awk $(srcdir)/go/os/user/*.go
+	rm -f os_user_linknames.go.tmp
+	$(AWK) -f $(srcdir)/mklinknames.awk -v package=user `cat os-user-list` > os_user_linknames.go.tmp
+	$(SHELL) $(srcdir)/mvifdiff.sh os_user_linknames.go.tmp os_user_linknames.go
+	$(STAMP) $@
+
+os-user-list: s-os-user-list; @true
+s-os-user-list: Makefile $(srcdir)/go/os/user/*.go
+	rm -f os-user-list.tmp
+	$(SHELL) $(srcdir)/match.sh --goarch=$(GOARCH) --goos=$(GOOS) --srcdir=$(srcdir)/go/os/user > os-user-list.tmp
+	$(SHELL) $(srcdir)/mvifdiff.sh os-user-list.tmp os-user-list
+	$(STAMP) $@
+
+runtime_linknames.go: s-runtime_linknames; @true
+s-runtime_linknames: runtime-list gen-sysinfo.go $(srcdir)/mklinknames.awk $(srcdir)/go/runtime/*.go
+	rm -f runtime_linknames.go.tmp
+	$(AWK) -f $(srcdir)/mklinknames.awk -v package=runtime `cat runtime-list` > runtime_linknames.go.tmp
+	$(SHELL) $(srcdir)/mvifdiff.sh runtime_linknames.go.tmp runtime_linknames.go
+	$(STAMP) $@
+
+runtime-list: s-runtime-list; @true
+s-runtime-list: Makefile $(srcdir)/go/runtime/*.go
+	rm -f runtime-list.tmp
+	$(SHELL) $(srcdir)/match.sh --goarch=$(GOARCH) --goos=$(GOOS) --srcdir=$(srcdir)/go/runtime > runtime-list.tmp
+	$(SHELL) $(srcdir)/mvifdiff.sh runtime-list.tmp runtime-list
+	$(STAMP) $@
+
 runtime_sysinfo.go: s-runtime_sysinfo; @true
 s-runtime_sysinfo: $(srcdir)/mkrsysinfo.sh gen-sysinfo.go
 	GOARCH=$(GOARCH) GOOS=$(GOOS) $(SHELL) $(srcdir)/mkrsysinfo.sh
@@ -654,6 +696,13 @@
 	$(SHELL) $(srcdir)/mvifdiff.sh syscall_arch.go.tmp syscall_arch.go
 	$(STAMP) $@
 
+syscall_linknames.go: s-syscall_linknames; @true
+s-syscall_linknames: libcalls.go gen-sysinfo.go $(srcdir)/mklinknames.awk
+	rm -f syscall_linknames.go.tmp
+	$(AWK) -v package=syscall -f $(srcdir)/mklinknames.awk libcalls.go > syscall_linknames.go.tmp
+	$(SHELL) $(srcdir)/mvifdiff.sh syscall_linknames.go.tmp syscall_linknames.go
+	$(STAMP) $@
+
 SYSINFO_FLAGS = \
 	$(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
 	$(CPPFLAGS) $(OSCFLAGS) -O
@@ -940,8 +989,8 @@
 math_lo_GOCFLAGS = $(MATH_FLAG)
 math_check_GOCFLAGS = $(MATH_FLAG)
 
-# Add the generated file runtime_sysinfo.go to the runtime package.
-extra_go_files_runtime = runtime_sysinfo.go sigtab.go
+# Add generated files to the runtime package.
+extra_go_files_runtime = runtime_linknames.go runtime_sysinfo.go sigtab.go
 runtime.lo.dep: $(extra_go_files_runtime)
 
 # Add generated files to the syscall package.
@@ -949,6 +998,7 @@
 	libcalls.go \
 	sysinfo.go \
 	syscall_arch.go \
+	syscall_linknames.go \
 	$(syscall_epoll_file)
 syscall.lo.dep: $(extra_go_files_syscall)
 
@@ -1006,6 +1056,12 @@
 extra_go_files_cmd_go_internal_cfg = zdefaultcc.go
 cmd/go/internal/cfg.lo.dep: $(extra_go_files_cmd_go_internal_cfg)
 
+extra_go_files_os = os_linknames.go
+os.lo.dep: $(extra_go_files_os)
+
+extra_go_files_os_user = os_user_linknames.go
+os/user.lo.dep: $(extra_go_files_os_user)
+
 extra_check_libs_cmd_go_internal_cache = $(abs_builddir)/libgotool.a
 extra_check_libs_cmd_go_internal_generate = $(abs_builddir)/libgotool.a
 extra_check_libs_cmd_go_internal_get = $(abs_builddir)/libgotool.a
diff --git a/libgo/Makefile.in b/libgo/Makefile.in
index d300ab6..ba202a6 100644
--- a/libgo/Makefile.in
+++ b/libgo/Makefile.in
@@ -1085,14 +1085,15 @@
 math_lo_GOCFLAGS = $(MATH_FLAG)
 math_check_GOCFLAGS = $(MATH_FLAG)
 
-# Add the generated file runtime_sysinfo.go to the runtime package.
-extra_go_files_runtime = runtime_sysinfo.go sigtab.go
+# Add generated files to the runtime package.
+extra_go_files_runtime = runtime_linknames.go runtime_sysinfo.go sigtab.go
 
 # Add generated files to the syscall package.
 extra_go_files_syscall = \
 	libcalls.go \
 	sysinfo.go \
 	syscall_arch.go \
+	syscall_linknames.go \
 	$(syscall_epoll_file)
 
 
@@ -1128,6 +1129,8 @@
 extra_go_files_go_types = gccgosizes.go
 extra_go_files_cmd_internal_objabi = objabi.go
 extra_go_files_cmd_go_internal_cfg = zdefaultcc.go
+extra_go_files_os = os_linknames.go
+extra_go_files_os_user = os_user_linknames.go
 extra_check_libs_cmd_go_internal_cache = $(abs_builddir)/libgotool.a
 extra_check_libs_cmd_go_internal_generate = $(abs_builddir)/libgotool.a
 extra_check_libs_cmd_go_internal_get = $(abs_builddir)/libgotool.a
@@ -2748,6 +2751,48 @@
 	$(SHELL) $(srcdir)/mvifdiff.sh gccgosizes.go.tmp gccgosizes.go
 	$(STAMP) $@
 
+os_linknames.go: s-os_linknames; @true
+s-os_linknames: os-list gen-sysinfo.go $(srcdir)/mklinknames.awk $(srcdir)/go/os/*.go
+	rm -f os_linknames.go.tmp
+	$(AWK) -f $(srcdir)/mklinknames.awk -v package=os `cat os-list` > os_linknames.go.tmp
+	$(SHELL) $(srcdir)/mvifdiff.sh os_linknames.go.tmp os_linknames.go
+	$(STAMP) $@
+
+os-list: s-os-list; @true
+s-os-list: Makefile $(srcdir)/go/os/*.go
+	rm -f os-list.tmp
+	$(SHELL) $(srcdir)/match.sh --goarch=$(GOARCH) --goos=$(GOOS) --srcdir=$(srcdir)/go/os > os-list.tmp
+	$(SHELL) $(srcdir)/mvifdiff.sh os-list.tmp os-list
+	$(STAMP) $@
+
+os_user_linknames.go: s-os_user_linknames; @true
+s-os_user_linknames: os-user-list gen-sysinfo.go $(srcdir)/mklinknames.awk $(srcdir)/go/os/user/*.go
+	rm -f os_user_linknames.go.tmp
+	$(AWK) -f $(srcdir)/mklinknames.awk -v package=user `cat os-user-list` > os_user_linknames.go.tmp
+	$(SHELL) $(srcdir)/mvifdiff.sh os_user_linknames.go.tmp os_user_linknames.go
+	$(STAMP) $@
+
+os-user-list: s-os-user-list; @true
+s-os-user-list: Makefile $(srcdir)/go/os/user/*.go
+	rm -f os-user-list.tmp
+	$(SHELL) $(srcdir)/match.sh --goarch=$(GOARCH) --goos=$(GOOS) --srcdir=$(srcdir)/go/os/user > os-user-list.tmp
+	$(SHELL) $(srcdir)/mvifdiff.sh os-user-list.tmp os-user-list
+	$(STAMP) $@
+
+runtime_linknames.go: s-runtime_linknames; @true
+s-runtime_linknames: runtime-list gen-sysinfo.go $(srcdir)/mklinknames.awk $(srcdir)/go/runtime/*.go
+	rm -f runtime_linknames.go.tmp
+	$(AWK) -f $(srcdir)/mklinknames.awk -v package=runtime `cat runtime-list` > runtime_linknames.go.tmp
+	$(SHELL) $(srcdir)/mvifdiff.sh runtime_linknames.go.tmp runtime_linknames.go
+	$(STAMP) $@
+
+runtime-list: s-runtime-list; @true
+s-runtime-list: Makefile $(srcdir)/go/runtime/*.go
+	rm -f runtime-list.tmp
+	$(SHELL) $(srcdir)/match.sh --goarch=$(GOARCH) --goos=$(GOOS) --srcdir=$(srcdir)/go/runtime > runtime-list.tmp
+	$(SHELL) $(srcdir)/mvifdiff.sh runtime-list.tmp runtime-list
+	$(STAMP) $@
+
 runtime_sysinfo.go: s-runtime_sysinfo; @true
 s-runtime_sysinfo: $(srcdir)/mkrsysinfo.sh gen-sysinfo.go
 	GOARCH=$(GOARCH) GOOS=$(GOOS) $(SHELL) $(srcdir)/mkrsysinfo.sh
@@ -2816,6 +2861,13 @@
 	$(SHELL) $(srcdir)/mvifdiff.sh syscall_arch.go.tmp syscall_arch.go
 	$(STAMP) $@
 
+syscall_linknames.go: s-syscall_linknames; @true
+s-syscall_linknames: libcalls.go gen-sysinfo.go $(srcdir)/mklinknames.awk
+	rm -f syscall_linknames.go.tmp
+	$(AWK) -v package=syscall -f $(srcdir)/mklinknames.awk libcalls.go > syscall_linknames.go.tmp
+	$(SHELL) $(srcdir)/mvifdiff.sh syscall_linknames.go.tmp syscall_linknames.go
+	$(STAMP) $@
+
 gen-sysinfo.go: s-gen-sysinfo; @true
 s-gen-sysinfo: $(srcdir)/sysinfo.c config.h
 	$(CC) $(SYSINFO_FLAGS) -fdump-go-spec=tmp-gen-sysinfo.go -std=gnu99 -S -o sysinfo.s $(srcdir)/sysinfo.c
@@ -2918,6 +2970,8 @@
 go/types.lo.dep: $(extra_go_files_go_types)
 cmd/internal/objabi.lo.dep: $(extra_go_files_cmd_internal_objabi)
 cmd/go/internal/cfg.lo.dep: $(extra_go_files_cmd_go_internal_cfg)
+os.lo.dep: $(extra_go_files_os)
+os/user.lo.dep: $(extra_go_files_os_user)
 
 # FIXME: The following C files may as well move to the runtime
 # directory and be treated like other C files.
diff --git a/libgo/config.h.in b/libgo/config.h.in
index 532640b..1126790 100644
--- a/libgo/config.h.in
+++ b/libgo/config.h.in
@@ -138,6 +138,9 @@
 /* Define to 1 if you have the `logl' function. */
 #undef HAVE_LOGL
 
+/* Define to 1 if you have the <lwp.h> header file. */
+#undef HAVE_LWP_H
+
 /* Define to 1 if you have the `matherr' function. */
 #undef HAVE_MATHERR
 
diff --git a/libgo/configure b/libgo/configure
index 81331dd..e7379f8 100755
--- a/libgo/configure
+++ b/libgo/configure
@@ -15202,7 +15202,7 @@
   fi
 
 
-for ac_header in port.h sched.h semaphore.h sys/file.h sys/mman.h syscall.h sys/epoll.h sys/event.h sys/inotify.h sys/ptrace.h sys/syscall.h sys/sysctl.h sys/user.h sys/utsname.h sys/select.h sys/socket.h net/bpf.h net/if.h net/if_arp.h net/route.h netpacket/packet.h sys/prctl.h sys/mount.h sys/vfs.h sys/statfs.h sys/timex.h sys/sysinfo.h utime.h linux/ether.h linux/fs.h linux/ptrace.h linux/reboot.h netinet/in_syst.h netinet/ip.h netinet/ip_mroute.h netinet/if_ether.h
+for ac_header in port.h sched.h semaphore.h sys/file.h sys/mman.h syscall.h sys/epoll.h sys/event.h sys/inotify.h sys/ptrace.h sys/syscall.h sys/sysctl.h sys/user.h sys/utsname.h sys/select.h sys/socket.h net/bpf.h net/if.h net/if_arp.h net/route.h netpacket/packet.h sys/prctl.h sys/mount.h sys/vfs.h sys/statfs.h sys/timex.h sys/sysinfo.h utime.h linux/ether.h linux/fs.h linux/ptrace.h linux/reboot.h netinet/in_syst.h netinet/ip.h netinet/ip_mroute.h netinet/if_ether.h lwp.h
 do :
   as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
 ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
diff --git a/libgo/configure.ac b/libgo/configure.ac
index f87ab65..80537f5 100644
--- a/libgo/configure.ac
+++ b/libgo/configure.ac
@@ -580,7 +580,7 @@
 
 GCC_CHECK_UNWIND_GETIPINFO
 
-AC_CHECK_HEADERS(port.h sched.h semaphore.h sys/file.h sys/mman.h syscall.h sys/epoll.h sys/event.h sys/inotify.h sys/ptrace.h sys/syscall.h sys/sysctl.h sys/user.h sys/utsname.h sys/select.h sys/socket.h net/bpf.h net/if.h net/if_arp.h net/route.h netpacket/packet.h sys/prctl.h sys/mount.h sys/vfs.h sys/statfs.h sys/timex.h sys/sysinfo.h utime.h linux/ether.h linux/fs.h linux/ptrace.h linux/reboot.h netinet/in_syst.h netinet/ip.h netinet/ip_mroute.h netinet/if_ether.h)
+AC_CHECK_HEADERS(port.h sched.h semaphore.h sys/file.h sys/mman.h syscall.h sys/epoll.h sys/event.h sys/inotify.h sys/ptrace.h sys/syscall.h sys/sysctl.h sys/user.h sys/utsname.h sys/select.h sys/socket.h net/bpf.h net/if.h net/if_arp.h net/route.h netpacket/packet.h sys/prctl.h sys/mount.h sys/vfs.h sys/statfs.h sys/timex.h sys/sysinfo.h utime.h linux/ether.h linux/fs.h linux/ptrace.h linux/reboot.h netinet/in_syst.h netinet/ip.h netinet/ip_mroute.h netinet/if_ether.h lwp.h)
 
 AC_CHECK_HEADERS([netinet/icmp6.h], [], [],
 [#include <netinet/in.h>
diff --git a/libgo/go/os/dir_regfile.go b/libgo/go/os/dir_regfile.go
index 1f18bab..b2e6623 100644
--- a/libgo/go/os/dir_regfile.go
+++ b/libgo/go/os/dir_regfile.go
@@ -15,5 +15,5 @@
 
 import "syscall"
 
-//extern readdir_r
+//extern-sysinfo readdir_r
 func libc_readdir_r(*syscall.DIR, *syscall.Dirent, **syscall.Dirent) syscall.Errno
diff --git a/libgo/go/os/user/decls_unix.go b/libgo/go/os/user/decls_unix.go
index 276468c..6ffaced 100644
--- a/libgo/go/os/user/decls_unix.go
+++ b/libgo/go/os/user/decls_unix.go
@@ -11,17 +11,17 @@
 
 // Declarations for the libc functions on most Unix systems.
 
-//extern getpwnam_r
+//extern-sysinfo getpwnam_r
 func libc_getpwnam_r(name *byte, pwd *syscall.Passwd, buf *byte, buflen syscall.Size_t, result **syscall.Passwd) int
 
-//extern getpwuid_r
+//extern-sysinfo getpwuid_r
 func libc_getpwuid_r(uid syscall.Uid_t, pwd *syscall.Passwd, buf *byte, buflen syscall.Size_t, result **syscall.Passwd) int
 
-//extern getgrnam_r
+//extern-sysinfo getgrnam_r
 func libc_getgrnam_r(name *byte, grp *syscall.Group, buf *byte, buflen syscall.Size_t, result **syscall.Group) int
 
-//extern getgrgid_r
+//extern-sysinfo getgrgid_r
 func libc_getgrgid_r(gid syscall.Gid_t, grp *syscall.Group, buf *byte, buflen syscall.Size_t, result **syscall.Group) int
 
-//extern getgrouplist
+//extern-sysinfo getgrouplist
 func libc_getgrouplist(user *byte, group syscall.Gid_t, groups *syscall.Gid_t, ngroups *int32) int
diff --git a/libgo/go/runtime/netpoll_kqueue.go b/libgo/go/runtime/netpoll_kqueue.go
index c41a7d0..1724f37 100644
--- a/libgo/go/runtime/netpoll_kqueue.go
+++ b/libgo/go/runtime/netpoll_kqueue.go
@@ -13,11 +13,11 @@
 	"unsafe"
 )
 
-//extern kqueue
+//extern-sysinfo kqueue
 func kqueue() int32
 
 //go:noescape
-//extern kevent
+//extern-sysinfo kevent
 func kevent(kq int32, ch *keventt, nch uintptr, ev *keventt, nev uintptr, ts *timespec) int32
 
 var (
diff --git a/libgo/go/runtime/os_gccgo.go b/libgo/go/runtime/os_gccgo.go
index a8859c0..79331c5 100644
--- a/libgo/go/runtime/os_gccgo.go
+++ b/libgo/go/runtime/os_gccgo.go
@@ -52,7 +52,7 @@
 }
 
 //go:noescape
-//extern pipe
+//extern-sysinfo pipe
 func libcPipe(*[2]int32) int32
 
 func pipe() (r, w int32, e int32) {
@@ -65,7 +65,7 @@
 }
 
 //go:noescape
-//extern pipe2
+//extern-sysinfo pipe2
 func libcPipe2(*[2]int32, int32) int32
 
 func pipe2(flags int32) (r, w int32, e int32) {
diff --git a/libgo/go/runtime/os_netbsd.go b/libgo/go/runtime/os_netbsd.go
index 9ebb652..00c3285 100644
--- a/libgo/go/runtime/os_netbsd.go
+++ b/libgo/go/runtime/os_netbsd.go
@@ -18,19 +18,19 @@
 	return uint64(lwp_self())
 }
 
-//extern _lwp_self
+//extern-sysinfo _lwp_self
 func lwp_self() int32
 
 //go:noescape
-//extern _lwp_park
+//extern-sysinfo _lwp_park
 func lwp_park(ts int32, rel int32, abstime *timespec, unpark int32, hint, unparkhint unsafe.Pointer) int32
 
 //go:noescape
-//extern _lwp_unpark
+//extern-sysinfo _lwp_unpark
 func lwp_unpark(lwp int32, hint unsafe.Pointer) int32
 
 //go:noescape
-//extern sysctl
+//extern-sysinfo sysctl
 func sysctl(*uint32, uint32, *byte, *uintptr, *byte, uintptr) int32
 
 func getncpu() int32 {
diff --git a/libgo/go/runtime/signal_gccgo.go b/libgo/go/runtime/signal_gccgo.go
index c555712..2eece68 100644
--- a/libgo/go/runtime/signal_gccgo.go
+++ b/libgo/go/runtime/signal_gccgo.go
@@ -14,44 +14,44 @@
 // these are written in OS-specific files and in assembler.
 
 //go:noescape
-//extern sigaction
+//extern-sysinfo sigaction
 func sigaction(signum uint32, act *_sigaction, oact *_sigaction) int32
 
 //go:noescape
-//extern sigprocmask
+//extern-sysinfo sigprocmask
 func sigprocmask(how int32, set *sigset, oldset *sigset) int32
 
 //go:noescape
-//extern sigfillset
+//extern-sysinfo sigfillset
 func sigfillset(set *sigset) int32
 
 //go:noescape
-//extern sigemptyset
+//extern-sysinfo sigemptyset
 func sigemptyset(set *sigset) int32
 
 //go:noescape
-//extern sigaddset
+//extern-sysinfo sigaddset
 func c_sigaddset(set *sigset, signum uint32) int32
 
 //go:noescape
-//extern sigdelset
+//extern-sysinfo sigdelset
 func c_sigdelset(set *sigset, signum uint32) int32
 
 //go:noescape
-//extern sigaltstack
+//extern-sysinfo sigaltstack
 func sigaltstack(ss *_stack_t, oss *_stack_t) int32
 
-//extern raise
+//extern-sysinfo raise
 func raise(sig uint32) int32
 
-//extern getpid
+//extern-sysinfo getpid
 func getpid() _pid_t
 
-//extern kill
+//extern-sysinfo kill
 func kill(pid _pid_t, sig uint32) int32
 
 //go:noescape
-//extern setitimer
+//extern-sysinfo setitimer
 func setitimer(which int32, new *_itimerval, old *_itimerval) int32
 
 type sigctxt struct {
diff --git a/libgo/go/runtime/stubs2.go b/libgo/go/runtime/stubs2.go
index 454afee..0aaed29 100644
--- a/libgo/go/runtime/stubs2.go
+++ b/libgo/go/runtime/stubs2.go
@@ -17,7 +17,7 @@
 
 func closefd(fd int32) int32
 
-//extern exit
+//extern-sysinfo exit
 func exit(code int32)
 func usleep(usec uint32)
 
diff --git a/libgo/go/syscall/mksyscall.awk b/libgo/go/syscall/mksyscall.awk
index 50802d9..5f46727 100644
--- a/libgo/go/syscall/mksyscall.awk
+++ b/libgo/go/syscall/mksyscall.awk
@@ -28,7 +28,7 @@
 # type, without a name.
 
 BEGIN {
-    print "// This file was automatically generated by mksyscall.awk"
+    print "// Code generated by mksyscall.awk. DO NOT EDIT."
     print ""
     print "package syscall"
     print ""
@@ -99,7 +99,7 @@
     if (!(cfnname in cfns)) {
         cfns[cfnname] = 1
         printf("//go:noescape\n")
-        printf("//extern %s\n", cfnname)
+        printf("//extern-sysinfo %s\n", cfnname)
         printf("func c_%s(%s) %s\n", cfnname, cfnparams, cfnresult)
     }
     printf("func %s(%s) %s%s%s%s{\n",
diff --git a/libgo/mklinknames.awk b/libgo/mklinknames.awk
new file mode 100644
index 0000000..71cb3be
--- /dev/null
+++ b/libgo/mklinknames.awk
@@ -0,0 +1,46 @@
+# Copyright 2020 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.
+
+# This AWK script reads a Go file with special //extern-sysinfo
+# comments annotating functions which should be linked to libc
+# functions. It generates a Go file containing the appropriate
+# //go:linkname directives.
+#
+# For each annotated function, the script searches gen-sysinfo.go
+# to see if a different assembly name is known for the function.
+# For example, on NetBSD, the timegm symbol is renamed to
+# __timegm50 by an __asm__ annotation on its declaration in time.h.
+
+BEGIN {
+    print "// Code generated by mklinknames.awk. DO NOT EDIT."
+    print ""
+    print "package", package
+    print ""
+    print "import _ \"unsafe\""
+    print ""
+}
+
+/^\/\/extern-sysinfo/ {
+    cfnname = $2
+    getline
+    if ($1 != "func") {
+	printf("mklinknames.awk: error: %s:%d: unattached extern-sysinfo directive\n", FILENAME, FNR) | "cat 1>&2"
+	exit 1
+    }
+    split($2, a, "(")
+    gofnname = a[1]
+    def = sprintf("grep '^func _%s[ (]' gen-sysinfo.go", cfnname)
+    # def looks like one of the following:
+    #     func _timegm (*_tm) int64 __asm__("__timegm50")
+    #     func _timegm (*_tm) int64 __asm__("*__timegm50")
+    # The goal is to extract "__timegm50".
+    if ((def | getline fndef) > 0 && match(fndef, "__asm__\\(\"\\*?")) {
+	asmname = substr(fndef, RSTART + RLENGTH)
+	asmname = substr(asmname, 0, length(asmname) - 2)
+	printf("//go:linkname %s %s\n", gofnname, asmname)
+    } else {
+	# Assume the asm name is the same as the declared C name.
+	printf("//go:linkname %s %s\n", gofnname, cfnname)
+    }
+}
diff --git a/libgo/sysinfo.c b/libgo/sysinfo.c
index ba84071..7086381 100644
--- a/libgo/sysinfo.c
+++ b/libgo/sysinfo.c
@@ -10,6 +10,7 @@
 #include "config.h"
 
 #include <stddef.h>
+#include <stdlib.h>
 #include <sys/types.h>
 #include <dirent.h>
 #include <errno.h>
@@ -177,6 +178,9 @@
 #if defined(HAVE_PORT_H)
 #include <port.h>
 #endif
+#if defined(HAVE_LWP_H)
+#include <lwp.h>
+#endif
 
 #ifdef USE_LIBFFI
 #include "ffi.h"