Skip to content

Commit bb004a1

Browse files
prattmicgopherbot
authored andcommitted
syscall: define Syscall in terms of RawSyscall on linux
This is a re-do of CL 388477, fixing #52472. It is unsafe to call syscall.RawSyscall from syscall.Syscall with -coverpkg=all and -race. This is because: 1. Coverage adds a sync/atomic call in RawSyscall to increment the coverage counter. 2. Race mode instruments sync/atomic calls with TSAN runtime calls. TSAN eventually calls runtime.racecallbackfunc, which expects getg().m.p != 0, which is no longer true after entersyscall(). cmd/go actually avoids adding coverage instrumention to package runtime in race mode entirely to avoid these kinds of problems. Rather than also excluding all of syscall for this one function, work around by calling RawSyscall6 instead, which avoids coverage instrumention both by being written in assembly and in package runtime/*. For #51087 Fixes #52472 Change-Id: Iaffd27df03753020c4716059a455d6ca7b62f347 Reviewed-on: https://go-review.googlesource.com/c/go/+/401654 Run-TryBot: Michael Pratt <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Auto-Submit: Michael Pratt <[email protected]> Reviewed-by: Cherry Mui <[email protected]>
1 parent 889a902 commit bb004a1

11 files changed

+35
-235
lines changed

