]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: create library startup for aix/ppc64
authorClément Chigot <clement.chigot@atos.net>
Mon, 25 Mar 2019 09:31:30 +0000 (10:31 +0100)
committerIan Lance Taylor <iant@golang.org>
Wed, 27 Mar 2019 17:22:11 +0000 (17:22 +0000)
As .init_array section aren't available on AIX, the Go runtime
initialization is made with gcc constructor attribute.
However, as cgo tool is building a binary in order to get imported
C symbols, Go symbols imported for this initilization must be ignored.
-Wl,-berok is mandatory otherwize ld will fail to create this binary,
_rt0_aix_ppc64_lib and runtime_rt0_go aren't defined in runtime/cgo.
These two symbols must also be ignored when creating _cgo_import.go.

Change-Id: Icf2e0282f5b50de5fa82007439a428e6147efef1
Reviewed-on: https://go-review.googlesource.com/c/go/+/169118
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/cmd/cgo/out.go
src/cmd/go/internal/work/security.go
src/runtime/cgo/callbacks_aix.go
src/runtime/cgo/cgo.go
src/runtime/cgo/gcc_aix_ppc64.c
src/runtime/os2_aix.go
src/runtime/os_aix.go
src/runtime/rt0_aix_ppc64.s
src/runtime/symtab.go
src/runtime/sys_aix_ppc64.s

index 5d61a2fb8a0dccc6320c67c53e1b31e3835ea8ef..5b3a7cb9c1ea0f69ef25bb8faae1970521364534 100644 (file)
@@ -336,6 +336,12 @@ func dynimport(obj string) {
                        fatalf("cannot load imported symbols from XCOFF file %s: %v", obj, err)
                }
                for _, s := range sym {
+                       if s.Name == "runtime_rt0_go" || s.Name == "_rt0_ppc64_aix_lib" {
+                               // These symbols are imported by runtime/cgo but
+                               // must not be added to _cgo_import.go as there are
+                               // Go symbols.
+                               continue
+                       }
                        fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, s.Name, s.Library)
                }
                lib, err := f.ImportedLibraries()
