Skip to content

Commit

Permalink
add unexported func name removing for tiny mode
Browse files Browse the repository at this point in the history
  • Loading branch information
pagran committed Jan 9, 2023
1 parent 2519657 commit 0ad83c1
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 2 deletions.
1 change: 1 addition & 0 deletions internal/linker/linker.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (

const (
MagicValueEnv = "GARBLE_LINKER_MAGIC"
TinyEnv = "GARBLE_LINK_TINY"

cacheDirName = "garble"
versionExt = ".version"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
From fa9696c29047882eb54344ce911ecf02c7281247 Mon Sep 17 00:00:00 2001
From: pagran <pagran@protonmail.com>
Date: Mon, 9 Jan 2023 00:03:05 +0100
Subject: [PATCH] add unexported function name removing

---
cmd/link/internal/ld/pcln.go | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)

diff --git a/cmd/link/internal/ld/pcln.go b/cmd/link/internal/ld/pcln.go
index 1ec237ffc8..e1bea2032c 100644
--- a/cmd/link/internal/ld/pcln.go
+++ b/cmd/link/internal/ld/pcln.go
@@ -321,10 +321,19 @@ func (state *pclntab) generateFuncnametab(ctxt *Link, funcs []loader.Sym) map[lo
return name[:i], "[...]", name[j+1:]
}

+ garbleIsRemove := os.Getenv("GARBLE_LINK_TINY") == "true"
+
// Write the null terminated strings.
writeFuncNameTab := func(ctxt *Link, s loader.Sym) {
symtab := ctxt.loader.MakeSymbolUpdater(s)
+ if garbleIsRemove {
+ symtab.AddStringAt(0, "")
+ }
+
for s, off := range nameOffsets {
+ if garbleIsRemove && off == 0 {
+ continue
+ }
a, b, c := nameParts(ctxt.loader.SymName(s))
o := int64(off)
o = symtab.AddStringAt(o, a)
@@ -335,7 +344,25 @@ func (state *pclntab) generateFuncnametab(ctxt *Link, funcs []loader.Sym) map[lo

// Loop through the CUs, and calculate the size needed.
var size int64
+
+ if garbleIsRemove {
+ size = 1 // first byte is reserved for empty string used for all non-exportable method names
+ }
+ garbleIsUnexported := func(s loader.Sym) bool {
+ name, _, _ := nameParts(ctxt.loader.SymName(s))
+ if name[len(name)-1] == '.' {
+ return true
+ }
+ c := name[strings.LastIndexByte(name, '.')+1]
+ return 'a' <= c && c <= 'z'
+ }
+
walkFuncs(ctxt, funcs, func(s loader.Sym) {
+ if garbleIsRemove && garbleIsUnexported(s) {
+ nameOffsets[s] = 0 // redirect name to empty string
+ return
+ }
+
nameOffsets[s] = uint32(size)
a, b, c := nameParts(ctxt.loader.SymName(s))
size += int64(len(a) + len(b) + len(c) + 1) // NULL terminate
--
2.38.1.windows.1

3 changes: 3 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,9 @@ func mainErr(args []string) error {

executablePath = modifiedLinkPath
os.Setenv(linker.MagicValueEnv, strconv.FormatUint(uint64(magicValue()), 10))
if flagTiny {
os.Setenv(linker.TinyEnv, "true")
}

log.Printf("replaced linker with: %s", executablePath)
}
Expand Down
30 changes: 28 additions & 2 deletions testdata/script/tiny.txtar
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ stderr '^caller: \?\? 1$' # position info is removed
stderr '^recovered: ya like jazz?'
! stderr '^init runtime' # GODEBUG prints are hidden, like inittrace=1
! stderr 'panic: oh noes' # panics are hidden

stderr 'funcExported false funcUnexported true'
stderr 'funcStructExported false funcStructUnexported true'

[short] stop # no need to verify this with -short

Expand All @@ -21,16 +22,41 @@ garble build
stderr '^caller: [0-9a-zA-Z_]+\.go [1-9]'
stderr '^recovered: ya like jazz?'
stderr 'panic: oh noes'
stderr 'funcExported false funcUnexported false'
stderr 'funcStructExported false funcStructUnexported false'
-- go.mod --
module test/main

go 1.19
-- garble_main.go --
package main

import "runtime"
import (
"reflect"
"runtime"
)

type testStruct struct {}

func (testStruct) unexportedFunc() { println("dummy") }

func (testStruct) ExportedFunc() { println("dummy") }

func ExportedFunc() { println("dummy") }

func unexportedFunc() { println("dummy") }

func isEmptyFuncName(i interface{}) bool {
name := runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
return len(name) == 0
}

func main() {
println("funcExported", isEmptyFuncName(ExportedFunc), "funcUnexported", isEmptyFuncName(unexportedFunc))

var s testStruct
println("funcStructExported", isEmptyFuncName(s.ExportedFunc), "funcStructUnexported", isEmptyFuncName(s.unexportedFunc))

var v any = "tada"
println(v)

Expand Down

0 comments on commit 0ad83c1

Please sign in to comment.