From: David Crawshaw Date: Thu, 3 Mar 2016 15:51:30 +0000 (-0500) Subject: cmd/link: combine all string data into one symbol X-Git-Tag: go1.7beta1~1574 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=0c84c4f19cedd13445c64fcdc409b4821ff9a7d2;p=gostls13.git cmd/link: combine all string data into one symbol This CL introduces a mergestrings pass after the reachability analysis to combine all reachable go.string."..." character data symbols into a single symbol. Shrinks juju by 1.2mb (1.5%). Shrinks cmd/go by 0.5% when building without DWARF. No noticable effect on linker speed. Change-Id: I2ba3e60bf418f65766bda257f6ca9eea26d895b6 Reviewed-on: https://go-review.googlesource.com/20165 Run-TryBot: David Crawshaw TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- diff --git a/src/cmd/link/internal/ld/mergestrings.go b/src/cmd/link/internal/ld/mergestrings.go new file mode 100644 index 0000000000..0e16b36177 --- /dev/null +++ b/src/cmd/link/internal/ld/mergestrings.go @@ -0,0 +1,66 @@ +// 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 ( + "cmd/internal/obj" + "strings" +) + +// mergestrings merges all go.string.* character data into a single symbol. +// +// Combining string data symbols reduces the total binary size and +// makes deduplication possible. +func mergestrings() { + if Buildmode == BuildmodeShared { + return + } + + strs := make([]*LSym, 0, 256) + seenStr := make(map[string]bool, 256) // symbol name -> in strs slice + relocsToStrs := make(map[*LSym][]*Reloc, 256) // string -> relocation to string + size := 0 // number of bytes in all strings + + // Collect strings and relocations that point to strings. + for _, s := range Ctxt.Allsym { + if !s.Attr.Reachable() || s.Attr.Special() { + continue + } + for i := range s.R { + r := &s.R[i] + if r.Sym == nil { + continue + } + if !seenStr[r.Sym.Name] { + if !strings.HasPrefix(r.Sym.Name, "go.string.") { + continue + } + if strings.HasPrefix(r.Sym.Name, "go.string.hdr") { + continue + } + strs = append(strs, r.Sym) + seenStr[r.Sym.Name] = true + size += len(r.Sym.P) + } + relocsToStrs[r.Sym] = append(relocsToStrs[r.Sym], r) + } + } + + // Put all string data into a single symbol and update the relocations. + alldata := Linklookup(Ctxt, "go.string.alldata", 0) + alldata.Type = obj.SGOSTRING + alldata.Attr |= AttrReachable + alldata.Size = int64(size) + alldata.P = make([]byte, 0, size) + for _, str := range strs { + off := len(alldata.P) + alldata.P = append(alldata.P, str.P...) + str.Attr.Set(AttrReachable, false) + for _, r := range relocsToStrs[str] { + r.Add += int64(off) + r.Sym = alldata + } + } +} diff --git a/src/cmd/link/internal/ld/pobj.go b/src/cmd/link/internal/ld/pobj.go index a66843fc11..d36dfc1b68 100644 --- a/src/cmd/link/internal/ld/pobj.go +++ b/src/cmd/link/internal/ld/pobj.go @@ -197,6 +197,7 @@ func Ldmain() { checkstrdata() deadcode() callgraph() + mergestrings() doelf() if HEADTYPE == obj.Hdarwin {