index 9e26ab8353c49c337c0f60953477891778eea07d..8351e4c731756c16c76a6d20ae0f025292e65caa 100644 (file)
@@ -171,6 +171,7 @@ var validLinkerFlags = []*lazyregexp.Regexp{
        re(`-Wl,--(no-)?allow-shlib-undefined`),
        re(`-Wl,--(no-)?as-needed`),
        re(`-Wl,-Bdynamic`),
+       re(`-Wl,-berok`),
        re(`-Wl,-Bstatic`),
        re(`-WL,-O([^@,\-][^,]*)?`),
        re(`-Wl,-d[ny]`),
index 7dafb6b310d646e3453cacdf58e4d8d25c3ea0d6..f4b6fe25fa268fead1aa12ef3910d6f429dac807 100644 (file)
@@ -8,3 +8,4 @@ package cgo
 // longcall on cgo programs (cf gcc_aix_ppc64.c).
 //go:cgo_export_static __cgo_topofstack
 //go:cgo_export_static runtime.rt0_go
+//go:cgo_export_static _rt0_ppc64_aix_lib
index 241a821e4f0e8fb18ecba2ad8c01f8e4a2e6befd..eb11c0e100aca9e2fc8641b5cc4a0cbd1df093b9 100644 (file)
@@ -20,6 +20,7 @@ package cgo
 #cgo !android,linux LDFLAGS: -lpthread
 #cgo netbsd LDFLAGS: -lpthread
 #cgo openbsd LDFLAGS: -lpthread
+#cgo aix LDFLAGS: -Wl,-berok
 
 #cgo CFLAGS: -Wall -Werror
 
index d54c0ff32d39919f2e8957b37e26aa5ffb724a5a..f4f50b89ce0411cea1a372918231255b1f68c93b 100644 (file)
@@ -12,6 +12,7 @@
  */
 extern int __attribute__((longcall)) __cgo_topofstack(void);
 extern int __attribute__((longcall)) runtime_rt0_go(int argc, char **argv);
+extern void __attribute__((longcall)) _rt0_ppc64_aix_lib(void);
 
 int _cgo_topofstack(void) {
        return __cgo_topofstack();
@@ -20,3 +21,18 @@ int _cgo_topofstack(void) {
 int main(int argc, char **argv) {
        return runtime_rt0_go(argc, argv);
 }
+
+static void libinit(void) __attribute__ ((constructor));
+
+/*
+ * libinit aims to replace .init_array section which isn't available on aix.
+ * Using __attribute__ ((constructor)) let gcc handles this instead of
+ * adding special code in cmd/link.
+ * However, it will be called for every Go programs which has cgo.
+ * Inside _rt0_ppc64_aix_lib(), runtime.isarchive is checked in order
+ * to know if this program is a c-archive or a simple cgo program.
+ * If it's not set, _rt0_ppc64_ax_lib() returns directly.
+ */
+static void libinit() {
+       _rt0_ppc64_aix_lib();
+}
index e2ae04a55d3daae1d657f7cf81b15d59f8395041..2ec32feb9c3c6c2228df3e10f9b54da2bacbba6b 100644 (file)
@@ -363,15 +363,34 @@ func syscall6(fn *libFunc, a0, a1, a2, a3, a4, a5 uintptr) (r, err uintptr) {
        return c.r1, c.err
 }
 
+func exit1(code int32)
+
 //go:nosplit
 func exit(code int32) {
-       syscall1(&libc_exit, uintptr(code))
+       _g_ := getg()
+
+       // Check the validity of g because without a g during
+       // newosproc0.
+       if _g_ != nil {
+               syscall1(&libc_exit, uintptr(code))
+               return
+       }
+       exit1(code)
 }
 
+func write1(fd, p uintptr, n int32) int32
+
 //go:nosplit
 func write(fd uintptr, p unsafe.Pointer, n int32) int32 {
-       r, _ := syscall3(&libc_write, uintptr(fd), uintptr(p), uintptr(n))
-       return int32(r)
+       _g_ := getg()
+
+       // Check the validity of g because without a g during
+       // newosproc0.
+       if _g_ != nil {
+               r, _ := syscall3(&libc_write, uintptr(fd), uintptr(p), uintptr(n))
+               return int32(r)
+       }
+       return write1(fd, uintptr(p), n)
 
 }
 
@@ -428,13 +447,24 @@ func madvise(addr unsafe.Pointer, n uintptr, flags int32) {
        }
 }
 
+func sigaction1(sig, new, old uintptr)
+
 //go:nosplit
 func sigaction(sig uintptr, new, old *sigactiont) {
-       r, err := syscall3(&libc_sigaction, sig, uintptr(unsafe.Pointer(new)), uintptr(unsafe.Pointer(old)))
-       if int32(r) == -1 {
-               println("Sigaction failed for sig: ", sig, " with error:", hex(err))
-               throw("syscall sigaction")
+       _g_ := getg()
+
+       // Check the validity of g because without a g during
+       // runtime.libpreinit.
+       if _g_ != nil {
+               r, err := syscall3(&libc_sigaction, sig, uintptr(unsafe.Pointer(new)), uintptr(unsafe.Pointer(old)))
+               if int32(r) == -1 {
+                       println("Sigaction failed for sig: ", sig, " with error:", hex(err))
+                       throw("syscall sigaction")
+               }
+               return
        }
+
+       sigaction1(sig, uintptr(unsafe.Pointer(new)), uintptr(unsafe.Pointer(old)))
 }
 
 //go:nosplit
@@ -574,16 +604,36 @@ func pthread_attr_destroy(attr *pthread_attr) int32 {
        return int32(r)
 }
 
+func pthread_attr_init1(attr uintptr) int32
+
 //go:nosplit
 func pthread_attr_init(attr *pthread_attr) int32 {
-       r, _ := syscall1(&libpthread_attr_init, uintptr(unsafe.Pointer(attr)))
-       return int32(r)
+       _g_ := getg()
+
+       // Check the validity of g because without a g during
+       // newosproc0.
+       if _g_ != nil {
+               r, _ := syscall1(&libpthread_attr_init, uintptr(unsafe.Pointer(attr)))
+               return int32(r)
+       }
+
+       return pthread_attr_init1(uintptr(unsafe.Pointer(attr)))
 }
 
+func pthread_attr_setdetachstate1(attr uintptr, state int32) int32
+
 //go:nosplit
 func pthread_attr_setdetachstate(attr *pthread_attr, state int32) int32 {
-       r, _ := syscall2(&libpthread_attr_setdetachstate, uintptr(unsafe.Pointer(attr)), uintptr(state))
-       return int32(r)
+       _g_ := getg()
+
+       // Check the validity of g because without a g during
+       // newosproc0.
+       if _g_ != nil {
+               r, _ := syscall2(&libpthread_attr_setdetachstate, uintptr(unsafe.Pointer(attr)), uintptr(state))
+               return int32(r)
+       }
+
+       return pthread_attr_setdetachstate1(uintptr(unsafe.Pointer(attr)), state)
 }
 
 //go:nosplit
@@ -598,16 +648,36 @@ func pthread_attr_getstacksize(attr *pthread_attr, size *uint64) int32 {
        return int32(r)
 }
 
+func pthread_attr_setstacksize1(attr uintptr, size uint64) int32
+
 //go:nosplit
 func pthread_attr_setstacksize(attr *pthread_attr, size uint64) int32 {
-       r, _ := syscall2(&libpthread_attr_setstacksize, uintptr(unsafe.Pointer(attr)), uintptr(size))
-       return int32(r)
+       _g_ := getg()
+
+       // Check the validity of g because without a g during
+       // newosproc0.
+       if _g_ != nil {
+               r, _ := syscall2(&libpthread_attr_setstacksize, uintptr(unsafe.Pointer(attr)), uintptr(size))
+               return int32(r)
+       }
+
+       return pthread_attr_setstacksize1(uintptr(unsafe.Pointer(attr)), size)
 }
 
+func pthread_create1(tid, attr, fn, arg uintptr) int32
+
 //go:nosplit
 func pthread_create(tid *pthread, attr *pthread_attr, fn *funcDescriptor, arg unsafe.Pointer) int32 {
-       r, _ := syscall4(&libpthread_create, uintptr(unsafe.Pointer(tid)), uintptr(unsafe.Pointer(attr)), uintptr(unsafe.Pointer(fn)), uintptr(arg))
-       return int32(r)
+       _g_ := getg()
+
+       // Check the validity of g because without a g during
+       // newosproc0.
+       if _g_ != nil {
+               r, _ := syscall4(&libpthread_create, uintptr(unsafe.Pointer(tid)), uintptr(unsafe.Pointer(attr)), uintptr(unsafe.Pointer(fn)), uintptr(arg))
+               return int32(r)
+       }
+
+       return pthread_create1(uintptr(unsafe.Pointer(tid)), uintptr(unsafe.Pointer(attr)), uintptr(unsafe.Pointer(fn)), uintptr(arg))
 }
 
 // On multi-thread program, sigprocmask must not be called.
index 45c7174e058479038aed97b3ed7de2ff70fd33c1..faec9ac113f72f51f444d6e98c371ce3e909da55 100644 (file)
@@ -97,6 +97,66 @@ func osinit() {
        setupSystemConf()
 }
 
+// newosproc0 is a version of newosproc that can be called before the runtime
+// is initialized.
+//
+// This function is not safe to use after initialization as it does not pass an M as fnarg.
+//
+//go:nosplit
+func newosproc0(stacksize uintptr, fn *funcDescriptor) {
+       var (
+               attr pthread_attr
+               oset sigset
+               tid  pthread
+       )
+
+       if pthread_attr_init(&attr) != 0 {
+               write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
+               exit(1)
+       }
+
+       if pthread_attr_setstacksize(&attr, threadStackSize) != 0 {
+               write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
+               exit(1)
+       }
+
+       if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 {
+               write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
+               exit(1)
+       }
+
+       // Disable signals during create, so that the new thread starts
+       // with signals disabled. It will enable them in minit.
+       sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
+       var ret int32
+       for tries := 0; tries < 20; tries++ {
+               // pthread_create can fail with EAGAIN for no reasons
+               // but it will be ok if it retries.
+               ret = pthread_create(&tid, &attr, fn, nil)
+               if ret != _EAGAIN {
+                       break
+               }
+               usleep(uint32(tries+1) * 1000) // Milliseconds.
+       }
+       sigprocmask(_SIG_SETMASK, &oset, nil)
+       if ret != 0 {
+               write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
+               exit(1)
+       }
+
+}
+
+var failthreadcreate = []byte("runtime: failed to create new OS thread\n")
+
+// Called to do synchronous initialization of Go code built with
+// -buildmode=c-archive or -buildmode=c-shared.
+// None of the Go runtime is initialized.
+//go:nosplit
+//go:nowritebarrierrec
+func libpreinit() {
+       initsig(true)
+}
+
 // Ms related functions
 func mpreinit(mp *m) {
        mp.gsignal = malg(32 * 1024) // AIX wants >= 8K
@@ -213,7 +273,13 @@ func setsig(i uint32, fn uintptr) {
 //go:nosplit
 //go:nowritebarrierrec
 func setsigstack(i uint32) {
-       throw("Not yet implemented\n")
+       var sa sigactiont
+       sigaction(uintptr(i), nil, &sa)
+       if sa.sa_flags&_SA_ONSTACK != 0 {
+               return
+       }
+       sa.sa_flags |= _SA_ONSTACK
+       sigaction(uintptr(i), &sa, nil)
 }
 
 //go:nosplit
index 843494b202c36be7aa956a19c03f5492af132d13..e06caa1671e4344ec6a670a15e90f09ab7433f18 100644 (file)
@@ -47,3 +47,153 @@ TEXT _main(SB),NOSPLIT,$-8
        MOVD R12, CTR
        BR (CTR)
 
+
+TEXT _rt0_ppc64_aix_lib(SB),NOSPLIT,$-8
+       // Start with standard C stack frame layout and linkage.
+       MOVD    LR, R0
+       MOVD    R0, 16(R1) // Save LR in caller's frame.
+       MOVW    CR, R0     // Save CR in caller's frame
+       MOVD    R0, 8(R1)
+
+       MOVDU   R1, -344(R1) // Allocate frame.
+
+       // Preserve callee-save registers.
+       MOVD    R14, 48(R1)
+       MOVD    R15, 56(R1)
+       MOVD    R16, 64(R1)
+       MOVD    R17, 72(R1)
+       MOVD    R18, 80(R1)
+       MOVD    R19, 88(R1)
+       MOVD    R20, 96(R1)
+       MOVD    R21,104(R1)
+       MOVD    R22, 112(R1)
+       MOVD    R23, 120(R1)
+       MOVD    R24, 128(R1)
+       MOVD    R25, 136(R1)
+       MOVD    R26, 144(R1)
+       MOVD    R27, 152(R1)
+       MOVD    R28, 160(R1)
+       MOVD    R29, 168(R1)
+       MOVD    g, 176(R1) // R30
+       MOVD    R31, 184(R1)
+       FMOVD   F14, 192(R1)
+       FMOVD   F15, 200(R1)
+       FMOVD   F16, 208(R1)
+       FMOVD   F17, 216(R1)
+       FMOVD   F18, 224(R1)
+       FMOVD   F19, 232(R1)
+       FMOVD   F20, 240(R1)
+       FMOVD   F21, 248(R1)
+       FMOVD   F22, 256(R1)
+       FMOVD   F23, 264(R1)
+       FMOVD   F24, 272(R1)
+       FMOVD   F25, 280(R1)
+       FMOVD   F26, 288(R1)
+       FMOVD   F27, 296(R1)
+       FMOVD   F28, 304(R1)
+       FMOVD   F29, 312(R1)
+       FMOVD   F30, 320(R1)
+       FMOVD   F31, 328(R1)
+
+       // Synchronous initialization.
+       MOVD    $runtime·reginit(SB), R12
+       MOVD    R12, CTR
+       BL      (CTR)
+
+       MOVBZ   runtime·isarchive(SB), R3      // Check buildmode = c-archive
+       CMP             $0, R3
+       BEQ             done
+
+       MOVD    R14, _rt0_ppc64_aix_lib_argc<>(SB)
+       MOVD    R15, _rt0_ppc64_aix_lib_argv<>(SB)
+
+       MOVD    $runtime·libpreinit(SB), R12
+       MOVD    R12, CTR
+       BL      (CTR)
+
+       // Create a new thread to do the runtime initialization and return.
+       MOVD    _cgo_sys_thread_create(SB), R12
+       CMP     $0, R12
+       BEQ     nocgo
+       MOVD    $_rt0_ppc64_aix_lib_go(SB), R3
+       MOVD    $0, R4
+       MOVD    R2, 40(R1)
+       MOVD    8(R12), R2
+       MOVD    (R12), R12
+       MOVD    R12, CTR
+       BL      (CTR)
+       MOVD    40(R1), R2
+       BR      done
+
+nocgo:
+       MOVD    $0x800000, R12                                     // stacksize = 8192KB
+       MOVD    R12, 8(R1)
+       MOVD    $_rt0_ppc64_aix_lib_go(SB), R12
+       MOVD    R12, 16(R1)
+       MOVD    $runtime·newosproc0(SB),R12
+       MOVD    R12, CTR
+       BL      (CTR)
+
+done:
+       // Restore saved registers.
+       MOVD    48(R1), R14
+       MOVD    56(R1), R15
+       MOVD    64(R1), R16
+       MOVD    72(R1), R17
+       MOVD    80(R1), R18
+       MOVD    88(R1), R19
+       MOVD    96(R1), R20
+       MOVD    104(R1), R21
+       MOVD    112(R1), R22
+       MOVD    120(R1), R23
+       MOVD    128(R1), R24
+       MOVD    136(R1), R25
+       MOVD    144(R1), R26
+       MOVD    152(R1), R27
+       MOVD    160(R1), R28
+       MOVD    168(R1), R29
+       MOVD    176(R1), g // R30
+       MOVD    184(R1), R31
+       FMOVD   196(R1), F14
+       FMOVD   200(R1), F15
+       FMOVD   208(R1), F16
+       FMOVD   216(R1), F17
+       FMOVD   224(R1), F18
+       FMOVD   232(R1), F19
+       FMOVD   240(R1), F20
+       FMOVD   248(R1), F21
+       FMOVD   256(R1), F22
+       FMOVD   264(R1), F23
+       FMOVD   272(R1), F24
+       FMOVD   280(R1), F25
+       FMOVD   288(R1), F26
+       FMOVD   296(R1), F27
+       FMOVD   304(R1), F28
+       FMOVD   312(R1), F29
+       FMOVD   320(R1), F30
+       FMOVD   328(R1), F31
+
+       ADD     $344, R1
+
+       MOVD    8(R1), R0
+       MOVFL   R0, $0xff
+       MOVD    16(R1), R0
+       MOVD    R0, LR
+       RET
+
+DATA   _rt0_ppc64_aix_lib_go+0(SB)/8, $__rt0_ppc64_aix_lib_go(SB)
+DATA   _rt0_ppc64_aix_lib_go+8(SB)/8, $TOC(SB)
+DATA   _rt0_ppc64_aix_lib_go+16(SB)/8, $0
+GLOBL  _rt0_ppc64_aix_lib_go(SB), NOPTR, $24
+
+TEXT __rt0_ppc64_aix_lib_go(SB),NOSPLIT,$0
+       MOVD    _rt0_ppc64_aix_lib_argc<>(SB), R3
+       MOVD    _rt0_ppc64_aix_lib_argv<>(SB), R4
+       MOVD    $runtime·rt0_go(SB), R12
+       MOVD    R12, CTR
+       BR      (CTR)
+
+DATA _rt0_ppc64_aix_lib_argc<>(SB)/8, $0
+GLOBL _rt0_ppc64_aix_lib_argc<>(SB),NOPTR, $8
+DATA _rt0_ppc64_aix_lib_argv<>(SB)/8, $0
+GLOBL _rt0_ppc64_aix_lib_argv<>(SB),NOPTR, $8
index a7538482dc6f02d2202c9d6f617a8e9be6208ffc..d61affa54a88e07a3dd2cde74f72a8cad201075c 100644 (file)
@@ -445,6 +445,9 @@ func moduledataverify1(datap *moduledata) {
                        for j := 0; j <= i; j++ {
                                print("\t", hex(datap.ftab[j].entry), " ", funcname(funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff])), datap}), "\n")
                        }
+                       if GOOS == "aix" && isarchive {
+                               println("-Wl,-bnoobjreorder is mandatory on aix/ppc64 with c-archive")
+                       }
                        throw("invalid runtime symbol table")
                }
        }
index 65fcae0c0c6620d0f447c618223416bea64943fc..9e1a95f31ea8d26ac1d052e0643ae422f7a07499 100644 (file)
@@ -216,17 +216,22 @@ TEXT runtime·_tstart(SB),NOSPLIT,$0
        MOVD R0, R3
        RET
 
+
+#define CSYSCALL()                     \
+       MOVD    0(R12), R12             \
+       MOVD    R2, 40(R1)              \
+       MOVD    0(R12), R0              \
+       MOVD    8(R12), R2              \
+       MOVD    R0, CTR                 \
+       BL      (CTR)                   \
+       MOVD    40(R1), R2              \
+       BL runtime·reginit(SB)
+
+
 // Runs on OS stack, called from runtime·osyield.
 TEXT runtime·osyield1(SB),NOSPLIT,$0
        MOVD    $libc_sched_yield(SB), R12
-       MOVD    0(R12), R12
-       MOVD    R2, 40(R1)
-       MOVD    0(R12), R0
-       MOVD    8(R12), R2
-       MOVD    R0, CTR
-       BL      (CTR)
-       MOVD    40(R1), R2
-       BL runtime·reginit(SB)
+       CSYSCALL()
        RET
 
 
@@ -236,26 +241,75 @@ TEXT runtime·sigprocmask1(SB),NOSPLIT,$0-24
        MOVD    new+8(FP), R4
        MOVD    old+16(FP), R5
        MOVD    $libpthread_sigthreadmask(SB), R12
-       MOVD    0(R12), R12
-       MOVD    R2, 40(R1)
-       MOVD    0(R12), R0
-       MOVD    8(R12), R2
-       MOVD    R0, CTR
-       BL      (CTR)
-       MOVD    40(R1), R2
-       BL runtime·reginit(SB)
+       CSYSCALL()
        RET
 
 // Runs on OS stack, called from runtime·usleep.
-TEXT runtime·usleep1(SB),NOSPLIT,$0-8
+TEXT runtime·usleep1(SB),NOSPLIT,$0-4
        MOVW    us+0(FP), R3
        MOVD    $libc_usleep(SB), R12
-       MOVD    0(R12), R12
-       MOVD    R2, 40(R1)
-       MOVD    0(R12), R0
-       MOVD    8(R12), R2
-       MOVD    R0, CTR
-       BL      (CTR)
-       MOVD    40(R1), R2
-       BL runtime·reginit(SB)
+       CSYSCALL()
+       RET
+
+// Runs on OS stack, called from runtime·exit.
+TEXT runtime·exit1(SB),NOSPLIT,$0-4
+       MOVW    code+0(FP), R3
+       MOVD    $libc_exit(SB), R12
+       CSYSCALL()
+       RET
+
+// Runs on OS stack, called from runtime·write.
+TEXT runtime·write1(SB),NOSPLIT,$0-28
+       MOVD    fd+0(FP), R3
+       MOVD    p+8(FP), R4
+       MOVW    n+16(FP), R5
+       MOVD    $libc_write(SB), R12
+       CSYSCALL()
+       MOVW    R3, ret+24(FP)
+       RET
+
+// Runs on OS stack, called from runtime·pthread_attr_init.
+TEXT runtime·pthread_attr_init1(SB),NOSPLIT,$0-12
+       MOVD    attr+0(FP), R3
+       MOVD    $libpthread_attr_init(SB), R12
+       CSYSCALL()
+       MOVW    R3, ret+8(FP)
+       RET
+
+// Runs on OS stack, called from runtime·pthread_attr_setstacksize.
+TEXT runtime·pthread_attr_setstacksize1(SB),NOSPLIT,$0-20
+       MOVD    attr+0(FP), R3
+       MOVD    size+8(FP), R4
+       MOVD    $libpthread_attr_setstacksize(SB), R12
+       CSYSCALL()
+       MOVW    R3, ret+16(FP)
+       RET
+
+// Runs on OS stack, called from runtime·pthread_setdetachstate.
+TEXT runtime·pthread_attr_setdetachstate1(SB),NOSPLIT,$0-20
+       MOVD    attr+0(FP), R3
+       MOVW    state+8(FP), R4
+       MOVD    $libpthread_attr_setdetachstate(SB), R12
+       CSYSCALL()
+       MOVW    R3, ret+16(FP)
+       RET
+
+// Runs on OS stack, called from runtime·pthread_create.
+TEXT runtime·pthread_create1(SB),NOSPLIT,$0-36
+       MOVD    tid+0(FP), R3
+       MOVD    attr+8(FP), R4
+       MOVD    fn+16(FP), R5
+       MOVD    arg+24(FP), R6
+       MOVD    $libpthread_create(SB), R12
+       CSYSCALL()
+       MOVW    R3, ret+32(FP)
+       RET
+
+// Runs on OS stack, called from runtime·sigaction.
+TEXT runtime·sigaction1(SB),NOSPLIT,$0-24
+       MOVD    sig+0(FP), R3
+       MOVD    new+8(FP), R4
+       MOVD    old+16(FP), R5
+       MOVD    $libc_sigaction(SB), R12
+       CSYSCALL()
        RET