From 0d8063d9af410ceb914ba75b19a98686fe5f119c 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 ffe8fdf7a1..c47b9eab72 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"
@@ -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)
 
+	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, 1, writeFuncNameTab)
-- 
2.53.0

