detached 9391e74

fix unintended R27 clobber on arm64 (#165)

For some reason the Go assembler uses R27 as a scratch register when loading in a variable's address. Since callbackasm1 is called from C and the arm64 ABI states that R27 is callee saved it was unexpectedly clobbering the value. This commit now saves R27 and restores it at the end of the function.

I also cleaned up some of the other parts of this function. I store the floats in pairs which saved 4 instructions. I also use the zero register to put zero in callbackArgs.result directly

Updates #124
Closes #162
commit
9391e746f6cf0f5b9337d6535ee920253f104078
author
TotallyGamerJet · · 2023-09-22 11:48 UTC
committer
Hajime Hoshi · · 2023-09-22 14:47 UTC
parent
2fcc65d
signature
unsigned
refs
tag: v0.4.1
1 file · +27 -21
M sys_unix_arm64.s +27 -21
@@ -17,31 +17,37 @@ TEXT callbackasm1(SB), NOSPLIT|NOFRAME, $0
1717 // Save callback register arguments R0-R7 and F0-F7.
1818 // We do this at the top of the frame so they're contiguous with stack arguments.
1919 SUB $(16*8), RSP, R14
20- FMOVD F0, (0*8)(R14)
21- FMOVD F1, (1*8)(R14)
22- FMOVD F2, (2*8)(R14)
23- FMOVD F3, (3*8)(R14)
24- FMOVD F4, (4*8)(R14)
25- FMOVD F5, (5*8)(R14)
26- FMOVD F6, (6*8)(R14)
27- FMOVD F7, (7*8)(R14)
20+ FSTPD (F0, F1), (0*8)(R14)
21+ FSTPD (F2, F3), (2*8)(R14)
22+ FSTPD (F4, F5), (4*8)(R14)
23+ FSTPD (F6, F7), (6*8)(R14)
2824 STP (R0, R1), (8*8)(R14)
2925 STP (R2, R3), (10*8)(R14)
3026 STP (R4, R5), (12*8)(R14)
3127 STP (R6, R7), (14*8)(R14)
3228
3329 // Adjust SP by frame size.
34- // crosscall2 clobbers FP in the frame record so only save/restore SP.
35- SUB $(28*8), RSP
36- MOVD R30, (RSP)
30+ SUB $(26*8), RSP
31+
32+ // It is important to save R27 because the go assembler
33+ // uses it for move instructions for a variable.
34+ // This line:
35+ // MOVD ·callbackWrap_call(SB), R0
36+ // Creates the instructions:
37+ // ADRP 14335(PC), R27
38+ // MOVD 388(27), R0
39+ // R27 is a callee saved register so we are responsible
40+ // for ensuring its value doesn't change. So save it and
41+ // restore it at the end of this function.
42+ // R30 is the link register. crosscall2 doesn't save it
43+ // so it's saved here.
44+ STP (R27, R30), 0(RSP)
3745
3846 // Create a struct callbackArgs on our stack.
39- ADD $(callbackArgs__size + 3*8), RSP, R13
40- MOVD R12, callbackArgs_index(R13) // callback index
41- MOVD R14, R0
42- MOVD R0, callbackArgs_args(R13) // address of args vector
43- MOVD $0, R0
44- MOVD R0, callbackArgs_result(R13) // result
47+ MOVD $(callbackArgs__size)(RSP), R13
48+ MOVD R12, callbackArgs_index(R13) // callback index
49+ MOVD R14, callbackArgs_args(R13) // address of args vector
50+ MOVD ZR, callbackArgs_result(R13) // result
4551
4652 // Move parameters into registers
4753 // Get the ABIInternal function pointer
@@ -54,11 +60,11 @@ TEXT callbackasm1(SB), NOSPLIT|NOFRAME, $0
5460 BL crosscall2(SB)
5561
5662 // Get callback result.
57- ADD $(callbackArgs__size + 3*8), RSP, R13
63+ MOVD $(callbackArgs__size)(RSP), R13
5864 MOVD callbackArgs_result(R13), R0
5965
60- // Restore SP
61- MOVD (RSP), R30
62- ADD $(28*8), RSP
66+ // Restore LR and R27
67+ LDP 0(RSP), (R27, R30)
68+ ADD $(26*8), RSP
6369
6470 RET
@@ -17,31 +17,37 @@ TEXT callbackasm1(SB), NOSPLIT|NOFRAME, $0
17 // Save callback register arguments R0-R7 and F0-F7.17 // Save callback register arguments R0-R7 and F0-F7.
18 // We do this at the top of the frame so they're contiguous with stack arguments.18 // We do this at the top of the frame so they're contiguous with stack arguments.
19 SUB $(16*8), RSP, R1419 SUB $(16*8), RSP, R14
20- FMOVD F0, (0*8)(R14)20+ FSTPD (F0, F1), (0*8)(R14)
21- FMOVD F1, (1*8)(R14)21+ FSTPD (F2, F3), (2*8)(R14)
22- FMOVD F2, (2*8)(R14)22+ FSTPD (F4, F5), (4*8)(R14)
23- FMOVD F3, (3*8)(R14)23+ FSTPD (F6, F7), (6*8)(R14)
24- FMOVD F4, (4*8)(R14)
25- FMOVD F5, (5*8)(R14)
26- FMOVD F6, (6*8)(R14)
27- FMOVD F7, (7*8)(R14)
28 STP (R0, R1), (8*8)(R14)24 STP (R0, R1), (8*8)(R14)
29 STP (R2, R3), (10*8)(R14)25 STP (R2, R3), (10*8)(R14)
30 STP (R4, R5), (12*8)(R14)26 STP (R4, R5), (12*8)(R14)
31 STP (R6, R7), (14*8)(R14)27 STP (R6, R7), (14*8)(R14)
32 28
33 // Adjust SP by frame size.29 // Adjust SP by frame size.
34- // crosscall2 clobbers FP in the frame record so only save/restore SP.30+ SUB $(26*8), RSP
35- SUB $(28*8), RSP31+
36- MOVD R30, (RSP)32+ // It is important to save R27 because the go assembler
33+ // uses it for move instructions for a variable.
34+ // This line:
35+ // MOVD ·callbackWrap_call(SB), R0
36+ // Creates the instructions:
37+ // ADRP 14335(PC), R27
38+ // MOVD 388(27), R0
39+ // R27 is a callee saved register so we are responsible
40+ // for ensuring its value doesn't change. So save it and
41+ // restore it at the end of this function.
42+ // R30 is the link register. crosscall2 doesn't save it
43+ // so it's saved here.
44+ STP (R27, R30), 0(RSP)
37 45
38 // Create a struct callbackArgs on our stack.46 // Create a struct callbackArgs on our stack.
39- ADD $(callbackArgs__size + 3*8), RSP, R1347+ MOVD $(callbackArgs__size)(RSP), R13
40- MOVD R12, callbackArgs_index(R13) // callback index48+ MOVD R12, callbackArgs_index(R13) // callback index
41- MOVD R14, R049+ MOVD R14, callbackArgs_args(R13) // address of args vector
42- MOVD R0, callbackArgs_args(R13) // address of args vector50+ MOVD ZR, callbackArgs_result(R13) // result
43- MOVD $0, R0
44- MOVD R0, callbackArgs_result(R13) // result
45 51
46 // Move parameters into registers52 // Move parameters into registers
47 // Get the ABIInternal function pointer53 // Get the ABIInternal function pointer
@@ -54,11 +60,11 @@ TEXT callbackasm1(SB), NOSPLIT|NOFRAME, $0
54 BL crosscall2(SB)60 BL crosscall2(SB)
55 61
56 // Get callback result.62 // Get callback result.
57- ADD $(callbackArgs__size + 3*8), RSP, R1363+ MOVD $(callbackArgs__size)(RSP), R13
58 MOVD callbackArgs_result(R13), R064 MOVD callbackArgs_result(R13), R0
59 65
60- // Restore SP66+ // Restore LR and R27
61- MOVD (RSP), R3067+ LDP 0(RSP), (R27, R30)
62- ADD $(28*8), RSP68+ ADD $(26*8), RSP
63 69
64 RET70 RET

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 102

↑↓ moveenter openesc close