diff --git a/src/cmd/internal/ld/decodesym.go b/src/cmd/internal/ld/decodesym.go index 4bad549fd4946ebb1525629f1850e1b5765f0ef4..19d2502c7a39c141d71a23372ee1e56157a86b18 100644 --- a/src/cmd/internal/ld/decodesym.go +++ b/src/cmd/internal/ld/decodesym.go @@ -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 } diff --git a/src/cmd/internal/ld/lib.go b/src/cmd/internal/ld/lib.go index 3d466e5e184d8146740c0fbe3382501ffd16b53b..3f7b04fbbb2501599a5880fafde9c29853a499db 100644 --- a/src/cmd/internal/ld/lib.go +++ b/src/cmd/internal/ld/lib.go @@ -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 diff --git a/src/cmd/internal/ld/link.go b/src/cmd/internal/ld/link.go index fd480733f7dfaa88353f3a6a1fbb3e967e0dcb4d..a92ab59499e81a2cc0426d70065281a169312445 100644 --- a/src/cmd/internal/ld/link.go +++ b/src/cmd/internal/ld/link.go @@ -75,6 +75,7 @@ type LSym struct { P []byte R []Reloc Local bool + gcmask []byte } type Reloc struct { diff --git a/src/cmd/internal/ld/objfile.go b/src/cmd/internal/ld/objfile.go index c424cdca8c2533b1908e56c5ad9e3d3a17bf6d71..1e45d72fd8b009c84819e9f6a96b061425147b44 100644 --- a/src/cmd/internal/ld/objfile.go +++ b/src/cmd/internal/ld/objfile.go @@ -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 }