fix a link issue when obfuscating complex cgo packages

The added test case, which is obfuscating and linking os/user, would fail
before this fix:

	> garble build
	[stderr]
	# test/main
	/usr/lib/go/pkg/tool/linux_amd64/link: running gcc failed: exit status 1
	/usr/bin/ld: $WORK/.tmp/go-link-073246656/go.o: in function `Chz0Yfs2._cgo_cmalloc':
	go.go:(.text+0x993cc): undefined reference to `Chz0Yfs2.runtime_throw'
	/usr/bin/ld: $WORK/.tmp/go-link-073246656/go.o: in function `Chz0Yfs2.tDfhQ8uK':
	go.go:(.text+0x99801): undefined reference to `Chz0Yfs2._cgo_runtime_gostring'
	/usr/bin/ld: go.go:(.text+0x9982a): undefined reference to `Chz0Yfs2._cgo_runtime_gostring'
	/usr/bin/ld: go.go:(.text+0x99853): undefined reference to `Chz0Yfs2._cgo_runtime_gostring'
	collect2: error: ld returned 1 exit status

The reason is that we would alter the linkname directives of cgo-generated
code, but we would not obfuscate the code itself at all.

The generated code would end up being transformed into:

	//go:linkname zh_oKZIy runtime.throw
	func runtime_throw(string)

One can clearly see the error there; handleDirectives obfuscated the
local linkname name, but since transformGo didn't run, the actual Go
declaration was not obfuscated in the same way. Thus, the linker fails
to find a function body for runtime_throw, and fails.

The solution is simple: handleDirectives assumes that it's running on
code being obfuscated, so only run it when transformGo is running.

We can also remove the cgo skip check in handleDirectives, as it never
runs on cgo-generated code now.

Fixes a number of build errors that have been noticed since
907aebd770.
pull/356/head
Daniel Martí 4 years ago committed by lu4p
parent 64317883c9
commit 68b39e8195

@ -680,9 +680,9 @@ func transformCompile(args []string) ([]string, error) {
newPaths := make([]string, 0, len(files))
for i, file := range files {
tf.handleDirectives(file.Comments)
name := filepath.Base(paths[i])
// TODO(mvdan): allow running handleDirectives and transformGo
// on runtime too, by splitting the conditionals here.
switch {
case curPkg.ImportPath == "runtime":
// strip unneeded runtime code
@ -704,6 +704,7 @@ func transformCompile(args []string) ([]string, error) {
case strings.HasPrefix(name, "_cgo_"):
// Don't obfuscate cgo code, since it's generated and it gets messy.
default:
tf.handleDirectives(file.Comments)
file = tf.transformGo(file)
}
if newPkgPath != "" {
@ -789,9 +790,6 @@ func (tf *transformer) handleDirectives(comments []*ast.CommentGroup) {
pkgPath, name = target[0], target[1]
}
if pkgPath == "runtime" && strings.HasPrefix(name, "cgo") {
continue // ignore cgo-generated linknames
}
lpkg, err := listPackage(pkgPath)
if err != nil {
// probably a made up symbol name, replace the comment

@ -7,6 +7,13 @@ binsubstr main$exe 'privateAdd'
[short] stop # no need to verify this with -short
env GOPRIVATE=*
garble build
exec ./main
cmp stderr main.stderr
binsubstr main$exe 'privateAdd'
env GOPRIVATE=test/main
garble -tiny build
exec ./main
cmp stderr main.stderr
@ -23,6 +30,8 @@ go 1.16
-- main.go --
package main
import "os/user"
/*
static int privateAdd(int a, int b) {
return a + b;
@ -32,6 +41,7 @@ import "C"
func main() {
println(C.privateAdd(C.int(1), C.int(2)))
_, _ = user.Current()
}
-- main.stderr --
3

Loading…
Cancel
Save