Skip to content

Commit c47eac7

Browse files
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 <[email protected]> Run-TryBot: Ian Lance Taylor <[email protected]> Reviewed-by: Than McIntosh <[email protected]> TryBot-Result: Go Bot <[email protected]>
1 parent 3fd4917 commit c47eac7

File tree

3 files changed

+98
-15
lines changed

3 files changed

+98
-15
lines changed

src/cmd/cgo/out.go

+13-10
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ func (p *Package) writeDefs() {
186186
panic(fmt.Errorf("invalid var kind %q", n.Kind))
187187
}
188188
if *gccgo {
189-
fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, n.Mangle)
189+
fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, gccgoToSymbol(n.Mangle))
190190
fmt.Fprintf(&gccgoInit, "\t%s = &%s;\n", n.Mangle, n.C)
191191
fmt.Fprintf(fc, "\n")
192192
}
@@ -1148,7 +1148,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
11481148
// will not be able to link against it from the C
11491149
// code.
11501150
goName := "Cgoexp_" + exp.ExpName
1151-
fmt.Fprintf(fgcc, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, goName)
1151+
fmt.Fprintf(fgcc, `extern %s %s %s __asm__("%s.%s");`, cRet, goName, cParams, gccgoSymbolPrefix, gccgoToSymbol(goName))
11521152
fmt.Fprint(fgcc, "\n")
11531153

11541154
fmt.Fprint(fgcc, "\nCGO_NO_SANITIZE_THREAD\n")
@@ -1182,7 +1182,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
11821182
fmt.Fprint(fgcc, "}\n")
11831183

11841184
// Dummy declaration for _cgo_main.c
1185-
fmt.Fprintf(fm, `char %s[1] __asm__("%s.%s");`, goName, gccgoSymbolPrefix, goName)
1185+
fmt.Fprintf(fm, `char %s[1] __asm__("%s.%s");`, goName, gccgoSymbolPrefix, gccgoToSymbol(goName))
11861186
fmt.Fprint(fm, "\n")
11871187

11881188
// For gccgo we use a wrapper function in Go, in order
@@ -1266,9 +1266,8 @@ func (p *Package) writeExportHeader(fgcch io.Writer) {
12661266
fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
12671267
}
12681268

