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
}
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`.
buf.Write(remaining[:pkgStart])
// If the name was qualified, fetch the package, and write the
// 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
// one of its assembly files, and we currently do not always collect
// test packages in appendListedPackages for the sake of performance.
// 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
if asmPkgPath != "" && asmPkgPath != "runtime_test" {
var err error
lpkg, err = listPackage(goPkgPath)
if err != nil {
panic(err) // shouldn't happen
if asmPkgPath != "" && asmPkgPath != "main" && asmPkgPath != "runtime_test" {
if asmPkgPath != curPkg.Name {
goPkgPath := asmPkgPath
goPkgPath = strings.ReplaceAll(goPkgPath, string(asmPeriod), string(goPeriod))
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 {
// 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.
buf.WriteString(lpkg.obfuscatedImportPath())
} else {

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

Loading…
Cancel
Save