return Pkglookup(t.tconv(FmtLeft)+"."+f.Sym.Name, trackpkg)
}
-func typelinkLSym(t *Type) *obj.LSym {
- name := "go.typelink." + t.tconv(FmtLeft) // complete, unambiguous type name
- return obj.Linklookup(Ctxt, name, 0)
-}
-
func typesymprefix(prefix string, t *Type) *Sym {
p := prefix + "." + t.tconv(FmtLeft)
s := Pkglookup(p, typepkg)
ot = dextratypeData(s, ot, t)
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
// types in the binary, so the runtime can find them.
//
keep = true
}
}
- if keep {
- slink := typelinkLSym(t)
- dsymptrOffLSym(slink, 0, Linksym(s), 0)
- ggloblLSym(slink, 4, int16(dupok|obj.RODATA))
- }
+ s.Lsym.MakeTypelink = keep
return s
}
Seenglobl bool
Onlist bool
+ // MakeTypelink means that the type should have an entry in the typelink table.
+ MakeTypelink bool
+
// ReflectMethod means the function may call reflect.Type.Method or
// reflect.Type.MethodByName. Matching is imprecise (as reflect.Type
// can be used through a custom interface), so ReflectMethod may be
// - type [int]
// - name & version [symref index]
// - flags [int]
-// 1 dupok
+// 1<<0 dupok
+// 1<<1 local
+// 1<<2 add to typelink table
// - size [int]
// - gotype [symref index]
// - p [data block]
if s.Local {
flags |= 1 << 1
}
+ if s.MakeTypelink {
+ flags |= 1 << 2
+ }
w.writeInt(flags)
w.writeInt(s.Size)
w.writeRefIndex(s.Gotype)
_64bit uintptr // size on 64bit platforms
}{
{Addr{}, 40, 64},
- {LSym{}, 80, 136},
+ {LSym{}, 84, 136},
{Prog{}, 144, 224},
}
sect.Align = dataMaxAlign[obj.STYPELINK]
datsize = Rnd(datsize, int64(sect.Align))
sect.Vaddr = uint64(datsize)
- ctxt.Syms.Lookup("runtime.typelink", 0).Sect = sect
- ctxt.Syms.Lookup("runtime.etypelink", 0).Sect = sect
- for _, s := range data[obj.STYPELINK] {
- datsize = aligndatsize(datsize, s)
- s.Sect = sect
- s.Type = obj.SRODATA
- s.Value = int64(uint64(datsize) - sect.Vaddr)
- datsize += s.Size
- }
+ typelink := ctxt.Syms.Lookup("runtime.typelink", 0)
+ typelink.Sect = sect
+ typelink.Type = obj.RODATA
+ datsize += typelink.Size
checkdatsize(ctxt, datsize, obj.STYPELINK)
sect.Length = uint64(datsize) - sect.Vaddr
// we skip size comparison and fall through to the name
// comparison (conveniently, .got sorts before .toc).
key.size = 0
- case obj.STYPELINK:
- // Sort typelinks by the rtype.string field so the reflect
- // package can binary search type links.
- key.name = string(decodetypeStr(s.R[0].Sym))
}
symsSort = append(symsSort, key)
var (
text = Segtext.Sect
rodata = ctxt.Syms.Lookup("runtime.rodata", 0).Sect
- typelink = ctxt.Syms.Lookup("runtime.typelink", 0).Sect
itablink = ctxt.Syms.Lookup("runtime.itablink", 0).Sect
symtab = ctxt.Syms.Lookup("runtime.symtab", 0).Sect
pclntab = ctxt.Syms.Lookup("runtime.pclntab", 0).Sect
ctxt.xdefine("runtime.erodata", obj.SRODATA, int64(rodata.Vaddr+rodata.Length))
ctxt.xdefine("runtime.types", obj.SRODATA, int64(types.Vaddr))
ctxt.xdefine("runtime.etypes", obj.SRODATA, int64(types.Vaddr+types.Length))
- ctxt.xdefine("runtime.typelink", obj.SRODATA, int64(typelink.Vaddr))
- ctxt.xdefine("runtime.etypelink", obj.SRODATA, int64(typelink.Vaddr+typelink.Length))
ctxt.xdefine("runtime.itablink", obj.SRODATA, int64(itablink.Vaddr))
ctxt.xdefine("runtime.eitablink", obj.SRODATA, int64(itablink.Vaddr+itablink.Length))
}
if Buildmode != BuildmodeShared {
- // Keep a typelink or itablink if the symbol it points at is being kept.
- // (When BuildmodeShared, always keep typelinks and itablinks.)
+ // Keep a itablink if the symbol it points at is being kept.
+ // (When BuildmodeShared, always keep itablinks.)
for _, s := range ctxt.Syms.Allsym {
- if strings.HasPrefix(s.Name, "go.typelink.") ||
- strings.HasPrefix(s.Name, "go.itablink.") {
+ if strings.HasPrefix(s.Name, "go.itablink.") {
s.Attr.Set(AttrReachable, len(s.R) == 1 && s.R[0].Sym.Attr.Reachable())
}
}
AttrOnList
AttrLocal
AttrReflectMethod
+ AttrMakeTypelink
)
func (a Attribute) DuplicateOK() bool { return a&AttrDuplicateOK != 0 }
func (a Attribute) OnList() bool { return a&AttrOnList != 0 }
func (a Attribute) Local() bool { return a&AttrLocal != 0 }
func (a Attribute) ReflectMethod() bool { return a&AttrReflectMethod != 0 }
+func (a Attribute) MakeTypelink() bool { return a&AttrMakeTypelink != 0 }
func (a Attribute) CgoExport() bool {
return a.CgoExportDynamic() || a.CgoExportStatic()
ctxt.textaddress()
ctxt.pclntab()
ctxt.findfunctab()
+ ctxt.typelink()
ctxt.symtab()
ctxt.dodata()
ctxt.address()
// - type [int]
// - name & version [symref index]
// - flags [int]
-// 1 dupok
+// 1<<0 dupok
+// 1<<1 local
+// 1<<2 add to typelink table
// - size [int]
// - gotype [symref index]
// - p [data block]
flags := r.readInt()
dupok := flags&1 != 0
local := flags&2 != 0
+ makeTypelink := flags&4 != 0
size := r.readInt()
typ := r.readSymIndex()
data := r.readData()
s.Size = int64(size)
}
s.Attr.Set(AttrLocal, local)
+ s.Attr.Set(AttrMakeTypelink, makeTypelink)
if typ != nil {
s.Gotype = typ
}
ctxt.xdefine("runtime.text", obj.STEXT, 0)
ctxt.xdefine("runtime.etext", obj.STEXT, 0)
- ctxt.xdefine("runtime.typelink", obj.SRODATA, 0)
- ctxt.xdefine("runtime.etypelink", obj.SRODATA, 0)
ctxt.xdefine("runtime.itablink", obj.SRODATA, 0)
ctxt.xdefine("runtime.eitablink", obj.SRODATA, 0)
ctxt.xdefine("runtime.rodata", obj.SRODATA, 0)
}
}
- symtypelink := ctxt.Syms.Lookup("runtime.typelink", 0)
- symtypelink.Type = obj.STYPELINK
-
symitablink := ctxt.Syms.Lookup("runtime.itablink", 0)
symitablink.Type = obj.SITABLINK
symt.Size = 0
symt.Attr |= AttrReachable
- ntypelinks := 0
nitablinks := 0
// assign specific types so that they sort together.
// names, as they can be referred to by a section offset.
s.Type = obj.STYPERELRO
- case strings.HasPrefix(s.Name, "go.typelink."):
- ntypelinks++
- s.Type = obj.STYPELINK
- s.Attr |= AttrHidden
- s.Outer = symtypelink
-
case strings.HasPrefix(s.Name, "go.itablink."):
nitablinks++
s.Type = obj.SITABLINK
adduint(ctxt, moduledata, uint64(nsections))
// The typelinks slice
- Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.typelink", 0))
- adduint(ctxt, moduledata, uint64(ntypelinks))
- adduint(ctxt, moduledata, uint64(ntypelinks))
+ typelinkSym := ctxt.Syms.Lookup("runtime.typelink", 0)
+ ntypelinks := uint64(typelinkSym.Size) / 4
+ Addaddr(ctxt, moduledata, typelinkSym)
+ adduint(ctxt, moduledata, ntypelinks)
+ adduint(ctxt, moduledata, ntypelinks)
// The itablinks slice
Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.itablink", 0))
adduint(ctxt, moduledata, uint64(nitablinks))
--- /dev/null
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ld
+
+import (
+ "sort"
+
+ "cmd/internal/obj"
+)
+
+type byTypeStr []typelinkSortKey
+
+type typelinkSortKey struct {
+ TypeStr string
+ Type *Symbol
+}
+
+func (s byTypeStr) Less(i, j int) bool { return s[i].TypeStr < s[j].TypeStr }
+func (s byTypeStr) Len() int { return len(s) }
+func (s byTypeStr) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+// typelink generates the typelink table which is used by reflect.typelinks().
+// Types that should be added to the typelinks table are marked with the
+// MakeTypelink attribute by the compiler.
+func (ctxt *Link) typelink() {
+ typelinks := byTypeStr{}
+ for _, s := range ctxt.Syms.Allsym {
+ if s.Attr.Reachable() && s.Attr.MakeTypelink() {
+ typelinks = append(typelinks, typelinkSortKey{decodetypeStr(s), s})
+ }
+ }
+ sort.Sort(typelinks)
+
+ tl := ctxt.Syms.Lookup("runtime.typelink", 0)
+ tl.Type = obj.STYPELINK
+ tl.Attr |= AttrReachable | AttrLocal
+ tl.Size = int64(4 * len(typelinks))
+ tl.P = make([]byte, tl.Size)
+ tl.R = make([]Reloc, len(typelinks))
+ for i, s := range typelinks {
+ r := &tl.R[i]
+ r.Sym = s.Type
+ r.Off = int32(i * 4)
+ r.Siz = 4
+ r.Type = obj.R_ADDROFF
+ }
+}