Skip to content

Commit 876d477

Browse files
committed
runtime: refactor ARM VDSO call setup to helper
We have a very complex process to make VDSO calls on ARM. Create a wrapper helper function which reduces duplication and allows for additional calls from other packages. vdsoCall has a few differences from the original code in walltime/nanotime: * It does not use R0-R3, as they are passed through as arguments to fn. * It does not save g if g.m.gsignal.stack.lo is zero. This may occur if it called at startup on g0 between assigning g0.m.gsignal and setting its stack. For #49182 Change-Id: I51aca514b4835b71142011341d2f09125334d30f Reviewed-on: https://go-review.googlesource.com/c/go/+/362795 Run-TryBot: Michael Pratt <[email protected]> Reviewed-by: Michael Knyszek <[email protected]> Reviewed-by: Cherry Mui <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent c7f870e commit 876d477

File tree

2 files changed

+82
-125
lines changed

2 files changed

+82
-125
lines changed

src/runtime/os_linux_arm.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ const (
1111
_HWCAP_VFPv3 = 1 << 13 // introduced in 2.6.30
1212
)
1313

14+
func vdsoCall()
15+
1416
func checkgoarm() {
1517
// On Android, /proc/self/auxv might be unreadable and hwcap won't
1618
// reflect the CPU capabilities. Assume that every Android arm device

src/runtime/sys_linux_arm.s

Lines changed: 80 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -262,187 +262,141 @@ TEXT runtime·mincore(SB),NOSPLIT,$0
262262
MOVW R0, ret+12(FP)
263263
RET
264264

265-
TEXT runtime·walltime(SB),NOSPLIT,$8-12
265+
// Call a VDSO function.
266+
//
267+
// R0-R3: arguments to VDSO function (C calling convention)
268+
// R4: uintptr function to call
269+
//
270+
// There is no return value.
271+
TEXT runtime·vdsoCall(SB),NOSPLIT,$8-0
272+
// R0-R3 may be arguments to fn, do not touch.
273+
// R4 is function to call.
274+
// R5-R9 are available as locals. They are unchanged by the C call
275+
// (callee-save).
276+
266277
// We don't know how much stack space the VDSO code will need,
267278
// so switch to g0.
268279

269280
// Save old SP. Use R13 instead of SP to avoid linker rewriting the offsets.
270-
MOVW R13, R4 // R4 is unchanged by C code.
281+
MOVW R13, R5
271282

272-
MOVW g_m(g), R5 // R5 is unchanged by C code.
283+
MOVW g_m(g), R6
273284

274285
// Set vdsoPC and vdsoSP for SIGPROF traceback.
275286
// Save the old values on stack and restore them on exit,
276287
// so this function is reentrant.
277-
MOVW m_vdsoPC(R5), R1
278-
MOVW m_vdsoSP(R5), R2
279-
MOVW R1, 4(R13)
280-
MOVW R2, 8(R13)
288+
MOVW m_vdsoPC(R6), R7
289+
MOVW m_vdsoSP(R6), R8
290+
MOVW R7, 4(R13)
291+
MOVW R8, 8(R13)
281292

282-
MOVW $ret-4(FP), R2 // caller's SP
283-
MOVW LR, m_vdsoPC(R5)
284-
MOVW R2, m_vdsoSP(R5)
293+
MOVW $sp-4(FP), R7 // caller's SP
294+
MOVW LR, m_vdsoPC(R6)
295+
MOVW R7, m_vdsoSP(R6)
285296

286-
MOVW m_curg(R5), R0
297+
MOVW m_curg(R6), R7
287298

288-
CMP g, R0 // Only switch if on curg.
299+
CMP g, R7 // Only switch if on curg.
289300
B.NE noswitch
290301

291-
MOVW m_g0(R5), R0
292-
MOVW (g_sched+gobuf_sp)(R0), R13 // Set SP to g0 stack
302+
MOVW m_g0(R6), R7
303+
MOVW (g_sched+gobuf_sp)(R7), R13 // Set SP to g0 stack
293304

294305
noswitch:
295-
SUB $24, R13 // Space for results
296306
BIC $0x7, R13 // Align for C code
297307

298-
MOVW $CLOCK_REALTIME, R0
299-
MOVW $8(R13), R1 // timespec
300-
MOVW runtime·vdsoClockgettimeSym(SB), R2
301-
CMP $0, R2
302-
B.EQ fallback
303-
304308
// Store g on gsignal's stack, so if we receive a signal
305309
// during VDSO code we can find the g.
306-
// If we don't have a signal stack, we won't receive signal,
307-
// so don't bother saving g.
308-
// When using cgo, we already saved g on TLS, also don't save
309-
// g here.
310-
// Also don't save g if we are already on the signal stack.
311-
// We won't get a nested signal.
312-
MOVB runtime·iscgo(SB), R6
313-
CMP $0, R6
310+
311+
// When using cgo, we already saved g on TLS, also don't save g here.
312+
MOVB runtime·iscgo(SB), R7
313+
CMP $0, R7
314314
BNE nosaveg
315-
MOVW m_gsignal(R5), R6 // g.m.gsignal
316-
CMP $0, R6
315+
// If we don't have a signal stack, we won't receive signal, so don't
316+
// bother saving g.
317+
MOVW m_gsignal(R6), R7 // g.m.gsignal
318+
CMP $0, R7
319+
BEQ nosaveg
320+
// Don't save g if we are already on the signal stack, as we won't get
321+
// a nested signal.
322+
CMP g, R7
317323
BEQ nosaveg
318-
CMP g, R6
324+
// If we don't have a signal stack, we won't receive signal, so don't
325+
// bother saving g.
326+
MOVW (g_stack+stack_lo)(R7), R7 // g.m.gsignal.stack.lo
327+
CMP $0, R7
319328
BEQ nosaveg
320-
MOVW (g_stack+stack_lo)(R6), R6 // g.m.gsignal.stack.lo
321-
MOVW g, (R6)
329+
MOVW g, (R7)
322330

323-
BL (R2)
331+
BL (R4)
324332

325-
MOVW $0, R1
326-
MOVW R1, (R6) // clear g slot, R6 is unchanged by C code
333+
MOVW $0, R8
334+
MOVW R8, (R7) // clear g slot
327335

328336
JMP finish
329337

330338
nosaveg:
331-
BL (R2)
332-
JMP finish
333-
334-
fallback:
335-
MOVW $SYS_clock_gettime, R7
336-
SWI $0
339+
BL (R4)
337340

338341
finish:
339-
MOVW 8(R13), R0 // sec
340-
MOVW 12(R13), R2 // nsec
341-
342-
MOVW R4, R13 // Restore real SP
342+
MOVW R5, R13 // Restore real SP
343343
// Restore vdsoPC, vdsoSP
344344
// We don't worry about being signaled between the two stores.
345345
// If we are not in a signal handler, we'll restore vdsoSP to 0,
346346
// and no one will care about vdsoPC. If we are in a signal handler,
347347
// we cannot receive another signal.
348-
MOVW 8(R13), R1
349-
MOVW R1, m_vdsoSP(R5)
350-
MOVW 4(R13), R1
351-
MOVW R1, m_vdsoPC(R5)
352-
353-
MOVW R0, sec_lo+0(FP)
354-
MOVW $0, R1
355-
MOVW R1, sec_hi+4(FP)
356-
MOVW R2, nsec+8(FP)
348+
MOVW 8(R13), R7
349+
MOVW R7, m_vdsoSP(R6)
350+
MOVW 4(R13), R7
351+
MOVW R7, m_vdsoPC(R6)
357352
RET
358353

359-
// int64 nanotime1(void)
360-
TEXT runtime·nanotime1(SB),NOSPLIT,$8-8
361-
// Switch to g0 stack. See comment above in runtime·walltime.
362-
363-
// Save old SP. Use R13 instead of SP to avoid linker rewriting the offsets.
364-
MOVW R13, R4 // R4 is unchanged by C code.
365-
366-
MOVW g_m(g), R5 // R5 is unchanged by C code.
354+
TEXT runtime·walltime(SB),NOSPLIT,$12-12
355+
MOVW $CLOCK_REALTIME, R0
356+
MOVW $spec-12(SP), R1 // timespec
367357

368-
// Set vdsoPC and vdsoSP for SIGPROF traceback.
369-
// Save the old values on stack and restore them on exit,
370-
// so this function is reentrant.
371-
MOVW m_vdsoPC(R5), R1
372-
MOVW m_vdsoSP(R5), R2
373-
MOVW R1, 4(R13)
374-
MOVW R2, 8(R13)
358+
MOVW runtime·vdsoClockgettimeSym(SB), R4
359+
CMP $0, R4
360+
B.EQ fallback
375361

376-
MOVW $ret-4(FP), R2 // caller's SP
377-
MOVW LR, m_vdsoPC(R5)
378-
MOVW R2, m_vdsoSP(R5)
362+
BL runtime·vdsoCall(SB)
379363

380-
MOVW m_curg(R5), R0
364+
JMP finish
381365

382-
CMP g, R0 // Only switch if on curg.
383-
B.NE noswitch
366+
fallback:
367+
MOVW $SYS_clock_gettime, R7
368+
SWI $0
384369

385-
MOVW m_g0(R5), R0
386-
MOVW (g_sched+gobuf_sp)(R0), R13 // Set SP to g0 stack
370+
finish:
371+
MOVW sec-12(SP), R0 // sec
372+
MOVW nsec-8(SP), R2 // nsec
387373

388-
noswitch:
389-
SUB $24, R13 // Space for results
390-
BIC $0x7, R13 // Align for C code
374+
MOVW R0, sec_lo+0(FP)
375+
MOVW $0, R1
376+
MOVW R1, sec_hi+4(FP)
377+
MOVW R2, nsec+8(FP)
378+
RET
391379

380+
// func nanotime1() int64
381+
TEXT runtime·nanotime1(SB),NOSPLIT,$12-8
392382
MOVW $CLOCK_MONOTONIC, R0
393-
MOVW $8(R13), R1 // timespec
394-
MOVW runtime·vdsoClockgettimeSym(SB), R2
395-
CMP $0, R2
396-
B.EQ fallback
397-
398-
// Store g on gsignal's stack, so if we receive a signal
399-
// during VDSO code we can find the g.
400-
// If we don't have a signal stack, we won't receive signal,
401-
// so don't bother saving g.
402-
// When using cgo, we already saved g on TLS, also don't save
403-
// g here.
404-
// Also don't save g if we are already on the signal stack.
405-
// We won't get a nested signal.
406-
MOVB runtime·iscgo(SB), R6
407-
CMP $0, R6
408-
BNE nosaveg
409-
MOVW m_gsignal(R5), R6 // g.m.gsignal
410-
CMP $0, R6
411-
BEQ nosaveg
412-
CMP g, R6
413-
BEQ nosaveg
414-
MOVW (g_stack+stack_lo)(R6), R6 // g.m.gsignal.stack.lo
415-
MOVW g, (R6)
416-
417-
BL (R2)
383+
MOVW $spec-12(SP), R1 // timespec
418384

419-
MOVW $0, R1
420-
MOVW R1, (R6) // clear g slot, R6 is unchanged by C code
385+
MOVW runtime·vdsoClockgettimeSym(SB), R4
386+
CMP $0, R4
387+
B.EQ fallback
421388

422-
JMP finish
389+
BL runtime·vdsoCall(SB)
423390

424-
nosaveg:
425-
BL (R2)
426391
JMP finish
427392

428393
fallback:
429394
MOVW $SYS_clock_gettime, R7
430395
SWI $0
431396

432397
finish:
433-
MOVW 8(R13), R0 // sec
434-
MOVW 12(R13), R2 // nsec
435-
436-
MOVW R4, R13 // Restore real SP
437-
// Restore vdsoPC, vdsoSP
438-
// We don't worry about being signaled between the two stores.
439-
// If we are not in a signal handler, we'll restore vdsoSP to 0,
440-
// and no one will care about vdsoPC. If we are in a signal handler,
441-
// we cannot receive another signal.
442-
MOVW 8(R13), R4
443-
MOVW R4, m_vdsoSP(R5)
444-
MOVW 4(R13), R4
445-
MOVW R4, m_vdsoPC(R5)
398+
MOVW sec-12(SP), R0 // sec
399+
MOVW nsec-8(SP), R2 // nsec
446400

447401
MOVW $1000000000, R3
448402
MULLU R0, R3, (R1, R0)
@@ -451,6 +405,7 @@ finish:
451405

452406
MOVW R0, ret_lo+0(FP)
453407
MOVW R1, ret_hi+4(FP)
408+
454409
RET
455410

456411
// int32 futex(int32 *uaddr, int32 op, int32 val,

0 commit comments

Comments
 (0)