cmd/internal/gc, cmd/internal/ld: fixes for global vars of types from other modules

To make the gcprog for global data containing variables of types defined in other shared
libraries, we need to know a lot about those types. So read the value of any symbol with
a name starting with "type.". If a type uses a mask, the name of the symbol defining the
mask unfortunately cannot be predicted from the type name so I have to keep track of the
addresses of every such symbol and associate them with the type symbols after the fact.

I'm not very happy about this change, but something like this is needed and this is as
pleasant as I know how to make it.

Change-Id: I408d831b08b3b31e0610688c41367b23998e975c
Reviewed-on: https://go-review.googlesource.com/8334
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
Michael Hudson-Doyle 2015-04-01 16:20:44 +13:00 committed by Ian Lance Taylor
parent ac1cdd13e0
commit 7820d27049
4 changed files with 70 additions and 2 deletions

View File

@ -67,10 +67,20 @@ func decodetype_size(s *LSym) int64 {
// Type.commonType.gc
func decodetype_gcprog(s *LSym) *LSym {
if s.Type == obj.SDYNIMPORT {
// The gcprog for "type.$name" is calle "type..gcprog.$name".
x := "type..gcprog." + s.Name[5:]
return Linklookup(Ctxt, x, 0)
}
return decode_reloc_sym(s, 1*int32(Thearch.Ptrsize)+8+2*int32(Thearch.Ptrsize))
}
func decodetype_gcmask(s *LSym) []byte {
if s.Type == obj.SDYNIMPORT {
// ldshlibsyms makes special efforts to read the value
// of gcmask for types defined in that shared library.
return s.gcmask
}
mask := decode_reloc_sym(s, 1*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize))
return mask.P
}

View File

@ -1136,11 +1136,23 @@ func ldshlibsyms(shlib string) {
return
}
defer f.Close()
syms, err := f.DynamicSymbols()
syms, err := f.Symbols()
if err != nil {
Diag("cannot read symbols from shared library: %s", libpath)
return
}
// If a package has a global variable of a type defined in another shared
// library, we need to know the gcmask used by the type, if any. To support
// this, we read all the runtime.gcbits.* symbols, keep a map of address to
// gcmask, and after we're read all the symbols, read the addresses of the
// gcmasks symbols out of the type data to look up the gcmask for each type.
// This depends on the fact that the runtime.gcbits.* symbols are local (so
// the address is actually present in the type data and we don't have to
// search all relocations to find the ones which correspond to gcmasks) and
// also that the shared library we are linking against has not had the symbol
// table removed.
gcmasks := make(map[uint64][]byte)
types := []*LSym{}
for _, s := range syms {
if elf.ST_TYPE(s.Info) == elf.STT_NOTYPE || elf.ST_TYPE(s.Info) == elf.STT_SECTION {
continue
@ -1151,6 +1163,20 @@ func ldshlibsyms(shlib string) {
if strings.HasPrefix(s.Name, "_") {
continue
}
if strings.HasPrefix(s.Name, "runtime.gcbits.0x") {
data := make([]byte, s.Size)
sect := f.Sections[s.Section]
if sect.Type == elf.SHT_PROGBITS {
n, err := sect.ReadAt(data, int64(s.Value-sect.Offset))
if uint64(n) != s.Size {
Diag("Error reading contents of %s: %v", s.Name, err)
}
}
gcmasks[s.Value] = data
}
if elf.ST_BIND(s.Info) != elf.STB_GLOBAL {
continue
}
lsym := Linklookup(Ctxt, s.Name, 0)
if lsym.Type != 0 && lsym.Dupok == 0 {
Diag(
@ -1159,6 +1185,35 @@ func ldshlibsyms(shlib string) {
}
lsym.Type = obj.SDYNIMPORT
lsym.File = libpath
if strings.HasPrefix(lsym.Name, "type.") {
data := make([]byte, s.Size)
sect := f.Sections[s.Section]
if sect.Type == elf.SHT_PROGBITS {
n, err := sect.ReadAt(data, int64(s.Value-sect.Offset))
if uint64(n) != s.Size {
Diag("Error reading contents of %s: %v", s.Name, err)
}
lsym.P = data
}
if !strings.HasPrefix(lsym.Name, "type..") {
types = append(types, lsym)
}
}
}
for _, t := range types {
if decodetype_noptr(t) != 0 || decodetype_usegcprog(t) != 0 {
continue
}
// The expression on the next line is a copy of the expression from
// decodetype_gcmask in decodesym.go, which in turn depends on details of
// how the type data is laid out, as seen in gc/reflect.go:dcommontype.
addr := decode_inuxi(t.P[1*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize):], Thearch.Ptrsize)
tgcmask, ok := gcmasks[addr]
if !ok {
Diag("bits not found for %s at %d", t.Name, addr)
}
t.gcmask = tgcmask
}
// We might have overwritten some functions above (this tends to happen for the

View File

@ -75,6 +75,7 @@ type LSym struct {
P []byte
R []Reloc
Local bool
gcmask []byte
}
type Reloc struct {

View File

@ -340,6 +340,8 @@ func rdsym(ctxt *Link, f *Biobuf, pkg string) *LSym {
s.Reachable = false
}
}
if v == 0 && strings.HasPrefix(s.Name, "runtime.gcbits.0x") {
s.Local = true
}
return s
}