]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/internal/ld: do not depend on local symbols to read a type's gcdata
authorMichael Hudson-Doyle <michael.hudson@canonical.com>
Mon, 25 May 2015 04:13:50 +0000 (16:13 +1200)
committerIan Lance Taylor <iant@golang.org>
Wed, 27 May 2015 14:11:16 +0000 (14:11 +0000)
We already read the address of a gcmask/gcprog out of the type data, but I
didn't know how many bytes to read. But it turns out that it's easy to
calculate, so change to do that. This means that we no longer depend on the
local symbols being present, allowing me to strip the shared libraries for
distribution and make them a lot smaller.

As a bonus, this makes LSym another 24 bytes smaller, down to 296 bytes now.

Change-Id: I379d359e28d63afae6753efd23efdf1fbb716992
Reviewed-on: https://go-review.googlesource.com/10377
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

misc/cgo/testshared/src/dep/dep.go
misc/cgo/testshared/src/dep2/dep2.go
src/cmd/link/internal/ld/data.go
src/cmd/link/internal/ld/decodesym.go
src/cmd/link/internal/ld/lib.go
src/cmd/link/internal/ld/link.go

index fb112cdb82fd33dfeda8397e5170b4e1973c8d3e..d3bed3f8ff501c409fb1f468406e08dc49071a8a 100644 (file)
@@ -2,6 +2,12 @@ package dep
 
 var V int = 1
 
+var HasMask []string = []string{"hi"}
+
+type HasProg struct {
+       array [1024]*byte
+}
+
 func F() int {
        return V
 }
index af8ad5e756b7ce68f47fb3c96dd304d2a7092d72..bac1086a4a6760fd19419e613094be989492a70d 100644 (file)
@@ -4,6 +4,8 @@ import "dep"
 
 var W int = 1
 
+var hasProg dep.HasProg
+
 func G() int {
        return dep.F() + 1
 }
index e8d30f6a8975dd43645190cd324daa343528f99c..fd1cdd64bbf20e7839d577db0816409f5165f8c2 100644 (file)
@@ -1104,7 +1104,7 @@ func (p *GCProg) AddSym(s *LSym) {
        // Copy program.
        prog := decodetype_gcprog(typ)
        p.w.ZeroUntil(s.Value / ptrsize)
-       p.w.Append(prog.P[4:prog.Size], nptr)
+       p.w.Append(prog[4:], nptr)
 }
 
 func growdatsize(datsizep *int64, s *LSym) {
index fcc664dde735da365f044d6492384a3f915fc229..c1cf4d7181253062f71aca47aaf340943d98dbcb 100644 (file)
@@ -4,7 +4,10 @@
 
 package ld
 
-import "cmd/internal/obj"
+import (
+       "cmd/internal/obj"
+       "debug/elf"
+)
 
 // Decoding the type.* symbols.         This has to be in sync with
 // ../../runtime/type.go, or more specifically, with what
@@ -72,14 +75,38 @@ func decodetype_ptrdata(s *LSym) int64 {
        return int64(decode_inuxi(s.P[Thearch.Ptrsize:], Thearch.Ptrsize)) // 0x8 / 0x10
 }
 
+// Find the elf.Section of a given shared library that contains a given address.
+func findShlibSection(path string, addr uint64) *elf.Section {
+       for _, shlib := range Ctxt.Shlibs {
+               if shlib.Path == path {
+                       for _, sect := range shlib.File.Sections {
+                               if sect.Addr <= addr && addr <= sect.Addr+sect.Size {
+                                       return sect
+                               }
+                       }
+               }
+       }
+       return nil
+}
+
 // Type.commonType.gc
-func decodetype_gcprog(s *LSym) *LSym {
+func decodetype_gcprog(s *LSym) []byte {
        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)
+               addr := decodetype_gcprog_shlib(s)
+               sect := findShlibSection(s.File, addr)
+               if sect != nil {
+                       // A gcprog is a 4-byte uint32 indicating length, followed by
+                       // the actual program.
+                       progsize := make([]byte, 4)
+                       sect.ReadAt(progsize, int64(addr-sect.Addr))
+                       progbytes := make([]byte, Ctxt.Arch.ByteOrder.Uint32(progsize))
+                       sect.ReadAt(progbytes, int64(addr-sect.Addr+4))
+                       return append(progsize, progbytes...)
+               }
+               Exitf("cannot find gcprog for %s", s.Name)
+               return nil
        }
-       return decode_reloc_sym(s, 2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize))
+       return decode_reloc_sym(s, 2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize)).P
 }
 
 func decodetype_gcprog_shlib(s *LSym) uint64 {
@@ -88,9 +115,16 @@ func decodetype_gcprog_shlib(s *LSym) uint64 {
 
 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
+               addr := decodetype_gcprog_shlib(s)
+               ptrdata := decodetype_ptrdata(s)
+               sect := findShlibSection(s.File, addr)
+               if sect != nil {
+                       r := make([]byte, ptrdata/int64(Thearch.Ptrsize))
+                       sect.ReadAt(r, int64(addr-sect.Addr))
+                       return r
+               }
+               Exitf("cannot find gcmask for %s", s.Name)
+               return nil
        }
        mask := decode_reloc_sym(s, 2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize))
        return mask.P
