2026-08-21 00:03:30 +02:00
|
|
|
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
|
|
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
|
|
|
|
|
|
#include "textflag.h"
|
|
|
|
|
|
|
|
|
|
// ABI0 JIT trampoline for arm64.
|
|
|
|
|
//
|
|
|
|
|
// enterJIT saves the Go SP and LR, switches to the prepared stack, and
|
|
|
|
|
// branches to the JIT function. When the function RETs (BR LR), control
|
|
|
|
|
// lands in leaveJIT, which restores the Go stack and returns.
|
|
|
|
|
//
|
|
|
|
|
// The prepared stack layout:
|
|
|
|
|
// [0] leaveJIT address (loaded into LR before jumping to fn)
|
|
|
|
|
// [8] ABI0 argument area
|
|
|
|
|
|
|
|
|
|
// func enterJIT(fn uintptr, stack uintptr)
|
|
|
|
|
TEXT ·enterJIT(SB), NOSPLIT, $0-16
|
2026-09-17 20:33:18 +02:00
|
|
|
MOVD fn+0(FP), R0 // target function address
|
|
|
|
|
MOVD R30, savedLR(SB) // save link register
|
2026-09-19 23:49:19 +02:00
|
|
|
MOVD RSP, R3 // save Go stack pointer: R3 relays the value, the
|
|
|
|
|
MOVD R3, savedSP(SB) // arm64 assembler cannot store RSP to memory
|
2026-09-17 20:33:18 +02:00
|
|
|
MOVD stack+8(FP), R3 // load prepared stack pointer
|
|
|
|
|
MOVD 0(R3), R30 // load leaveJIT address into LR
|
|
|
|
|
MOVD R3, RSP // switch to the prepared stack: SP stays on
|
|
|
|
|
// the leave slot, so the kernel reads its
|
|
|
|
|
// first argument at SP+8 per the frame
|
|
|
|
|
// convention (amd64 lays the stack out the
|
|
|
|
|
// same way)
|
|
|
|
|
JMP (R0) // branch to JIT function
|
2026-08-21 00:03:30 +02:00
|
|
|
|
2026-09-17 20:33:18 +02:00
|
|
|
// func leaveJIT()
|
2026-08-21 00:03:30 +02:00
|
|
|
TEXT ·leaveJIT(SB), NOSPLIT, $0-0
|
2026-09-17 20:33:18 +02:00
|
|
|
MOVD savedSP(SB), R3 // restore Go stack pointer
|
2026-08-21 00:03:30 +02:00
|
|
|
MOVD R3, RSP
|
2026-09-17 20:33:18 +02:00
|
|
|
MOVD savedLR(SB), R30 // restore link register
|
|
|
|
|
RET // return to Go caller
|
2026-08-21 00:03:30 +02:00
|
|
|
|
2026-08-30 22:27:20 +02:00
|
|
|
// leaveRawAddr holds the raw .abi0 address of leaveJIT, read by call_arm64.go
|
|
|
|
|
// in preference to reflect.ValueOf(leaveJIT), which returns the address of the
|
|
|
|
|
// ABIInternal wrapper the linker interposes: the wrapper's prologue clobbers
|
|
|
|
|
// the saved-register window the JIT call depends on.
|
|
|
|
|
GLOBL ·leaveRawAddr(SB), NOPTR, $8
|
2026-09-17 20:33:18 +02:00
|
|
|
DATA ·leaveRawAddr(SB)/8, $·leaveJIT(SB)
|
2026-08-30 22:27:20 +02:00
|
|
|
|
2026-08-21 00:03:30 +02:00
|
|
|
// Package-level storage for saved registers.
|
|
|
|
|
GLOBL savedLR(SB), NOPTR, $8
|
2026-09-17 20:33:18 +02:00
|
|
|
|
2026-08-21 00:03:30 +02:00
|
|
|
GLOBL savedSP(SB), NOPTR, $8
|