From 0efda1d4db4d7253796d96e4ab6bb6a64c95997c Mon Sep 17 00:00:00 2001 From: Rick Guo Date: Tue, 20 Oct 2026 00:21:45 +0800 Subject: [PATCH 1/2] Publish expanded unified libc classification for c/setjmp --- c/setjmp/libc_darwin_arm64.go | 17 +++++++++++++++ c/setjmp/libc_linux_amd64.go | 36 ++++++++++++++++++++++++++++++++ c/setjmp/libc_linux_arm64.go | 39 +++++++++++++++++++++++++++++++++++ c/setjmp/llcppg.pub | 2 ++ 4 files changed, 94 insertions(+) create mode 100644 c/setjmp/libc_darwin_arm64.go create mode 100644 c/setjmp/libc_linux_amd64.go create mode 100644 c/setjmp/libc_linux_arm64.go create mode 100644 c/setjmp/llcppg.pub diff --git a/c/setjmp/libc_darwin_arm64.go b/c/setjmp/libc_darwin_arm64.go new file mode 100644 index 00000000..b803eeaa --- /dev/null +++ b/c/setjmp/libc_darwin_arm64.go @@ -0,0 +1,17 @@ +//go:build darwin && arm64 && !ios + +// Code generated by llcppg; DO NOT EDIT. +// Classified from the common libc binding. + +package setjmp + +import ( + "github.com/goplus/lib/c" + _ "unsafe" +) + +//go:linkname X_setjmp C._setjmp +func X_setjmp(_llcppg_param1 JmpBuf) c.Int + +//go:linkname X_longjmp C._longjmp +func X_longjmp(_llcppg_param1 JmpBuf, _llcppg_param2 c.Int) diff --git a/c/setjmp/libc_linux_amd64.go b/c/setjmp/libc_linux_amd64.go new file mode 100644 index 00000000..aac5e262 --- /dev/null +++ b/c/setjmp/libc_linux_amd64.go @@ -0,0 +1,36 @@ +//go:build linux && amd64 && !android + +// Code generated by llcppg; DO NOT EDIT. +// Classified from the common libc binding. + +package setjmp + +import ( + "github.com/goplus/lib/c" + llsignal "github.com/goplus/lib/c/signal" +) + +type X__JmpBuf = [8]c.Long + +// Calling environment, plus possibly a saved signal mask. +type X__JmpBufTag struct { + X__Jmpbuf X__JmpBuf + X__MaskWasSaved c.Int + X__SavedMask llsignal.SigsetT +} + +// Store the calling environment in ENV, not saving the signal mask. +// Return 0. +// +// llgo:link (*X__JmpBufTag).X_setjmp C._setjmp +func (self *X__JmpBufTag) X_setjmp() c.Int { + return 0 +} + +// Same. Usually `_longjmp' is used with `_setjmp', which does not save +// the signal mask. But it is how ENV was saved that determines whether +// `longjmp' restores the mask; `_longjmp' is just an alias. +// +// llgo:link (*X__JmpBufTag).X_longjmp C._longjmp +func (self *X__JmpBufTag) X_longjmp(__val c.Int) { +} diff --git a/c/setjmp/libc_linux_arm64.go b/c/setjmp/libc_linux_arm64.go new file mode 100644 index 00000000..7d867358 --- /dev/null +++ b/c/setjmp/libc_linux_arm64.go @@ -0,0 +1,39 @@ +//go:build linux && arm64 && !android + +// Code generated by llcppg; DO NOT EDIT. +// Classified from the common libc binding. + +package setjmp + +import ( + "github.com/goplus/lib/c" + llsignal "github.com/goplus/lib/c/signal" +) + +// Jump buffer contains: +// x19-x28, x29(fp), x30(lr), (x31)sp, d8-d15. Other registers are not +// saved. +type X__JmpBuf = [22]c.UlongLong + +// Calling environment, plus possibly a saved signal mask. +type X__JmpBufTag struct { + X__Jmpbuf X__JmpBuf + X__MaskWasSaved c.Int + X__SavedMask llsignal.SigsetT +} + +// Store the calling environment in ENV, not saving the signal mask. +// Return 0. +// +// llgo:link (*X__JmpBufTag).X_setjmp C._setjmp +func (self *X__JmpBufTag) X_setjmp() c.Int { + return 0 +} + +// Same. Usually `_longjmp' is used with `_setjmp', which does not save +// the signal mask. But it is how ENV was saved that determines whether +// `longjmp' restores the mask; `_longjmp' is just an alias. +// +// llgo:link (*X__JmpBufTag).X_longjmp C._longjmp +func (self *X__JmpBufTag) X_longjmp(__val c.Int) { +} diff --git a/c/setjmp/llcppg.pub b/c/setjmp/llcppg.pub new file mode 100644 index 00000000..609675df --- /dev/null +++ b/c/setjmp/llcppg.pub @@ -0,0 +1,2 @@ +T __jmp_buf X__JmpBuf +T __jmp_buf_tag X__JmpBufTag From d6e2afc006914a161ee4dedabdc1b1e8a9594541 Mon Sep 17 00:00:00 2001 From: Rick Guo Date: Tue, 20 Oct 2026 14:03:34 +0800 Subject: [PATCH 2/2] Regenerate c/setjmp native APIs and verify native calls --- ...generated_native_darwin_arm64_llgo_test.go | 23 +++++++++++++++ c/setjmp/generated_native_linux_llgo_test.go | 24 +++++++++++++++ c/setjmp/libc_darwin_arm64.go | 19 ++++++++++-- c/setjmp/libc_linux_amd64.go | 29 +++++++++++++++++++ c/setjmp/libc_linux_arm64.go | 29 +++++++++++++++++++ c/setjmp/llcppg.pub | 2 ++ 6 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 c/setjmp/generated_native_darwin_arm64_llgo_test.go create mode 100644 c/setjmp/generated_native_linux_llgo_test.go diff --git a/c/setjmp/generated_native_darwin_arm64_llgo_test.go b/c/setjmp/generated_native_darwin_arm64_llgo_test.go new file mode 100644 index 00000000..8da744e9 --- /dev/null +++ b/c/setjmp/generated_native_darwin_arm64_llgo_test.go @@ -0,0 +1,23 @@ +//go:build llgo && darwin && arm64 && !ios + +package setjmp_test + +import ( + "github.com/goplus/lib/c" + "github.com/goplus/lib/c/setjmp" + "testing" +) + +func TestGeneratedSetjmpWritesCallerBuffer(t *testing.T) { + var buffer [48]c.Int + if result := setjmp.NativeSetjmp(&buffer[0]); result != 0 { + t.Fatalf("initial setjmp = %d", result) + } + changed := false + for _, word := range buffer { + changed = changed || word != 0 + } + if !changed { + t.Fatal("setjmp did not write the caller-owned buffer") + } +} diff --git a/c/setjmp/generated_native_linux_llgo_test.go b/c/setjmp/generated_native_linux_llgo_test.go new file mode 100644 index 00000000..2844ab8a --- /dev/null +++ b/c/setjmp/generated_native_linux_llgo_test.go @@ -0,0 +1,24 @@ +//go:build llgo && linux && (amd64 || arm64) && !android + +package setjmp_test + +import ( + "github.com/goplus/lib/c/setjmp" + "testing" + "unsafe" +) + +func TestGeneratedSetjmpWritesCallerBuffer(t *testing.T) { + var buffer setjmp.X__JmpBufTag + if result := buffer.NativeSetjmp(); result != 0 { + t.Fatalf("initial setjmp = %d", result) + } + bytes := unsafe.Slice((*byte)(unsafe.Pointer(&buffer)), unsafe.Sizeof(buffer)) + changed := false + for _, b := range bytes { + changed = changed || b != 0 + } + if !changed { + t.Fatal("setjmp did not write the caller-owned buffer") + } +} diff --git a/c/setjmp/libc_darwin_arm64.go b/c/setjmp/libc_darwin_arm64.go index b803eeaa..b7f5bf2a 100644 --- a/c/setjmp/libc_darwin_arm64.go +++ b/c/setjmp/libc_darwin_arm64.go @@ -10,8 +10,23 @@ import ( _ "unsafe" ) +//go:linkname NativeSetjmp C.setjmp +func NativeSetjmp(_llcppg_param1 *c.Int) c.Int + +//go:linkname NativeLongjmp C.longjmp +func NativeLongjmp(_llcppg_param1 *c.Int, _llcppg_param2 c.Int) + //go:linkname X_setjmp C._setjmp -func X_setjmp(_llcppg_param1 JmpBuf) c.Int +func X_setjmp(_llcppg_param1 *c.Int) c.Int //go:linkname X_longjmp C._longjmp -func X_longjmp(_llcppg_param1 JmpBuf, _llcppg_param2 c.Int) +func X_longjmp(_llcppg_param1 *c.Int, _llcppg_param2 c.Int) + +//go:linkname NativeSigsetjmp C.sigsetjmp +func NativeSigsetjmp(_llcppg_param1 *c.Int, _llcppg_param2 c.Int) c.Int + +//go:linkname NativeSiglongjmp C.siglongjmp +func NativeSiglongjmp(_llcppg_param1 *c.Int, _llcppg_param2 c.Int) + +//go:linkname Longjmperror C.longjmperror +func Longjmperror() diff --git a/c/setjmp/libc_linux_amd64.go b/c/setjmp/libc_linux_amd64.go index aac5e262..62611c19 100644 --- a/c/setjmp/libc_linux_amd64.go +++ b/c/setjmp/libc_linux_amd64.go @@ -12,6 +12,11 @@ import ( type X__JmpBuf = [8]c.Long +// llgo:link (*X__JmpBufTag).NativeX__Sigsetjmp C.__sigsetjmp +func (self *X__JmpBufTag) NativeX__Sigsetjmp(__savemask c.Int) c.Int { + return 0 +} + // Calling environment, plus possibly a saved signal mask. type X__JmpBufTag struct { X__Jmpbuf X__JmpBuf @@ -19,6 +24,14 @@ type X__JmpBufTag struct { X__SavedMask llsignal.SigsetT } +// Store the calling environment in ENV, also saving the signal mask. +// Return 0. +// +// llgo:link (*X__JmpBufTag).NativeSetjmp C.setjmp +func (self *X__JmpBufTag) NativeSetjmp() c.Int { + return 0 +} + // Store the calling environment in ENV, not saving the signal mask. // Return 0. // @@ -27,6 +40,13 @@ func (self *X__JmpBufTag) X_setjmp() c.Int { return 0 } +// Jump to the environment saved in ENV, making the +// `setjmp' call there return VAL, or 1 if VAL is 0. +// +// llgo:link (*X__JmpBufTag).NativeLongjmp C.longjmp +func (self *X__JmpBufTag) NativeLongjmp(__val c.Int) { +} + // Same. Usually `_longjmp' is used with `_setjmp', which does not save // the signal mask. But it is how ENV was saved that determines whether // `longjmp' restores the mask; `_longjmp' is just an alias. @@ -34,3 +54,12 @@ func (self *X__JmpBufTag) X_setjmp() c.Int { // llgo:link (*X__JmpBufTag).X_longjmp C._longjmp func (self *X__JmpBufTag) X_longjmp(__val c.Int) { } + +// Jump to the environment saved in ENV, making the +// sigsetjmp call there return VAL, or 1 if VAL is 0. +// Restore the signal mask if that sigsetjmp call saved it. +// This is just an alias `longjmp'. +// +// llgo:link (*X__JmpBufTag).NativeSiglongjmp C.siglongjmp +func (self *X__JmpBufTag) NativeSiglongjmp(__val c.Int) { +} diff --git a/c/setjmp/libc_linux_arm64.go b/c/setjmp/libc_linux_arm64.go index 7d867358..f1c5879a 100644 --- a/c/setjmp/libc_linux_arm64.go +++ b/c/setjmp/libc_linux_arm64.go @@ -15,6 +15,11 @@ import ( // saved. type X__JmpBuf = [22]c.UlongLong +// llgo:link (*X__JmpBufTag).NativeX__Sigsetjmp C.__sigsetjmp +func (self *X__JmpBufTag) NativeX__Sigsetjmp(__savemask c.Int) c.Int { + return 0 +} + // Calling environment, plus possibly a saved signal mask. type X__JmpBufTag struct { X__Jmpbuf X__JmpBuf @@ -22,6 +27,14 @@ type X__JmpBufTag struct { X__SavedMask llsignal.SigsetT } +// Store the calling environment in ENV, also saving the signal mask. +// Return 0. +// +// llgo:link (*X__JmpBufTag).NativeSetjmp C.setjmp +func (self *X__JmpBufTag) NativeSetjmp() c.Int { + return 0 +} + // Store the calling environment in ENV, not saving the signal mask. // Return 0. // @@ -30,6 +43,13 @@ func (self *X__JmpBufTag) X_setjmp() c.Int { return 0 } +// Jump to the environment saved in ENV, making the +// `setjmp' call there return VAL, or 1 if VAL is 0. +// +// llgo:link (*X__JmpBufTag).NativeLongjmp C.longjmp +func (self *X__JmpBufTag) NativeLongjmp(__val c.Int) { +} + // Same. Usually `_longjmp' is used with `_setjmp', which does not save // the signal mask. But it is how ENV was saved that determines whether // `longjmp' restores the mask; `_longjmp' is just an alias. @@ -37,3 +57,12 @@ func (self *X__JmpBufTag) X_setjmp() c.Int { // llgo:link (*X__JmpBufTag).X_longjmp C._longjmp func (self *X__JmpBufTag) X_longjmp(__val c.Int) { } + +// Jump to the environment saved in ENV, making the +// sigsetjmp call there return VAL, or 1 if VAL is 0. +// Restore the signal mask if that sigsetjmp call saved it. +// This is just an alias `longjmp'. +// +// llgo:link (*X__JmpBufTag).NativeSiglongjmp C.siglongjmp +func (self *X__JmpBufTag) NativeSiglongjmp(__val c.Int) { +} diff --git a/c/setjmp/llcppg.pub b/c/setjmp/llcppg.pub index 609675df..724d7981 100644 --- a/c/setjmp/llcppg.pub +++ b/c/setjmp/llcppg.pub @@ -1,2 +1,4 @@ T __jmp_buf X__JmpBuf T __jmp_buf_tag X__JmpBufTag +T jmp_buf JmpBuf +T sigjmp_buf SigjmpBuf