src/runtime/proc.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -3658,7 +3658,7 @@ func reentersyscall(pc, sp uintptr) {
36583658

36593659
// Standard syscall entry used by the go syscall library and normal cgo calls.
36603660
//
3661-
// This is exported via linkname to assembly in the syscall package.
3661+
// This is exported via linkname to assembly in the syscall package and x/sys.
36623662
//
36633663
//go:nosplit
36643664
//go:linkname entersyscall

src/syscall/asm_linux_386.s

-26
Original file line numberDiff line numberDiff line change
@@ -13,32 +13,6 @@
1313
// instead of the glibc-specific "CALL 0x10(GS)".
1414
#define INVOKE_SYSCALL INT $0x80
1515

16-
// func Syscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr);
17-
// Trap # in AX, args in BX CX DX SI DI, return in AX
18-
TEXT ·Syscall(SB),NOSPLIT,$0-28
19-
CALL runtime·entersyscall(SB)
20-
MOVL trap+0(FP), AX // syscall entry
21-
MOVL a1+4(FP), BX
22-
MOVL a2+8(FP), CX
23-
MOVL a3+12(FP), DX
24-
MOVL $0, SI
25-
MOVL $0, DI
26-
INVOKE_SYSCALL
27-
CMPL AX, $0xfffff001
28-
JLS ok
29-
MOVL $-1, r1+16(FP)
30-
MOVL $0, r2+20(FP)
31-
NEGL AX
32-
MOVL AX, err+24(FP)
33-
CALL runtime·exitsyscall(SB)
34-
RET
35-
ok:
36-
MOVL AX, r1+16(FP)
37-
MOVL DX, r2+20(FP)
38-
MOVL $0, err+24(FP)
39-
CALL runtime·exitsyscall(SB)
40-
RET
41-
4216
// func Syscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
4317
TEXT ·Syscall6(SB),NOSPLIT,$0-40
4418
CALL runtime·entersyscall(SB)

src/syscall/asm_linux_amd64.s

-27
Original file line numberDiff line numberDiff line change
@@ -11,33 +11,6 @@
1111

1212
#define SYS_gettimeofday 96
1313

14-
// func Syscall(trap int64, a1, a2, a3 uintptr) (r1, r2, err uintptr);
15-
// Trap # in AX, args in DI SI DX R10 R8 R9, return in AX DX
16-
// Note that this differs from "standard" ABI convention, which
17-
// would pass 4th arg in CX, not R10.
18-
19-
TEXT ·Syscall(SB),NOSPLIT,$0-56
20-
CALL runtime·entersyscall<ABIInternal>(SB)
21-
MOVQ a1+8(FP), DI
22-
MOVQ a2+16(FP), SI
23-
MOVQ a3+24(FP), DX
24-
MOVQ trap+0(FP), AX // syscall entry
25-
SYSCALL
26-
CMPQ AX, $0xfffffffffffff001
27-
JLS ok
28-
MOVQ $-1, r1+32(FP)
29-
MOVQ $0, r2+40(FP)
30-
NEGQ AX
31-
MOVQ AX, err+48(FP)
32-
CALL runtime·exitsyscall<ABIInternal>(SB)
33-
RET
34-
ok:
35-
MOVQ AX, r1+32(FP)
36-
MOVQ DX, r2+40(FP)
37-
MOVQ $0, err+48(FP)
38-
CALL runtime·exitsyscall<ABIInternal>(SB)
39-
RET
40-
4114
// func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
4215
TEXT ·Syscall6(SB),NOSPLIT,$0-80
4316
CALL runtime·entersyscall<ABIInternal>(SB)

src/syscall/asm_linux_arm.s

-30
Original file line numberDiff line numberDiff line change
@@ -9,36 +9,6 @@
99
// System calls for arm, Linux
1010
//
1111

12-
// func Syscall(syscall uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr);
13-
TEXT ·Syscall(SB),NOSPLIT,$0-28
14-
BL runtime·entersyscall(SB)
15-
MOVW trap+0(FP), R7
16-
MOVW a1+4(FP), R0
17-
MOVW a2+8(FP), R1
18-
MOVW a3+12(FP), R2
19-
MOVW $0, R3
20-
MOVW $0, R4
21-
MOVW $0, R5
22-
SWI $0
23-
MOVW $0xfffff001, R1
24-
CMP R1, R0
25-
BLS ok
26-
MOVW $-1, R1
27-
MOVW R1, r1+16(FP)
28-
MOVW $0, R2
29-
MOVW R2, r2+20(FP)
30-
RSB $0, R0, R0
31-
MOVW R0, err+24(FP)
32-
BL runtime·exitsyscall(SB)
33-
RET
34-
ok:
35-
MOVW R0, r1+16(FP)
36-
MOVW $0, R0
37-
MOVW R0, r2+20(FP)
38-
MOVW R0, err+24(FP)
39-
BL runtime·exitsyscall(SB)
40-
RET
41-
4212
// func Syscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
4313
// Actually Syscall5 but the rest of the code expects it to be named Syscall6.
4414
TEXT ·Syscall6(SB),NOSPLIT,$0-40

src/syscall/asm_linux_arm64.s

-27
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,6 @@
44

55
#include "textflag.h"
66

7-
// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
8-
TEXT ·Syscall(SB),NOSPLIT,$0-56
9-
BL runtime·entersyscall<ABIInternal>(SB)
10-
MOVD a1+8(FP), R0
11-
MOVD a2+16(FP), R1
12-
MOVD a3+24(FP), R2
13-
MOVD $0, R3
14-
MOVD $0, R4
15-
MOVD $0, R5
16-
MOVD trap+0(FP), R8 // syscall entry
17-
SVC
18-
CMN $4095, R0
19-
BCC ok
20-
MOVD $-1, R4
21-
MOVD R4, r1+32(FP) // r1
22-
MOVD ZR, r2+40(FP) // r2
23-
NEG R0, R0
24-
MOVD R0, err+48(FP) // errno
25-
BL runtime·exitsyscall<ABIInternal>(SB)
26-
RET
27-
ok:
28-
MOVD R0, r1+32(FP) // r1
29-
MOVD R1, r2+40(FP) // r2
30-
MOVD ZR, err+48(FP) // errno
31-
BL runtime·exitsyscall<ABIInternal>(SB)
32-
RET
33-
347
TEXT ·Syscall6(SB),NOSPLIT,$0-80
358
BL runtime·entersyscall<ABIInternal>(SB)
369
MOVD a1+8(FP), R0

src/syscall/asm_linux_mips64x.s

-25
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,6 @@
1010
// System calls for mips64, Linux
1111
//
1212

13-
// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
14-
TEXT ·Syscall(SB),NOSPLIT,$0-56
15-
JAL runtime·entersyscall(SB)
16-
MOVV a1+8(FP), R4
17-
MOVV a2+16(FP), R5
18-
MOVV a3+24(FP), R6
19-
MOVV R0, R7
20-
MOVV R0, R8
21-
MOVV R0, R9
22-
MOVV trap+0(FP), R2 // syscall entry
23-
SYSCALL
24-
BEQ R7, ok
25-
MOVV $-1, R1
26-
MOVV R1, r1+32(FP) // r1
27-
MOVV R0, r2+40(FP) // r2
28-
MOVV R2, err+48(FP) // errno
29-
JAL runtime·exitsyscall(SB)
30-
RET
31-
ok:
32-
MOVV R2, r1+32(FP) // r1
33-
MOVV R3, r2+40(FP) // r2
34-
MOVV R0, err+48(FP) // errno
35-
JAL runtime·exitsyscall(SB)
36-
RET
37-
3813
TEXT ·Syscall6(SB),NOSPLIT,$0-80
3914
JAL runtime·entersyscall(SB)
4015
MOVV a1+8(FP), R4

src/syscall/asm_linux_mipsx.s

-23
Original file line numberDiff line numberDiff line change
@@ -11,29 +11,6 @@
1111
// System calls for mips, Linux
1212
//
1313

14-
// func Syscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr);
15-
TEXT ·Syscall(SB),NOSPLIT,$0-28
16-
JAL runtime·entersyscall(SB)
17-
MOVW a1+4(FP), R4
18-
MOVW a2+8(FP), R5
19-
MOVW a3+12(FP), R6
20-
MOVW R0, R7
21-
MOVW trap+0(FP), R2 // syscall entry
22-
SYSCALL
23-
BEQ R7, ok
24-
MOVW $-1, R1
25-
MOVW R1, r1+16(FP) // r1
26-
MOVW R0, r2+20(FP) // r2
27-
MOVW R2, err+24(FP) // errno
28-
JAL runtime·exitsyscall(SB)
29-
RET
30-
ok:
31-
MOVW R2, r1+16(FP) // r1
32-
MOVW R3, r2+20(FP) // r2
33-
MOVW R0, err+24(FP) // errno
34-
JAL runtime·exitsyscall(SB)
35-
RET
36-
3714
// func Syscall6(trap trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
3815
// 5th and 6th arg go at sp+16, sp+20.
3916
// Note that frame size of 20 means that 24 bytes gets reserved on stack.

src/syscall/asm_linux_ppc64x.s

-25
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,6 @@
1010
// System calls for ppc64, Linux
1111
//
1212

13-
// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
14-
TEXT ·Syscall(SB),NOSPLIT,$0-56
15-
BL runtime·entersyscall<ABIInternal>(SB)
16-
MOVD a1+8(FP), R3
17-
MOVD a2+16(FP), R4
18-
MOVD a3+24(FP), R5
19-
MOVD R0, R6
20-
MOVD R0, R7
21-
MOVD R0, R8
22-
MOVD trap+0(FP), R9 // syscall entry
23-
SYSCALL R9
24-
BVC ok
25-
MOVD $-1, R4
26-
MOVD R4, r1+32(FP) // r1
27-
MOVD R0, r2+40(FP) // r2
28-
MOVD R3, err+48(FP) // errno
29-
BL runtime·exitsyscall<ABIInternal>(SB)
30-
RET
31-
ok:
32-
MOVD R3, r1+32(FP) // r1
33-
MOVD R0, r2+40(FP) // r2
34-
MOVD R0, err+48(FP) // errno
35-
BL runtime·exitsyscall<ABIInternal>(SB)
36-
RET
37-
3813
TEXT ·Syscall6(SB),NOSPLIT,$0-80
3914
BL runtime·entersyscall<ABIInternal>(SB)
4015
MOVD a1+8(FP), R3

src/syscall/asm_linux_riscv64.s

-24
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,6 @@
88
// System calls for riscv64, Linux
99
//
1010

11-
// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64)
12-
TEXT ·Syscall(SB),NOSPLIT,$0-56
13-
CALL runtime·entersyscall(SB)
14-
MOV a1+8(FP), A0
15-
MOV a2+16(FP), A1
16-
MOV a3+24(FP), A2
17-
MOV trap+0(FP), A7 // syscall entry
18-
ECALL
19-
MOV $-4096, T0
20-
BLTU T0, A0, err
21-
MOV A0, r1+32(FP) // r1
22-
MOV A1, r2+40(FP) // r2
23-
MOV ZERO, err+48(FP) // errno
24-
CALL runtime·exitsyscall(SB)
25-
RET
26-
err:
27-
MOV $-1, T0
28-
MOV T0, r1+32(FP) // r1
29-
MOV ZERO, r2+40(FP) // r2
30-
SUB A0, ZERO, A0
31-
MOV A0, err+48(FP) // errno
32-
CALL runtime·exitsyscall(SB)
33-
RET
34-
3511
// func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
3612
TEXT ·Syscall6(SB),NOSPLIT,$0-80
3713
CALL runtime·entersyscall(SB)

src/syscall/asm_linux_s390x.s

-26
Original file line numberDiff line numberDiff line change
@@ -8,32 +8,6 @@
88
// System calls for s390x, Linux
99
//
1010

11-
// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64)
12-
TEXT ·Syscall(SB),NOSPLIT,$0-56
13-
BL runtime·entersyscall(SB)
14-
MOVD a1+8(FP), R2
15-
MOVD a2+16(FP), R3
16-
MOVD a3+24(FP), R4
17-
MOVD $0, R5
18-
MOVD $0, R6
19-
MOVD $0, R7
20-
MOVD trap+0(FP), R1 // syscall entry
21-
SYSCALL
22-
MOVD $0xfffffffffffff001, R8
23-
CMPUBLT R2, R8, ok
24-
MOVD $-1, r1+32(FP)
25-
MOVD $0, r2+40(FP)
26-
NEG R2, R2
27-
MOVD R2, err+48(FP) // errno
28-
BL runtime·exitsyscall(SB)
29-
RET
30-
ok:
31-
MOVD R2, r1+32(FP)
32-
MOVD R3, r2+40(FP)
33-
MOVD $0, err+48(FP) // errno
34-
BL runtime·exitsyscall(SB)
35-
RET
36-
3711
// func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
3812
TEXT ·Syscall6(SB),NOSPLIT,$0-80
3913
BL runtime·entersyscall(SB)

src/syscall/syscall_linux.go

+34-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616
"unsafe"
1717
)
1818

