// Copyright (c) 2026 Petr BalvĂ­n (https://petrbalvin.org) // SPDX-License-Identifier: BSD-3-Clause package verify import ( "testing" "unsafe" ) func loadABIKernel(t *testing.T) *Kernel { t.Helper() k, err := Load("../testdata/verify/abi_amd64.s") if err != nil { t.Fatalf("Load: %v", err) } t.Cleanup(k.Close) return k } func TestABIClean(t *testing.T) { k := loadABIKernel(t) args := make([]byte, 24) PutUint64(args, 0, 3) PutUint64(args, 8, 4) out, report, err := k.CallFuncChecked("cleanAdd", args) if err != nil { t.Fatalf("CallFuncChecked: %v", err) } if got := int64(GetUint64(out, 16)); got != 7 { t.Errorf("cleanAdd(3, 4) = %d, want 7", got) } if !report.OK() { t.Errorf("cleanAdd: %s", report) } } func TestABIBPClobbered(t *testing.T) { k := loadABIKernel(t) args := make([]byte, 16) PutUint64(args, 0, 42) out, report, err := k.CallFuncChecked("dirtyBP", args) if err != nil { t.Fatalf("CallFuncChecked: %v", err) } if got := int64(GetUint64(out, 8)); got != 42 { t.Errorf("dirtyBP(42) = %d, want 42", got) } if !report.BPClobbered { t.Error("dirtyBP: expected BP clobbered, but report says clean") } if report.R14Clobbered { t.Error("dirtyBP: R14 should not be clobbered") } } func TestABIR14Clobbered(t *testing.T) { k := loadABIKernel(t) args := make([]byte, 16) PutUint64(args, 0, 99) out, report, err := k.CallFuncChecked("dirtyR14", args) if err != nil { t.Fatalf("CallFuncChecked: %v", err) } if got := int64(GetUint64(out, 8)); got != 99 { t.Errorf("dirtyR14(99) = %d, want 99", got) } if !report.R14Clobbered { t.Error("dirtyR14: expected R14 clobbered, but report says clean") } if report.BPClobbered { t.Error("dirtyR14: BP should not be clobbered") } } // TestABILZ4Kernels verifies that the production go-lz4 kernels are ABI-clean: // they preserve BP and R14 and do not write into the red zone. func TestABILZ4Kernels(t *testing.T) { k := loadLZ4Kernel(t) // wideCopyAVX2 with a real copy. src := make([]byte, 128) for i := range src { src[i] = byte(i) } dst := make([]byte, 128) args := make([]byte, 48) PutPtr(args, 0, unsafe.Pointer(&dst[0])) PutUint64(args, 8, 128) PutUint64(args, 16, 128) PutPtr(args, 24, unsafe.Pointer(&src[0])) PutUint64(args, 32, 128) PutUint64(args, 40, 128) _, report, err := k.CallFuncChecked("wideCopyAVX2", args) if err != nil { t.Fatalf("CallFuncChecked(wideCopyAVX2): %v", err) } if !report.OK() { t.Errorf("wideCopyAVX2: %s", report) } // decodeBlockAVX2 with a simple block. decSrc := []byte{0x50, 'H', 'e', 'l', 'l', 'o'} decDst := make([]byte, 64) decArgs := make([]byte, 64) PutPtr(decArgs, 0, unsafe.Pointer(&decSrc[0])) PutUint64(decArgs, 8, uint64(len(decSrc))) PutUint64(decArgs, 16, uint64(cap(decSrc))) PutPtr(decArgs, 24, unsafe.Pointer(&decDst[0])) PutUint64(decArgs, 32, uint64(len(decDst))) PutUint64(decArgs, 40, uint64(cap(decDst))) _, report, err = k.CallFuncChecked("decodeBlockAVX2", decArgs) if err != nil { t.Fatalf("CallFuncChecked(decodeBlockAVX2): %v", err) } if !report.OK() { t.Errorf("decodeBlockAVX2: %s", report) } } func TestCallFuncCheckedErrors(t *testing.T) { k := loadABIKernel(t) // Nonexistent function. _, _, err := k.CallFuncChecked("nope", make([]byte, 8)) if err == nil { t.Fatal("expected error for nonexistent function") } // Arg block too small. _, _, err = k.CallFuncChecked("cleanAdd", make([]byte, 8)) if err == nil { t.Fatal("expected error for too-small arg block") } }