]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/link: process data symbols with slices
authorDavid Crawshaw <crawshaw@golang.org>
Mon, 18 Apr 2016 18:50:14 +0000 (14:50 -0400)
committerDavid Crawshaw <crawshaw@golang.org>
Wed, 20 Apr 2016 22:45:03 +0000 (22:45 +0000)
First (and largest single) step to switching cmd/link from linked
lists of symbols to slices.

Sort sections independently and concurrently.
This reduces jujud link times on linux/amd64 by ~4%.

Updates #15374

Change-Id: I452bc8f33081039468636502fe3c1cc8d6ed9efa
Reviewed-on: https://go-review.googlesource.com/22205
Reviewed-by: Michael Hudson-Doyle <michael.hudson@canonical.com>
src/cmd/link/internal/ld/data.go
src/cmd/link/internal/ld/elf.go
src/cmd/link/internal/ld/lib.go
src/cmd/link/internal/ld/macho.go
src/cmd/link/internal/ld/pe.go

index b89644f229b96850fef9faa2f4a5a8350908f3fd..cc509fbc6d111d863b373439871e5de8d3057d67 100644 (file)
@@ -32,7 +32,6 @@
 package ld
 
 import (
-       "bytes"
        "cmd/internal/gcprog"
        "cmd/internal/obj"
        "cmd/internal/sys"
@@ -42,6 +41,7 @@ import (
        "sort"
        "strconv"
        "strings"
+       "sync"
 )
 
 func Symgrow(ctxt *Link, s *LSym, siz int64) {
@@ -651,8 +651,8 @@ func reloc() {
        for s := Ctxt.Textp; s != nil; s = s.Next {
                relocsym(s)
        }
-       for s := datap; s != nil; s = s.Next {
-               relocsym(s)
+       for _, sym := range datap {
+               relocsym(sym)
        }
        for s := dwarfp; s != nil; s = s.Next {
                relocsym(s)
@@ -713,7 +713,7 @@ func dynrelocsym(s *LSym) {
        }
 }
 
-func dynreloc() {
+func dynreloc(data *[obj.SXREF][]*LSym) {
        // -d suppresses dynamic loader format, so we may as well not
        // compute these sections or mark their symbols as reachable.
        if Debug['d'] != 0 && HEADTYPE != obj.Hwindows {
@@ -727,8 +727,10 @@ func dynreloc() {
        for s := Ctxt.Textp; s != nil; s = s.Next {
                dynrelocsym(s)
        }
-       for s := datap; s != nil; s = s.Next {
-               dynrelocsym(s)
+       for _, syms := range data {
+               for _, sym := range syms {
+                       dynrelocsym(sym)
+               }
        }
        if Iself {
                elfdynhash()
@@ -849,27 +851,77 @@ func Codeblk(addr int64, size int64) {
        Bso.Flush()
 }
 
+// blkSlice is a variant of blk that processes slices.
+// After text symbols are converted from a linked list to a slice,
+// delete blk and give this function its name.
+func blkSlice(syms []*LSym, addr, size int64) {
+       for i, s := range syms {
+               if s.Type&obj.SSUB == 0 && s.Value >= addr {
+                       syms = syms[i:]
+                       break
+               }
+       }
+
+       eaddr := addr + size
+       for _, s := range syms {
+               if s.Type&obj.SSUB != 0 {
+                       continue
+               }
+               if s.Value >= eaddr {
+                       break
+               }
+               Ctxt.Cursym = s
+               if s.Value < addr {
+                       Diag("phase error: addr=%#x but sym=%#x type=%d", addr, s.Value, s.Type)
+                       errorexit()
+               }
+               if addr < s.Value {
+                       strnput("", int(s.Value-addr))
+                       addr = s.Value
+               }
+               Cwrite(s.P)
+               addr += int64(len(s.P))
+               if addr < s.Value+s.Size {
+                       strnput("", int(s.Value+s.Size-addr))
+                       addr = s.Value + s.Size
+               }
+               if addr != s.Value+s.Size {
+                       Diag("phase error: addr=%#x value+size=%#x", addr, s.Value+s.Size)
+                       errorexit()
+               }
+               if s.Value+s.Size >= eaddr {
+                       break
+               }
+       }
+
+       if addr < eaddr {
+               strnput("", int(eaddr-addr))
+       }
+       Cflush()
+}
+
 func Datblk(addr int64, size int64) {
        if Debug['a'] != 0 {
                fmt.Fprintf(Bso, "datblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos())
        }
 
-       blk(datap, addr, size)
+       blkSlice(datap, addr, size)
 
        /* again for printing */
        if Debug['a'] == 0 {
                return
        }
 
-       var sym *LSym
-       for sym = datap; sym != nil; sym = sym.Next {
+       syms := datap
+       for i, sym := range syms {
                if sym.Value >= addr {
+                       syms = syms[i:]
                        break
                }
        }
 
        eaddr := addr + size
-       for ; sym != nil; sym = sym.Next {
+       for _, sym := range syms {
                if sym.Value >= eaddr {
                        break
                }
@@ -1080,18 +1132,15 @@ func aligndatsize(datsize int64, s *LSym) int64 {
 }
 
 // maxalign returns the maximum required alignment for
-// the list of symbols s; the list stops when s->type exceeds type.
-func maxalign(s *LSym, type_ int) int32 {
-       var align int32
-
-       max := int32(0)
-       for ; s != nil && int(s.Type) <= type_; s = s.Next {
-               align = symalign(s)
+// the slice of symbols syms
+func maxalign(syms []*LSym) int32 {
+       var max int32
+       for _, sym := range syms {
+               align := symalign(sym)
                if max < align {
                        max = align
                }
        }
-
        return max
 }
 
@@ -1156,41 +1205,24 @@ func (p *GCProg) AddSym(s *LSym) {
        p.w.Append(prog[4:], nptr)
 }
 
+// dataSortKey is used to sort a slice of data symbol *LSym pointers.
+// The sort keys are kept inline to improve cache behaviour while sorting.
 type dataSortKey struct {
-       // keep sort keys inline to improve cache behaviour while sorting
-       Type int16
-       Size int64
-       Name string
-
-       Lsym *LSym
+       size int64
+       name string
+       lsym *LSym
 }
 
-type dataSlice []dataSortKey
-
-func (d dataSlice) Len() int      { return len(d) }
-func (d dataSlice) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
-func (d dataSlice) Less(i, j int) bool {
-       s1, s2 := &d[i], &d[j]
-       if s1.Type != s2.Type {
-               return s1.Type < s2.Type
-       }
-
-       // For ppc64, we want to interleave the .got and .toc sections
-       // from input files. Both are type SELFGOT, so in that case
-       // fall through to the name comparison (conveniently, .got
-       // sorts before .toc).
-       if s1.Type != obj.SELFGOT && s1.Size != s2.Size {
-               return s1.Size < s2.Size
-       }
+type bySizeAndName []dataSortKey
 
-       // Sort typelinks by the string field.
-       if strings.HasPrefix(s1.Name, "go.typelink.") && strings.HasPrefix(s2.Name, "go.typelink.") {
-               s1n := decodetype_string(s1.Lsym.R[0].Sym)
-               s2n := decodetype_string(s2.Lsym.R[0].Sym)
-               return bytes.Compare(s1n, s2n) < 0
+func (d bySizeAndName) Len() int      { return len(d) }
+func (d bySizeAndName) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
+func (d bySizeAndName) Less(i, j int) bool {
+       s1, s2 := d[i], d[j]
+       if s1.size != s2.size {
+               return s1.size < s2.size
        }
-
-       return s1.Name < s2.Name
+       return s1.name < s2.name
 }
 
 func growdatsize(datsizep *int64, s *LSym) {
@@ -1207,38 +1239,17 @@ func growdatsize(datsizep *int64, s *LSym) {
        *datsizep = datsize + s.Size
 }
 
-func list2Slice(head *LSym) dataSlice {
-       n := 0
-       for s := datap; s != nil; s = s.Next {
-               n++
-       }
-       slice := make(dataSlice, n)
-       i := 0
-       for s := datap; s != nil; s = s.Next {
-               k := &slice[i]
-               k.Type = s.Type
-               k.Size = s.Size
-               k.Name = s.Name
-               k.Lsym = s
-
-               i++
-       }
-       return slice
-}
-
-func slice2List(d dataSlice) *LSym {
-       for i := 0; i < len(d)-1; i++ {
-               d[i].Lsym.Next = d[i+1].Lsym
+func list2slice(s *LSym) []*LSym {
+       var syms []*LSym
+       for ; s != nil; s = s.Next {
+               syms = append(syms, s)
        }
-       d[len(d)-1].Lsym.Next = nil
-       return d[0].Lsym
+       return syms
 }
 
-func dataSort(head *LSym) *LSym {
-       d := list2Slice(head)
-       sort.Sort(d)
-       return slice2List(d)
-}
+// datap is a collection of reachable data symbols in address order.
+// Generated by dodata.
+var datap []*LSym
 
 func dodata() {
        if Debug['v'] != 0 {
@@ -1246,153 +1257,122 @@ func dodata() {
        }
        Bso.Flush()
 
-       var last *LSym
-       datap = nil
-
+       // Collect data symbols by type into data.
+       var data [obj.SXREF][]*LSym
        for _, s := range Ctxt.Allsym {
                if !s.Attr.Reachable() || s.Attr.Special() {
                        continue
                }
-               if obj.STEXT < s.Type && s.Type < obj.SXREF {
-                       if s.Attr.OnList() {
-                               log.Fatalf("symbol %s listed multiple times", s.Name)
-                       }
-                       s.Attr |= AttrOnList
-                       if last == nil {
-                               datap = s
-                       } else {
-                               last.Next = s
-                       }
-                       s.Next = nil
-                       last = s
-               }
-       }
-
-       for s := datap; s != nil; s = s.Next {
-               if int64(len(s.P)) > s.Size {
-                       Diag("%s: initialize bounds (%d < %d)", s.Name, s.Size, len(s.P))
+               if s.Type <= obj.STEXT || s.Type >= obj.SXREF {
+                       continue
                }
+               data[s.Type] = append(data[s.Type], s)
        }
 
-       /*
-        * now that we have the datap list, but before we start
-        * to assign addresses, record all the necessary
-        * dynamic relocations.  these will grow the relocation
-        * symbol, which is itself data.
-        *
-        * on darwin, we need the symbol table numbers for dynreloc.
-        */
+       // Now that we have the data symbols, but before we start
+       // to assign addresses, record all the necessary
+       // dynamic relocations. These will grow the relocation
+       // symbol, which is itself data.
+       //
+       // On darwin, we need the symbol table numbers for dynreloc.
        if HEADTYPE == obj.Hdarwin {
                machosymorder()
        }
-       dynreloc()
-
-       /* some symbols may no longer belong in datap (Mach-O) */
-       var l **LSym
-       var s *LSym
-       for l = &datap; ; {
-               s = *l
-               if s == nil {
-                       break
-               }
-
-               if s.Type <= obj.STEXT || obj.SXREF <= s.Type {
-                       *l = s.Next
-               } else {
-                       l = &s.Next
-               }
-       }
-
-       *l = nil
+       dynreloc(&data)
 
        if UseRelro() {
                // "read only" data with relocations needs to go in its own section
                // when building a shared library. We do this by boosting objects of
                // type SXXX with relocations to type SXXXRELRO.
-               for s := datap; s != nil; s = s.Next {
-                       if (s.Type >= obj.STYPE && s.Type <= obj.SFUNCTAB && len(s.R) > 0) || s.Type == obj.STYPE || s.Type == obj.SGOSTRINGHDR {
-                               s.Type += (obj.STYPERELRO - obj.STYPE)
-                               if s.Outer != nil {
-                                       s.Outer.Type = s.Type
+               for symnro := int16(obj.STYPE); symnro < obj.STYPERELRO; symnro++ {
+                       symnrelro := symnro + obj.STYPERELRO - obj.STYPE
+
+                       ro := []*LSym{}
+                       relro := data[symnrelro]
+
+                       for _, s := range data[symnro] {
+                               isRelro := len(s.R) > 0
+                               switch s.Type {
+                               case obj.STYPE, obj.SGOSTRINGHDR, obj.STYPERELRO, obj.SGOSTRINGHDRRELRO:
+                                       // Symbols are not sorted yet, so it is possible
+                                       // that an Outer symbol has been changed to a
+                                       // relro Type before it reaches here.
+                                       isRelro = true
+                               }
+                               if isRelro {
+                                       s.Type = symnrelro
+                                       if s.Outer != nil {
+                                               s.Outer.Type = s.Type
+                                       }
+                                       relro = append(relro, s)
+                               } else {
+                                       ro = append(ro, s)
                                }
                        }
-               }
-               // Check that we haven't made two symbols with the same .Outer into
-               // different types (because references two symbols with non-nil Outer
-               // become references to the outer symbol + offset it's vital that the
-               // symbol and the outer end up in the same section).
-               for s := datap; s != nil; s = s.Next {
-                       if s.Outer != nil && s.Outer.Type != s.Type {
-                               Diag("inconsistent types for %s and its Outer %s (%d != %d)",
-                                       s.Name, s.Outer.Name, s.Type, s.Outer.Type)
-                       }
-               }
-
-       }
 
-       datap = dataSort(datap)
-
-       if Iself {
-               // Make .rela and .rela.plt contiguous, the ELF ABI requires this
-               // and Solaris actually cares.
-               var relplt *LSym
-               for l = &datap; *l != nil; l = &(*l).Next {
-                       if (*l).Name == ".rel.plt" || (*l).Name == ".rela.plt" {
-                               relplt = (*l)
-                               *l = (*l).Next
-                               break
-                       }
-               }
-               if relplt != nil {
-                       for s = datap; s != nil; s = s.Next {
-                               if s.Name == ".rel" || s.Name == ".rela" {
-                                       relplt.Next = s.Next
-                                       s.Next = relplt
+                       // Check that we haven't made two symbols with the same .Outer into
+                       // different types (because references two symbols with non-nil Outer
+                       // become references to the outer symbol + offset it's vital that the
+                       // symbol and the outer end up in the same section).
+                       for _, s := range relro {
+                               if s.Outer != nil && s.Outer.Type != s.Type {
+                                       Diag("inconsistent types for %s and its Outer %s (%d != %d)",
+                                               s.Name, s.Outer.Name, s.Type, s.Outer.Type)
                                }
                        }
+
+                       data[symnro] = ro
+                       data[symnrelro] = relro
                }
        }
 
-       /*
-        * allocate sections.  list is sorted by type,
-        * so we can just walk it for each piece we want to emit.
-        * segdata is processed before segtext, because we need
-        * to see all symbols in the .data and .bss sections in order
-        * to generate garbage collection information.
-        */
-
-       /* begin segdata */
-
-       /* skip symbols belonging to segtext */
-       s = datap
-
-       for ; s != nil && s.Type < obj.SELFSECT; s = s.Next {
+       // Sort symbols.
+       var wg sync.WaitGroup
+       for symn := range data {
+               symn := symn
+               wg.Add(1)
+               go func() {
+                       data[symn] = dodataSect(symn, data[symn])
+                       wg.Done()
+               }()
        }
+       wg.Wait()
 
-       /* writable ELF sections */
+       // Allocate sections.
+       // Data is processed before segtext, because we need
+       // to see all symbols in the .data and .bss sections in order
+       // to generate garbage collection information.
        datsize := int64(0)
 
-       var sect *Section
-       for ; s != nil && s.Type < obj.SELFGOT; s = s.Next {
-               sect = addsection(&Segdata, s.Name, 06)
-               sect.Align = symalign(s)
-               datsize = Rnd(datsize, int64(sect.Align))
-               sect.Vaddr = uint64(datsize)
-               s.Sect = sect
-               s.Type = obj.SDATA
-               s.Value = int64(uint64(datsize) - sect.Vaddr)
-               growdatsize(&datsize, s)
-               sect.Length = uint64(datsize) - sect.Vaddr
+       // Writable sections.
+       writableSects := []int{
+               obj.SELFSECT,
+               obj.SMACHO,
+               obj.SMACHOGOT,
+               obj.SWINDOWS,
+       }
+       for _, symn := range writableSects {
+               for _, s := range data[symn] {
+                       sect := addsection(&Segdata, s.Name, 06)
+                       sect.Align = symalign(s)
+                       datsize = Rnd(datsize, int64(sect.Align))
+                       sect.Vaddr = uint64(datsize)
+                       s.Sect = sect
+                       s.Type = obj.SDATA
+                       s.Value = int64(uint64(datsize) - sect.Vaddr)
+                       growdatsize(&datsize, s)
+                       sect.Length = uint64(datsize) - sect.Vaddr
+               }
        }
 
-       /* .got (and .toc on ppc64) */
-       if s.Type == obj.SELFGOT {
+       // .got (and .toc on ppc64)
+       if len(data[obj.SELFGOT]) > 0 {
                sect := addsection(&Segdata, ".got", 06)
-               sect.Align = maxalign(s, obj.SELFGOT)
+               sect.Align = maxalign(data[obj.SELFGOT])
                datsize = Rnd(datsize, int64(sect.Align))
                sect.Vaddr = uint64(datsize)
                var toc *LSym
-               for ; s != nil && s.Type == obj.SELFGOT; s = s.Next {
+               for _, s := range data[obj.SELFGOT] {
                        datsize = aligndatsize(datsize, s)
                        s.Sect = sect
                        s.Type = obj.SDATA
@@ -1400,7 +1380,6 @@ func dodata() {
 
                        // Resolve .TOC. symbol for this object file (ppc64)
                        toc = Linkrlookup(Ctxt, ".TOC.", int(s.Version))
-
                        if toc != nil {
                                toc.Sect = sect
                                toc.Outer = s
@@ -1412,26 +1391,24 @@ func dodata() {
 
                        growdatsize(&datsize, s)
                }
-
                sect.Length = uint64(datsize) - sect.Vaddr
        }
 
        /* pointer-free data */
-       sect = addsection(&Segdata, ".noptrdata", 06)
+       sect := addsection(&Segdata, ".noptrdata", 06)
 
-       sect.Align = maxalign(s, obj.SINITARR-1)
+       sect.Align = maxalign(data[obj.SNOPTRDATA])
        datsize = Rnd(datsize, int64(sect.Align))
        sect.Vaddr = uint64(datsize)
        Linklookup(Ctxt, "runtime.noptrdata", 0).Sect = sect
        Linklookup(Ctxt, "runtime.enoptrdata", 0).Sect = sect
-       for ; s != nil && s.Type < obj.SINITARR; s = s.Next {
+       for _, s := range data[obj.SNOPTRDATA] {
                datsize = aligndatsize(datsize, s)
                s.Sect = sect
                s.Type = obj.SDATA
                s.Value = int64(uint64(datsize) - sect.Vaddr)
                growdatsize(&datsize, s)
        }
-
        sect.Length = uint64(datsize) - sect.Vaddr
 
        hasinitarr := Linkshared
@@ -1441,37 +1418,30 @@ func dodata() {
        case BuildmodeCArchive, BuildmodeCShared, BuildmodeShared:
                hasinitarr = true
        }
-
        if hasinitarr {
                sect := addsection(&Segdata, ".init_array", 06)
-               sect.Align = maxalign(s, obj.SINITARR)
+               sect.Align = maxalign(data[obj.SINITARR])
                datsize = Rnd(datsize, int64(sect.Align))
                sect.Vaddr = uint64(datsize)
-               for ; s != nil && s.Type == obj.SINITARR; s = s.Next {
+               for _, s := range data[obj.SINITARR] {
                        datsize = aligndatsize(datsize, s)
                        s.Sect = sect
                        s.Value = int64(uint64(datsize) - sect.Vaddr)
                        growdatsize(&datsize, s)
                }
-
                sect.Length = uint64(datsize) - sect.Vaddr
        }
 
        /* data */
        sect = addsection(&Segdata, ".data", 06)
-       sect.Align = maxalign(s, obj.SBSS-1)
+       sect.Align = maxalign(data[obj.SDATA])
        datsize = Rnd(datsize, int64(sect.Align))
        sect.Vaddr = uint64(datsize)
        Linklookup(Ctxt, "runtime.data", 0).Sect = sect
        Linklookup(Ctxt, "runtime.edata", 0).Sect = sect
        var gc GCProg
        gc.Init("runtime.gcdata")
-       for ; s != nil && s.Type < obj.SBSS; s = s.Next {
-               if s.Type == obj.SINITARR {
-                       Ctxt.Cursym = s
-                       Diag("unexpected symbol type %d", s.Type)
-               }
-
+       for _, s := range data[obj.SDATA] {
                s.Sect = sect
                s.Type = obj.SDATA
                datsize = aligndatsize(datsize, s)
@@ -1484,14 +1454,14 @@ func dodata() {
 
        /* bss */
        sect = addsection(&Segdata, ".bss", 06)
-       sect.Align = maxalign(s, obj.SNOPTRBSS-1)
+       sect.Align = maxalign(data[obj.SBSS])
        datsize = Rnd(datsize, int64(sect.Align))
        sect.Vaddr = uint64(datsize)
        Linklookup(Ctxt, "runtime.bss", 0).Sect = sect
        Linklookup(Ctxt, "runtime.ebss", 0).Sect = sect
        gc = GCProg{}
        gc.Init("runtime.gcbss")
-       for ; s != nil && s.Type < obj.SNOPTRBSS; s = s.Next {
+       for _, s := range data[obj.SBSS] {
                s.Sect = sect
                datsize = aligndatsize(datsize, s)
                s.Value = int64(uint64(datsize) - sect.Vaddr)
@@ -1504,12 +1474,12 @@ func dodata() {
        /* pointer-free bss */
        sect = addsection(&Segdata, ".noptrbss", 06)
 
-       sect.Align = maxalign(s, obj.SNOPTRBSS)
+       sect.Align = maxalign(data[obj.SNOPTRBSS])
        datsize = Rnd(datsize, int64(sect.Align))
        sect.Vaddr = uint64(datsize)
        Linklookup(Ctxt, "runtime.noptrbss", 0).Sect = sect
        Linklookup(Ctxt, "runtime.enoptrbss", 0).Sect = sect
-       for ; s != nil && s.Type == obj.SNOPTRBSS; s = s.Next {
+       for _, s := range data[obj.SNOPTRBSS] {
                datsize = aligndatsize(datsize, s)
                s.Sect = sect
                s.Value = int64(uint64(datsize) - sect.Vaddr)
@@ -1519,22 +1489,21 @@ func dodata() {
        sect.Length = uint64(datsize) - sect.Vaddr
        Linklookup(Ctxt, "runtime.end", 0).Sect = sect
 
-       // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
+       // The compiler uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
        if datsize != int64(uint32(datsize)) {
                Diag("data or bss segment too large")
        }
 
-       if s != nil && s.Type == obj.STLSBSS {
+       if len(data[obj.STLSBSS]) > 0 {
+               var sect *Section
                if Iself && (Linkmode == LinkExternal || Debug['d'] == 0) && HEADTYPE != obj.Hopenbsd {
                        sect = addsection(&Segdata, ".tbss", 06)
                        sect.Align = int32(SysArch.PtrSize)
                        sect.Vaddr = 0
-               } else {
-                       sect = nil
                }
                datsize = 0
 
-               for ; s != nil && s.Type == obj.STLSBSS; s = s.Next {
+               for _, s := range data[obj.STLSBSS] {
                        datsize = aligndatsize(datsize, s)
                        s.Sect = sect
                        s.Value = datsize
@@ -1546,11 +1515,6 @@ func dodata() {
                }
        }
 
-       if s != nil {
-               Ctxt.Cursym = nil
-               Diag("unexpected symbol type %d for %s", s.Type, s.Name)
-       }
-
        /*
         * We finished data, begin read-only data.
         * Not all systems support a separate read-only non-executable data section.
@@ -1568,13 +1532,14 @@ func dodata() {
                segro = &Segtext
        }
 
-       s = datap
-
        datsize = 0
 
        /* read-only executable ELF, Mach-O sections */
-       for ; s != nil && s.Type < obj.STYPE; s = s.Next {
-               sect = addsection(&Segtext, s.Name, 04)
+       if len(data[obj.STEXT]) != 0 {
+               Diag("dodata found an STEXT symbol: %s", data[obj.STEXT][0].Name)
+       }
+       for _, s := range data[obj.SELFRXSECT] {
+               sect := addsection(&Segtext, s.Name, 04)
                sect.Align = symalign(s)
                datsize = Rnd(datsize, int64(sect.Align))
                sect.Vaddr = uint64(datsize)
@@ -1588,8 +1553,6 @@ func dodata() {
        /* read-only data */
        sect = addsection(segro, ".rodata", 04)
 
-       sect.Align = maxalign(s, obj.STYPERELRO-1)
-       datsize = Rnd(datsize, int64(sect.Align))
        sect.Vaddr = 0
        Linklookup(Ctxt, "runtime.rodata", 0).Sect = sect
        Linklookup(Ctxt, "runtime.erodata", 0).Sect = sect
@@ -1597,14 +1560,32 @@ func dodata() {
                Linklookup(Ctxt, "runtime.types", 0).Sect = sect
                Linklookup(Ctxt, "runtime.etypes", 0).Sect = sect
        }
-       for ; s != nil && s.Type < obj.STYPERELRO; s = s.Next {
-               datsize = aligndatsize(datsize, s)
-               s.Sect = sect
-               s.Type = obj.SRODATA
-               s.Value = int64(uint64(datsize) - sect.Vaddr)
-               growdatsize(&datsize, s)
+       roSects := []int{
+               obj.STYPE,
+               obj.SSTRING,
+               obj.SGOSTRING,
+               obj.SGOSTRINGHDR,
+               obj.SGOFUNC,
+               obj.SGCBITS,
+               obj.SRODATA,
+               obj.SFUNCTAB,
+       }
+       for _, symn := range roSects {
+               align := maxalign(data[symn])
+               if sect.Align < align {
+                       sect.Align = align
+               }
+       }
+       datsize = Rnd(datsize, int64(sect.Align))
+       for _, symn := range roSects {
+               for _, s := range data[symn] {
+                       datsize = aligndatsize(datsize, s)
+                       s.Sect = sect
+                       s.Type = obj.SRODATA
+                       s.Value = int64(uint64(datsize) - sect.Vaddr)
+                       growdatsize(&datsize, s)
+               }
        }
-
        sect.Length = uint64(datsize) - sect.Vaddr
 
        // There is some data that are conceptually read-only but are written to by
@@ -1626,20 +1607,37 @@ func dodata() {
                /* data only written by relocations */
                sect = addsection(segro, ".data.rel.ro", 06)
 
-               sect.Align = maxalign(s, obj.STYPELINK-1)
-               datsize = Rnd(datsize, int64(sect.Align))
                sect.Vaddr = 0
                Linklookup(Ctxt, "runtime.types", 0).Sect = sect
                Linklookup(Ctxt, "runtime.etypes", 0).Sect = sect
-               for ; s != nil && s.Type < obj.STYPELINK; s = s.Next {
-                       datsize = aligndatsize(datsize, s)
-                       if s.Outer != nil && s.Outer.Sect != nil && s.Outer.Sect != sect {
-                               Diag("s.Outer (%s) in different section from s (%s)", s.Outer.Name, s.Name)
+               relroSects := []int{
+                       obj.STYPERELRO,
+                       obj.SSTRINGRELRO,
+                       obj.SGOSTRINGRELRO,
+                       obj.SGOSTRINGHDRRELRO,
+                       obj.SGOFUNCRELRO,
+                       obj.SGCBITSRELRO,
+                       obj.SRODATARELRO,
+                       obj.SFUNCTABRELRO,
+               }
+               for _, symn := range relroSects {
+                       align := maxalign(data[symn])
+                       if sect.Align < align {
+                               sect.Align = align
+                       }
+               }
+               datsize = Rnd(datsize, int64(sect.Align))
+               for _, symn := range relroSects {
+                       for _, s := range data[symn] {
+                               datsize = aligndatsize(datsize, s)
+                               if s.Outer != nil && s.Outer.Sect != nil && s.Outer.Sect != sect {
+                                       Diag("s.Outer (%s) in different section from s (%s)", s.Outer.Name, s.Name)
+                               }
+                               s.Sect = sect
+                               s.Type = obj.SRODATA
+                               s.Value = int64(uint64(datsize) - sect.Vaddr)
+                               growdatsize(&datsize, s)
                        }
-                       s.Sect = sect
-                       s.Type = obj.SRODATA
-                       s.Value = int64(uint64(datsize) - sect.Vaddr)
-                       growdatsize(&datsize, s)
                }
 
                sect.Length = uint64(datsize) - sect.Vaddr
@@ -1648,78 +1646,85 @@ func dodata() {
 
        /* typelink */
        sect = addsection(segro, relro_prefix+".typelink", relro_perms)
-
-       sect.Align = maxalign(s, obj.STYPELINK)
+       sect.Align = maxalign(data[obj.STYPELINK])
        datsize = Rnd(datsize, int64(sect.Align))
        sect.Vaddr = uint64(datsize)
        Linklookup(Ctxt, "runtime.typelink", 0).Sect = sect
        Linklookup(Ctxt, "runtime.etypelink", 0).Sect = sect
-       for ; s != nil && s.Type == obj.STYPELINK; s = s.Next {
+       for _, s := range data[obj.STYPELINK] {
                datsize = aligndatsize(datsize, s)
                s.Sect = sect
                s.Type = obj.SRODATA
                s.Value = int64(uint64(datsize) - sect.Vaddr)
                growdatsize(&datsize, s)
        }
-
        sect.Length = uint64(datsize) - sect.Vaddr
 
        /* itablink */
        sect = addsection(segro, relro_prefix+".itablink", relro_perms)
 
-       sect.Align = maxalign(s, obj.SITABLINK)
+       sect.Align = maxalign(data[obj.SITABLINK])
        datsize = Rnd(datsize, int64(sect.Align))
        sect.Vaddr = uint64(datsize)
        Linklookup(Ctxt, "runtime.itablink", 0).Sect = sect
        Linklookup(Ctxt, "runtime.eitablink", 0).Sect = sect
-       for ; s != nil && s.Type == obj.SITABLINK; s = s.Next {
+       for _, s := range data[obj.SITABLINK] {
                datsize = aligndatsize(datsize, s)
                s.Sect = sect
                s.Type = obj.SRODATA
                s.Value = int64(uint64(datsize) - sect.Vaddr)
                growdatsize(&datsize, s)
        }
-
        sect.Length = uint64(datsize) - sect.Vaddr
 
        /* gosymtab */
        sect = addsection(segro, relro_prefix+".gosymtab", relro_perms)
 
-       sect.Align = maxalign(s, obj.SPCLNTAB-1)
+       sect.Align = maxalign(data[obj.SSYMTAB])
        datsize = Rnd(datsize, int64(sect.Align))
        sect.Vaddr = uint64(datsize)
        Linklookup(Ctxt, "runtime.symtab", 0).Sect = sect
        Linklookup(Ctxt, "runtime.esymtab", 0).Sect = sect
-       for ; s != nil && s.Type < obj.SPCLNTAB; s = s.Next {
+       for _, s := range data[obj.SSYMTAB] {
                datsize = aligndatsize(datsize, s)
                s.Sect = sect
                s.Type = obj.SRODATA
                s.Value = int64(uint64(datsize) - sect.Vaddr)
                growdatsize(&datsize, s)
        }
-
        sect.Length = uint64(datsize) - sect.Vaddr
 
        /* gopclntab */
        sect = addsection(segro, relro_prefix+".gopclntab", relro_perms)
 
-       sect.Align = maxalign(s, obj.SELFROSECT-1)
+       sect.Align = maxalign(data[obj.SPCLNTAB])
        datsize = Rnd(datsize, int64(sect.Align))
        sect.Vaddr = uint64(datsize)
        Linklookup(Ctxt, "runtime.pclntab", 0).Sect = sect
        Linklookup(Ctxt, "runtime.epclntab", 0).Sect = sect
-       for ; s != nil && s.Type < obj.SELFROSECT; s = s.Next {
+       for _, s := range data[obj.SPCLNTAB] {
                datsize = aligndatsize(datsize, s)
                s.Sect = sect
                s.Type = obj.SRODATA
                s.Value = int64(uint64(datsize) - sect.Vaddr)
                growdatsize(&datsize, s)
        }
-
        sect.Length = uint64(datsize) - sect.Vaddr
 
        /* read-only ELF, Mach-O sections */
-       for ; s != nil && s.Type < obj.SELFSECT; s = s.Next {
+       for _, s := range data[obj.SELFROSECT] {
+               sect = addsection(segro, s.Name, 04)
+               sect.Align = symalign(s)
+               datsize = Rnd(datsize, int64(sect.Align))
+               sect.Vaddr = uint64(datsize)
+               s.Sect = sect
+               s.Type = obj.SRODATA
+               s.Value = int64(uint64(datsize) - sect.Vaddr)
+               growdatsize(&datsize, s)
+               sect.Length = uint64(datsize) - sect.Vaddr
+       }
+
+       for _, s := range data[obj.SMACHOPLT] {
                sect = addsection(segro, s.Name, 04)
                sect.Align = symalign(s)
                datsize = Rnd(datsize, int64(sect.Align))
@@ -1736,8 +1741,13 @@ func dodata() {
                Diag("read-only data segment too large")
        }
 
+       for symn := obj.SELFRXSECT; symn < obj.SXREF; symn++ {
+               datap = append(datap, data[symn]...)
+       }
+
        dwarfgeneratedebugsyms()
 
+       var s *LSym
        for s = dwarfp; s != nil && s.Type == obj.SDWARFSECT; s = s.Next {
                sect = addsection(&Segdwarf, s.Name, 04)
                sect.Align = 1
@@ -1791,6 +1801,84 @@ func dodata() {
        }
 }
 
+func dodataSect(symn int, syms []*LSym) []*LSym {
+       if HEADTYPE == obj.Hdarwin {
+               // Some symbols may no longer belong in syms
+               // due to movement in machosymorder.
+               newSyms := make([]*LSym, 0, len(syms))
+               for _, s := range syms {
+                       if int(s.Type) == symn {
+                               newSyms = append(newSyms, s)
+                       }
+               }
+               syms = newSyms
+       }
+
+       symsSort := make([]dataSortKey, len(syms))
+       for i, s := range syms {
+               if s.Attr.OnList() {
+                       log.Fatalf("symbol %s listed multiple times", s.Name)
+               }
+               s.Attr |= AttrOnList
+               if int64(len(s.P)) > s.Size {
+                       Diag("%s: initialize bounds (%d < %d)", s.Name, s.Size, len(s.P))
+               }
+
+               symsSort[i] = dataSortKey{
+                       size: s.Size,
+                       name: s.Name,
+                       lsym: s,
+               }
+
+               switch s.Type {
+               case obj.SELFGOT:
+                       // For ppc64, we want to interleave the .got and .toc sections
+                       // from input files. Both are type SELFGOT, so in that case
+                       // we skip size comparison and fall through to the name
+                       // comparison (conveniently, .got sorts before .toc).
+                       symsSort[i].size = 0
+               case obj.STYPELINK:
+                       // Sort typelinks by the rtype.string field so the reflect
+                       // package can binary search type links.
+                       symsSort[i].name = string(decodetype_string(s.R[0].Sym))
+               }
+       }
+
+       sort.Sort(bySizeAndName(symsSort))
+
+       for i, symSort := range symsSort {
+               syms[i] = symSort.lsym
+       }
+
+       if Iself && symn == obj.SELFROSECT {
+               // Make .rela and .rela.plt contiguous, the ELF ABI requires this
+               // and Solaris actually cares.
+               reli, plti := -1, -1
+               for i, s := range syms {
+                       switch s.Name {
+                       case ".rel.plt", ".rela.plt":
+                               plti = i
+                       case ".rel", ".rela":
+                               reli = i
+                       }
+               }
+               if reli >= 0 && plti >= 0 && plti != reli+1 {
+                       newSyms := make([]*LSym, 0, len(syms))
+                       plt := syms[plti]
+                       newSyms = append(newSyms, syms[:reli+1]...)
+                       newSyms = append(newSyms, plt)
+                       newSyms = append(newSyms, syms[reli+1:plti]...)
+                       newSyms = append(newSyms, syms[plti+1:]...)
+                       if len(newSyms) != len(syms) {
+                               Diag("plt move failed: len %d/%d", len(newSyms), len(syms))
+                       }
+                       syms = newSyms
+               }
+       }
+
+       return syms
+}
+
 // Add buildid to beginning of text segment, on non-ELF systems.
 // Non-ELF binary formats are not always flexible enough to
 // give us a place to put the Go build ID. On those systems, we put it
@@ -1816,8 +1904,6 @@ func textbuildid() {
 
 // assign addresses to text
 func textaddress() {
-       var sub *LSym
-
        addsection(&Segtext, ".text", 05)
 
        // Assign PCs in text segment.
@@ -1844,7 +1930,7 @@ func textaddress() {
                        va = uint64(Rnd(int64(va), int64(Funcalign)))
                }
                sym.Value = 0
-               for sub = sym; sub != nil; sub = sub.Sub {
+               for sub := sym; sub != nil; sub = sub.Sub {
                        sub.Value += int64(va)
                }
                if sym.Size == 0 && sym.Sub != nil {
@@ -1982,22 +2068,22 @@ func address() {
        symtab := itablink.Next
        pclntab := symtab.Next
 
-       var sub *LSym
-       for sym := datap; sym != nil; sym = sym.Next {
-               Ctxt.Cursym = sym
-               if sym.Sect != nil {
-                       sym.Value += int64(sym.Sect.Vaddr)
+       for _, s := range datap {
+               Ctxt.Cursym = s
+               if s.Sect != nil {
+                       s.Value += int64(s.Sect.Vaddr)
                }
-               for sub = sym.Sub; sub != nil; sub = sub.Sub {
-                       sub.Value += sym.Value
+               for sub := s.Sub; sub != nil; sub = sub.Sub {
+                       sub.Value += s.Value
                }
        }
+
        for sym := dwarfp; sym != nil; sym = sym.Next {
                Ctxt.Cursym = sym
                if sym.Sect != nil {
                        sym.Value += int64(sym.Sect.Vaddr)
                }
-               for sub = sym.Sub; sub != nil; sub = sub.Sub {
+               for sub := sym.Sub; sub != nil; sub = sub.Sub {
                        sub.Value += sym.Value
                }
        }
index 15f0656aea0f0e70b2a5d362a4e7c622e292baa1..84aa58e7c76f710bd212f91ec95cb19ec747a7f7 100644 (file)
@@ -1670,7 +1670,7 @@ func elfshreloc(sect *Section) *ElfShdr {
        return sh
 }
 
-func elfrelocsect(sect *Section, first *LSym) {
+func elfrelocsect(sect *Section, syms []*LSym) {
        // If main section is SHT_NOBITS, nothing to relocate.
        // Also nothing to relocate in .shstrtab.
        if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
@@ -1681,18 +1681,18 @@ func elfrelocsect(sect *Section, first *LSym) {
        }
 
        sect.Reloff = uint64(Cpos())
-       var sym *LSym
-       for sym = first; sym != nil; sym = sym.Next {
-               if !sym.Attr.Reachable() {
+       for i, s := range syms {
+               if !s.Attr.Reachable() {
                        continue
                }
-               if uint64(sym.Value) >= sect.Vaddr {
+               if uint64(s.Value) >= sect.Vaddr {
+                       syms = syms[i:]
                        break
                }
        }
 
        eaddr := int32(sect.Vaddr + sect.Length)
-       for ; sym != nil; sym = sym.Next {
+       for _, sym := range syms {
                if !sym.Attr.Reachable() {
                        continue
                }
@@ -1710,7 +1710,6 @@ func elfrelocsect(sect *Section, first *LSym) {
                                Diag("missing xsym in relocation")
                                continue
                        }
-
                        if r.Xsym.ElfsymForReloc() == 0 {
                                Diag("reloc %d to non-elf symbol %s (outer=%s) %d", r.Type, r.Sym.Name, r.Xsym.Name, r.Sym.Type)
                        }
@@ -1728,7 +1727,7 @@ func Elfemitreloc() {
                Cput(0)
        }
 
-       elfrelocsect(Segtext.Sect, Ctxt.Textp)
+       elfrelocsect(Segtext.Sect, list2slice(Ctxt.Textp))
        for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next {
                elfrelocsect(sect, datap)
        }
@@ -1739,7 +1738,7 @@ func Elfemitreloc() {
                elfrelocsect(sect, datap)
        }
        for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
-               elfrelocsect(sect, dwarfp)
+               elfrelocsect(sect, list2slice(dwarfp))
        }
 }
 
index 24cdca5a3bfb587fe4c20772eb17f8e5f00964c6..d728dda5b659359f7984209c70b22ce1274fd899 100644 (file)
@@ -130,7 +130,6 @@ func (r *Rpath) String() string {
 
 var (
        Thearch Arch
-       datap   *LSym
        Debug   [128]int
        Lcsize  int32
        rpath   Rpath
@@ -2109,7 +2108,7 @@ func undef() {
        for s := Ctxt.Textp; s != nil; s = s.Next {
                undefsym(s)
        }
-       for s := datap; s != nil; s = s.Next {
+       for _, s := range datap {
                undefsym(s)
        }
        if nerrors > 0 {
index 6ca5ba58619757d7d1be6e538942ac0c144fa7b5..5b2906ee2725c0c25c70cb5b2db769f1d8c6520b 100644 (file)
@@ -806,25 +806,25 @@ func Domacholink() int64 {
        return Rnd(int64(size), int64(INITRND))
 }
 
-func machorelocsect(sect *Section, first *LSym) {
+func machorelocsect(sect *Section, syms []*LSym) {
        // If main section has no bits, nothing to relocate.
        if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
                return
        }
 
        sect.Reloff = uint64(Cpos())
-       var sym *LSym
-       for sym = first; sym != nil; sym = sym.Next {
-               if !sym.Attr.Reachable() {
+       for i, s := range syms {
+               if !s.Attr.Reachable() {
                        continue
                }
-               if uint64(sym.Value) >= sect.Vaddr {
+               if uint64(s.Value) >= sect.Vaddr {
+                       syms = syms[i:]
                        break
                }
        }
 
        eaddr := int32(sect.Vaddr + sect.Length)
-       for ; sym != nil; sym = sym.Next {
+       for _, sym := range syms {
                if !sym.Attr.Reachable() {
                        continue
                }
@@ -852,7 +852,7 @@ func Machoemitreloc() {
                Cput(0)
        }
 
-       machorelocsect(Segtext.Sect, Ctxt.Textp)
+       machorelocsect(Segtext.Sect, list2slice(Ctxt.Textp))
        for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next {
                machorelocsect(sect, datap)
        }
@@ -860,6 +860,6 @@ func Machoemitreloc() {
                machorelocsect(sect, datap)
        }
        for sect := Segdwarf.Sect; sect != nil; sect = sect.Next {
-               machorelocsect(sect, dwarfp)
+               machorelocsect(sect, list2slice(dwarfp))
        }
 }
index 3b477fd846ed08a25d66935c988a99d06050b2e7..c0df07d3595ad309b4b297216e8b3b113a70a04f 100644 (file)
@@ -764,7 +764,7 @@ func addexports() {
 
 // perelocsect relocates symbols from first in section sect, and returns
 // the total number of relocations emitted.
-func perelocsect(sect *Section, first *LSym) int {
+func perelocsect(sect *Section, syms []*LSym) int {
        // If main section has no bits, nothing to relocate.
        if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
                return 0
@@ -773,18 +773,18 @@ func perelocsect(sect *Section, first *LSym) int {
        relocs := 0
 
        sect.Reloff = uint64(Cpos())
-       var sym *LSym
-       for sym = first; sym != nil; sym = sym.Next {
-               if !sym.Attr.Reachable() {
+       for i, s := range syms {
+               if !s.Attr.Reachable() {
                        continue
                }
-               if uint64(sym.Value) >= sect.Vaddr {
+               if uint64(s.Value) >= sect.Vaddr {
+                       syms = syms[i:]
                        break
                }
        }
 
        eaddr := int32(sect.Vaddr + sect.Length)
-       for ; sym != nil; sym = sym.Next {
+       for _, sym := range syms {
                if !sym.Attr.Reachable() {
                        continue
                }
@@ -831,7 +831,7 @@ func peemitreloc(text, data, ctors *IMAGE_SECTION_HEADER) {
        Lputl(0)
        Wputl(0)
 
-       n := perelocsect(Segtext.Sect, Ctxt.Textp) + 1
+       n := perelocsect(Segtext.Sect, list2slice(Ctxt.Textp)) + 1
        for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next {
                n += perelocsect(sect, datap)
        }