1
0
mirror of https://github.com/golang/go synced 2024-11-26 10:48:22 -07:00

cmd/cgo, cmd/internal/pkgpath: support gofrontend mangler v3

The gofrontend mangling scheme used by gccgo and GoLLVM has changed again.
Support the new version. This is a port of the relevant parts of
https://golang.org/cl/271726.

For #41862

Change-Id: I9c961c8e17ec960a83a23e1d49ea900962b63393
Reviewed-on: https://go-review.googlesource.com/c/go/+/272127
Trust: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
This commit is contained in:
Ian Lance Taylor 2020-11-20 12:54:18 -08:00
parent 3fd4917472
commit c47eac7db0
3 changed files with 98 additions and 15 deletions

View File

@ -186,7 +186,7 @@ func (p *Package) writeDefs() {
panic(fmt.Errorf("invalid var kind %q", n.Kind)) panic(fmt.Errorf("invalid var kind %q", n.Kind))
} }
if *gccgo { if *gccgo {
fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, n.Mangle) fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, gccgoToSymbol(n.Mangle))
fmt.Fprintf(&gccgoInit, "\t%s = &%s;\n", n.Mangle, n.C) fmt.Fprintf(&gccgoInit, "\t%s = &%s;\n", n.Mangle, n.C)
fmt.Fprintf(fc, "\n") fmt.Fprintf(fc, "\n")
} }
@ -1148,7 +1148,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
// will not be able to link against it from the C // will not be able to link against it from the C
// code. // code.
goName := "Cgoexp_" + exp.ExpName goName := "Cgoexp_" + exp.ExpName
fmt.Fprintf(fgcc, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName) fmt.Fprintf(fgcc, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, gccgoToSymbol(goName))
fmt.Fprint(fgcc, "\n") fmt.Fprint(fgcc, "\n")
fmt.Fprint(fgcc, "\nCGO_NO_SANITIZE_THREAD\n") fmt.Fprint(fgcc, "\nCGO_NO_SANITIZE_THREAD\n")
@ -1182,7 +1182,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
fmt.Fprint(fgcc, "}\n") fmt.Fprint(fgcc, "}\n")
// Dummy declaration for _cgo_main.c // Dummy declaration for _cgo_main.c
fmt.Fprintf(fm, `char %s[1] __asm__("%s.%s");`, goName, gccgoSymbolPrefix, goName) fmt.Fprintf(fm, `char %s[1] __asm__("%s.%s");`, goName, gccgoSymbolPrefix, gccgoToSymbol(goName))
fmt.Fprint(fm, "\n") fmt.Fprint(fm, "\n")
// For gccgo we use a wrapper function in Go, in order // For gccgo we use a wrapper function in Go, in order
@ -1266,9 +1266,8 @@ func (p *Package) writeExportHeader(fgcch io.Writer) {
fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog()) fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
} }
// gccgoPkgpathToSymbol converts a package path to a mangled packagepath // gccgoToSymbol converts a name to a mangled symbol for gccgo.
// symbol. func gccgoToSymbol(ppath string) string {
func gccgoPkgpathToSymbol(ppath string) string {
if gccgoMangler == nil { if gccgoMangler == nil {
var err error var err error
cmd := os.Getenv("GCCGO") cmd := os.Getenv("GCCGO")
@ -1293,12 +1292,12 @@ func (p *Package) gccgoSymbolPrefix() string {
} }
if *gccgopkgpath != "" { if *gccgopkgpath != "" {
return gccgoPkgpathToSymbol(*gccgopkgpath) return gccgoToSymbol(*gccgopkgpath)
} }
if *gccgoprefix == "" && p.PackageName == "main" { if *gccgoprefix == "" && p.PackageName == "main" {
return "main" return "main"
} }
prefix := gccgoPkgpathToSymbol(*gccgoprefix) prefix := gccgoToSymbol(*gccgoprefix)
if prefix == "" { if prefix == "" {
prefix = "go" prefix = "go"
} }
@ -1687,8 +1686,12 @@ void _cgoPREFIX_Cfunc__Cmalloc(void *v) {
` `
func (p *Package) cPrologGccgo() string { func (p *Package) cPrologGccgo() string {
return strings.Replace(strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1), r := strings.NewReplacer(
"GCCGOSYMBOLPREF", p.gccgoSymbolPrefix(), -1) "PREFIX", cPrefix,
"GCCGOSYMBOLPREF", p.gccgoSymbolPrefix(),
"_cgoCheckPointer", gccgoToSymbol("_cgoCheckPointer"),
"_cgoCheckResult", gccgoToSymbol("_cgoCheckResult"))
return r.Replace(cPrologGccgo)
} }
const cPrologGccgo = ` const cPrologGccgo = `

View File

@ -50,9 +50,12 @@ func ToSymbolFunc(cmd, tmpdir string) (func(string) string, error) {
return nil, err return nil, err
} }
// New mangling: expect go.l..u00e4ufer.Run // Original mangling: go.l__ufer.Run
// Old mangling: expect go.l__ufer.Run // Mangling v2: go.l..u00e4ufer.Run
if bytes.Contains(buf, []byte("go.l..u00e4ufer.Run")) { // Mangling v3: go_0l_u00e4ufer.Run
if bytes.Contains(buf, []byte("go_0l_u00e4ufer.Run")) {
return toSymbolV3, nil
} else if bytes.Contains(buf, []byte("go.l..u00e4ufer.Run")) {
return toSymbolV2, nil return toSymbolV2, nil
} else if bytes.Contains(buf, []byte("go.l__ufer.Run")) { } else if bytes.Contains(buf, []byte("go.l__ufer.Run")) {
return toSymbolV1, nil return toSymbolV1, nil
@ -82,7 +85,7 @@ func toSymbolV1(ppath string) string {
return strings.Map(clean, ppath) return strings.Map(clean, ppath)
} }
// toSymbolV2 converts a package path using the newer mangling scheme. // toSymbolV2 converts a package path using the second mangling scheme.
func toSymbolV2(ppath string) string { func toSymbolV2(ppath string) string {
// This has to build at boostrap time, so it has to build // This has to build at boostrap time, so it has to build
// with Go 1.4, so we don't use strings.Builder. // with Go 1.4, so we don't use strings.Builder.
@ -112,3 +115,60 @@ func toSymbolV2(ppath string) string {
} }
return string(bsl) return string(bsl)
} }
// v3UnderscoreCodes maps from a character that supports an underscore
// encoding to the underscore encoding character.
var v3UnderscoreCodes = map[byte]byte{
'_': '_',
'.': '0',
'/': '1',
'*': '2',
',': '3',
'{': '4',
'}': '5',
'[': '6',
']': '7',
'(': '8',
')': '9',
'"': 'a',
' ': 'b',
';': 'c',
}
// toSymbolV3 converts a package path using the third mangling scheme.
func toSymbolV3(ppath string) string {
// This has to build at boostrap time, so it has to build
// with Go 1.4, so we don't use strings.Builder.
bsl := make([]byte, 0, len(ppath))
changed := false
for _, c := range ppath {
if ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || ('0' <= c && c <= '9') {
bsl = append(bsl, byte(c))
continue
}
if c < 0x80 {
if u, ok := v3UnderscoreCodes[byte(c)]; ok {
bsl = append(bsl, '_', u)
changed = true
continue
}
}
var enc string
switch {
case c < 0x80:
enc = fmt.Sprintf("_x%02x", c)
case c < 0x10000:
enc = fmt.Sprintf("_u%04x", c)
default:
enc = fmt.Sprintf("_U%08x", c)
}
bsl = append(bsl, enc...)
changed = true
}
if !changed {
return ppath
}
return string(bsl)
}

View File

@ -24,6 +24,9 @@ func init() {
case "v2": case "v2":
os.Stdout.WriteString(`.string "go.l..u00e4ufer.Run"`) os.Stdout.WriteString(`.string "go.l..u00e4ufer.Run"`)
os.Exit(0) os.Exit(0)
case "v3":
os.Stdout.WriteString(`.string "go_0l_u00e4ufer.Run"`)
os.Exit(0)
case "error": case "error":
os.Stdout.WriteString(`unknown string`) os.Stdout.WriteString(`unknown string`)
os.Exit(0) os.Exit(0)
@ -45,6 +48,10 @@ func TestToSymbolFunc(t *testing.T) {
env: "v2", env: "v2",
mangled: "p..u00e4..u4e16..U0001f703", mangled: "p..u00e4..u4e16..U0001f703",
}, },
{
env: "v3",
mangled: "p_u00e4_u4e16_U0001f703",
},
{ {
env: "error", env: "error",
fail: true, fail: true,
@ -75,32 +82,37 @@ func TestToSymbolFunc(t *testing.T) {
} }
var symbolTests = []struct { var symbolTests = []struct {
input, v1, v2 string input, v1, v2, v3 string
}{ }{
{ {
"", "",
"", "",
"", "",
"",
}, },
{ {
"bytes", "bytes",
"bytes", "bytes",
"bytes", "bytes",
"bytes",
}, },
{ {
"net/http", "net/http",
"net_http", "net_http",
"net..z2fhttp", "net..z2fhttp",
"net_1http",
}, },
{ {
"golang.org/x/net/http", "golang.org/x/net/http",
"golang_org_x_net_http", "golang_org_x_net_http",
"golang.x2eorg..z2fx..z2fnet..z2fhttp", "golang.x2eorg..z2fx..z2fnet..z2fhttp",
"golang_0org_1x_1net_1http",
}, },
{ {
"pä世.🜃", "pä世.🜃",
"p____", "p____",
"p..u00e4..u4e16.x2e..U0001f703", "p..u00e4..u4e16.x2e..U0001f703",
"p_u00e4_u4e16_0_U0001f703",
}, },
} }
@ -119,3 +131,11 @@ func TestV2(t *testing.T) {
} }
} }
} }
func TestV3(t *testing.T) {
for _, test := range symbolTests {
if got, want := toSymbolV3(test.input), test.v3; got != want {
t.Errorf("toSymbolV3(%q) = %q, want %q", test.input, got, want)
}
}
}