support referencing package paths with periods in assembly

The test case is lifted from github.com/bytedance/sonic/internal/native,
which had the following line:

	JMP github·com∕bytedance∕sonic∕internal∕native∕avx2·__quote(SB)

Updates #621.
pull/635/head
Daniel Martí 1 year ago
parent 6ace03322f
commit 417bcf27bb

@ -715,18 +715,21 @@ func replaceAsmNames(buf *bytes.Buffer, remaining []byte) {
//
// TEXT ·privateAdd(SB),$0-24
// TEXT runtimeinternalsys·Ctz64(SB), NOSPLIT, $0-12
const middleDot = '·'
middleDotLen := utf8.RuneLen(middleDot)
//
// Note that import paths in assembly, like `runtimeinternalsys` above,
// use a Unicode slash rather than the ASCII one used by Go and `go list`.
// use Unicode periods and slashes rather than the ASCII ones used by `go list`.
// We need to convert to ASCII to find the right package information.
const asmPkgSlash = ''
const goPkgSlash = '/'
const (
asmPeriod = '·'
goPeriod = '.'
asmSlash = ''
goSlash = '/'
)
asmPeriodLen := utf8.RuneLen(asmPeriod)
for {
i := bytes.IndexRune(remaining, middleDot)
if i < 0 {
periodIdx := bytes.IndexRune(remaining, asmPeriod)
if periodIdx < 0 {
buf.Write(remaining)
remaining = nil
break
@ -734,16 +737,37 @@ func replaceAsmNames(buf *bytes.Buffer, remaining []byte) {
// The package name ends at the first rune which cannot be part of a Go
// import path, such as a comma or space.
pkgStart := i
pkgStart := periodIdx
for pkgStart >= 0 {
c, size := utf8.DecodeLastRune(remaining[:pkgStart])
if !unicode.IsLetter(c) && c != '_' && c != asmPkgSlash && !unicode.IsDigit(c) {
if !unicode.IsLetter(c) && c != '_' && c != asmSlash && !unicode.IsDigit(c) {
break
}
pkgStart -= size
}
asmPkgPath := string(remaining[pkgStart:i])
goPkgPath := strings.ReplaceAll(asmPkgPath, string(asmPkgSlash), string(goPkgSlash))
// The package name might actually be longer, e.g:
//
// JMP testwith·many·dotsmainimported·PublicAdd(SB)
//
// We have `testwith` so far; grab `·many·dotsmainimported` as well.
pkgEnd := periodIdx
lastAsmPeriod := -1
for i := pkgEnd + asmPeriodLen; i <= len(remaining); {
c, size := utf8.DecodeRune(remaining[i:])
if c == asmPeriod {
lastAsmPeriod = i
} else if !unicode.IsLetter(c) && c != '_' && c != asmSlash && !unicode.IsDigit(c) {
if lastAsmPeriod > 0 {
pkgEnd = lastAsmPeriod
}
break
}
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])
@ -771,8 +795,8 @@ func replaceAsmNames(buf *bytes.Buffer, remaining []byte) {
}
// Write the middle dot and advance the remaining slice.
buf.WriteRune(middleDot)
remaining = remaining[i+middleDotLen:]
buf.WriteRune(asmPeriod)
remaining = remaining[pkgEnd+asmPeriodLen:]
// The declared name ends at the first rune which cannot be part of a Go
// identifier, such as a comma or space.

@ -26,14 +26,14 @@ exec ./main
cmp stderr main.stderr
binsubstr main$exe 'privateAdd' 'PublicAdd'
-- go.mod --
module test/main
module test/with.many.dots/main
go 1.19
-- main.go --
package main
import (
"test/main/imported"
"test/with.many.dots/main/imported"
)
func privateAdd(x, y int32) int32
@ -56,17 +56,13 @@ func main() {
println(imported.PublicAdd(3, 4))
}
-- garble_main_amd64.s --
TEXT ·privateAdd(SB),$0-16
MOVL x+0(FP), BX
MOVL y+4(FP), BP
ADDL BP, BX
MOVL BX, ret+8(FP)
RET
#include "garble_define_amd64.h"
#include "extra/garble_define2_amd64.h"
TEXT ·privateAdd(SB),$0-16
JMP testwith·many·dotsmainimported·PublicAdd(SB)
TEXT ·modifyGoData(SB),$0-16
addGoDataTo($12)
ADDL $34, ·goData+8(SB)

Loading…
Cancel
Save