1269-
// gccgoPkgpathToSymbol converts a package path to a mangled packagepath
1270-
// symbol.
1271-
func gccgoPkgpathToSymbol(ppath string) string {
1269+
// gccgoToSymbol converts a name to a mangled symbol for gccgo.
1270+
func gccgoToSymbol(ppath string) string {
12721271
if gccgoMangler == nil {
12731272
var err error
12741273
cmd := os.Getenv("GCCGO")
@@ -1293,12 +1292,12 @@ func (p *Package) gccgoSymbolPrefix() string {
12931292
}
12941293

12951294
if *gccgopkgpath != "" {
1296-
return gccgoPkgpathToSymbol(*gccgopkgpath)
1295+
return gccgoToSymbol(*gccgopkgpath)
12971296
}
12981297
if *gccgoprefix == "" && p.PackageName == "main" {
12991298
return "main"
13001299
}
1301-
prefix := gccgoPkgpathToSymbol(*gccgoprefix)
1300+
prefix := gccgoToSymbol(*gccgoprefix)
13021301
if prefix == "" {
13031302
prefix = "go"
13041303
}
@@ -1687,8 +1686,12 @@ void _cgoPREFIX_Cfunc__Cmalloc(void *v) {
16871686
`
16881687

16891688
func (p *Package) cPrologGccgo() string {
1690-
return strings.Replace(strings.Replace(cPrologGccgo, "PREFIX", cPrefix, -1),
1691-
"GCCGOSYMBOLPREF", p.gccgoSymbolPrefix(), -1)
1689+
r := strings.NewReplacer(
1690+
"PREFIX", cPrefix,
1691+
"GCCGOSYMBOLPREF", p.gccgoSymbolPrefix(),
1692+
"_cgoCheckPointer", gccgoToSymbol("_cgoCheckPointer"),
1693+
"_cgoCheckResult", gccgoToSymbol("_cgoCheckResult"))
1694+
return r.Replace(cPrologGccgo)
16921695
}
16931696

16941697
const cPrologGccgo = `

src/cmd/internal/pkgpath/pkgpath.go

+64-4
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,12 @@ func ToSymbolFunc(cmd, tmpdir string) (func(string) string, error) {
5050
return nil, err
5151
}
5252

53-
// New mangling: expect go.l..u00e4ufer.Run
54-
// Old mangling: expect go.l__ufer.Run
55-
if bytes.Contains(buf, []byte("go.l..u00e4ufer.Run")) {
53+
// Original mangling: go.l__ufer.Run
54+
// Mangling v2: go.l..u00e4ufer.Run
55+
// Mangling v3: go_0l_u00e4ufer.Run
56+
if bytes.Contains(buf, []byte("go_0l_u00e4ufer.Run")) {
57+
return toSymbolV3, nil
58+
} else if bytes.Contains(buf, []byte("go.l..u00e4ufer.Run")) {
5659
return toSymbolV2, nil
5760
} else if bytes.Contains(buf, []byte("go.l__ufer.Run")) {
5861
return toSymbolV1, nil
@@ -82,7 +85,7 @@ func toSymbolV1(ppath string) string {
8285
return strings.Map(clean, ppath)
8386
}
8487

85-
// toSymbolV2 converts a package path using the newer mangling scheme.
88+
// toSymbolV2 converts a package path using the second mangling scheme.
8689
func toSymbolV2(ppath string) string {
8790
// This has to build at boostrap time, so it has to build
8891
// with Go 1.4, so we don't use strings.Builder.
@@ -112,3 +115,60 @@ func toSymbolV2(ppath string) string {
112115
}
113116
return string(bsl)
114117
}
118+
119+
// v3UnderscoreCodes maps from a character that supports an underscore
120+
// encoding to the underscore encoding character.
121+
var v3UnderscoreCodes = map[byte]byte{
122+
'_': '_',
123+
'.': '0',
124+
'/': '1',
125+
'*': '2',
126+
',': '3',
127+
'{': '4',
128+
'}': '5',
129+
'[': '6',
130+
']': '7',
131+
'(': '8',
132+
')': '9',
133+
'"': 'a',
134+
' ': 'b',
135+
';': 'c',
136+
}
137+
138+
// toSymbolV3 converts a package path using the third mangling scheme.
139+
func toSymbolV3(ppath string) string {
140+
// This has to build at boostrap time, so it has to build
141+
// with Go 1.4, so we don't use strings.Builder.
142+
bsl := make([]byte, 0, len(ppath))
143+
changed := false
144+
for _, c := range ppath {
145+
if ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || ('0' <= c && c <= '9') {
146+
bsl = append(bsl, byte(c))
147+
continue
148+
}
149+
150+
if c < 0x80 {
151+
if u, ok := v3UnderscoreCodes[byte(c)]; ok {
152+
bsl = append(bsl, '_', u)
153+
changed = true
154+
continue
155+
}
156+
}
157+
158+
var enc string
159+
switch {
160+
case c < 0x80:
161+
enc = fmt.Sprintf("_x%02x", c)
162+
case c < 0x10000:
163+
enc = fmt.Sprintf("_u%04x", c)
164+
default:
165+
enc = fmt.Sprintf("_U%08x", c)
166+
}
167+
bsl = append(bsl, enc...)
168+
changed = true
169+
}
170+
if !changed {
171+
return ppath
172+
}
173+
return string(bsl)
174+
}

src/cmd/internal/pkgpath/pkgpath_test.go

+21-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ func init() {
2424
case "v2":
2525
os.Stdout.WriteString(`.string "go.l..u00e4ufer.Run"`)
2626
os.Exit(0)
27+
case "v3":
28+
os.Stdout.WriteString(`.string "go_0l_u00e4ufer.Run"`)
29+
os.Exit(0)
2730
case "error":
2831
os.Stdout.WriteString(`unknown string`)
2932
os.Exit(0)
@@ -45,6 +48,10 @@ func TestToSymbolFunc(t *testing.T) {
4548
env: "v2",
4649
mangled: "p..u00e4..u4e16..U0001f703",
4750
},
51+
{
52+
env: "v3",
53+
mangled: "p_u00e4_u4e16_U0001f703",
54+
},
4855
{
4956
env: "error",
5057
fail: true,
@@ -75,32 +82,37 @@ func TestToSymbolFunc(t *testing.T) {
7582
}
7683

7784
var symbolTests = []struct {
78-
input, v1, v2 string
85+
input, v1, v2, v3 string
7986
}{
8087
{
8188
"",
8289
"",
8390
"",
91+
"",
8492
},
8593
{
8694
"bytes",
8795
"bytes",
8896
"bytes",
97+
"bytes",
8998
},
9099
{
91100
"net/http",
92101
"net_http",
93102
"net..z2fhttp",
103+
"net_1http",
94104
},
95105
{
96106
"golang.org/x/net/http",
97107
"golang_org_x_net_http",
98108
"golang.x2eorg..z2fx..z2fnet..z2fhttp",
109+
"golang_0org_1x_1net_1http",
99110
},
100111
{
101112
"pä世.🜃",
102113
"p____",
103114
"p..u00e4..u4e16.x2e..U0001f703",
115+
"p_u00e4_u4e16_0_U0001f703",
104116
},
105117
}
106118

@@ -119,3 +131,11 @@ func TestV2(t *testing.T) {
119131
}
120132
}
121133
}
134+
135+
func TestV3(t *testing.T) {
136+
for _, test := range symbolTests {
137+
if got, want := toSymbolV3(test.input), test.v3; got != want {
138+
t.Errorf("toSymbolV3(%q) = %q, want %q", test.input, got, want)
139+
}
140+
}
141+
}

0 commit comments

Comments
 (0)