drop support for Go 1.23

A pretty small patch, given that 1.23 and 1.24 are quite similar
in terms of what garble does.
master
Daniel Martí 5 days ago committed by Paul Scheduikat
parent ad998763a2
commit ffed9e5438

@ -2,7 +2,7 @@
go install mvdan.cc/garble@latest
Obfuscate Go code by wrapping the Go toolchain. Requires Go 1.23.5 or later.
Obfuscate Go code by wrapping the Go toolchain. Requires Go 1.24 or later.
garble build [build flags] [packages]

@ -1,8 +1,6 @@
module mvdan.cc/garble
// Before the .5 bugfix release, alias tracking via go/types
// was broken; see https://go.dev/issue/70517.
go 1.23.5
go 1.24
require (
github.com/bluekeyes/go-gitdiff v0.8.1

@ -1,6 +1,6 @@
// Code generated by scripts/gen_go_std_tables.go; DO NOT EDIT.
// Generated from Go versions [go1.23.7 go1.24.1].
// Generated from Go versions [go1.24.1].
package main
@ -27,8 +27,6 @@ var runtimeAndDeps = map[string]bool{
"internal/runtime/syscall": true, // go1.24
"internal/stringslite": true, // go1.24
"runtime": true, // go1.24
"runtime/internal/math": true, // go1.23
"runtime/internal/sys": true, // go1.23
"unsafe": true, // go1.24
}
@ -49,7 +47,6 @@ var runtimeLinknamed = []string{
"internal/synctest", // go1.24
"internal/syscall/unix", // go1.24
"internal/syscall/windows", // go1.24
"internal/weak", // go1.23
"maps", // go1.24
"os", // go1.24
"os/signal", // go1.24
@ -134,8 +131,6 @@ var compilerIntrinsics = map[string]map[string]bool{
"ctrlGroupMatchH2": true, // go1.24
},
"internal/runtime/math": {
"Add64": true, // go1.24
"Mul64": true, // go1.24
"MulUintptr": true, // go1.24
},
"internal/runtime/sys": {
@ -204,22 +199,6 @@ var compilerIntrinsics = map[string]map[string]bool{
"runtime": {
"publicationBarrier": true, // go1.24
},
"runtime/internal/math": {
"Add64": true, // go1.23
"Mul64": true, // go1.23
},
"runtime/internal/sys": {
"Bswap32": true, // go1.23
"Bswap64": true, // go1.23
"Len64": true, // go1.23
"Len8": true, // go1.23
"OnesCount64": true, // go1.23
"Prefetch": true, // go1.23
"PrefetchStreamed": true, // go1.23
"TrailingZeros32": true, // go1.23
"TrailingZeros64": true, // go1.23
"TrailingZeros8": true, // go1.23
},
"sync": {
"runtime_LoadAcquintptr": true, // go1.24
"runtime_StoreReluintptr": true, // go1.24

@ -1,47 +0,0 @@
From a67db18d018b3626e80190cf33b5e7582b6e63cf Mon Sep 17 00:00:00 2001
From: pagran <pagran@protonmail.com>
Date: Mon, 9 Jan 2023 13:30:00 +0100
Subject: [PATCH 1/3] add custom magic value
---
cmd/link/internal/ld/pcln.go | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/cmd/link/internal/ld/pcln.go b/cmd/link/internal/ld/pcln.go
index 57c88c03af..c09ae07e33 100644
--- a/cmd/link/internal/ld/pcln.go
+++ b/cmd/link/internal/ld/pcln.go
@@ -4,6 +4,10 @@
package ld
+import (
+ "os"
+)
+
import (
"cmd/internal/goobj"
"cmd/internal/objabi"
@@ -262,6 +266,19 @@ func (state *pclntab) generatePCHeader(ctxt *Link) {
if off != size {
panic(fmt.Sprintf("pcHeader size: %d != %d", off, size))
}
+
+ // Use garble prefix in variable names to minimize collision risk
+ garbleMagicStr := os.Getenv("GARBLE_LINK_MAGIC")
+ if garbleMagicStr == "" {
+ panic("[garble] magic value must be set")
+ }
+ var garbleMagicVal uint32
+ // Use fmt package instead of strconv to avoid importing a new package
+ if _, err := fmt.Sscan(garbleMagicStr, &garbleMagicVal); err != nil {
+ panic(fmt.Errorf("[garble] invalid magic value %s: %v", garbleMagicStr, err))
+ }
+
+ header.SetUint32(ctxt.Arch, 0, garbleMagicVal)
}
state.pcheader = state.addGeneratedSym(ctxt, "runtime.pcheader", size, writeHeader)
--
2.46.0

@ -1,85 +0,0 @@
From 05b8be787564fdcd9532e1aac5eca3ef41d4e0a1 Mon Sep 17 00:00:00 2001
From: pagran <pagran@protonmail.com>
Date: Mon, 9 Jan 2023 13:30:36 +0100
Subject: [PATCH 2/3] add unexported function name removing
---
cmd/link/internal/ld/pcln.go | 43 +++++++++++++++++++++++++++++++++++-
1 file changed, 42 insertions(+), 1 deletion(-)
diff --git a/cmd/link/internal/ld/pcln.go b/cmd/link/internal/ld/pcln.go
index c09ae07e33..056a1d3a72 100644
--- a/cmd/link/internal/ld/pcln.go
+++ b/cmd/link/internal/ld/pcln.go
@@ -8,6 +8,10 @@ import (
"os"
)
+import (
+ "unicode"
+)
+
import (
"cmd/internal/goobj"
"cmd/internal/objabi"
@@ -318,19 +322,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)
+ garbleTiny := os.Getenv("GARBLE_LINK_TINY") == "true"
+
// Write the null terminated strings.
writeFuncNameTab := func(ctxt *Link, s loader.Sym) {
symtab := ctxt.loader.MakeSymbolUpdater(s)
+ if garbleTiny {
+ symtab.AddStringAt(0, "")
+ }
+
for s, off := range nameOffsets {
+ if garbleTiny && off == 0 {
+ continue
+ }
symtab.AddCStringAt(int64(off), ctxt.loader.SymName(s))
}
}
// Loop through the CUs, and calculate the size needed.
var size int64
+
+ if garbleTiny {
+ size = 1 // first byte is reserved for empty string used for all non-exportable method names
+ }
+ // Kinds of SymNames found in the wild:
+ //
+ // * reflect.Value.CanAddr
+ // * reflect.(*Value).String
+ // * reflect.w6cEoKc
+ // * internal/abi.(*RegArgs).IntRegArgAddr
+ // * type:.eq.runtime.special
+ // * runtime/internal/atomic.(*Pointer[go.shape.string]).Store
+ //
+ // Checking whether the first rune after the last dot is uppercase seems enough.
+ isExported := func(name string) bool {
+ for _, r := range name[strings.LastIndexByte(name, '.')+1:] {
+ return unicode.IsUpper(r)
+ }
+ return false
+ }
+
walkFuncs(ctxt, funcs, func(s loader.Sym) {
+ name := ctxt.loader.SymName(s)
+
+ if garbleTiny && !isExported(name) {
+ nameOffsets[s] = 0 // redirect name to empty string
+ return
+ }
+
nameOffsets[s] = uint32(size)
- size += int64(len(ctxt.loader.SymName(s)) + 1) // NULL terminate
+ size += int64(len(name) + 1) // NULL terminate
})
state.funcnametab = state.addGeneratedSym(ctxt, "runtime.funcnametab", size, writeFuncNameTab)
--
2.46.0

@ -1,43 +0,0 @@
From 6bb03c1a0c523530b29fe6fdc48ca8f24f0bb13c Mon Sep 17 00:00:00 2001
From: pagran <pagran@protonmail.com>
Date: Sat, 14 Jan 2023 21:36:16 +0100
Subject: [PATCH 3/3] add entryOff encryption
---
cmd/link/internal/ld/pcln.go | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/cmd/link/internal/ld/pcln.go b/cmd/link/internal/ld/pcln.go
index 056a1d3a72..37226d0327 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))
}
}
+
+ // Moving next code higher is not recommended.
+ // Only at the end of the current function no edits between go versions
+ garbleEntryOffKeyStr := os.Getenv("GARBLE_LINK_ENTRYOFF_KEY")
+ if garbleEntryOffKeyStr == "" {
+ panic("[garble] entryOff key must be set")
+ }
+ var garbleEntryOffKey uint32
+ // Use fmt package instead of strconv to avoid importing a new package
+ if _, err := fmt.Sscan(garbleEntryOffKeyStr, &garbleEntryOffKey); err != nil {
+ panic(fmt.Errorf("[garble] invalid entryOff key %s: %v", garbleEntryOffKeyStr, err))
+ }
+
+ garbleData := sb.Data()
+ for _, off := range startLocations {
+ entryOff := ctxt.Arch.ByteOrder.Uint32(garbleData[off:])
+ nameOff := ctxt.Arch.ByteOrder.Uint32(garbleData[off+4:])
+
+ sb.SetUint32(ctxt.Arch, int64(off), entryOff^(nameOff*garbleEntryOffKey))
+ }
}
// pclntab initializes the pclntab symbol with
--
2.46.0

@ -291,8 +291,8 @@ func (e errJustExit) Error() string { return fmt.Sprintf("exit: %d", e) }
func goVersionOK() bool {
const (
minGoVersion = "go1.23.5" // the minimum Go version we support; could be a bugfix release if needed
unsupportedGo = "go1.25" // the first major version we don't support
minGoVersion = "go1.24" // the minimum Go version we support; could be a bugfix release if needed
unsupportedGo = "go1.25" // the first major version we don't support
)
// rxVersion looks for a version like "go1.2" or "go1.2.3" in `go env GOVERSION`.

@ -21,7 +21,7 @@ import (
"text/template"
)
var goVersions = []string{"go1.23.7", "go1.24.1"}
var goVersions = []string{"go1.24.1"}
var tmplTables = template.Must(template.New("").Parse(`
// Code generated by scripts/gen_go_std_tables.go; DO NOT EDIT.
@ -158,7 +158,7 @@ func main() {
panic(err)
}
for _, goFile := range runtimeGoFiles {
for _, line := range strings.Split(readFile(goFile), "\n") {
for line := range strings.SplitSeq(readFile(goFile), "\n") {
m := rxLinkname.FindStringSubmatch(line)
if m == nil {
continue
@ -189,13 +189,8 @@ func main() {
compilerIntrinsicsIndexByPath := make(map[string]int)
var compilerIntrinsics []tmplIntrinsic
for _, goroot := range goroots {
// Go 1.24 moved the "alias" intrinsic calls from ssa.go to intrinsics.go.
name := "ssa.go"
if goroot.GoVersionLang == "go1.24" {
name = "intrinsics.go"
}
for _, line := range strings.Split(readFile(filepath.Join(
goroot.String, "src", "cmd", "compile", "internal", "ssagen", name,
for line := range strings.SplitSeq(readFile(filepath.Join(
goroot.String, "src", "cmd", "compile", "internal", "ssagen", "intrinsics.go",
)), "\n") {
m := rxIntrinsic.FindStringSubmatch(line)
if m == nil {

@ -7,31 +7,31 @@ 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\.23\.5 or newer'
stderr 'Go version is too old; please upgrade to go1\.24 or newer'
# We should error on a devel version that's too old.
# Note that they lacked the "goN.M-" prefix.
env TOOLCHAIN_GOVERSION='devel +afb5fca Sun Aug 07 00:00:00 2020 +0000'
! exec garble build
stderr 'Go version is too old; please upgrade to go1\.23\.5 or newer'
stderr 'Go version is too old; please upgrade to go1\.24 or newer'
# Another form of old version; with an old "goN.M-" prefix.
env TOOLCHAIN_GOVERSION='devel go1.15-afb5fca Sun Aug 07 00:00:00 2020 +0000'
! exec garble build
stderr 'Go version "devel go1\.15-.*2020.*" is too old; please upgrade to go1\.23'
stderr 'Go version "devel go1\.15-.*2020.*" is too old; please upgrade to go1\.24 or newer'
# A current devel version should be fine.
# Note that we don't look at devel version timestamps.
env GARBLE_TEST_GOVERSION='go1.23.5'
env GARBLE_TEST_GOVERSION='go1.24.5'
# TODO: temporarily disabled while we do not support tip.
# env TOOLCHAIN_GOVERSION='devel go1.23-ad97d204f0 Sun Sep 12 16:46:58 2023 +0000'
# env TOOLCHAIN_GOVERSION='devel go1.24-ad97d204f0 Sun Sep 12 16:46:58 2023 +0000'
# ! exec garble build
# stderr 'mocking the real build'
# 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\.23\.5 or newer'
stderr 'Go version "go1\.14" is too old; please upgrade to go1\.24 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.
@ -41,39 +41,39 @@ env TOOLCHAIN_GOVERSION='go1.28.2'
stderr 'Go version "go1\.28\.2" is too new; Go linker patches aren''t available for go1\.25 or later yet'
# We should accept custom devel strings.
env TOOLCHAIN_GOVERSION='devel go1.23.5-somecustomversion'
env TOOLCHAIN_GOVERSION='devel go1.24.5-somecustomversion'
! 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.23.22'
env TOOLCHAIN_GOVERSION='go1.23.21'
env GARBLE_TEST_GOVERSION='go1.24.22'
env TOOLCHAIN_GOVERSION='go1.24.21'
! 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.23.25'
env TOOLCHAIN_GOVERSION='go1.23.25'
env GARBLE_TEST_GOVERSION='go1.24.25'
env TOOLCHAIN_GOVERSION='go1.24.25'
! 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.23.25'
env TOOLCHAIN_GOVERSION='go1.24.25'
! exec garble build
stderr 'garble was built with "go1\.18" and can''t be used with the newer "go1\.23\.25"; rebuild '
stderr 'garble was built with "go1\.18" and can''t be used with the newer "go1\.24\.25"; 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.23.11'
env TOOLCHAIN_GOVERSION='go1.23.14'
env GARBLE_TEST_GOVERSION='go1.24.11'
env TOOLCHAIN_GOVERSION='go1.24.14'
! exec garble build
stderr 'garble was built with "go1\.23\.11" and can''t be used with the newer "go1\.23\.14"; rebuild '
stderr 'garble was built with "go1\.24\.11" and can''t be used with the newer "go1\.24\.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.23.25'
env TOOLCHAIN_GOVERSION='go1.24.25'
! exec garble build
stderr 'mocking the real build'
-- go.mod --

Loading…
Cancel
Save