You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
garble/testdata/script/cgo.txtar

123 lines
2.0 KiB
Plaintext

[!cgo] skip 'this test requires cgo to be enabled'
garble build
! stderr 'warning' # check that the C toolchain is happy
exec ./main
cmp stdout main.stdout
! binsubstr main$exe 'PortedField' 'test/main'
[short] stop # no need to verify this with -short
# Ensure that reversing works with cgo.
env GARBLE_TEST_REVERSING=true
exec ./main
cp stdout reversing.stdout
stdin reversing.stdout
garble reverse .
cmp stdout reversed.stdout
env GARBLE_TEST_REVERSING=false
garble -tiny build
exec ./main
cmp stdout main.stdout
go build
! stderr 'warning' # check that the C toolchain is happy
exec ./main
cmp stdout main.stdout
stop loading obfuscated type information from deps If package P1 imports package P2, P1 needs to know which names from P2 weren't obfuscated. For instance, if P2 declares T2 and does "reflect.TypeOf(T2{...})", then P2 won't obfuscate the name T2, and neither should P1. This information should flow from P2 to P1, as P2 builds before P1. We do this via obfuscatedTypesPackage; P1 loads the type information of the obfuscated version of P2, and does a lookup for T2. If T2 exists, then it wasn't obfuscated. This mechanism has served us well, but it has downsides: 1) It wastes CPU; we load the type information for the entire package. 2) It's complex; for instance, we need KnownObjectFiles as an extra. 3) It makes our code harder to understand, as we load both the original and obfuscated type informaiton. Instead, we now have each package record what names were not obfuscated as part of its cachedOuput file. Much like KnownObjectFiles, the map records incrementally through the import graph, to avoid having to load cachedOutput files for indirect dependencies. We shouldn't need to worry about those maps getting large; we only skip obfuscating declared names in a few uncommon scenarios, such as the use of reflection or cgo's "//export". Since go/types is relatively allocation-heavy, and the export files contain a lot of data, we get a nice speed-up: name old time/op new time/op delta Build-16 11.5s ± 2% 11.1s ± 3% -3.77% (p=0.008 n=5+5) name old bin-B new bin-B delta Build-16 5.15M ± 0% 5.15M ± 0% ~ (all equal) name old cached-time/op new cached-time/op delta Build-16 375ms ± 3% 341ms ± 6% -8.96% (p=0.008 n=5+5) name old sys-time/op new sys-time/op delta Build-16 283ms ±17% 289ms ±13% ~ (p=0.841 n=5+5) name old user-time/op new user-time/op delta Build-16 687ms ± 6% 664ms ± 7% ~ (p=0.548 n=5+5) Fixes #456. Updates #475.
2 years ago
binsubstr main$exe 'privateAdd'
-- go.mod --
module test/main
go 1.20
-- main.go --
package main
func main() {
regularFunc()
cgoFunc()
}
-- regular_main.go --
package main
import (
"fmt"
"os"
"runtime"
)
func regularFunc() {
if os.Getenv("GARBLE_TEST_REVERSING") == "true" {
_, filename, _, _ := runtime.Caller(0)
fmt.Println("regular filename:", filename)
}
}
-- cgo_main.go --
package main
import (
"fmt"
"os"
"os/user"
"runtime"
)
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.
3 years ago
/*
#include "separate.h"
static int privateAdd(int a, int b) {
return a + b;
}
extern void goCallback();
static void callGoCallback() {
goCallback();
separateFunction();
}
struct portedStruct {
stop loading obfuscated type information from deps If package P1 imports package P2, P1 needs to know which names from P2 weren't obfuscated. For instance, if P2 declares T2 and does "reflect.TypeOf(T2{...})", then P2 won't obfuscate the name T2, and neither should P1. This information should flow from P2 to P1, as P2 builds before P1. We do this via obfuscatedTypesPackage; P1 loads the type information of the obfuscated version of P2, and does a lookup for T2. If T2 exists, then it wasn't obfuscated. This mechanism has served us well, but it has downsides: 1) It wastes CPU; we load the type information for the entire package. 2) It's complex; for instance, we need KnownObjectFiles as an extra. 3) It makes our code harder to understand, as we load both the original and obfuscated type informaiton. Instead, we now have each package record what names were not obfuscated as part of its cachedOuput file. Much like KnownObjectFiles, the map records incrementally through the import graph, to avoid having to load cachedOutput files for indirect dependencies. We shouldn't need to worry about those maps getting large; we only skip obfuscating declared names in a few uncommon scenarios, such as the use of reflection or cgo's "//export". Since go/types is relatively allocation-heavy, and the export files contain a lot of data, we get a nice speed-up: name old time/op new time/op delta Build-16 11.5s ± 2% 11.1s ± 3% -3.77% (p=0.008 n=5+5) name old bin-B new bin-B delta Build-16 5.15M ± 0% 5.15M ± 0% ~ (all equal) name old cached-time/op new cached-time/op delta Build-16 375ms ± 3% 341ms ± 6% -8.96% (p=0.008 n=5+5) name old sys-time/op new sys-time/op delta Build-16 283ms ±17% 289ms ±13% ~ (p=0.841 n=5+5) name old user-time/op new user-time/op delta Build-16 687ms ± 6% 664ms ± 7% ~ (p=0.548 n=5+5) Fixes #456. Updates #475.
2 years ago
char* PortedField;
};
*/
import "C"
func cgoFunc() {
fmt.Println(C.privateAdd(C.int(1), C.int(2)))
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.
3 years ago
_, _ = user.Current()
stop loading obfuscated type information from deps If package P1 imports package P2, P1 needs to know which names from P2 weren't obfuscated. For instance, if P2 declares T2 and does "reflect.TypeOf(T2{...})", then P2 won't obfuscate the name T2, and neither should P1. This information should flow from P2 to P1, as P2 builds before P1. We do this via obfuscatedTypesPackage; P1 loads the type information of the obfuscated version of P2, and does a lookup for T2. If T2 exists, then it wasn't obfuscated. This mechanism has served us well, but it has downsides: 1) It wastes CPU; we load the type information for the entire package. 2) It's complex; for instance, we need KnownObjectFiles as an extra. 3) It makes our code harder to understand, as we load both the original and obfuscated type informaiton. Instead, we now have each package record what names were not obfuscated as part of its cachedOuput file. Much like KnownObjectFiles, the map records incrementally through the import graph, to avoid having to load cachedOutput files for indirect dependencies. We shouldn't need to worry about those maps getting large; we only skip obfuscating declared names in a few uncommon scenarios, such as the use of reflection or cgo's "//export". Since go/types is relatively allocation-heavy, and the export files contain a lot of data, we get a nice speed-up: name old time/op new time/op delta Build-16 11.5s ± 2% 11.1s ± 3% -3.77% (p=0.008 n=5+5) name old bin-B new bin-B delta Build-16 5.15M ± 0% 5.15M ± 0% ~ (all equal) name old cached-time/op new cached-time/op delta Build-16 375ms ± 3% 341ms ± 6% -8.96% (p=0.008 n=5+5) name old sys-time/op new sys-time/op delta Build-16 283ms ±17% 289ms ±13% ~ (p=0.841 n=5+5) name old user-time/op new user-time/op delta Build-16 687ms ± 6% 664ms ± 7% ~ (p=0.548 n=5+5) Fixes #456. Updates #475.
2 years ago
st := C.struct_portedStruct{}
fmt.Println(st.PortedField == nil)
C.callGoCallback()
}
//export goCallback
func goCallback() {
fmt.Println("go callback")
// TODO: support reversing filenames in cgo files
if false && os.Getenv("GARBLE_TEST_REVERSING") == "true" {
_, filename, _, _ := runtime.Caller(0)
fmt.Println("cgo filename:", filename)
}
}
-- separate.h --
void separateFunction();
-- separate.c --
#include "_cgo_export.h"
void separateFunction() {
goCallback();
}
-- main.stdout --
3
stop loading obfuscated type information from deps If package P1 imports package P2, P1 needs to know which names from P2 weren't obfuscated. For instance, if P2 declares T2 and does "reflect.TypeOf(T2{...})", then P2 won't obfuscate the name T2, and neither should P1. This information should flow from P2 to P1, as P2 builds before P1. We do this via obfuscatedTypesPackage; P1 loads the type information of the obfuscated version of P2, and does a lookup for T2. If T2 exists, then it wasn't obfuscated. This mechanism has served us well, but it has downsides: 1) It wastes CPU; we load the type information for the entire package. 2) It's complex; for instance, we need KnownObjectFiles as an extra. 3) It makes our code harder to understand, as we load both the original and obfuscated type informaiton. Instead, we now have each package record what names were not obfuscated as part of its cachedOuput file. Much like KnownObjectFiles, the map records incrementally through the import graph, to avoid having to load cachedOutput files for indirect dependencies. We shouldn't need to worry about those maps getting large; we only skip obfuscating declared names in a few uncommon scenarios, such as the use of reflection or cgo's "//export". Since go/types is relatively allocation-heavy, and the export files contain a lot of data, we get a nice speed-up: name old time/op new time/op delta Build-16 11.5s ± 2% 11.1s ± 3% -3.77% (p=0.008 n=5+5) name old bin-B new bin-B delta Build-16 5.15M ± 0% 5.15M ± 0% ~ (all equal) name old cached-time/op new cached-time/op delta Build-16 375ms ± 3% 341ms ± 6% -8.96% (p=0.008 n=5+5) name old sys-time/op new sys-time/op delta Build-16 283ms ±17% 289ms ±13% ~ (p=0.841 n=5+5) name old user-time/op new user-time/op delta Build-16 687ms ± 6% 664ms ± 7% ~ (p=0.548 n=5+5) Fixes #456. Updates #475.
2 years ago
true
go callback
go callback
-- reversed.stdout --
regular filename: test/main/regular_main.go
3
true
go callback
go callback