From d44e4e062bd6deb56a7db03fd385209be5be9f29 Mon Sep 17 00:00:00 2001 From: Ariel Otilibili Date: Thu, 23 Apr 2026 00:06:03 +0000 Subject: [PATCH] runtime/arm64: use ABIInternal convention in cgocallbackg This change follows from CL 765581. As expected, the program panics when an unpinned pointed is passed from Go to C. The stack trace showing an autogenerated frame by the linker. # cat -n main.c 1 #include 2 #include "parse.h" 3 4 int main(void) { 5 GoMap m = GoFoo(); 6 (void)m; 7 return 0; 8 } # cat -n callbackErr.go 1 package main 2 3 import ( 4 "C" 5 ) 6 7 //export GoFoo 8 func GoFoo() map[int]int { 9 return map[int]int{0: 1,} 10 } 11 12 func main() { 13 } # GOOS=linux GOARCH=arm64 CGO_ENABLED=1 CC=aarch64-linux-gnu-gcc go build -buildmode=c-shared -o callbackErr.so callbackErr.go # aarch64-linux-gnu-gcc -o main main.c callbackErr.so -Wl,-rpath,'$ORIGIN' # qemu-aarch64-static -L /usr/aarch64-linux-gnu ./main [...] goroutine 17 [running, locked to thread]: panic({0x74edf75f1300?, 0x2e980159a010?}) /usr/lib/go/src/runtime/panic.go:879 +0x15c runtime.cgoCheckArg(0x74edf75f2580, 0x2e9801598060, 0x0?, 0x0, 0x1) /usr/lib/go/src/runtime/cgocall.go:659 +0x45c runtime.cgoCheckResult({0x74edf75f2580, 0x2e9801598060}) /usr/lib/go/src/runtime/cgocall.go:829 +0x48 _cgoexp_35a35dd190e3_GoFoo(0x74edf7e9fb78) /mnt/tmp/callbackErr.go:8 +0x7c runtime.cgocallbackg1(0x74edf75535a0, 0x74edf7e9fb78, 0x0) /usr/lib/go/src/runtime/cgocall.go:466 +0x2a8 runtime.cgocallbackg(0x74edf75535a0, 0x74edf7e9fb78, 0x0) /usr/lib/go/src/runtime/cgocall.go:362 +0x104 runtime.cgocallbackg(0x74edf75535a0, 0x74edf7e9fb78, 0x0) :1 +0x1c runtime.cgocallback(0x0, 0x0, 0x0) /usr/lib/go/src/runtime/asm_arm64.s:1359 +0xb0 runtime.goexit({}) /usr/lib/go/src/runtime/asm_arm64.s:1447 +0x4 qemu: uncaught target signal 6 (Aborted) - core dumped Aborted (core dumped) qemu-aarch64-static -L /usr/aarch64-linux-gnu ./main Load the cgocallbackg arguments into the registers expected by ABIInternal. Restore BP after switching back to curg. [...] goroutine 17 [running, locked to thread]: panic({0x7be74abd6d38?, 0x7561e2902030?}) /mnt/go/src/runtime/panic.go:878 +0x150 runtime.cgoCheckArg(0x7be74abd15e8, 0x7561e2928060, 0x0?, 0x0, 0x1) /mnt/go/src/runtime/cgocall.go:667 +0x460 runtime.cgoCheckResult({0x7be74abd15e8, 0x7561e2928060}) /mnt/go/src/runtime/cgocall.go:837 +0x48 _cgoexp_187a5a3ff50c_GoFoo(0x7be74bc7fbb8) /mnt/tmp/callbackErr.go:6 +0x7c runtime.cgocallbackg1(0x7be74ab32fd0, 0x7be74bc7fbb8, 0x0) /mnt/go/src/runtime/cgocall.go:474 +0x2bc runtime.cgocallbackg(0x7be74ab32fd0, 0x7be74bc7fbb8, 0x0) /mnt/go/src/runtime/cgocall.go:362 +0x100 runtime.cgocallback(0x0, 0x0, 0x0) /mnt/go/src/runtime/asm_arm64.s:1334 +0xa4 runtime.goexit({}) /mnt/go/src/runtime/asm_arm64.s:1424 +0x4 qemu: uncaught target signal 6 (Aborted) - core dumped Aborted (core dumped) qemu-aarch64-static -L /usr/aarch64-linux-gnu ./main Change-Id: I959a756a8bde3baa94b19c1634fc2b46d8eea07d GitHub-Last-Rev: 221ee88762963c40e66fe368d7e1116b4e057b5e GitHub-Pull-Request: golang/go#78850 Reviewed-on: https://go-review.googlesource.com/c/go/+/768780 Auto-Submit: Keith Randall Reviewed-by: Carlos Amedee LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com Reviewed-by: Keith Randall Reviewed-by: Keith Randall --- src/runtime/asm_arm64.s | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/runtime/asm_arm64.s b/src/runtime/asm_arm64.s index 88c8d7477d..b140118bbe 100644 --- a/src/runtime/asm_arm64.s +++ b/src/runtime/asm_arm64.s @@ -1320,23 +1320,24 @@ havem: MOVD (g_sched+gobuf_sp)(g), R4 // prepare stack as R4 MOVD (g_sched+gobuf_pc)(g), R5 MOVD R5, -48(R4) - MOVD (g_sched+gobuf_bp)(g), R5 - MOVD R5, -56(R4) + MOVD (g_sched+gobuf_bp)(g), R6 + MOVD R6, -56(R4) + // Gather our arguments into registers. - MOVD fn+0(FP), R1 - MOVD frame+8(FP), R2 - MOVD ctxt+16(FP), R3 - MOVD $-48(R4), R0 // maintain 16-byte SP alignment - MOVD R0, RSP // switch stack - MOVD R1, 8(RSP) - MOVD R2, 16(RSP) - MOVD R3, 24(RSP) - MOVD $runtime·cgocallbackg(SB), R0 - CALL (R0) // indirect call to bypass nosplit check. We're on a different stack now. + MOVD fn+0(FP), R0 + MOVD frame+8(FP), R1 + MOVD ctxt+16(FP), R2 + + SUB $48, R4 // Allocate the same frame size on the g stack + MOVD R4, RSP // switch stack + MOVD $runtime·cgocallbackg(SB), R11 + CALL (R11) // indirect call to bypass nosplit check. We're on a different stack now. // Restore g->sched (== m->curg->sched) from saved values. MOVD 0(RSP), R5 MOVD R5, (g_sched+gobuf_pc)(g) + MOVD -8(RSP), R6 + MOVD R6, (g_sched+gobuf_bp)(g) MOVD RSP, R4 ADD $48, R4, R4 MOVD R4, (g_sched+gobuf_sp)(g)