index 8caac0f89c6c72c235011502a5feaec4e7dcce97..32ee45bcec2734bc63827d005c927fe8a8a5c5a5 100644 (file)
@@ -1178,7 +1178,7 @@ func readelfsymboldata(f *elf.File, sym *elf.Symbol) []byte {
        if sect.Type != elf.SHT_PROGBITS && sect.Type != elf.SHT_NOTE {
                Diag("reading %s from non-data section", sym.Name)
        }
-       n, err := sect.ReadAt(data, int64(sym.Value-sect.Offset))
+       n, err := sect.ReadAt(data, int64(sym.Value-sect.Addr))
        if uint64(n) != sym.Size {
                Diag("reading contents of %s: %v", sym.Name, err)
        }
@@ -1265,7 +1265,6 @@ func ldshlibsyms(shlib string) {
                Diag("cannot open shared library: %s", libpath)
                return
        }
-       defer f.Close()
 
        hash, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GOABIHASH_TAG)
        if err != nil {
@@ -1280,33 +1279,15 @@ func ldshlibsyms(shlib string) {
        }
        deps := strings.Split(string(depsbytes), "\n")
 
-       syms, err := f.Symbols()
+       syms, err := f.DynamicSymbols()
        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
                }
-               if strings.HasPrefix(s.Name, "runtime.gcbits.") {
-                       gcmasks[s.Value] = readelfsymboldata(f, &s)
-               }
-               if elf.ST_BIND(s.Info) != elf.STB_GLOBAL {
-                       continue
-               }
                lsym := Linklookup(Ctxt, s.Name, 0)
                if lsym.Type != 0 && lsym.Type != obj.SDYNIMPORT && lsym.Dupok == 0 {
                        Diag(
@@ -1315,27 +1296,15 @@ func ldshlibsyms(shlib string) {
                }
                lsym.Type = obj.SDYNIMPORT
                lsym.ElfType = elf.ST_TYPE(s.Info)
-               lsym.File = libpath
-               if strings.HasPrefix(lsym.Name, "type.") {
-                       if f.Sections[s.Section].Type == elf.SHT_PROGBITS {
+               if s.Section != elf.SHN_UNDEF {
+                       // Set .File for the library that actually defines the symbol.
+                       lsym.File = libpath
+                       // The decodetype_* functions in decodetype.go need access to
+                       // the type data.
+                       if strings.HasPrefix(lsym.Name, "type.") && !strings.HasPrefix(lsym.Name, "type..") {
                                lsym.P = readelfsymboldata(f, &s)
                        }
-                       if !strings.HasPrefix(lsym.Name, "type..") {
-                               types = append(types, lsym)
-                       }
-               }
-       }
-
-       for _, t := range types {
-               if decodetype_noptr(t) != 0 || decodetype_usegcprog(t) != 0 {
-                       continue
-               }
-               addr := decodetype_gcprog_shlib(t)
-               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
@@ -1365,7 +1334,7 @@ func ldshlibsyms(shlib string) {
                Ctxt.Etextp = last
        }
 
-       Ctxt.Shlibs = append(Ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps})
+       Ctxt.Shlibs = append(Ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f})
 }
 
 func mywhatsys() {
index a288148a5a906f3815453f2d22afdcd82550fb80..33b17c59852b85e76e3084fd29512d006292c1c6 100644 (file)
@@ -84,7 +84,6 @@ type LSym struct {
        P           []byte
        R           []Reloc
        Local       bool
-       gcmask      []byte
 }
 
 func (s *LSym) String() string {
@@ -118,6 +117,7 @@ type Shlib struct {
        Path string
        Hash []byte
        Deps []string
+       File *elf.File
 }
 
 type Link struct {