Skip to content

Commit

Permalink
add linker patches for Go 1.23
Browse files Browse the repository at this point in the history
Rebasing the Go 1.22 patches on top of Go 1.23.0,
as published on burrowers/go-patches#7.

Updates #859.
  • Loading branch information
mvdan committed Sep 4, 2024
1 parent 6e35ed3 commit 04df5ea
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 2 deletions.
47 changes: 47 additions & 0 deletions internal/linker/patches/go1.23/0001-add-custom-magic-value.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
From a67db18d018b3626e80190cf33b5e7582b6e63cf Mon Sep 17 00:00:00 2001
From: pagran <[email protected]>
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

Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
From 05b8be787564fdcd9532e1aac5eca3ef41d4e0a1 Mon Sep 17 00:00:00 2001
From: pagran <[email protected]>
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

43 changes: 43 additions & 0 deletions internal/linker/patches/go1.23/0003-add-entryOff-encryption.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
From 6bb03c1a0c523530b29fe6fdc48ca8f24f0bb13c Mon Sep 17 00:00:00 2001
From: pagran <[email protected]>
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

2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ func (e errJustExit) Error() string { return fmt.Sprintf("exit: %d", e) }
func goVersionOK() bool {
const (
minGoVersion = "go1.22" // the first major version we support
maxGoVersion = "go1.23" // the first major version we don't support
maxGoVersion = "go1.24" // the first major version we don't support
)

// rxVersion looks for a version like "go1.2" or "go1.2.3" in `go env GOVERSION`.
Expand Down
2 changes: 1 addition & 1 deletion testdata/script/goversion.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ stderr 'Go version "go1\.14" is too old; please upgrade to go1\.22 or newer'
env GARBLE_TEST_GOVERSION='go1.28.2'
env TOOLCHAIN_GOVERSION='go1.28.2'
! exec garble build
stderr 'Go version "go1\.28\.2" is too new; Go linker patches aren''t available for go1\.23 or later yet'
stderr 'Go version "go1\.28\.2" is too new; Go linker patches aren''t available for go1\.24 or later yet'

# We should accept custom devel strings.
env TOOLCHAIN_GOVERSION='devel go1.22-somecustomversion'
Expand Down

0 comments on commit 04df5ea

Please sign in to comment.