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) {
if p.As == x86.ALEAQ || info.Flags == gc.Pseudo || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
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.Regset |= R15
return
......
......@@ -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.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_EXTERN
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.Offset = int64(width)
p.From3.Offset = int64(flags)
......
......@@ -245,7 +245,7 @@ func stringsym(s string) *Sym {
off = duint8(sym, off, 0) // terminating NUL for runtime
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
}
......@@ -269,7 +269,7 @@ func slicebytes(nam *Node, s string, len int) {
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 {
Fatal("slicebytes %v", nam)
......
......@@ -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,
......
......@@ -814,7 +814,7 @@ func dcommontype(s *Sym, ot int, t *Type) int {
for i := 0; i < 2*Widthptr; 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)
......@@ -1203,7 +1203,7 @@ ok:
}
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.
// The linker will leave a table of all the typelinks for
......@@ -1229,7 +1229,7 @@ ok:
case TARRAY, TCHAN, TFUNC, TMAP:
slink := typelinksym(t)
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) {
if v != 0 && v != 1 {
log.Fatalf("invalid symbol version %d", v)
}
dupok := int(rdint(f))
dupok &= 1
flags := int(rdint(f))
dupok := flags & 1
local := false
if flags&2 != 0 {
local = true
}
size := int(rdint(f))
typ := rdsym(ctxt, f, pkg)
var data []byte
......@@ -125,6 +129,7 @@ overwrite:
if 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
s.Gotype = typ
}
......
......@@ -373,15 +373,7 @@ func symtab() {
// just defined above will be first.
// hide the specific symbols.
for s := Ctxt.Allsym; s != nil; s = s.Allsym {
if !s.Reachable || s.Special != 0 {
continue
}
if strings.Contains(s.Name, "..gostring.") || strings.Contains(s.Name, "..gobytes.") {
s.Local = true
}
if s.Type != obj.SRODATA {
if !s.Reachable || s.Special != 0 || s.Type != obj.SRODATA {
continue
}
......
......@@ -273,6 +273,7 @@ const (
A_ARCHSPECIFIC
)
// An LSym is the sort of symbol that is written to an object file.
type LSym struct {
Name string
Type int16
......@@ -283,18 +284,25 @@ type LSym struct {
Leaf uint8
Seenglobl uint8
Onlist uint8
Args int32
Locals int32
Value int64
Size int64
Next *LSym
Gotype *LSym
Autom *Auto
Text *Prog
Etext *Prog
Pcln *Pcln
P []byte
R []Reloc
// Local means make the symbol local even when compiling Go code to reference Go
// symbols in other shared libraries, as in this mode symbols are global by
// default. "local" here means in the sense of the dynamic linker, i.e. not
// visible outside of the module (shared library or executable) that contains its
// definition. (When not compiling to support Go shared libraries, all symbols are
// local in this sense unless there is a cgo_export_* directive).
Local bool
Args int32
Locals int32
Value int64
Size int64
Next *LSym
Gotype *LSym
Autom *Auto
Text *Prog
Etext *Prog
Pcln *Pcln
P []byte
R []Reloc
}
type Pcln struct {
......
......@@ -400,7 +400,11 @@ func writesym(ctxt *Link, b *Biobuf, s *LSym) {
wrint(b, int64(s.Type))
wrstring(b, s.Name)
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)
wrsym(b, s.Gotype)
wrdata(b, s.P)
......
......@@ -30,4 +30,7 @@ const (
// This function uses its incoming context register.
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) {
p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_EXTERN
p.From.Sym = s
p.From.Sym.Local = true
p.From.Offset = 0
}
......@@ -294,6 +295,7 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_EXTERN
p.From.Sym = s
p.From.Sym.Local = true
p.From.Offset = 0
}
}
......@@ -327,11 +329,11 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
}
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.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 {
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) {
ctxt.Diag("don't know how to handle %v with -dynlink", p)
}
var source *obj.Addr
if p.From.Name == obj.NAME_EXTERN {
if p.To.Name == obj.NAME_EXTERN {
if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
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)
}
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
} else {
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