Commit ca9128f1 authored by Srdjan Petrovic's avatar Srdjan Petrovic Committed by David Crawshaw

runtime: merge clone0 and clone

We initially added clone0 to handle the case when G or M don't exist, but
it turns out that we could have just modified clone.  (It also helps that
the function we're invoking in clone0 no longer needs arguments.)

As a side-effect, newosproc0 is now supported on all linux archs.

Change-Id: Ie603af75d8f164310fc16446052d83743961f3ca
Reviewed-on: https://go-review.googlesource.com/9164Reviewed-by: 's avatarDavid Crawshaw <crawshaw@golang.org>
parent 3f91a017
// Copyright 2015 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.
// Export guts for testing.
package runtime
var NewOSProc0 = newosproc0
...@@ -22,6 +22,8 @@ var Entersyscall = entersyscall ...@@ -22,6 +22,8 @@ var Entersyscall = entersyscall
var Exitsyscall = exitsyscall var Exitsyscall = exitsyscall
var LockedOSThread = lockedOSThread var LockedOSThread = lockedOSThread
var FuncPC = funcPC
type LFNode struct { type LFNode struct {
Next uint64 Next uint64
Pushcnt uintptr Pushcnt uintptr
......
// Copyright 2015 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.
// The file contains tests that can not run under race detector for some reason.
// +build !race
package runtime_test
import (
"runtime"
"testing"
"time"
"unsafe"
)
var newOSProcDone bool
//go:nosplit
func newOSProcCreated() {
newOSProcDone = true
}
func TestNewOSProc0(t *testing.T) {
runtime.NewOSProc0(0x800000, unsafe.Pointer(runtime.FuncPC(newOSProcCreated)))
check, end := time.Tick(1*time.Second), time.Tick(5*time.Second)
for {
select {
case <-check:
if newOSProcDone {
return
}
case <-end:
t.Fatalf("couldn't create new OS process")
}
}
}
...@@ -143,16 +143,16 @@ func newosproc(mp *m, stk unsafe.Pointer) { ...@@ -143,16 +143,16 @@ func newosproc(mp *m, stk unsafe.Pointer) {
} }
} }
// Version of newosproc that doesn't require any Go structs to be allocated. // Version of newosproc that doesn't require a valid G.
//go:nosplit //go:nosplit
func newosproc0(stacksize uintptr, fn unsafe.Pointer, fnarg unsafe.Pointer) { func newosproc0(stacksize uintptr, fn unsafe.Pointer) {
var dummy uint64 var dummy uint64
stack := sysAlloc(stacksize, &dummy) stack := sysAlloc(stacksize, &dummy)
if stack == nil { if stack == nil {
write(2, unsafe.Pointer(&failallocatestack[0]), int32(len(failallocatestack))) write(2, unsafe.Pointer(&failallocatestack[0]), int32(len(failallocatestack)))
exit(1) exit(1)
} }
ret := clone0(cloneFlags, unsafe.Pointer(uintptr(stack)+stacksize), fn, fnarg) ret := clone(cloneFlags, unsafe.Pointer(uintptr(stack)+stacksize), nil, nil, fn)
if ret < 0 { if ret < 0 {
write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate))) write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
exit(1) exit(1)
......
...@@ -12,9 +12,6 @@ func futex(addr unsafe.Pointer, op int32, val uint32, ts, addr2 unsafe.Pointer, ...@@ -12,9 +12,6 @@ func futex(addr unsafe.Pointer, op int32, val uint32, ts, addr2 unsafe.Pointer,
//go:noescape //go:noescape
func clone(flags int32, stk, mm, gg, fn unsafe.Pointer) int32 func clone(flags int32, stk, mm, gg, fn unsafe.Pointer) int32
//go:noescape
func clone0(flags int32, stk, fn, fnarg unsafe.Pointer) int32
//go:noescape //go:noescape
func rt_sigaction(sig uintptr, new, old *sigactiont, size uintptr) int32 func rt_sigaction(sig uintptr, new, old *sigactiont, size uintptr) int32
......
...@@ -42,7 +42,6 @@ nocgo: ...@@ -42,7 +42,6 @@ nocgo:
MOVL $0x800000, 0(SP) // stacksize = 8192KB MOVL $0x800000, 0(SP) // stacksize = 8192KB
MOVL $_rt0_386_linux_lib_go(SB), AX MOVL $_rt0_386_linux_lib_go(SB), AX
MOVL AX, 4(SP) // fn MOVL AX, 4(SP) // fn
MOVL $0, 8(SP) // fnarg
MOVL $runtime·newosproc0(SB), AX MOVL $runtime·newosproc0(SB), AX
CALL AX CALL AX
......
...@@ -12,13 +12,13 @@ TEXT _rt0_amd64_linux(SB),NOSPLIT,$-8 ...@@ -12,13 +12,13 @@ TEXT _rt0_amd64_linux(SB),NOSPLIT,$-8
// When building with -buildmode=c-shared, this symbol is called when the shared // When building with -buildmode=c-shared, this symbol is called when the shared
// library is loaded. // library is loaded.
TEXT _rt0_amd64_linux_lib(SB),NOSPLIT,$0x58 TEXT _rt0_amd64_linux_lib(SB),NOSPLIT,$0x40
MOVQ BX, 0x18(SP) MOVQ BX, 0x10(SP)
MOVQ BP, 0x20(SP) MOVQ BP, 0x18(SP)
MOVQ R12, 0x28(SP) MOVQ R12, 0x20(SP)
MOVQ R13, 0x30(SP) MOVQ R13, 0x28(SP)
MOVQ R14, 0x38(SP) MOVQ R14, 0x30(SP)
MOVQ R15, 0x40(SP) MOVQ R15, 0x38(SP)
MOVQ DI, _rt0_amd64_linux_lib_argc<>(SB) MOVQ DI, _rt0_amd64_linux_lib_argc<>(SB)
MOVQ SI, _rt0_amd64_linux_lib_argv<>(SB) MOVQ SI, _rt0_amd64_linux_lib_argv<>(SB)
...@@ -36,17 +36,16 @@ nocgo: ...@@ -36,17 +36,16 @@ nocgo:
MOVQ $8388608, 0(SP) // stacksize MOVQ $8388608, 0(SP) // stacksize
MOVQ $_rt0_amd64_linux_lib_go(SB), AX MOVQ $_rt0_amd64_linux_lib_go(SB), AX
MOVQ AX, 8(SP) // fn MOVQ AX, 8(SP) // fn
MOVQ $0, 0x10(SP) // fnarg
MOVQ $runtime·newosproc0(SB), AX MOVQ $runtime·newosproc0(SB), AX
CALL AX CALL AX
restore: restore:
MOVQ 0x18(SP), BX MOVQ 0x10(SP), BX
MOVQ 0x20(SP), BP MOVQ 0x18(SP), BP
MOVQ 0x28(SP), R12 MOVQ 0x20(SP), R12
MOVQ 0x30(SP), R13 MOVQ 0x28(SP), R13
MOVQ 0x38(SP), R14 MOVQ 0x30(SP), R14
MOVQ 0x40(SP), R15 MOVQ 0x38(SP), R15
RET RET
TEXT _rt0_amd64_linux_lib_go(SB),NOSPLIT,$0 TEXT _rt0_amd64_linux_lib_go(SB),NOSPLIT,$0
......
...@@ -12,15 +12,15 @@ TEXT _rt0_arm_linux(SB),NOSPLIT,$-4 ...@@ -12,15 +12,15 @@ TEXT _rt0_arm_linux(SB),NOSPLIT,$-4
// When building with -buildmode=c-shared, this symbol is called when the shared // When building with -buildmode=c-shared, this symbol is called when the shared
// library is loaded. // library is loaded.
TEXT _rt0_arm_linux_lib(SB),NOSPLIT,$40 TEXT _rt0_arm_linux_lib(SB),NOSPLIT,$32
// Preserve callee-save registers. Raspberry Pi's dlopen(), for example, // Preserve callee-save registers. Raspberry Pi's dlopen(), for example,
// actually cares that R11 is preserved. // actually cares that R11 is preserved.
MOVW R4, 16(R13) MOVW R4, 12(R13)
MOVW R5, 20(R13) MOVW R5, 16(R13)
MOVW R6, 24(R13) MOVW R6, 20(R13)
MOVW R7, 28(R13) MOVW R7, 24(R13)
MOVW R8, 32(R13) MOVW R8, 28(R13)
MOVW R11, 36(R13) MOVW R11, 32(R13)
// Save argc/argv. // Save argc/argv.
MOVW R0, _rt0_arm_linux_lib_argc<>(SB) MOVW R0, _rt0_arm_linux_lib_argc<>(SB)
...@@ -37,19 +37,17 @@ TEXT _rt0_arm_linux_lib(SB),NOSPLIT,$40 ...@@ -37,19 +37,17 @@ TEXT _rt0_arm_linux_lib(SB),NOSPLIT,$40
nocgo: nocgo:
MOVW $0x800000, R0 // stacksize = 8192KB MOVW $0x800000, R0 // stacksize = 8192KB
MOVW $_rt0_arm_linux_lib_go<>(SB), R1 // fn MOVW $_rt0_arm_linux_lib_go<>(SB), R1 // fn
MOVW $0, R2 // fnarg
MOVW R0, 4(R13) MOVW R0, 4(R13)
MOVW R1, 8(R13) MOVW R1, 8(R13)
MOVW R2, 12(R13)
BL runtime·newosproc0(SB) BL runtime·newosproc0(SB)
rr: rr:
// Restore callee-save registers and return. // Restore callee-save registers and return.
MOVW 16(R13), R4 MOVW 12(R13), R4
MOVW 20(R13), R5 MOVW 16(R13), R5
MOVW 24(R13), R6 MOVW 20(R13), R6
MOVW 28(R13), R7 MOVW 24(R13), R7
MOVW 32(R13), R8 MOVW 28(R13), R8
MOVW 36(R13), R11 MOVW 32(R13), R11
RET RET
TEXT _rt0_arm_linux_lib_go<>(SB),NOSPLIT,$8 TEXT _rt0_arm_linux_lib_go<>(SB),NOSPLIT,$8
......
...@@ -291,18 +291,18 @@ TEXT runtime·futex(SB),NOSPLIT,$0 ...@@ -291,18 +291,18 @@ TEXT runtime·futex(SB),NOSPLIT,$0
// int32 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void)); // int32 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void));
TEXT runtime·clone(SB),NOSPLIT,$0 TEXT runtime·clone(SB),NOSPLIT,$0
MOVL $120, AX // clone MOVL $120, AX // clone
MOVL flags+4(SP), BX MOVL flags+0(FP), BX
MOVL stack+8(SP), CX MOVL stack+4(FP), CX
MOVL $0, DX // parent tid ptr MOVL $0, DX // parent tid ptr
MOVL $0, DI // child tid ptr MOVL $0, DI // child tid ptr
// Copy mp, gp, fn off parent stack for use by child. // Copy mp, gp, fn off parent stack for use by child.
SUBL $16, CX SUBL $16, CX
MOVL mm+12(SP), SI MOVL mm+8(FP), SI
MOVL SI, 0(CX) MOVL SI, 0(CX)
MOVL gg+16(SP), SI MOVL gg+12(FP), SI
MOVL SI, 4(CX) MOVL SI, 4(CX)
MOVL fn+20(SP), SI MOVL fn+16(FP), SI
MOVL SI, 8(CX) MOVL SI, 8(CX)
MOVL $1234, 12(CX) MOVL $1234, 12(CX)
...@@ -319,7 +319,7 @@ TEXT runtime·clone(SB),NOSPLIT,$0 ...@@ -319,7 +319,7 @@ TEXT runtime·clone(SB),NOSPLIT,$0
RET RET
// Paranoia: check that SP is as we expect. // Paranoia: check that SP is as we expect.
MOVL mm+8(FP), BP MOVL 12(SP), BP
CMPL BP, $1234 CMPL BP, $1234
JEQ 2(PC) JEQ 2(PC)
INT $3 INT $3
...@@ -328,10 +328,14 @@ TEXT runtime·clone(SB),NOSPLIT,$0 ...@@ -328,10 +328,14 @@ TEXT runtime·clone(SB),NOSPLIT,$0
MOVL $224, AX MOVL $224, AX
CALL *runtime·_vdso(SB) CALL *runtime·_vdso(SB)
// In child on new stack. Reload registers (paranoia). MOVL 0(SP), BX // m
MOVL 0(SP), BX // m MOVL 4(SP), DX // g
MOVL flags+0(FP), DX // g MOVL 8(SP), SI // fn
MOVL stk+4(FP), SI // fn
CMPL BX, $0
JEQ nog
CMPL DX, $0
JEQ nog
MOVL AX, m_procid(BX) // save tid as m->procid MOVL AX, m_procid(BX) // save tid as m->procid
...@@ -365,16 +369,11 @@ TEXT runtime·clone(SB),NOSPLIT,$0 ...@@ -365,16 +369,11 @@ TEXT runtime·clone(SB),NOSPLIT,$0
CALL runtime·emptyfunc(SB) CALL runtime·emptyfunc(SB)
POPAL POPAL
nog:
CALL SI // fn() CALL SI // fn()
CALL runtime·exit1(SB) CALL runtime·exit1(SB)
MOVL $0x1234, 0x1005 MOVL $0x1234, 0x1005
// int32 clone0(int32 flags, void *stack, void* fn, void* fnarg);
TEXT runtime·clone0(SB),NOSPLIT,$0
// TODO(spetrovic): Implement this method.
MOVL $-1, ret+16(FP)
RET
TEXT runtime·sigaltstack(SB),NOSPLIT,$-8 TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
MOVL $186, AX // sigaltstack MOVL $186, AX // sigaltstack
MOVL new+4(SP), BX MOVL new+4(SP), BX
......
...@@ -302,14 +302,16 @@ TEXT runtime·futex(SB),NOSPLIT,$0 ...@@ -302,14 +302,16 @@ TEXT runtime·futex(SB),NOSPLIT,$0
// int32 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void)); // int32 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void));
TEXT runtime·clone(SB),NOSPLIT,$0 TEXT runtime·clone(SB),NOSPLIT,$0
MOVL flags+8(SP), DI MOVL flags+0(FP), DI
MOVQ stack+16(SP), SI MOVQ stack+8(FP), SI
MOVQ $0, DX
MOVQ $0, R10
// Copy mp, gp, fn off parent stack for use by child. // Copy mp, gp, fn off parent stack for use by child.
// Careful: Linux system call clobbers CX and R11. // Careful: Linux system call clobbers CX and R11.
MOVQ mm+24(SP), R8 MOVQ mp+16(FP), R8
MOVQ gg+32(SP), R9 MOVQ gp+24(FP), R9
MOVQ fn+40(SP), R12 MOVQ fn+32(FP), R12
MOVL $56, AX MOVL $56, AX
SYSCALL SYSCALL
...@@ -323,6 +325,12 @@ TEXT runtime·clone(SB),NOSPLIT,$0 ...@@ -323,6 +325,12 @@ TEXT runtime·clone(SB),NOSPLIT,$0
// In child, on new stack. // In child, on new stack.
MOVQ SI, SP MOVQ SI, SP
// If g or m are nil, skip Go-related setup.
CMPQ R8, $0 // m
JEQ nog
CMPQ R9, $0 // g
JEQ nog
// Initialize m->procid to Linux tid // Initialize m->procid to Linux tid
MOVL $186, AX // gettid MOVL $186, AX // gettid
SYSCALL SYSCALL
...@@ -338,6 +346,7 @@ TEXT runtime·clone(SB),NOSPLIT,$0 ...@@ -338,6 +346,7 @@ TEXT runtime·clone(SB),NOSPLIT,$0
MOVQ R9, g(CX) MOVQ R9, g(CX)
CALL runtime·stackcheck(SB) CALL runtime·stackcheck(SB)
nog:
// Call fn // Call fn
CALL R12 CALL R12
...@@ -347,34 +356,6 @@ TEXT runtime·clone(SB),NOSPLIT,$0 ...@@ -347,34 +356,6 @@ TEXT runtime·clone(SB),NOSPLIT,$0
SYSCALL SYSCALL
JMP -3(PC) // keep exiting JMP -3(PC) // keep exiting
// int32 clone0(int32 flags, void *stack, void* fn, void* fnarg);
TEXT runtime·clone0(SB),NOSPLIT,$16-36
MOVL flags+0(FP), DI
MOVQ stack+8(FP), SI
MOVQ fn+16(FP), R12 // used by the child
MOVQ fnarg+24(FP), R13 // used by the child
MOVL $0, DX
MOVL $0, R10
MOVL $56, AX
SYSCALL
CMPQ AX, $0
JEQ child
// In parent, return.
MOVL AX, ret+32(FP)
RET
child:
MOVQ SI, SP
MOVQ R12, AX // fn
MOVQ R13, DI // fnarg
CALL AX
// fn shouldn't return; if it does, exit.
MOVL $111, DI
MOVL $60, AX
SYSCALL
JMP -3(PC) // keep exiting
TEXT runtime·sigaltstack(SB),NOSPLIT,$-8 TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
MOVQ new+8(SP), DI MOVQ new+8(SP), DI
MOVQ old+16(SP), SI MOVQ old+16(SP), SI
......
...@@ -241,7 +241,6 @@ TEXT runtime·futex(SB),NOSPLIT,$0 ...@@ -241,7 +241,6 @@ TEXT runtime·futex(SB),NOSPLIT,$0
MOVW R0, ret+24(FP) MOVW R0, ret+24(FP)
RET RET
// int32 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void)); // int32 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void));
TEXT runtime·clone(SB),NOSPLIT,$0 TEXT runtime·clone(SB),NOSPLIT,$0
MOVW flags+0(FP), R0 MOVW flags+0(FP), R0
...@@ -279,8 +278,15 @@ TEXT runtime·clone(SB),NOSPLIT,$0 ...@@ -279,8 +278,15 @@ TEXT runtime·clone(SB),NOSPLIT,$0
BEQ 2(PC) BEQ 2(PC)
BL runtime·abort(SB) BL runtime·abort(SB)
MOVW 4(R13), g MOVW 0(R13), R8 // m
MOVW 0(R13), R8 MOVW 4(R13), R0 // g
CMP $0, R8
BEQ nog
CMP $0, R0
BEQ nog
MOVW R0, g
MOVW R8, g_m(g) MOVW R8, g_m(g)
// paranoia; check they are not nil // paranoia; check they are not nil
...@@ -295,54 +301,17 @@ TEXT runtime·clone(SB),NOSPLIT,$0 ...@@ -295,54 +301,17 @@ TEXT runtime·clone(SB),NOSPLIT,$0
MOVW g_m(g), R8 MOVW g_m(g), R8
MOVW R0, m_procid(R8) MOVW R0, m_procid(R8)
nog:
// Call fn // Call fn
MOVW 8(R13), R0 MOVW 8(R13), R0
MOVW $16(R13), R13 MOVW $16(R13), R13
BL (R0) BL (R0)
MOVW $0, R0
MOVW R0, 4(R13)
BL runtime·exit1(SB)
// It shouldn't return // It shouldn't return
MOVW $1234, R0
MOVW $1005, R1
MOVW R0, (R1)
// int32 clone0(int32 flags, void *stack, void* fn, void* fnarg);
TEXT runtime·clone0(SB),NOSPLIT,$0-20
MOVW flags+0(FP), R0
MOVW stack+4(FP), R1
// Update child's future stack and save fn and fnarg on it.
MOVW $-8(R1), R1
MOVW fn+8(FP), R6
MOVW R6, 0(R1)
MOVW fnarg+12(FP), R6
MOVW R6, 4(R1)
MOVW $0, R2 // parent tid ptr
MOVW $0, R3 // tls_val
MOVW $0, R4 // child tid ptr
MOVW $0, R5
MOVW $SYS_clone, R7
SWI $0
// In parent, return.
CMP $0, R0
BEQ 3(PC)
MOVW R0, ret+16(FP)
RET
// In child.
MOVW 0(R13), R6 // fn
MOVW 4(R13), R0 // fnarg
MOVW $8(R13), R13
BL (R6)
MOVW $0, R0 MOVW $0, R0
MOVW R0, 4(R13) MOVW R0, 4(R13)
BL runtime·exit1(SB) BL runtime·exit1(SB)
// It shouldn't return
MOVW $1234, R0 MOVW $1234, R0
MOVW $1005, R1 MOVW $1005, R1
MOVW R0, (R1) MOVW R0, (R1)
......
...@@ -333,14 +333,19 @@ child: ...@@ -333,14 +333,19 @@ child:
MOVD $0, R0 MOVD $0, R0
MOVD R0, (R0) // crash MOVD R0, (R0) // crash
// Initialize m->procid to Linux tid
good: good:
// Initialize m->procid to Linux tid
MOVD $SYS_gettid, R8 MOVD $SYS_gettid, R8
SVC SVC
MOVD -24(RSP), R12 MOVD -24(RSP), R12 // fn
MOVD -16(RSP), R11 MOVD -16(RSP), R11 // g
MOVD -8(RSP), R10 MOVD -8(RSP), R10 // m
CMP $0, R10
BEQ nog
CMP $0, R11
BEQ nog
MOVD R0, m_procid(R10) MOVD R0, m_procid(R10)
...@@ -351,6 +356,7 @@ good: ...@@ -351,6 +356,7 @@ good:
MOVD R11, g MOVD R11, g
//CALL runtime·stackcheck(SB) //CALL runtime·stackcheck(SB)
nog:
// Call fn // Call fn
MOVD R12, R0 MOVD R12, R0
BL (R0) BL (R0)
...@@ -362,13 +368,6 @@ again: ...@@ -362,13 +368,6 @@ again:
SVC SVC
B again // keep exiting B again // keep exiting
// int32 clone0(int32 flags, void *stack, void* fn, void* fnarg);
TEXT runtime·clone0(SB),NOSPLIT,$0
// TODO(spetrovic): Implement this method.
MOVW $-1, R0
MOVW R0, ret+32(FP)
RET
TEXT runtime·sigaltstack(SB),NOSPLIT,$-8 TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
MOVD new+0(FP), R0 MOVD new+0(FP), R0
MOVD old+8(FP), R1 MOVD old+8(FP), R1
......
...@@ -323,9 +323,14 @@ TEXT runtime·clone(SB),NOSPLIT,$-8 ...@@ -323,9 +323,14 @@ TEXT runtime·clone(SB),NOSPLIT,$-8
// Initialize m->procid to Linux tid // Initialize m->procid to Linux tid
SYSCALL $SYS_gettid SYSCALL $SYS_gettid
MOVD -24(R1), R12 MOVD -24(R1), R12 // fn
MOVD -16(R1), R8 MOVD -16(R1), R8 // g
MOVD -8(R1), R7 MOVD -8(R1), R7 // m
CMP R7, $0
BEQ nog
CMP R8, $0
BEQ nog
MOVD R3, m_procid(R7) MOVD R3, m_procid(R7)
...@@ -336,6 +341,7 @@ TEXT runtime·clone(SB),NOSPLIT,$-8 ...@@ -336,6 +341,7 @@ TEXT runtime·clone(SB),NOSPLIT,$-8
MOVD R8, g MOVD R8, g
//CALL runtime·stackcheck(SB) //CALL runtime·stackcheck(SB)
nog:
// Call fn // Call fn
MOVD R12, CTR MOVD R12, CTR
BL (CTR) BL (CTR)
...@@ -345,13 +351,6 @@ TEXT runtime·clone(SB),NOSPLIT,$-8 ...@@ -345,13 +351,6 @@ TEXT runtime·clone(SB),NOSPLIT,$-8
SYSCALL $SYS_exit_group SYSCALL $SYS_exit_group
BR -2(PC) // keep exiting BR -2(PC) // keep exiting
// int32 clone0(int32 flags, void *stack, void* fn, void* fnarg);
TEXT runtime·clone0(SB),NOSPLIT,$0
// TODO(spetrovic): Implement this method.
MOVW $-1, R3
MOVW R3, ret+32(FP)
RETURN
TEXT runtime·sigaltstack(SB),NOSPLIT,$-8 TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
MOVD new+0(FP), R3 MOVD new+0(FP), R3
MOVD old+8(FP), R4 MOVD old+8(FP), R4
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment