feat(asm): encode indirect JMP and CALL on all four architectures

Assisted-by: GLM 5.3 Flash
This commit is contained in:
2026-09-19 19:17:07 +02:00
parent 96e81cc98d
commit 23c001be51
24 changed files with 494 additions and 27 deletions
+2 -2
View File
@@ -39,7 +39,7 @@ TEXT ·enterJITChecked(SB), NOSPLIT, $0-16
MOVV 0(R5), R1 // load leaveJITCheckedRaw into RA
MOVV R5, R3 // SP stays on the leave slot: the kernel
// reads its first argument at SP+8
JIRL R0, R4, 0 // jump to JIT function
JMP (R4) // jump to JIT function
// leaveJITCheckedRaw is the raw return trampoline. It has NO Go function
// declaration, so no ABIInternal wrapper is generated; the JIT function's
@@ -61,6 +61,6 @@ g_ok:
MOVV savedRA(SB), R1 // restore return address
MOVV savedG(SB), g // restore g: Go code needs it the moment it
// resumes, violation or not
JIRL R0, R1, 0 // return to Go caller
JMP (R1) // return to Go caller
GLOBL savedG(SB), NOPTR, $8
+1
View File
@@ -25,6 +25,7 @@ func TestGroundTruthARM64(t *testing.T) {
"../testdata/verify/call_arm64.s",
"../testdata/verify/bigframe_arm64.s",
"../testdata/verify/guard_arm64.s",
"../testdata/verify/indirect_arm64.s",
} {
t.Run(path, func(t *testing.T) {
src, err := os.ReadFile(path)
+1
View File
@@ -98,6 +98,7 @@ func TestGroundTruthAMD64(t *testing.T) {
"../testdata/verify/basic_amd64.s",
"../testdata/verify/bigframe_amd64.s",
"../testdata/verify/guard_amd64.s",
"../testdata/verify/indirect_amd64.s",
} {
t.Run(path, func(t *testing.T) {
f, errs := parser.Parse(path, mustRead(t, path))
+2
View File
@@ -24,6 +24,8 @@ func TestGroundTruthLOONG64(t *testing.T) {
"../testdata/verify/fp_loong64.s",
"../testdata/verify/bigframe_loong64.s",
"../testdata/verify/guard_loong64.s",
"../testdata/verify/indirect_loong64.s",
"trampoline_loong64.s",
} {
t.Run(path, func(t *testing.T) {
src, err := os.ReadFile(path)
+2
View File
@@ -27,6 +27,8 @@ func TestGroundTruthRISCV(t *testing.T) {
"../testdata/verify/call_riscv64.s",
"../testdata/verify/bigframe_riscv64.s",
"../testdata/verify/guard_riscv64.s",
"../testdata/verify/indirect_riscv64.s",
"trampoline_riscv64.s",
} {
t.Run(path, func(t *testing.T) {
testGroundTruthRISCVFile(t, path)
+3 -3
View File
@@ -6,7 +6,7 @@
// ABI0 JIT trampoline for LoongArch 64.
//
// enterJIT saves Go SP and RA (R1), switches to the prepared stack, and
// jumps to the JIT function. When the function RETs (JIRL zero, ra, 0),
// jumps to the JIT function. When the function RETs (JMP (R1), the toolchain's spelling for jirl zero, ra, 0),
// control lands in leaveJIT.
// func enterJIT(fn uintptr, stack uintptr)
@@ -19,14 +19,14 @@ TEXT ·enterJIT(SB), NOSPLIT, $0-16
MOVV R5, R3 // switch to the prepared stack: SP stays on
// the leave slot, so the kernel reads its
// first argument at SP+8
JIRL R0, R4, 0 // jump to JIT function
JMP (R4) // jump to JIT function
// func leaveJIT()
TEXT ·leaveJIT(SB), NOSPLIT, $0-0
MOVV savedSP(SB), R5 // restore Go stack pointer
MOVV R5, R3 // restore SP
MOVV savedRA(SB), R1 // restore return address
JIRL R0, R1, 0 // return to Go caller
JMP (R1) // return to Go caller
GLOBL savedRA(SB), NOPTR, $8