Commit 029c7bbd authored by Michael Hudson-Doyle's avatar Michael Hudson-Doyle Committed by Ian Lance Taylor

cmd/internal/gc, cmd/internal/ld, cmd/internal/obj: teach compiler about local symbols

This lets us avoid loading string constants via the GOT and (together with
http://golang.org/cl/9102) results in the fannkuch benchmark having very similar
register usage with -dynlink as without.

Change-Id: Ic3892b399074982b76773c3e547cfbba5dabb6f9
Reviewed-on: https://go-review.googlesource.com/9103Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
parent 0e6a6c51
...@@ -299,7 +299,7 @@ func proginfo(p *obj.Prog) { ...@@ -299,7 +299,7 @@ func proginfo(p *obj.Prog) {
if p.As == x86.ALEAQ || info.Flags == gc.Pseudo || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP { if p.As == x86.ALEAQ || info.Flags == gc.Pseudo || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
return return
} }
if p.As == obj.ADUFFZERO || p.As == obj.ADUFFCOPY || p.From.Name == obj.NAME_EXTERN || p.To.Name == obj.NAME_EXTERN { if p.As == obj.ADUFFZERO || p.As == obj.ADUFFCOPY || (p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local) || (p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local) {
info.Reguse |= R15 info.Reguse |= R15
info.Regset |= R15 info.Regset |= R15
return return
......
...@@ -218,11 +218,15 @@ func ggloblnod(nam *Node) { ...@@ -218,11 +218,15 @@ func ggloblnod(nam *Node) {
} }
} }
func ggloblsym(s *Sym, width int32, flags int8) { func ggloblsym(s *Sym, width int32, flags int16) {
p := Thearch.Gins(obj.AGLOBL, nil, nil) p := Thearch.Gins(obj.AGLOBL, nil, nil)
p.From.Type = obj.TYPE_MEM p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_EXTERN p.From.Name = obj.NAME_EXTERN
p.From.Sym = Linksym(s) p.From.Sym = Linksym(s)
if flags&obj.LOCAL != 0 {
p.From.Sym.Local = true
flags &= ^obj.LOCAL
}
p.To.Type = obj.TYPE_CONST p.To.Type = obj.TYPE_CONST
p.To.Offset = int64(width) p.To.Offset = int64(width)
p.From3.Offset = int64(flags) p.From3.Offset = int64(flags)
......
...@@ -245,7 +245,7 @@ func stringsym(s string) *Sym { ...@@ -245,7 +245,7 @@ func stringsym(s string) *Sym {
off = duint8(sym, off, 0) // terminating NUL for runtime off = duint8(sym, off, 0) // terminating NUL for runtime
off = (off + Widthptr - 1) &^ (Widthptr - 1) // round to pointer alignment off = (off + Widthptr - 1) &^ (Widthptr - 1) // round to pointer alignment
ggloblsym(sym, int32(off), obj.DUPOK|obj.RODATA) ggloblsym(sym, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
return sym return sym
} }
...@@ -269,7 +269,7 @@ func slicebytes(nam *Node, s string, len int) { ...@@ -269,7 +269,7 @@ func slicebytes(nam *Node, s string, len int) {
off = dsname(sym, off, s[n:n+m]) off = dsname(sym, off, s[n:n+m])
} }
ggloblsym(sym, int32(off), obj.NOPTR) ggloblsym(sym, int32(off), obj.NOPTR|obj.LOCAL)
if nam.Op != ONAME { if nam.Op != ONAME {
Fatal("slicebytes %v", nam) Fatal("slicebytes %v", nam)
......
...@@ -161,7 +161,7 @@ func emitptrargsmap() { ...@@ -161,7 +161,7 @@ func emitptrargsmap() {
} }
} }
ggloblsym(sym, int32(off), obj.RODATA) ggloblsym(sym, int32(off), obj.RODATA|obj.LOCAL)
} }
// Sort the list of stack variables. Autos after anything else, // Sort the list of stack variables. Autos after anything else,
......
...@@ -814,7 +814,7 @@ func dcommontype(s *Sym, ot int, t *Type) int { ...@@ -814,7 +814,7 @@ func dcommontype(s *Sym, ot int, t *Type) int {
for i := 0; i < 2*Widthptr; i++ { for i := 0; i < 2*Widthptr; i++ {
duint8(sbits, i, gcmask[i]) duint8(sbits, i, gcmask[i])
} }
ggloblsym(sbits, 2*int32(Widthptr), obj.DUPOK|obj.RODATA) ggloblsym(sbits, 2*int32(Widthptr), obj.DUPOK|obj.RODATA|obj.LOCAL)
} }
ot = dsymptr(s, ot, sbits, 0) ot = dsymptr(s, ot, sbits, 0)
...@@ -1203,7 +1203,7 @@ ok: ...@@ -1203,7 +1203,7 @@ ok:
} }
ot = dextratype(s, ot, t, xt) ot = dextratype(s, ot, t, xt)
ggloblsym(s, int32(ot), int8(dupok|obj.RODATA)) ggloblsym(s, int32(ot), int16(dupok|obj.RODATA))
// generate typelink.foo pointing at s = type.foo. // generate typelink.foo pointing at s = type.foo.
// The linker will leave a table of all the typelinks for // The linker will leave a table of all the typelinks for
...@@ -1229,7 +1229,7 @@ ok: ...@@ -1229,7 +1229,7 @@ ok:
case TARRAY, TCHAN, TFUNC, TMAP: case TARRAY, TCHAN, TFUNC, TMAP:
slink := typelinksym(t) slink := typelinksym(t)
dsymptr(slink, 0, s, 0) dsymptr(slink, 0, s, 0)
ggloblsym(slink, int32(Widthptr), int8(dupok|obj.RODATA)) ggloblsym(slink, int32(Widthptr), int16(dupok|obj.RODATA))
} }
} }
......
...@@ -72,8 +72,12 @@ func readsym(ctxt *Link, f *Biobuf, pkg string, pn string) { ...@@ -72,8 +72,12 @@ func readsym(ctxt *Link, f *Biobuf, pkg string, pn string) {
if v != 0 && v != 1 { if v != 0 && v != 1 {
log.Fatalf("invalid symbol version %d", v) log.Fatalf("invalid symbol version %d", v)
} }
dupok := int(rdint(f)) flags := int(rdint(f))
dupok &= 1 dupok := flags & 1
local := false
if flags&2 != 0 {
local = true
}
size := int(rdint(f)) size := int(rdint(f))
typ := rdsym(ctxt, f, pkg) typ := rdsym(ctxt, f, pkg)
var data []byte var data []byte
...@@ -125,6 +129,7 @@ overwrite: ...@@ -125,6 +129,7 @@ overwrite:
if s.Size < int64(size) { if s.Size < int64(size) {
s.Size = int64(size) s.Size = int64(size)
} }
s.Local = local
if typ != nil { // if bss sym defined multiple times, take type from any one def if typ != nil { // if bss sym defined multiple times, take type from any one def
s.Gotype = typ s.Gotype = typ
} }
......
...@@ -373,15 +373,7 @@ func symtab() { ...@@ -373,15 +373,7 @@ func symtab() {
// just defined above will be first. // just defined above will be first.
// hide the specific symbols. // hide the specific symbols.
for s := Ctxt.Allsym; s != nil; s = s.Allsym { for s := Ctxt.Allsym; s != nil; s = s.Allsym {
if !s.Reachable || s.Special != 0 { if !s.Reachable || s.Special != 0 || s.Type != obj.SRODATA {
continue
}
if strings.Contains(s.Name, "..gostring.") || strings.Contains(s.Name, "..gobytes.") {
s.Local = true
}
if s.Type != obj.SRODATA {
continue continue
} }
......
...@@ -273,6 +273,7 @@ const ( ...@@ -273,6 +273,7 @@ const (
A_ARCHSPECIFIC A_ARCHSPECIFIC
) )
// An LSym is the sort of symbol that is written to an object file.
type LSym struct { type LSym struct {
Name string Name string
Type int16 Type int16
...@@ -283,18 +284,25 @@ type LSym struct { ...@@ -283,18 +284,25 @@ type LSym struct {
Leaf uint8 Leaf uint8
Seenglobl uint8 Seenglobl uint8
Onlist uint8 Onlist uint8
Args int32 // Local means make the symbol local even when compiling Go code to reference Go
Locals int32 // symbols in other shared libraries, as in this mode symbols are global by
Value int64 // default. "local" here means in the sense of the dynamic linker, i.e. not
Size int64 // visible outside of the module (shared library or executable) that contains its
Next *LSym // definition. (When not compiling to support Go shared libraries, all symbols are
Gotype *LSym // local in this sense unless there is a cgo_export_* directive).
Autom *Auto Local bool
Text *Prog Args int32
Etext *Prog Locals int32
Pcln *Pcln Value int64
P []byte Size int64
R []Reloc Next *LSym
Gotype *LSym
Autom *Auto
Text *Prog
Etext *Prog
Pcln *Pcln
P []byte
R []Reloc
} }
type Pcln struct { type Pcln struct {
......
...@@ -400,7 +400,11 @@ func writesym(ctxt *Link, b *Biobuf, s *LSym) { ...@@ -400,7 +400,11 @@ func writesym(ctxt *Link, b *Biobuf, s *LSym) {
wrint(b, int64(s.Type)) wrint(b, int64(s.Type))
wrstring(b, s.Name) wrstring(b, s.Name)
wrint(b, int64(s.Version)) wrint(b, int64(s.Version))
wrint(b, int64(s.Dupok)) flags := int64(s.Dupok)
if s.Local {
flags |= 2
}
wrint(b, flags)
wrint(b, s.Size) wrint(b, s.Size)
wrsym(b, s.Gotype) wrsym(b, s.Gotype)
wrdata(b, s.P) wrdata(b, s.P)
......
...@@ -30,4 +30,7 @@ const ( ...@@ -30,4 +30,7 @@ const (
// This function uses its incoming context register. // This function uses its incoming context register.
NEEDCTXT = 64 NEEDCTXT = 64
// When passed to ggloblsym, causes Local to be set to true on the LSym it creates.
LOCAL = 128
) )
...@@ -251,6 +251,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) { ...@@ -251,6 +251,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
p.From.Type = obj.TYPE_MEM p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_EXTERN p.From.Name = obj.NAME_EXTERN
p.From.Sym = s p.From.Sym = s
p.From.Sym.Local = true
p.From.Offset = 0 p.From.Offset = 0
} }
...@@ -294,6 +295,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) { ...@@ -294,6 +295,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
p.From.Type = obj.TYPE_MEM p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_EXTERN p.From.Name = obj.NAME_EXTERN
p.From.Sym = s p.From.Sym = s
p.From.Sym.Local = true
p.From.Offset = 0 p.From.Offset = 0
} }
} }
...@@ -327,11 +329,11 @@ func progedit(ctxt *obj.Link, p *obj.Prog) { ...@@ -327,11 +329,11 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
} }
if ctxt.Flag_dynlink { if ctxt.Flag_dynlink {
if p.As == ALEAQ && p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_EXTERN { if p.As == ALEAQ && p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
p.As = AMOVQ p.As = AMOVQ
p.From.Type = obj.TYPE_ADDR p.From.Type = obj.TYPE_ADDR
} }
if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN { if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
if p.As != AMOVQ { if p.As != AMOVQ {
ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p) ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
} }
...@@ -356,12 +358,12 @@ func progedit(ctxt *obj.Link, p *obj.Prog) { ...@@ -356,12 +358,12 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
ctxt.Diag("don't know how to handle %v with -dynlink", p) ctxt.Diag("don't know how to handle %v with -dynlink", p)
} }
var source *obj.Addr var source *obj.Addr
if p.From.Name == obj.NAME_EXTERN { if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
if p.To.Name == obj.NAME_EXTERN { if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local {
ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p) ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
} }
source = &p.From source = &p.From
} else if p.To.Name == obj.NAME_EXTERN { } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local {
source = &p.To source = &p.To
} else { } else {
return return
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment