]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/gc, cmd/internal/ld: fixes for global vars of types from other modules
authorMichael Hudson-Doyle <michael.hudson@canonical.com>
Wed, 1 Apr 2015 03:20:44 +0000 (16:20 +1300)
committerIan Lance Taylor <iant@golang.org>
Wed, 22 Apr 2015 19:07:34 +0000 (19:07 +0000)
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>

src/cmd/internal/ld/decodesym.go
src/cmd/internal/ld/lib.go
src/cmd/internal/ld/link.go
src/cmd/internal/ld/objfile.go

index 4bad549fd4946ebb1525629f1850e1b5765f0ef4..19d2502c7a39c141d71a23372ee1e56157a86b18 100644 (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
 }
index 3d466e5e184d8146740c0fbe3382501ffd16b53b..3f7b04fbbb2501599a5880fafde9c29853a499db 100644 (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
index fd480733f7dfaa88353f3a6a1fbb3e967e0dcb4d..a92ab59499e81a2cc0426d70065281a169312445 100644 (file)
@@ -75,6 +75,7 @@ type LSym struct {
        P           []byte
        R           []Reloc
        Local       bool
+       gcmask      []byte
 }
 
 type Reloc struct {
index c424cdca8c2533b1908e56c5ad9e3d3a17bf6d71..1e45d72fd8b009c84819e9f6a96b061425147b44 100644 (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
 }