support assembly references to package names

Go's package runtime/internal/atomic contains references to functions
which refer to the current package by its package name alone:

	src/runtime/internal/atomic/atomic_loong64.s:   JMP atomic·Load(SB)
	src/runtime/internal/atomic/atomic_loong64.s:   JMP atomic·Load64(SB)
	src/runtime/internal/atomic/atomic_loong64.s:   JMP atomic·Load64(SB)
	src/runtime/internal/atomic/atomic_mips64x.s:   JMP atomic·Load(SB)
	src/runtime/internal/atomic/atomic_mips64x.s:   JMP atomic·Load64(SB)
	src/runtime/internal/atomic/atomic_mips64x.s:   JMP atomic·Load64(SB)

We could only handle unqualified or fully qualified references, like:

	JMP ·Load64(SB)
	JMP runtime∕internal∕atomic·Load64(SB)

Apparently, all three forms are equally valid.
Add a test case and fix it.

I checked whether referencing an imported package by its name worked;
it does not seem to be the case.
This feature appears to be restricted to the current package alone.

While here, we only need goPkgPath when we need to call listPackage.

Fixes #619.
pull/637/head
Daniel Martí 1 year ago
parent 7e95fcf1cb
commit 5dd6b2dc43

@ -787,28 +787,34 @@ func replaceAsmNames(buf *bytes.Buffer, remaining []byte) {
i += size i += size
} }
asmPkgPath := string(remaining[pkgStart:pkgEnd]) asmPkgPath := string(remaining[pkgStart:pkgEnd])
goPkgPath := asmPkgPath
goPkgPath = strings.ReplaceAll(goPkgPath, string(asmPeriod), string(goPeriod))
goPkgPath = strings.ReplaceAll(goPkgPath, string(asmSlash), string(goSlash))
// Write the bytes before our unqualified `·foo` or qualified `pkg·foo`. // Write the bytes before our unqualified `·foo` or qualified `pkg·foo`.
buf.Write(remaining[:pkgStart]) buf.Write(remaining[:pkgStart])
// If the name was qualified, fetch the package, and write the // If the name was qualified, fetch the package, and write the
// obfuscated import path if needed. // obfuscated import path if needed.
// Note that we don't obfuscate the package path "main".
//
// Note that runtime/internal/startlinetest refers to runtime_test in // Note that runtime/internal/startlinetest refers to runtime_test in
// one of its assembly files, and we currently do not always collect // one of its assembly files, and we currently do not always collect
// test packages in appendListedPackages for the sake of performance. // test packages in appendListedPackages for the sake of performance.
// We don't care about testing the runtime just yet, so work around it. // We don't care about testing the runtime just yet, so work around it.
// TODO(mvdan): this runtime_test reference was removed in Go 1.20 per
// https://github.com/golang/go/issues/57334; remove at a later time.
lpkg := curPkg lpkg := curPkg
if asmPkgPath != "" && asmPkgPath != "runtime_test" { if asmPkgPath != "" && asmPkgPath != "main" && asmPkgPath != "runtime_test" {
var err error if asmPkgPath != curPkg.Name {
lpkg, err = listPackage(goPkgPath) goPkgPath := asmPkgPath
if err != nil { goPkgPath = strings.ReplaceAll(goPkgPath, string(asmPeriod), string(goPeriod))
panic(err) // shouldn't happen goPkgPath = strings.ReplaceAll(goPkgPath, string(asmSlash), string(goSlash))
var err error
lpkg, err = listPackage(goPkgPath)
if err != nil {
panic(err) // shouldn't happen
}
} }
if lpkg.ToObfuscate { if lpkg.ToObfuscate {
// Note that we don't need to worry about asmPkgSlash here, // Note that we don't need to worry about asmSlash here,
// because our obfuscated import paths contain no slashes right now. // because our obfuscated import paths contain no slashes right now.
buf.WriteString(lpkg.obfuscatedImportPath()) buf.WriteString(lpkg.obfuscatedImportPath())
} else { } else {

@ -6,7 +6,7 @@
garble build garble build
exec ./main exec ./main
cmp stderr main.stderr cmp stderr main.stderr
! binsubstr main$exe 'test/main' 'privateAdd' 'PublicAdd' 'garble_' ! binsubstr main$exe 'test/main' 'addJmp' 'AddImpl' 'garble_'
# We used to panic on broken packages with assembly. # We used to panic on broken packages with assembly.
! garble build ./broken/... ! garble build ./broken/...
@ -24,12 +24,12 @@ stdin empty-reverse.txt
garble -tiny build garble -tiny build
exec ./main exec ./main
cmp stderr main.stderr cmp stderr main.stderr
! binsubstr main$exe 'privateAdd' 'PublicAdd' ! binsubstr main$exe 'addJmp' 'AddImpl'
go build go build
exec ./main exec ./main
cmp stderr main.stderr cmp stderr main.stderr
binsubstr main$exe 'privateAdd' 'PublicAdd' binsubstr main$exe 'addJmp' 'AddImpl'
-- go.mod -- -- go.mod --
module test/with.many.dots/main module test/with.many.dots/main
@ -41,7 +41,8 @@ import (
"test/with.many.dots/main/imported" "test/with.many.dots/main/imported"
) )
func privateAdd(x, y int32) int32 func addJmpPkgPath(x, y int32) int32
func addJmpPkgName(x, y int32) int32
// goData is used from both assembly and header files. // goData is used from both assembly and header files.
var goData = [4]uint64{1, 2, 3, 4} var goData = [4]uint64{1, 2, 3, 4}
@ -50,7 +51,8 @@ func modifyGoData()
func modifyGoData2() func modifyGoData2()
func main() { func main() {
println(privateAdd(1, 2)) println(addJmpPkgPath(1, 2))
println(addJmpPkgName(1, 2))
println(goData[0], goData[1]) println(goData[0], goData[1])
modifyGoData() modifyGoData()
@ -58,7 +60,7 @@ func main() {
modifyGoData2() modifyGoData2()
println(goData[0], goData[1]) println(goData[0], goData[1])
println(imported.PublicAdd(3, 4)) println(imported.AddImpl(3, 4))
} }
-- garble_main_amd64.s -- -- garble_main_amd64.s --
#include "garble_define_amd64.h" #include "garble_define_amd64.h"
@ -69,8 +71,13 @@ func main() {
// Or the same with leading whitespace: // Or the same with leading whitespace:
// A comment may include many·specialasm·runes and it's okay. // A comment may include many·specialasm·runes and it's okay.
TEXT ·privateAdd(SB),$0-16 // Reference an imported package by its package path.
JMP testwith·many·dotsmainimported·PublicAdd(SB) TEXT ·addJmpPkgPath(SB),$0-16
JMP testwith·many·dotsmainimported·AddImpl(SB)
// Reference the current package by its package name.
TEXT ·addJmpPkgName(SB),$0-16
JMP main·addJmpPkgPath(SB)
TEXT ·modifyGoData(SB),$0-16 TEXT ·modifyGoData(SB),$0-16
addGoDataTo($12) addGoDataTo($12)
@ -93,22 +100,34 @@ TEXT ·modifyGoData2(SB),$0-16
-- imported/imported.go -- -- imported/imported.go --
package imported package imported
func PublicAdd(x, y int32) int32 func AddImpl(x, y int32) int32
// Reference the current package by its package path.
func addJmpPkgPath(x, y int32) int32
// Reference the current package by its package path.
func addJmpPkgName(x, y int32) int32
-- imported/imported_amd64.s -- -- imported/imported_amd64.s --
TEXT ·PublicAdd(SB),$0-16 TEXT ·AddImpl(SB),$0-16
MOVL x+0(FP), BX MOVL x+0(FP), BX
MOVL y+4(FP), BP MOVL y+4(FP), BP
ADDL BP, BX ADDL BP, BX
MOVL BX, ret+8(FP) MOVL BX, ret+8(FP)
RET RET
TEXT ·addJmpPkgPath(SB),$0-16
JMP testwith·many·dotsmainimported·AddImpl(SB)
TEXT ·addJmpPkgName(SB),$0-16
JMP imported·AddImpl(SB)
-- broken/syntax/broken.go -- -- broken/syntax/broken.go --
package broken package broken
func PublicAdd func AddImpl
-- broken/asm/imported_amd64.s -- -- broken/asm/imported_amd64.s --
TEXT ·PublicAdd(SB),$0-16 TEXT ·AddImpl(SB),$0-16
MOVL x+0(FP), BX MOVL x+0(FP), BX
MOVL y+4(FP), BP MOVL y+4(FP), BP
ADDL BP, BX ADDL BP, BX
@ -117,10 +136,10 @@ TEXT ·PublicAdd(SB),$0-16
-- broken/asm/broken.go -- -- broken/asm/broken.go --
package broken package broken
func PublicAdd(x, y int32) MissingType func AddImpl(x, y int32) MissingType
-- broken/imported_amd64.s -- -- broken/imported_amd64.s --
TEXT ·PublicAdd(SB),$0-16 TEXT ·AddImpl(SB),$0-16
MOVL x+0(FP), BX MOVL x+0(FP), BX
MOVL y+4(FP), BP MOVL y+4(FP), BP
ADDL BP, BX ADDL BP, BX
@ -128,6 +147,7 @@ TEXT ·PublicAdd(SB),$0-16
RET RET
-- main.stderr -- -- main.stderr --
3 3
3
1 2 1 2
13 36 13 36
25 70 25 70

Loading…
Cancel
Save