19-
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
2019
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
2120

2221
// N.B. RawSyscall6 is provided via linkname by runtime/internal/syscall.
@@ -26,6 +25,18 @@ func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
2625

2726
func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
2827

28+
// Pull in entersyscall/exitsyscall for Syscall/Syscall6.
29+
//
30+
// Note that this can't be a push linkname because the runtime already has a
31+
// nameless linkname to export to assembly here and in x/sys. Additionally,
32+
// entersyscall fetches the caller PC and SP and thus can't have a wrapper
33+
// inbetween.
34+
35+
//go:linkname runtime_entersyscall runtime.entersyscall
36+
func runtime_entersyscall()
37+
//go:linkname runtime_exitsyscall runtime.exitsyscall
38+
func runtime_exitsyscall()
39+
2940
// N.B. For the Syscall functions below:
3041
//
3142
// //go:uintptrkeepalive because the uintptr argument may be converted pointers
@@ -47,6 +58,28 @@ func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
4758
return RawSyscall6(trap, a1, a2, a3, 0, 0, 0)
4859
}
4960

61+
//go:uintptrkeepalive
62+
//go:nosplit
63+
//go:linkname Syscall
64+
func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
65+
runtime_entersyscall()
66+
// N.B. Calling RawSyscall here is unsafe with atomic coverage
67+
// instrumentation and race mode.
68+
//
69+
// Coverage instrumentation will add a sync/atomic call to RawSyscall.
70+
// Race mode will add race instrumentation to sync/atomic. Race
71+
// instrumentation requires a P, which we no longer have.
72+
//
73+
// RawSyscall6 is fine because it is implemented in assembly and thus
74+
// has no coverage instrumentation.
75+
//
76+
// This is typically not a problem in the runtime because cmd/go avoids
77+
// adding coverage instrumentation to the runtime in race mode.
78+
r1, r2, err = RawSyscall6(trap, a1, a2, a3, 0, 0, 0)
79+
runtime_exitsyscall()
80+
return
81+
}
82+
5083
func rawSyscallNoError(trap, a1, a2, a3 uintptr) (r1, r2 uintptr)
5184

5285
/*

0 commit comments

Comments
 (0)