From 71144037860e477cd31df290952e73d4b3fada53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Mart=C3=AD?= Date: Wed, 11 Feb 2026 22:12:25 +0000 Subject: [PATCH] drop Go 1.25, support Go 1.26 Beyond the usual updating of version strings, re-running `go generate`, and updating the patches for the linker, we needed extra changes. First, the linker started being stricter about which packages are allowed to linkname runtime names by import path. Stop obfuscating import paths in runtimeAndLinknamed. Second, the compiler's intrinsics code adds an "add" function much like the existing "addF", so tweak the regular expression. Third, note that there is a new runtimeAndDeps windows-only package, which we find thanks to the recent improvement to cover many platforms. Fourth, the code around magic numbers in the runtime has changed, so rewrite the code which patches it via go/ast. Fixes #990. --- .github/workflows/test.yml | 18 +- README.md | 2 +- cache_shared.go | 14 +- go.mod | 2 +- go_std_tables.go | 459 +++++++++--------- .../0001-add-custom-magic-value.patch | 10 +- ...dd-unexported-function-name-removing.patch | 10 +- .../0003-add-entryOff-encryption.patch | 10 +- main.go | 4 +- runtime_patch.go | 56 +-- scripts/gen_go_std_tables.go | 4 +- testdata/script/goversion.txtar | 42 +- transformer.go | 8 +- 13 files changed, 324 insertions(+), 315 deletions(-) rename internal/linker/patches/{go1.25 => go1.26}/0001-add-custom-magic-value.patch (84%) rename internal/linker/patches/{go1.25 => go1.26}/0002-add-unexported-function-name-removing.patch (91%) rename internal/linker/patches/{go1.25 => go1.26}/0003-add-entryOff-encryption.patch (83%) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 504a6eb..dfe4d2d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,11 +25,11 @@ jobs: test: strategy: matrix: - go-version: [1.25.x] + go-version: [1.26.x] os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: actions/setup-go@v5 with: go-version: ${{ matrix.go-version }} @@ -53,17 +53,17 @@ jobs: # Static checks from this point forward. Only run on one Go version and on # linux, since it's the fastest platform, and the tools behave the same. - name: Test third-party project builds - if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.25.x' + if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.26.x' run: | go install ./scripts/check-third-party.sh - - if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.25.x' + - if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.26.x' run: ./scripts/crlf-test.sh - - if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.25.x' + - if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.26.x' run: diff <(echo -n) <(gofmt -d .) - - if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.25.x' + - if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.26.x' run: go vet ./... - - if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.25.x' + - if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.26.x' uses: dominikh/staticcheck-action@v1 with: version: "2025.1" @@ -78,9 +78,9 @@ jobs: env: GOARCH: 386 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: actions/setup-go@v5 with: - go-version: 1.25.x + go-version: 1.26.x cache: false - run: go test -short ./... diff --git a/README.md b/README.md index 452f40a..03c1170 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ go install mvdan.cc/garble@latest -Obfuscate Go code by wrapping the Go toolchain. Requires Go 1.25 or later. +Obfuscate Go code by wrapping the Go toolchain. Requires Go 1.26 or later. garble build [build flags] [packages] diff --git a/cache_shared.go b/cache_shared.go index f0789a8..b5e5503 100644 --- a/cache_shared.go +++ b/cache_shared.go @@ -243,9 +243,6 @@ func (p *listedPackage) obfuscatedImportPath() string { case "runtime", "reflect", "embed", // TODO: collect directly from cmd/internal/objabi/pkgspecial.go, // in this particular case from allowAsmABIPkgs. - "syscall", - "internal/bytealg", - "internal/chacha8rand", "internal/runtime/syscall/linux", "internal/runtime/syscall/windows", "internal/runtime/startlinetest": @@ -255,6 +252,17 @@ func (p *listedPackage) obfuscatedImportPath() string { if _, ok := compilerIntrinsics[p.ImportPath]; ok { return p.ImportPath } + // The linker forbids linknaming to certain runtime declarations + // unless a package is known to be allowed by import path string. + // The alternative would be to use -checklinkname=false, but that disables all checks entirely. + // + // TODO: we could probably remove this once we obfuscate the runtime, + // because then these runtime package and declaration names will be obfuscated too, + // so the linker will stop recognising them for the extra checks. + if _, ok := runtimeAndLinknamed[p.ImportPath]; ok { + return p.ImportPath + } + newPath := hashWithPackage(p, p.ImportPath) log.Printf("import path %q hashed with %x to %q", p.ImportPath, p.GarbleActionID, newPath) return newPath diff --git a/go.mod b/go.mod index 181cc8f..d9b9b08 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module mvdan.cc/garble -go 1.25 +go 1.26 require ( github.com/bluekeyes/go-gitdiff v0.8.1 diff --git a/go_std_tables.go b/go_std_tables.go index 8fdebde..e5ceedc 100644 --- a/go_std_tables.go +++ b/go_std_tables.go @@ -1,39 +1,43 @@ // Code generated by scripts/gen_go_std_tables.go; DO NOT EDIT. -// Generated from Go versions [go1.25.8]. +// Generated from Go versions [go1.26.1]. package main // runtimeAndDeps contains the runtime package and all of its transitive dependencies // as reported by 'go list -deps'. var runtimeAndDeps = map[string]bool{ - "internal/abi": true, // go1.25 linux/amd64 - "internal/asan": true, // go1.25 linux/amd64 - "internal/bytealg": true, // go1.25 linux/amd64 - "internal/byteorder": true, // go1.25 linux/amd64 - "internal/chacha8rand": true, // go1.25 linux/amd64 - "internal/coverage/rtcov": true, // go1.25 linux/amd64 - "internal/cpu": true, // go1.25 linux/amd64 - "internal/goarch": true, // go1.25 linux/amd64 - "internal/godebugs": true, // go1.25 linux/amd64 - "internal/goexperiment": true, // go1.25 linux/amd64 - "internal/goos": true, // go1.25 linux/amd64 - "internal/msan": true, // go1.25 linux/amd64 - "internal/profilerecord": true, // go1.25 linux/amd64 - "internal/race": true, // go1.25 linux/amd64 - "internal/runtime/atomic": true, // go1.25 linux/amd64 - "internal/runtime/cgroup": true, // go1.25 linux/amd64 - "internal/runtime/exithook": true, // go1.25 linux/amd64 - "internal/runtime/gc": true, // go1.25 linux/amd64 - "internal/runtime/maps": true, // go1.25 linux/amd64 - "internal/runtime/math": true, // go1.25 linux/amd64 - "internal/runtime/strconv": true, // go1.25 linux/amd64 - "internal/runtime/sys": true, // go1.25 linux/amd64 - "internal/runtime/syscall": true, // go1.25 linux/amd64 - "internal/stringslite": true, // go1.25 linux/amd64 - "internal/trace/tracev2": true, // go1.25 linux/amd64 - "runtime": true, // go1.25 linux/amd64 - "unsafe": true, // go1.25 linux/amd64 + "internal/abi": true, // go1.26 linux/amd64 + "internal/asan": true, // go1.26 linux/amd64 + "internal/bytealg": true, // go1.26 linux/amd64 + "internal/byteorder": true, // go1.26 linux/amd64 + "internal/chacha8rand": true, // go1.26 linux/amd64 + "internal/coverage/rtcov": true, // go1.26 linux/amd64 + "internal/cpu": true, // go1.26 linux/amd64 + "internal/goarch": true, // go1.26 linux/amd64 + "internal/godebugs": true, // go1.26 linux/amd64 + "internal/goexperiment": true, // go1.26 linux/amd64 + "internal/goos": true, // go1.26 linux/amd64 + "internal/msan": true, // go1.26 linux/amd64 + "internal/profilerecord": true, // go1.26 linux/amd64 + "internal/race": true, // go1.26 linux/amd64 + "internal/runtime/atomic": true, // go1.26 linux/amd64 + "internal/runtime/cgroup": true, // go1.26 linux/amd64 + "internal/runtime/exithook": true, // go1.26 linux/amd64 + "internal/runtime/gc": true, // go1.26 linux/amd64 + "internal/runtime/gc/scan": true, // go1.26 linux/amd64 + "internal/runtime/maps": true, // go1.26 linux/amd64 + "internal/runtime/math": true, // go1.26 linux/amd64 + "internal/runtime/pprof/label": true, // go1.26 linux/amd64 + "internal/runtime/sys": true, // go1.26 linux/amd64 + "internal/runtime/syscall/linux": true, // go1.26 linux/amd64 + "internal/runtime/syscall/windows": true, // go1.26 windows/386 + "internal/strconv": true, // go1.26 linux/amd64 + "internal/stringslite": true, // go1.26 linux/amd64 + "internal/trace/tracev2": true, // go1.26 linux/amd64 + "math/bits": true, // go1.26 linux/amd64 + "runtime": true, // go1.26 linux/amd64 + "unsafe": true, // go1.26 linux/amd64 } // runtimeAndLinknamed contains the runtime package and all the packages @@ -47,45 +51,48 @@ var runtimeAndDeps = map[string]bool{ // from the runtime package via //go:linkname directives on those platforms. // To make sure we have coverage on all platforms, we allow duplicates. var runtimeAndLinknamed = map[string]bool{ - "arena": true, // go1.25 - "crypto/internal/boring": true, // go1.25 - "crypto/internal/boring/bcache": true, // go1.25 - "crypto/internal/fips140": true, // go1.25 - "crypto/internal/sysrand": true, // go1.25 - "crypto/rand": true, // go1.25 - "crypto/x509/internal/macos": true, // go1.25 - "internal/bytealg": true, // go1.25 - "internal/coverage/cfile": true, // go1.25 - "internal/cpu": true, // go1.25 - "internal/godebug": true, // go1.25 - "internal/poll": true, // go1.25 - "internal/race": true, // go1.25 - "internal/reflectlite": true, // go1.25 - "internal/runtime/atomic": true, // go1.25 - "internal/runtime/cgroup": true, // go1.25 - "internal/runtime/maps": true, // go1.25 - "internal/sync": true, // go1.25 - "internal/synctest": true, // go1.25 - "internal/syscall/unix": true, // go1.25 - "internal/syscall/windows": true, // go1.25 - "maps": true, // go1.25 - "os": true, // go1.25 - "os/signal": true, // go1.25 - "plugin": true, // go1.25 - "reflect": true, // go1.25 - "runtime": true, // go1.25 - "runtime/debug": true, // go1.25 - "runtime/metrics": true, // go1.25 - "runtime/pprof": true, // go1.25 - "runtime/trace": true, // go1.25 - "sync": true, // go1.25 - "sync/atomic": true, // go1.25 - "sync_test": true, // go1.25 - "syscall": true, // go1.25 - "syscall/js": true, // go1.25 - "time": true, // go1.25 - "unique": true, // go1.25 - "weak": true, // go1.25 + "arena": true, // go1.26 + "crypto/fips140": true, // go1.26 + "crypto/internal/boring": true, // go1.26 + "crypto/internal/boring/bcache": true, // go1.26 + "crypto/internal/fips140": true, // go1.26 + "crypto/internal/sysrand": true, // go1.26 + "crypto/rand": true, // go1.26 + "crypto/subtle": true, // go1.26 + "crypto/x509/internal/macos": true, // go1.26 + "internal/bytealg": true, // go1.26 + "internal/coverage/cfile": true, // go1.26 + "internal/cpu": true, // go1.26 + "internal/godebug": true, // go1.26 + "internal/poll": true, // go1.26 + "internal/race": true, // go1.26 + "internal/reflectlite": true, // go1.26 + "internal/runtime/atomic": true, // go1.26 + "internal/runtime/cgroup": true, // go1.26 + "internal/runtime/maps": true, // go1.26 + "internal/sync": true, // go1.26 + "internal/synctest": true, // go1.26 + "internal/syscall/unix": true, // go1.26 + "internal/syscall/windows": true, // go1.26 + "maps": true, // go1.26 + "os": true, // go1.26 + "os/signal": true, // go1.26 + "plugin": true, // go1.26 + "reflect": true, // go1.26 + "runtime": true, // go1.26 + "runtime/debug": true, // go1.26 + "runtime/metrics": true, // go1.26 + "runtime/pprof": true, // go1.26 + "runtime/secret": true, // go1.26 + "runtime/trace": true, // go1.26 + "sync": true, // go1.26 + "sync/atomic": true, // go1.26 + "sync_test": true, // go1.26 + "syscall": true, // go1.26 + "syscall/js": true, // go1.26 + "time": true, // go1.26 + "unique": true, // go1.26 + "weak": true, // go1.26 // The net package linknames to the runtime, not the other way around. "net": true, // The testing package uses a //go:linkname directive pointing to testing/synctest, @@ -94,179 +101,189 @@ var runtimeAndLinknamed = map[string]bool{ } var compilerIntrinsics = map[string]map[string]bool{ + "crypto/internal/constanttime": { + "Select": true, // go1.26 + "boolToUint8": true, // go1.26 + }, "internal/runtime/atomic": { - "And": true, // go1.25 - "And32": true, // go1.25 - "And64": true, // go1.25 - "And8": true, // go1.25 - "Anduintptr": true, // go1.25 - "Cas": true, // go1.25 - "Cas64": true, // go1.25 - "CasRel": true, // go1.25 - "Casint32": true, // go1.25 - "Casint64": true, // go1.25 - "Casp1": true, // go1.25 - "Casuintptr": true, // go1.25 - "Load": true, // go1.25 - "Load64": true, // go1.25 - "Load8": true, // go1.25 - "LoadAcq": true, // go1.25 - "LoadAcq64": true, // go1.25 - "LoadAcquintptr": true, // go1.25 - "Loadint32": true, // go1.25 - "Loadint64": true, // go1.25 - "Loadp": true, // go1.25 - "Loaduint": true, // go1.25 - "Loaduintptr": true, // go1.25 - "Or": true, // go1.25 - "Or32": true, // go1.25 - "Or64": true, // go1.25 - "Or8": true, // go1.25 - "Oruintptr": true, // go1.25 - "Store": true, // go1.25 - "Store64": true, // go1.25 - "Store8": true, // go1.25 - "StoreRel": true, // go1.25 - "StoreRel64": true, // go1.25 - "StoreReluintptr": true, // go1.25 - "Storeint32": true, // go1.25 - "Storeint64": true, // go1.25 - "StorepNoWB": true, // go1.25 - "Storeuintptr": true, // go1.25 - "Xadd": true, // go1.25 - "Xadd64": true, // go1.25 - "Xaddint32": true, // go1.25 - "Xaddint64": true, // go1.25 - "Xadduintptr": true, // go1.25 - "Xchg": true, // go1.25 - "Xchg64": true, // go1.25 - "Xchg8": true, // go1.25 - "Xchgint32": true, // go1.25 - "Xchgint64": true, // go1.25 - "Xchguintptr": true, // go1.25 + "And": true, // go1.26 + "And32": true, // go1.26 + "And64": true, // go1.26 + "And8": true, // go1.26 + "Anduintptr": true, // go1.26 + "Cas": true, // go1.26 + "Cas64": true, // go1.26 + "CasRel": true, // go1.26 + "Casint32": true, // go1.26 + "Casint64": true, // go1.26 + "Casp1": true, // go1.26 + "Casuintptr": true, // go1.26 + "Load": true, // go1.26 + "Load64": true, // go1.26 + "Load8": true, // go1.26 + "LoadAcq": true, // go1.26 + "LoadAcq64": true, // go1.26 + "LoadAcquintptr": true, // go1.26 + "Loadint32": true, // go1.26 + "Loadint64": true, // go1.26 + "Loadp": true, // go1.26 + "Loaduint": true, // go1.26 + "Loaduintptr": true, // go1.26 + "Or": true, // go1.26 + "Or32": true, // go1.26 + "Or64": true, // go1.26 + "Or8": true, // go1.26 + "Oruintptr": true, // go1.26 + "Store": true, // go1.26 + "Store64": true, // go1.26 + "Store8": true, // go1.26 + "StoreRel": true, // go1.26 + "StoreRel64": true, // go1.26 + "StoreReluintptr": true, // go1.26 + "Storeint32": true, // go1.26 + "Storeint64": true, // go1.26 + "StorepNoWB": true, // go1.26 + "Storeuintptr": true, // go1.26 + "Xadd": true, // go1.26 + "Xadd64": true, // go1.26 + "Xaddint32": true, // go1.26 + "Xaddint64": true, // go1.26 + "Xadduintptr": true, // go1.26 + "Xchg": true, // go1.26 + "Xchg64": true, // go1.26 + "Xchg8": true, // go1.26 + "Xchgint32": true, // go1.26 + "Xchgint64": true, // go1.26 + "Xchguintptr": true, // go1.26 }, "internal/runtime/maps": { - "bitsetFirst": true, // go1.25 - "bitsetLowestSet": true, // go1.25 - "bitsetRemoveBelow": true, // go1.25 - "bitsetShiftOutLowest": true, // go1.25 - "ctrlGroupMatchEmpty": true, // go1.25 - "ctrlGroupMatchEmptyOrDeleted": true, // go1.25 - "ctrlGroupMatchFull": true, // go1.25 - "ctrlGroupMatchH2": true, // go1.25 + "bitsetFirst": true, // go1.26 + "bitsetLowestSet": true, // go1.26 + "bitsetRemoveBelow": true, // go1.26 + "bitsetShiftOutLowest": true, // go1.26 + "ctrlGroupMatchEmpty": true, // go1.26 + "ctrlGroupMatchEmptyOrDeleted": true, // go1.26 + "ctrlGroupMatchFull": true, // go1.26 + "ctrlGroupMatchH2": true, // go1.26 }, "internal/runtime/math": { - "Add64": true, // go1.25 - "Mul64": true, // go1.25 - "MulUintptr": true, // go1.25 + "Add64": true, // go1.26 + "Mul64": true, // go1.26 + "MulUintptr": true, // go1.26 }, "internal/runtime/sys": { - "Bswap32": true, // go1.25 - "Bswap64": true, // go1.25 - "Len64": true, // go1.25 - "Len8": true, // go1.25 - "OnesCount64": true, // go1.25 - "Prefetch": true, // go1.25 - "PrefetchStreamed": true, // go1.25 - "TrailingZeros32": true, // go1.25 - "TrailingZeros64": true, // go1.25 - "TrailingZeros8": true, // go1.25 + "Bswap32": true, // go1.26 + "Bswap64": true, // go1.26 + "GetCallerPC": true, // go1.26 + "GetCallerSP": true, // go1.26 + "GetClosurePtr": true, // go1.26 + "Len64": true, // go1.26 + "Len8": true, // go1.26 + "OnesCount64": true, // go1.26 + "Prefetch": true, // go1.26 + "PrefetchStreamed": true, // go1.26 + "TrailingZeros32": true, // go1.26 + "TrailingZeros64": true, // go1.26 + "TrailingZeros8": true, // go1.26 }, "math": { - "Abs": true, // go1.25 - "Ceil": true, // go1.25 - "Copysign": true, // go1.25 - "FMA": true, // go1.25 - "Floor": true, // go1.25 - "Round": true, // go1.25 - "RoundToEven": true, // go1.25 - "Trunc": true, // go1.25 - "sqrt": true, // go1.25 + "Abs": true, // go1.26 + "Ceil": true, // go1.26 + "Copysign": true, // go1.26 + "FMA": true, // go1.26 + "Floor": true, // go1.26 + "Round": true, // go1.26 + "RoundToEven": true, // go1.26 + "Trunc": true, // go1.26 + "sqrt": true, // go1.26 }, "math/big": { - "mulWW": true, // go1.25 + "mulWW": true, // go1.26 }, "math/bits": { - "Add": true, // go1.25 - "Add64": true, // go1.25 - "Div": true, // go1.25 - "Div64": true, // go1.25 - "Len": true, // go1.25 - "Len16": true, // go1.25 - "Len32": true, // go1.25 - "Len64": true, // go1.25 - "Len8": true, // go1.25 - "Mul": true, // go1.25 - "Mul64": true, // go1.25 - "OnesCount": true, // go1.25 - "OnesCount16": true, // go1.25 - "OnesCount32": true, // go1.25 - "OnesCount64": true, // go1.25 - "OnesCount8": true, // go1.25 - "Reverse": true, // go1.25 - "Reverse16": true, // go1.25 - "Reverse32": true, // go1.25 - "Reverse64": true, // go1.25 - "Reverse8": true, // go1.25 - "ReverseBytes16": true, // go1.25 - "ReverseBytes32": true, // go1.25 - "ReverseBytes64": true, // go1.25 - "RotateLeft": true, // go1.25 - "RotateLeft16": true, // go1.25 - "RotateLeft32": true, // go1.25 - "RotateLeft64": true, // go1.25 - "RotateLeft8": true, // go1.25 - "Sub": true, // go1.25 - "Sub64": true, // go1.25 - "TrailingZeros16": true, // go1.25 - "TrailingZeros32": true, // go1.25 - "TrailingZeros64": true, // go1.25 - "TrailingZeros8": true, // go1.25 + "Add": true, // go1.26 + "Add64": true, // go1.26 + "Div": true, // go1.26 + "Div64": true, // go1.26 + "Len": true, // go1.26 + "Len16": true, // go1.26 + "Len32": true, // go1.26 + "Len64": true, // go1.26 + "Len8": true, // go1.26 + "Mul": true, // go1.26 + "Mul64": true, // go1.26 + "OnesCount": true, // go1.26 + "OnesCount16": true, // go1.26 + "OnesCount32": true, // go1.26 + "OnesCount64": true, // go1.26 + "OnesCount8": true, // go1.26 + "Reverse": true, // go1.26 + "Reverse16": true, // go1.26 + "Reverse32": true, // go1.26 + "Reverse64": true, // go1.26 + "Reverse8": true, // go1.26 + "ReverseBytes16": true, // go1.26 + "ReverseBytes32": true, // go1.26 + "ReverseBytes64": true, // go1.26 + "RotateLeft": true, // go1.26 + "RotateLeft16": true, // go1.26 + "RotateLeft32": true, // go1.26 + "RotateLeft64": true, // go1.26 + "RotateLeft8": true, // go1.26 + "Sub": true, // go1.26 + "Sub64": true, // go1.26 + "TrailingZeros16": true, // go1.26 + "TrailingZeros32": true, // go1.26 + "TrailingZeros64": true, // go1.26 + "TrailingZeros8": true, // go1.26 }, "runtime": { - "publicationBarrier": true, // go1.25 + "KeepAlive": true, // go1.26 + "memequal": true, // go1.26 + "publicationBarrier": true, // go1.26 + "slicebytetostringtmp": true, // go1.26 }, "sync": { - "runtime_LoadAcquintptr": true, // go1.25 - "runtime_StoreReluintptr": true, // go1.25 + "runtime_LoadAcquintptr": true, // go1.26 + "runtime_StoreReluintptr": true, // go1.26 }, "sync/atomic": { - "AddInt32": true, // go1.25 - "AddInt64": true, // go1.25 - "AddUint32": true, // go1.25 - "AddUint64": true, // go1.25 - "AddUintptr": true, // go1.25 - "AndInt32": true, // go1.25 - "AndInt64": true, // go1.25 - "AndUint32": true, // go1.25 - "AndUint64": true, // go1.25 - "AndUintptr": true, // go1.25 - "CompareAndSwapInt32": true, // go1.25 - "CompareAndSwapInt64": true, // go1.25 - "CompareAndSwapUint32": true, // go1.25 - "CompareAndSwapUint64": true, // go1.25 - "CompareAndSwapUintptr": true, // go1.25 - "LoadInt32": true, // go1.25 - "LoadInt64": true, // go1.25 - "LoadPointer": true, // go1.25 - "LoadUint32": true, // go1.25 - "LoadUint64": true, // go1.25 - "LoadUintptr": true, // go1.25 - "OrInt32": true, // go1.25 - "OrInt64": true, // go1.25 - "OrUint32": true, // go1.25 - "OrUint64": true, // go1.25 - "OrUintptr": true, // go1.25 - "StoreInt32": true, // go1.25 - "StoreInt64": true, // go1.25 - "StoreUint32": true, // go1.25 - "StoreUint64": true, // go1.25 - "StoreUintptr": true, // go1.25 - "SwapInt32": true, // go1.25 - "SwapInt64": true, // go1.25 - "SwapUint32": true, // go1.25 - "SwapUint64": true, // go1.25 - "SwapUintptr": true, // go1.25 + "AddInt32": true, // go1.26 + "AddInt64": true, // go1.26 + "AddUint32": true, // go1.26 + "AddUint64": true, // go1.26 + "AddUintptr": true, // go1.26 + "AndInt32": true, // go1.26 + "AndInt64": true, // go1.26 + "AndUint32": true, // go1.26 + "AndUint64": true, // go1.26 + "AndUintptr": true, // go1.26 + "CompareAndSwapInt32": true, // go1.26 + "CompareAndSwapInt64": true, // go1.26 + "CompareAndSwapUint32": true, // go1.26 + "CompareAndSwapUint64": true, // go1.26 + "CompareAndSwapUintptr": true, // go1.26 + "LoadInt32": true, // go1.26 + "LoadInt64": true, // go1.26 + "LoadPointer": true, // go1.26 + "LoadUint32": true, // go1.26 + "LoadUint64": true, // go1.26 + "LoadUintptr": true, // go1.26 + "OrInt32": true, // go1.26 + "OrInt64": true, // go1.26 + "OrUint32": true, // go1.26 + "OrUint64": true, // go1.26 + "OrUintptr": true, // go1.26 + "StoreInt32": true, // go1.26 + "StoreInt64": true, // go1.26 + "StoreUint32": true, // go1.26 + "StoreUint64": true, // go1.26 + "StoreUintptr": true, // go1.26 + "SwapInt32": true, // go1.26 + "SwapInt64": true, // go1.26 + "SwapUint32": true, // go1.26 + "SwapUint64": true, // go1.26 + "SwapUintptr": true, // go1.26 }, } diff --git a/internal/linker/patches/go1.25/0001-add-custom-magic-value.patch b/internal/linker/patches/go1.26/0001-add-custom-magic-value.patch similarity index 84% rename from internal/linker/patches/go1.25/0001-add-custom-magic-value.patch rename to internal/linker/patches/go1.26/0001-add-custom-magic-value.patch index 1ce6dad..1aebf57 100644 --- a/internal/linker/patches/go1.25/0001-add-custom-magic-value.patch +++ b/internal/linker/patches/go1.26/0001-add-custom-magic-value.patch @@ -1,4 +1,4 @@ -From 1eb3d02d33155831067ca7db2c6517108c4305ae Mon Sep 17 00:00:00 2001 +From b59e8e940e82f488d5d688277046f6cd87c75908 Mon Sep 17 00:00:00 2001 From: pagran Date: Mon, 9 Jan 2023 13:30:00 +0100 Subject: [PATCH 1/3] add custom magic value @@ -8,7 +8,7 @@ Subject: [PATCH 1/3] add custom magic value 1 file changed, 17 insertions(+) diff --git a/cmd/link/internal/ld/pcln.go b/cmd/link/internal/ld/pcln.go -index ea08fd3d31..7bae9f18c5 100644 +index 08c4d4db83..ffe8fdf7a1 100644 --- a/cmd/link/internal/ld/pcln.go +++ b/cmd/link/internal/ld/pcln.go @@ -4,6 +4,10 @@ @@ -22,7 +22,7 @@ index ea08fd3d31..7bae9f18c5 100644 import ( "cmd/internal/goobj" "cmd/internal/objabi" -@@ -262,6 +266,19 @@ func (state *pclntab) generatePCHeader(ctxt *Link) { +@@ -282,6 +286,19 @@ func (state *pclntab) generatePCHeader(ctxt *Link) { if off != size { panic(fmt.Sprintf("pcHeader size: %d != %d", off, size)) } @@ -41,7 +41,7 @@ index ea08fd3d31..7bae9f18c5 100644 + header.SetUint32(ctxt.Arch, 0, garbleMagicVal) } - state.pcheader = state.addGeneratedSym(ctxt, "runtime.pcheader", size, writeHeader) + state.pcheader = state.addGeneratedSym(ctxt, "runtime.pcheader", size, int32(ctxt.Arch.PtrSize), writeHeader) -- -2.48.1 +2.53.0 diff --git a/internal/linker/patches/go1.25/0002-add-unexported-function-name-removing.patch b/internal/linker/patches/go1.26/0002-add-unexported-function-name-removing.patch similarity index 91% rename from internal/linker/patches/go1.25/0002-add-unexported-function-name-removing.patch rename to internal/linker/patches/go1.26/0002-add-unexported-function-name-removing.patch index 6839c27..91e4c24 100644 --- a/internal/linker/patches/go1.25/0002-add-unexported-function-name-removing.patch +++ b/internal/linker/patches/go1.26/0002-add-unexported-function-name-removing.patch @@ -1,4 +1,4 @@ -From 2a691e00bc659059133cd5604c7a099981cf684c Mon Sep 17 00:00:00 2001 +From 0d8063d9af410ceb914ba75b19a98686fe5f119c Mon Sep 17 00:00:00 2001 From: pagran Date: Mon, 9 Jan 2023 13:30:36 +0100 Subject: [PATCH 2/3] add unexported function name removing @@ -8,7 +8,7 @@ Subject: [PATCH 2/3] add unexported function name removing 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/cmd/link/internal/ld/pcln.go b/cmd/link/internal/ld/pcln.go -index 7bae9f18c5..b497573b15 100644 +index ffe8fdf7a1..c47b9eab72 100644 --- a/cmd/link/internal/ld/pcln.go +++ b/cmd/link/internal/ld/pcln.go @@ -8,6 +8,10 @@ import ( @@ -22,7 +22,7 @@ index 7bae9f18c5..b497573b15 100644 import ( "cmd/internal/goobj" "cmd/internal/objabi" -@@ -318,19 +322,56 @@ func walkFuncs(ctxt *Link, funcs []loader.Sym, f func(loader.Sym)) { +@@ -335,19 +339,56 @@ func walkFuncs(ctxt *Link, funcs []loader.Sym, f func(loader.Sym)) { func (state *pclntab) generateFuncnametab(ctxt *Link, funcs []loader.Sym) map[loader.Sym]uint32 { nameOffsets := make(map[loader.Sym]uint32, state.nfunc) @@ -79,7 +79,7 @@ index 7bae9f18c5..b497573b15 100644 + size += int64(len(name) + 1) // NULL terminate }) - state.funcnametab = state.addGeneratedSym(ctxt, "runtime.funcnametab", size, writeFuncNameTab) + state.funcnametab = state.addGeneratedSym(ctxt, "runtime.funcnametab", size, 1, writeFuncNameTab) -- -2.48.1 +2.53.0 diff --git a/internal/linker/patches/go1.25/0003-add-entryOff-encryption.patch b/internal/linker/patches/go1.26/0003-add-entryOff-encryption.patch similarity index 83% rename from internal/linker/patches/go1.25/0003-add-entryOff-encryption.patch rename to internal/linker/patches/go1.26/0003-add-entryOff-encryption.patch index b60a2b3..508204a 100644 --- a/internal/linker/patches/go1.25/0003-add-entryOff-encryption.patch +++ b/internal/linker/patches/go1.26/0003-add-entryOff-encryption.patch @@ -1,4 +1,4 @@ -From 03342e79193875d08bf3f88154e77a453b28c076 Mon Sep 17 00:00:00 2001 +From 16b978956b323d88ef4a48dbef124304f5206e90 Mon Sep 17 00:00:00 2001 From: pagran Date: Sat, 14 Jan 2023 21:36:16 +0100 Subject: [PATCH 3/3] add entryOff encryption @@ -8,11 +8,11 @@ Subject: [PATCH 3/3] add entryOff encryption 1 file changed, 20 insertions(+) diff --git a/cmd/link/internal/ld/pcln.go b/cmd/link/internal/ld/pcln.go -index b497573b15..f1021fcee3 100644 +index c47b9eab72..d58338f7c3 100644 --- a/cmd/link/internal/ld/pcln.go +++ b/cmd/link/internal/ld/pcln.go -@@ -806,6 +806,26 @@ func writeFuncs(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, inlSym - sb.SetUint32(ctxt.Arch, dataoff, uint32(ldr.SymValue(fdsym)-gofuncBase)) +@@ -980,6 +980,26 @@ func writeFuncs(ctxt *Link, sb *loader.SymbolBuilder, funcs []loader.Sym, inlSym + sb.SetUint32(ctxt.Arch, dataoff, uint32(ldr.SymValue(fdsym))) } } + @@ -39,5 +39,5 @@ index b497573b15..f1021fcee3 100644 // pclntab initializes the pclntab symbol with -- -2.48.1 +2.53.0 diff --git a/main.go b/main.go index ca5469b..6d04de3 100644 --- a/main.go +++ b/main.go @@ -544,8 +544,8 @@ func (f *seedFlag) Set(s string) error { func goVersionOK() bool { const ( - minGoVersion = "go1.25.0" // the minimum Go version we support; could be a bugfix release if needed - unsupportedGo = "go1.26" // the first major version we don't support + minGoVersion = "go1.26.0" // the minimum Go version we support; could be a bugfix release if needed + unsupportedGo = "go1.27" // the first major version we don't support ) toolchainVersion := sharedCache.GoEnv.GOVERSION diff --git a/runtime_patch.go b/runtime_patch.go index 4002b18..875a282 100644 --- a/runtime_patch.go +++ b/runtime_patch.go @@ -12,46 +12,30 @@ import ( ah "mvdan.cc/garble/internal/asthelper" ) -// updateMagicValue updates hardcoded value of hdr.magic -// when verifying header in symtab.go +// updateMagicValue updates the global constant +// `Go120PCLnTabMagic PCLnTabMagic = 0xfffffff1` +// to use the provided magic value integer. +// This is the latest magic value in use as of Go 1.26. func updateMagicValue(file *ast.File, magicValue uint32) { magicUpdated := false - // Find `hdr.magic != 0xfffffff?` in symtab.go and update to random magicValue - updateMagic := func(node ast.Node) bool { - binExpr, ok := node.(*ast.BinaryExpr) - if !ok || binExpr.Op != token.NEQ { - return true - } - - selectorExpr, ok := binExpr.X.(*ast.SelectorExpr) - if !ok { - return true - } - - if ident, ok := selectorExpr.X.(*ast.Ident); !ok || ident.Name != "hdr" { - return true - } - if selectorExpr.Sel.Name != "magic" { - return true - } - - if _, ok := binExpr.Y.(*ast.BasicLit); !ok { - return true - } - binExpr.Y = &ast.BasicLit{ - Kind: token.INT, - Value: strconv.FormatUint(uint64(magicValue), 10), - } - magicUpdated = true - return false - } - for _, decl := range file.Decls { - funcDecl, ok := decl.(*ast.FuncDecl) - if ok && funcDecl.Name.Name == "moduledataverify1" { - ast.Inspect(funcDecl, updateMagic) - break + decl, ok := decl.(*ast.GenDecl) + if !ok || decl.Tok != token.CONST { + continue + } + for _, spec := range decl.Specs { + spec, ok := spec.(*ast.ValueSpec) + if !ok || len(spec.Names) != 1 || len(spec.Values) != 1 { + continue + } + if spec.Names[0].Name == "Go120PCLnTabMagic" { + spec.Values[0] = &ast.BasicLit{ + Kind: token.INT, + Value: strconv.FormatUint(uint64(magicValue), 10), + } + magicUpdated = true + } } } diff --git a/scripts/gen_go_std_tables.go b/scripts/gen_go_std_tables.go index 03d29ec..613fbaf 100644 --- a/scripts/gen_go_std_tables.go +++ b/scripts/gen_go_std_tables.go @@ -37,7 +37,7 @@ var goPlatforms = []goPlatform{ {"darwin", "arm64", 2}, {"windows", "386", 3}, } -var goVersions = []string{"go1.25.8"} +var goVersions = []string{"go1.26.1"} var tmplTables = template.Must(template.New("").Parse(` // Code generated by scripts/gen_go_std_tables.go; DO NOT EDIT. @@ -173,7 +173,7 @@ func lines(vs versionedString) []versionedString { } var rxLinkname = regexp.MustCompile(`^//go:linkname .* ([^.]*)\.[^.]*$`) -var rxIntrinsic = regexp.MustCompile(`\b(addF|alias)\("([^"]*)", "([^"]*)",`) +var rxIntrinsic = regexp.MustCompile(`\b(add|addF|alias)\("([^"]*)", "([^"]*)",`) func main() { var runtimeAndDeps []versionedString diff --git a/testdata/script/goversion.txtar b/testdata/script/goversion.txtar index 7d5278e..f32caf2 100644 --- a/testdata/script/goversion.txtar +++ b/testdata/script/goversion.txtar @@ -7,12 +7,12 @@ env PATH=${WORK}/.bin${:}${PATH} # An empty go version. env TOOLCHAIN_GOVERSION='' ! exec garble build -stderr 'Go version is too old; please upgrade to go1\.25\.0 or newer' +stderr 'Go version is too old; please upgrade to go1\.26\.0 or newer' # A clearly invalid go version. env TOOLCHAIN_GOVERSION='bogus version' ! exec garble build -stderr 'Go version "bogus" appears to be invalid or too old; use go1\.25\.0 or newer' +stderr 'Go version "bogus" appears to be invalid or too old; use go1\.26\.0 or newer' # We should error on a devel version that's too old; # note that they started with the string "devel", @@ -26,64 +26,60 @@ stderr 'Go version .* appears to be invalid or too old' # A current devel version should be fine. # Note that we don't look at devel version timestamps. -env GARBLE_TEST_GOVERSION='go1.25.0' -# TODO: we do not currently bother with supporting tip. -# env TOOLCHAIN_GOVERSION='go version go1.26-devel_36863d6194 2025-10-17 01:07:59 -0700 linux/amd64' -# ! exec garble build -# stderr 'mocking the real build' +env GARBLE_TEST_GOVERSION='go1.26.0' # We should error on a stable version that's too old. env TOOLCHAIN_GOVERSION='go1.14' ! exec garble build -stderr 'Go version "go1\.14" is too old; please upgrade to go1\.25\.0 or newer' +stderr 'Go version "go1\.14" is too old; please upgrade to go1\.26\.0 or newer' # We should reject a future stable version, as we don't have linker patches yet. # Note that we need to bump the version of Go that supposedly built it, too. -env GARBLE_TEST_GOVERSION='go1.28.2' -env TOOLCHAIN_GOVERSION='go1.28.2' +env GARBLE_TEST_GOVERSION='go1.38.2' +env TOOLCHAIN_GOVERSION='go1.38.2' ! exec garble build -stderr 'Go version "go1\.28\.2" is too new; Go linker patches aren''t available for go1\.26 or later yet' +stderr 'Go version "go1\.38\.2" is too new; Go linker patches aren''t available for go1\.27 or later yet' # We should accept custom devel strings. -env TOOLCHAIN_GOVERSION='go1.25.0-somecustomversion' +env TOOLCHAIN_GOVERSION='go1.26.0-somecustomversion' ! exec garble build stderr 'mocking the real build' # A stable version with a build-time GOEXPERIMENT. # See: https://github.com/golang/go/issues/75953 -env TOOLCHAIN_GOVERSION='go1.25.0 X:nodwarf5' +env TOOLCHAIN_GOVERSION='go1.26.0 X:nodwarf5' ! exec garble build stderr 'mocking the real build' # The current toolchain may be older than the one that built garble. -env GARBLE_TEST_GOVERSION='go1.25.1' -env TOOLCHAIN_GOVERSION='go1.25.0' +env GARBLE_TEST_GOVERSION='go1.26.1' +env TOOLCHAIN_GOVERSION='go1.26.0' ! exec garble build stderr 'mocking the real build' # The current toolchain may be equal to the one that built garble. -env GARBLE_TEST_GOVERSION='go1.25.0' -env TOOLCHAIN_GOVERSION='go1.25.0' +env GARBLE_TEST_GOVERSION='go1.26.0' +env TOOLCHAIN_GOVERSION='go1.26.0' ! exec garble build stderr 'mocking the real build' # The current toolchain must not be newer than the one that built garble. env GARBLE_TEST_GOVERSION='go1.18' -env TOOLCHAIN_GOVERSION='go1.25.0' +env TOOLCHAIN_GOVERSION='go1.26.0' ! exec garble build -stderr 'garble was built with "go1\.18" and can''t be used with the newer "go1\.25\.0"; rebuild ' +stderr 'garble was built with "go1\.18" and can''t be used with the newer "go1\.26\.0"; rebuild ' # We'll error even if the difference is a minor (bugfix) level. # In practice it probably wouldn't matter, but in theory it could still lead to tricky bugs. -env GARBLE_TEST_GOVERSION='go1.25.11' -env TOOLCHAIN_GOVERSION='go1.25.14' +env GARBLE_TEST_GOVERSION='go1.26.11' +env TOOLCHAIN_GOVERSION='go1.26.14' ! exec garble build -stderr 'garble was built with "go1\.25\.11" and can''t be used with the newer "go1\.25\.14"; rebuild ' +stderr 'garble was built with "go1\.26\.11" and can''t be used with the newer "go1\.26\.14"; rebuild ' # If garble builds itself and is then used, it won't know what version built it. # As a fallback, we drop the comparison against the toolchain's version. env GARBLE_TEST_GOVERSION='bogus version' -env TOOLCHAIN_GOVERSION='go1.25.0' +env TOOLCHAIN_GOVERSION='go1.26.0' ! exec garble build stderr 'mocking the real build' -- go.mod -- diff --git a/transformer.go b/transformer.go index b45374b..d6da74a 100644 --- a/transformer.go +++ b/transformer.go @@ -695,16 +695,20 @@ func (tf *transformer) transformCompile(args []string) ([]string, error) { for i, file := range files { basename := filepath.Base(paths[i]) log.Printf("obfuscating %s", basename) - if tf.curPkg.ImportPath == "runtime" { + switch tf.curPkg.ImportPath { + case "runtime": if flagTiny { // strip unneeded runtime code stripRuntime(basename, file) tf.useAllImports(file) } if basename == "symtab.go" { - updateMagicValue(file, magicValue()) updateEntryOffset(file, entryOffKey()) } + case "internal/abi": + if basename == "symtab.go" { + updateMagicValue(file, magicValue()) + } } if err := tf.transformDirectives(file.Comments); err != nil { return nil, err