runtime, syscall: fix kernel gettimeofday ABI change on iOS 10

Fixes #16570 on iOS.

Thanks Daniel Burhans for reporting the bug and testing the fix.

Change-Id: I43ae7b78c8f85a131ed3d93ea59da9f32a02cd8f
Reviewed-on: https://go-review.googlesource.com/25481
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/src/runtime/sys_darwin_arm.s b/src/runtime/sys_darwin_arm.s
index 6b6437d..52f6a94 100644
--- a/src/runtime/sys_darwin_arm.s
+++ b/src/runtime/sys_darwin_arm.s
@@ -162,11 +162,15 @@
 TEXT time·now(SB), 7, $32
 	MOVW	$8(R13), R0  // timeval
 	MOVW	$0, R1  // zone
+	MOVW	$0, R2	// see issue 16570
 	MOVW	$SYS_gettimeofday, R12
 	SWI	$0x80 // Note: R0 is tv_sec, R1 is tv_usec
-
+	CMP	$0, R0
+	BNE	inreg
+	MOVW	8(R13), R0
+	MOVW	12(R13), R1
+inreg:
 	MOVW    R1, R2  // usec
-
 	MOVW	R0, sec+0(FP)
 	MOVW	$0, R1
 	MOVW	R1, loc+4(FP)
@@ -178,9 +182,14 @@
 TEXT runtime·nanotime(SB),NOSPLIT,$32
 	MOVW	$8(R13), R0  // timeval
 	MOVW	$0, R1  // zone
+	MOVW	$0, R2	// see issue 16570
 	MOVW	$SYS_gettimeofday, R12
 	SWI	$0x80 // Note: R0 is tv_sec, R1 is tv_usec
-
+	CMP	$0, R0
+	BNE	inreg
+	MOVW	8(R13), R0
+	MOVW	12(R13), R1
+inreg:
 	MOVW    R1, R2
 	MOVW	$1000000000, R3
 	MULLU	R0, R3, (R1, R0)
diff --git a/src/runtime/sys_darwin_arm64.s b/src/runtime/sys_darwin_arm64.s
index a3b851d..8e6b5b1 100644
--- a/src/runtime/sys_darwin_arm64.s
+++ b/src/runtime/sys_darwin_arm64.s
@@ -155,9 +155,14 @@
 	MOVD	RSP, R0	// timeval
 	MOVD	R0, R9	// this is how dyld calls gettimeofday
 	MOVW	$0, R1	// zone
+	MOVD	$0, R2	// see issue 16570
 	MOVW	$SYS_gettimeofday, R16
 	SVC	$0x80	// Note: x0 is tv_sec, w1 is tv_usec
-
+	CMP	$0, R0
+	BNE	inreg
+	MOVD	0(RSP), R0
+	MOVW	8(RSP), R1
+inreg:
 	MOVD	R0, sec+0(FP)
 	MOVW	$1000, R3
 	MUL	R3, R1
@@ -168,9 +173,14 @@
 	MOVD	RSP, R0	// timeval
 	MOVD	R0, R9	// this is how dyld calls gettimeofday
 	MOVW	$0, R1	// zone
+	MOVD	$0, R2	// see issue 16570
 	MOVW	$SYS_gettimeofday, R16
 	SVC	$0x80	// Note: x0 is tv_sec, w1 is tv_usec
-
+	CMP	$0, R0
+	BNE	inreg
+	MOVD	0(RSP), R0
+	MOVW	8(RSP), R1
+inreg:
 	MOVW	$1000000000, R3
 	MUL	R3, R0
 	MOVW	$1000, R3
diff --git a/src/syscall/syscall_darwin_arm.go b/src/syscall/syscall_darwin_arm.go
index c302d83..fe43103 100644
--- a/src/syscall/syscall_darwin_arm.go
+++ b/src/syscall/syscall_darwin_arm.go
@@ -26,14 +26,19 @@
 }
 
 //sysnb	gettimeofday(tp *Timeval) (sec int32, usec int32, err error)
-func Gettimeofday(tv *Timeval) (err error) {
+func Gettimeofday(tv *Timeval) error {
 	// The tv passed to gettimeofday must be non-nil
 	// but is otherwise unused. The answers come back
 	// in the two registers.
 	sec, usec, err := gettimeofday(tv)
-	tv.Sec = int32(sec)
-	tv.Usec = int32(usec)
-	return err
+	if err != nil {
+		return err
+	}
+	if sec != 0 || usec != 0 {
+		tv.Sec = int32(sec)
+		tv.Usec = int32(usec)
+	}
+	return nil
 }
 
 func SetKevent(k *Kevent_t, fd, mode, flags int) {
diff --git a/src/syscall/syscall_darwin_arm64.go b/src/syscall/syscall_darwin_arm64.go
index 29f40d4..d396e25 100644
--- a/src/syscall/syscall_darwin_arm64.go
+++ b/src/syscall/syscall_darwin_arm64.go
@@ -26,14 +26,19 @@
 }
 
 //sysnb	gettimeofday(tp *Timeval) (sec int64, usec int32, err error)
-func Gettimeofday(tv *Timeval) (err error) {
+func Gettimeofday(tv *Timeval) error {
 	// The tv passed to gettimeofday must be non-nil
 	// but is otherwise unused. The answers come back
 	// in the two registers.
 	sec, usec, err := gettimeofday(tv)
-	tv.Sec = sec
-	tv.Usec = usec
-	return err
+	if err != nil {
+		return err
+	}
+	if sec != 0 || usec != 0 {
+		tv.Sec = sec
+		tv.Usec = usec
+	}
+	return nil
 }
 
 func SetKevent(k *Kevent_t, fd, mode, flags int) {
diff --git a/src/syscall/syscall_darwin_test.go b/src/syscall/syscall_darwin_test.go
index dd0e32b..cea5636 100644
--- a/src/syscall/syscall_darwin_test.go
+++ b/src/syscall/syscall_darwin_test.go
@@ -3,7 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // +build darwin
-// +build amd64 386
+// +build amd64 386 arm arm64
 
 package syscall_test