]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.link] cmd/link: refactor section creation in dodata
authorThan McIntosh <thanm@google.com>
Fri, 17 Apr 2020 21:23:02 +0000 (17:23 -0400)
committerThan McIntosh <thanm@google.com>
Tue, 21 Apr 2020 16:26:42 +0000 (16:26 +0000)
Additional cleanups and refactorings in the allocateSections portion
of dodata. Introduce some new helper routines to be used for common
cases in creating sections and assigning symbols, with a goal of
reducing duplicated code blocks and having more readable code.

No change in functionality.

Change-Id: I1b020b3ee993674329b2bebfd7c35995e3a2c043
Reviewed-on: https://go-review.googlesource.com/c/go/+/228883
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
src/cmd/link/internal/ld/data.go

index 204c237794300e5083249b89002f6097ca1bd2e9..49f5505f57d1075c07c92af1a1f43853ce1db04e 100644 (file)
@@ -1436,7 +1436,7 @@ func (ctxt *Link) dodata() {
        fixZeroSizedSymbols(ctxt)
 
        // Collect data symbols by type into data.
-       state := dodataState{}
+       state := dodataState{ctxt: ctxt}
        for _, s := range ctxt.Syms.Allsym {
                if !s.Attr.Reachable() || s.Attr.Special() || s.Attr.SubSymbol() {
                        continue
@@ -1507,6 +1507,42 @@ func (ctxt *Link) dodata() {
        }
 }
 
+// allocateDataSectionForSym creates a new sym.Section into which a a
+// single symbol will be placed. Here "seg" is the segment into which
+// the section will go, "s" is the symbol to be placed into the new
+// section, and "rwx" contains permissions for the section.
+func (state *dodataState) allocateDataSectionForSym(seg *sym.Segment, s *sym.Symbol, rwx int) *sym.Section {
+       sect := addsection(state.ctxt.Arch, seg, s.Name, rwx)
+       sect.Align = symalign(s)
+       state.datsize = Rnd(state.datsize, int64(sect.Align))
+       sect.Vaddr = uint64(state.datsize)
+       return sect
+}
+
+// allocateNamedDataSection creates a new sym.Section for a category
+// of data symbols. Here "seg" is the segment into which the section
+// will go, "sName" is the name to give to the section, "types" is a
+// range of symbol types to be put into the section, and "rwx"
+// contains permissions for the section.
+func (state *dodataState) allocateNamedDataSection(seg *sym.Segment, sName string, types []sym.SymKind, rwx int) *sym.Section {
+       sect := addsection(state.ctxt.Arch, seg, sName, rwx)
+       if len(types) == 0 {
+               sect.Align = 1
+       } else if len(types) == 1 {
+               sect.Align = state.dataMaxAlign[types[0]]
+       } else {
+               for _, symn := range types {
+                       align := state.dataMaxAlign[symn]
+                       if sect.Align < align {
+                               sect.Align = align
+                       }
+               }
+       }
+       state.datsize = Rnd(state.datsize, int64(sect.Align))
+       sect.Vaddr = uint64(state.datsize)
+       return sect
+}
+
 // assignDsymsToSection assigns a collection of data symbols to a
 // newly created section. "sect" is the section into which to place
 // the symbols, "syms" holds the list of symbols to assign,
@@ -1531,6 +1567,38 @@ func (state *dodataState) assignToSection(sect *sym.Section, symn sym.SymKind, f
        state.checkdatsize(symn)
 }
 
+// allocateSingleSymSections walks through the bucketed data symbols
+// with type 'symn', creates a new section for each sym, and assigns
+// the sym to a newly created section. Section name is set from the
+// symbol name. "Seg" is the segment into which to place the new
+// section, "forceType" is the new sym.SymKind to assign to the symbol
+// within the section, and "rwx" holds section permissions.
+func (state *dodataState) allocateSingleSymSections(seg *sym.Segment, symn sym.SymKind, forceType sym.SymKind, rwx int) {
+       for _, s := range state.data[symn] {
+               sect := state.allocateDataSectionForSym(seg, s, rwx)
+               s.Sect = sect
+               s.Type = forceType
+               s.Value = int64(uint64(state.datsize) - sect.Vaddr)
+               state.datsize += s.Size
+               sect.Length = uint64(state.datsize) - sect.Vaddr
+       }
+       state.checkdatsize(symn)
+}
+
+// allocateNamedSectionAndAssignSyms creates a new section with the
+// specified name, then walks through the bucketed data symbols with
+// type 'symn' and assigns each of them to this new section. "Seg" is
+// the segment into which to place the new section, "secName" is the
+// name to give to the new section, "forceType" (if non-zero) contains
+// a new sym type to apply to each sym during the assignment, and
+// "rwx" holds section permissions.
+func (state *dodataState) allocateNamedSectionAndAssignSyms(seg *sym.Segment, secName string, symn sym.SymKind, forceType sym.SymKind, rwx int) *sym.Section {
+
+       sect := state.allocateNamedDataSection(seg, secName, []sym.SymKind{symn}, rwx)
+       state.assignDsymsToSection(sect, state.data[symn], forceType, aligndatsize)
+       return sect
+}
+
 // allocateSections allocates sym.Section objects for data sections
 // of interest and assigns symbols into the sections.
 func (state *dodataState) allocateSections(ctxt *Link) {
@@ -1548,27 +1616,12 @@ func (state *dodataState) allocateSections(ctxt *Link) {
                sym.SWINDOWS,
        }
        for _, symn := range writable {
-               for _, s := range state.data[symn] {
-                       sect := addsection(ctxt.Arch, &Segdata, s.Name, 06)
-                       sect.Align = symalign(s)
-                       state.datsize = Rnd(state.datsize, int64(sect.Align))
-                       sect.Vaddr = uint64(state.datsize)
-                       s.Sect = sect
-                       s.Type = sym.SDATA
-                       s.Value = int64(uint64(state.datsize) - sect.Vaddr)
-                       state.datsize += s.Size
-                       sect.Length = uint64(state.datsize) - sect.Vaddr
-               }
-               state.checkdatsize(symn)
+               state.allocateSingleSymSections(&Segdata, symn, sym.SDATA, 06)
        }
 
        // .got (and .toc on ppc64)
        if len(state.data[sym.SELFGOT]) > 0 {
-               sect := addsection(ctxt.Arch, &Segdata, ".got", 06)
-               sect.Align = state.dataMaxAlign[sym.SELFGOT]
-               state.datsize = Rnd(state.datsize, int64(sect.Align))
-               sect.Vaddr = uint64(state.datsize)
-               state.assignToSection(sect, sym.SELFGOT, sym.SDATA)
+               sect := state.allocateNamedSectionAndAssignSyms(&Segdata, ".got", sym.SELFGOT, sym.SDATA, 06)
                if ctxt.IsPPC64() {
                        for _, s := range state.data[sym.SELFGOT] {
                                // Resolve .TOC. symbol for this object file (ppc64)
@@ -1586,13 +1639,9 @@ func (state *dodataState) allocateSections(ctxt *Link) {
        }
 
        /* pointer-free data */
-       sect := addsection(ctxt.Arch, &Segdata, ".noptrdata", 06)
-       sect.Align = state.dataMaxAlign[sym.SNOPTRDATA]
-       state.datsize = Rnd(state.datsize, int64(sect.Align))
-       sect.Vaddr = uint64(state.datsize)
+       sect := state.allocateNamedSectionAndAssignSyms(&Segdata, ".noptrdata", sym.SNOPTRDATA, sym.SDATA, 06)
        ctxt.Syms.Lookup("runtime.noptrdata", 0).Sect = sect
        ctxt.Syms.Lookup("runtime.enoptrdata", 0).Sect = sect
-       state.assignToSection(sect, sym.SNOPTRDATA, sym.SDATA)
 
        hasinitarr := ctxt.linkShared
 
@@ -1609,21 +1658,13 @@ func (state *dodataState) allocateSections(ctxt *Link) {
        }
 
        if hasinitarr && len(state.data[sym.SINITARR]) > 0 {
-               sect := addsection(ctxt.Arch, &Segdata, ".init_array", 06)
-               sect.Align = state.dataMaxAlign[sym.SINITARR]
-               state.datsize = Rnd(state.datsize, int64(sect.Align))
-               sect.Vaddr = uint64(state.datsize)
-               state.assignToSection(sect, sym.SINITARR, sym.Sxxx)
+               state.allocateNamedSectionAndAssignSyms(&Segdata, ".init_array", sym.SINITARR, sym.Sxxx, 06)
        }
 
        /* data */
-       sect = addsection(ctxt.Arch, &Segdata, ".data", 06)
-       sect.Align = state.dataMaxAlign[sym.SDATA]
-       state.datsize = Rnd(state.datsize, int64(sect.Align))
-       sect.Vaddr = uint64(state.datsize)
+       sect = state.allocateNamedSectionAndAssignSyms(&Segdata, ".data", sym.SDATA, sym.SDATA, 06)
        ctxt.Syms.Lookup("runtime.data", 0).Sect = sect
        ctxt.Syms.Lookup("runtime.edata", 0).Sect = sect
-       state.assignToSection(sect, sym.SDATA, sym.SDATA)
        dataGcEnd := state.datsize - int64(sect.Vaddr)
 
        // On AIX, TOC entries must be the last of .data
@@ -1633,13 +1674,9 @@ func (state *dodataState) allocateSections(ctxt *Link) {
        sect.Length = uint64(state.datsize) - sect.Vaddr
 
        /* bss */
-       sect = addsection(ctxt.Arch, &Segdata, ".bss", 06)
-       sect.Align = state.dataMaxAlign[sym.SBSS]
-       state.datsize = Rnd(state.datsize, int64(sect.Align))
-       sect.Vaddr = uint64(state.datsize)
+       sect = state.allocateNamedSectionAndAssignSyms(&Segdata, ".bss", sym.SBSS, sym.Sxxx, 06)
        ctxt.Syms.Lookup("runtime.bss", 0).Sect = sect
        ctxt.Syms.Lookup("runtime.ebss", 0).Sect = sect
-       state.assignToSection(sect, sym.SBSS, sym.Sxxx)
        bssGcEnd := state.datsize - int64(sect.Vaddr)
 
        // Emit gcdata for bcc symbols now that symbol values have been assigned.
@@ -1661,29 +1698,23 @@ func (state *dodataState) allocateSections(ctxt *Link) {
        }
 
        /* pointer-free bss */
-       sect = addsection(ctxt.Arch, &Segdata, ".noptrbss", 06)
-       sect.Align = state.dataMaxAlign[sym.SNOPTRBSS]
-       state.datsize = Rnd(state.datsize, int64(sect.Align))
-       sect.Vaddr = uint64(state.datsize)
+       sect = state.allocateNamedSectionAndAssignSyms(&Segdata, ".noptrbss", sym.SNOPTRBSS, sym.Sxxx, 06)
        ctxt.Syms.Lookup("runtime.noptrbss", 0).Sect = sect
        ctxt.Syms.Lookup("runtime.enoptrbss", 0).Sect = sect
        ctxt.Syms.Lookup("runtime.end", 0).Sect = sect
-       state.assignToSection(sect, sym.SNOPTRBSS, sym.Sxxx)
 
        // Coverage instrumentation counters for libfuzzer.
        if len(state.data[sym.SLIBFUZZER_EXTRA_COUNTER]) > 0 {
-               sect := addsection(ctxt.Arch, &Segdata, "__libfuzzer_extra_counters", 06)
-               sect.Align = state.dataMaxAlign[sym.SLIBFUZZER_EXTRA_COUNTER]
-               state.datsize = Rnd(state.datsize, int64(sect.Align))
-               sect.Vaddr = uint64(state.datsize)
-               state.assignToSection(sect, sym.SLIBFUZZER_EXTRA_COUNTER, sym.Sxxx)
+               state.allocateNamedSectionAndAssignSyms(&Segdata, "__libfuzzer_extra_counters", sym.SLIBFUZZER_EXTRA_COUNTER, sym.Sxxx, 06)
        }
 
        if len(state.data[sym.STLSBSS]) > 0 {
                var sect *sym.Section
+               // FIXME: not clear why it is sometimes necessary to suppress .tbss section creation.
                if (ctxt.IsELF || ctxt.HeadType == objabi.Haix) && (ctxt.LinkMode == LinkExternal || !*FlagD) {
                        sect = addsection(ctxt.Arch, &Segdata, ".tbss", 06)
                        sect.Align = int32(ctxt.Arch.PtrSize)
+                       // FIXME: why does this need to be set to zero?
                        sect.Vaddr = 0
                }
                state.datsize = 0
@@ -1725,36 +1756,16 @@ func (state *dodataState) allocateSections(ctxt *Link) {
        if len(state.data[sym.STEXT]) != 0 {
                Errorf(nil, "dodata found an sym.STEXT symbol: %s", state.data[sym.STEXT][0].Name)
        }
-       for _, s := range state.data[sym.SELFRXSECT] {
-               sect := addsection(ctxt.Arch, &Segtext, s.Name, 04)
-               sect.Align = symalign(s)
-               state.datsize = Rnd(state.datsize, int64(sect.Align))
-               sect.Vaddr = uint64(state.datsize)
-               s.Sect = sect
-               s.Type = sym.SRODATA
-               s.Value = int64(uint64(state.datsize) - sect.Vaddr)
-               state.datsize += s.Size
-               sect.Length = uint64(state.datsize) - sect.Vaddr
-               state.checkdatsize(sym.SELFRXSECT)
-       }
+       state.allocateSingleSymSections(&Segtext, sym.SELFRXSECT, sym.SRODATA, 04)
 
        /* read-only data */
-       sect = addsection(ctxt.Arch, segro, ".rodata", 04)
-
-       sect.Vaddr = 0
+       sect = state.allocateNamedDataSection(segro, ".rodata", sym.ReadOnly, 04)
        ctxt.Syms.Lookup("runtime.rodata", 0).Sect = sect
        ctxt.Syms.Lookup("runtime.erodata", 0).Sect = sect
        if !ctxt.UseRelro() {
                ctxt.Syms.Lookup("runtime.types", 0).Sect = sect
                ctxt.Syms.Lookup("runtime.etypes", 0).Sect = sect
        }
-       for _, symn := range sym.ReadOnly {
-               align := state.dataMaxAlign[symn]
-               if sect.Align < align {
-                       sect.Align = align
-               }
-       }
-       state.datsize = Rnd(state.datsize, int64(sect.Align))
        for _, symn := range sym.ReadOnly {
                symnStartValue := state.datsize
                state.assignToSection(sect, symn, sym.SRODATA)
@@ -1768,31 +1779,8 @@ func (state *dodataState) allocateSections(ctxt *Link) {
        }
 
        /* read-only ELF, Mach-O sections */
-       for _, s := range state.data[sym.SELFROSECT] {
-               sect = addsection(ctxt.Arch, segro, s.Name, 04)
-               sect.Align = symalign(s)
-               state.datsize = Rnd(state.datsize, int64(sect.Align))
-               sect.Vaddr = uint64(state.datsize)
-               s.Sect = sect
-               s.Type = sym.SRODATA
-               s.Value = int64(uint64(state.datsize) - sect.Vaddr)
-               state.datsize += s.Size
-               sect.Length = uint64(state.datsize) - sect.Vaddr
-       }
-       state.checkdatsize(sym.SELFROSECT)
-
-       for _, s := range state.data[sym.SMACHOPLT] {
-               sect = addsection(ctxt.Arch, segro, s.Name, 04)
-               sect.Align = symalign(s)
-               state.datsize = Rnd(state.datsize, int64(sect.Align))
-               sect.Vaddr = uint64(state.datsize)
-               s.Sect = sect
-               s.Type = sym.SRODATA
-               s.Value = int64(uint64(state.datsize) - sect.Vaddr)
-               state.datsize += s.Size
-               sect.Length = uint64(state.datsize) - sect.Vaddr
-       }
-       state.checkdatsize(sym.SMACHOPLT)
+       state.allocateSingleSymSections(segro, sym.SELFROSECT, sym.SRODATA, 04)
+       state.allocateSingleSymSections(segro, sym.SMACHOPLT, sym.SRODATA, 04)
 
        // There is some data that are conceptually read-only but are written to by
        // relocations. On GNU systems, we can arrange for the dynamic linker to
@@ -1804,9 +1792,13 @@ func (state *dodataState) allocateSections(ctxt *Link) {
        // situation.
        // TODO(mwhudson): It would make sense to do this more widely, but it makes
        // the system linker segfault on darwin.
-       addrelrosection := func(suffix string) *sym.Section {
-               return addsection(ctxt.Arch, segro, suffix, 04)
+       const relroPerm = 06
+       const fallbackPerm = 04
+       relroSecPerm := fallbackPerm
+       genrelrosecname := func(suffix string) string {
+               return suffix
        }
+       seg := segro
 
        if ctxt.UseRelro() {
                segrelro := &Segrelrodata
@@ -1823,26 +1815,23 @@ func (state *dodataState) allocateSections(ctxt *Link) {
                        state.datsize = 0
                }
 
-               addrelrosection = func(suffix string) *sym.Section {
-                       return addsection(ctxt.Arch, segrelro, ".data.rel.ro"+suffix, 06)
+               genrelrosecname = func(suffix string) string {
+                       return ".data.rel.ro" + suffix
                }
+               relroReadOnly := []sym.SymKind{}
+               for _, symnro := range sym.ReadOnly {
+                       symn := sym.RelROMap[symnro]
+                       relroReadOnly = append(relroReadOnly, symn)
+               }
+               seg = segrelro
+               relroSecPerm = relroPerm
 
                /* data only written by relocations */
-               sect = addrelrosection("")
+               sect = state.allocateNamedDataSection(segrelro, genrelrosecname(""), relroReadOnly, relroSecPerm)
 
                ctxt.Syms.Lookup("runtime.types", 0).Sect = sect
                ctxt.Syms.Lookup("runtime.etypes", 0).Sect = sect
 
-               for _, symnro := range sym.ReadOnly {
-                       symn := sym.RelROMap[symnro]
-                       align := state.dataMaxAlign[symn]
-                       if sect.Align < align {
-                               sect.Align = align
-                       }
-               }
-               state.datsize = Rnd(state.datsize, int64(sect.Align))
-               sect.Vaddr = uint64(state.datsize)
-
                for i, symnro := range sym.ReadOnly {
                        if i == 0 && symnro == sym.STYPE && ctxt.HeadType != objabi.Haix {
                                // Skip forward so that no type
@@ -1874,10 +1863,7 @@ func (state *dodataState) allocateSections(ctxt *Link) {
        }
 
        /* typelink */
-       sect = addrelrosection(".typelink")
-       sect.Align = state.dataMaxAlign[sym.STYPELINK]
-       state.datsize = Rnd(state.datsize, int64(sect.Align))
-       sect.Vaddr = uint64(state.datsize)
+       sect = state.allocateNamedDataSection(seg, genrelrosecname(".typelink"), []sym.SymKind{sym.STYPELINK}, relroSecPerm)
        typelink := ctxt.Syms.Lookup("runtime.typelink", 0)
        typelink.Sect = sect
        typelink.Type = sym.SRODATA
@@ -1886,13 +1872,9 @@ func (state *dodataState) allocateSections(ctxt *Link) {
        sect.Length = uint64(state.datsize) - sect.Vaddr
 
        /* itablink */
-       sect = addrelrosection(".itablink")
-       sect.Align = state.dataMaxAlign[sym.SITABLINK]
-       state.datsize = Rnd(state.datsize, int64(sect.Align))
-       sect.Vaddr = uint64(state.datsize)
+       sect = state.allocateNamedSectionAndAssignSyms(seg, genrelrosecname(".itablink"), sym.SITABLINK, sym.Sxxx, relroSecPerm)
        ctxt.Syms.Lookup("runtime.itablink", 0).Sect = sect
        ctxt.Syms.Lookup("runtime.eitablink", 0).Sect = sect
-       state.assignToSection(sect, sym.SITABLINK, sym.SRODATA)
        if ctxt.HeadType == objabi.Haix {
                // Store .itablink size because its symbols are wrapped
                // under an outer symbol: runtime.itablink.
@@ -1900,22 +1882,14 @@ func (state *dodataState) allocateSections(ctxt *Link) {
        }
 
        /* gosymtab */
-       sect = addrelrosection(".gosymtab")
-       sect.Align = state.dataMaxAlign[sym.SSYMTAB]
-       state.datsize = Rnd(state.datsize, int64(sect.Align))
-       sect.Vaddr = uint64(state.datsize)
+       sect = state.allocateNamedSectionAndAssignSyms(seg, genrelrosecname(".gosymtab"), sym.SSYMTAB, sym.SRODATA, relroSecPerm)
        ctxt.Syms.Lookup("runtime.symtab", 0).Sect = sect
        ctxt.Syms.Lookup("runtime.esymtab", 0).Sect = sect
-       state.assignToSection(sect, sym.SSYMTAB, sym.SRODATA)
 
        /* gopclntab */
-       sect = addrelrosection(".gopclntab")
-       sect.Align = state.dataMaxAlign[sym.SPCLNTAB]
-       state.datsize = Rnd(state.datsize, int64(sect.Align))
-       sect.Vaddr = uint64(state.datsize)
+       sect = state.allocateNamedSectionAndAssignSyms(seg, genrelrosecname(".gopclntab"), sym.SPCLNTAB, sym.SRODATA, relroSecPerm)
        ctxt.Syms.Lookup("runtime.pclntab", 0).Sect = sect
        ctxt.Syms.Lookup("runtime.epclntab", 0).Sect = sect
-       state.assignToSection(sect, sym.SPCLNTAB, sym.SRODATA)
 
        // 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
        if state.datsize != int64(uint32(state.datsize)) {
@@ -1931,11 +1905,8 @@ func (state *dodataState) allocateSections(ctxt *Link) {
        for i := 0; i < len(dwarfp); i++ {
                // First the section symbol.
                s := dwarfp[i].secSym()
-               sect = addsection(ctxt.Arch, &Segdwarf, s.Name, 04)
+               sect := state.allocateNamedDataSection(&Segdwarf, s.Name, []sym.SymKind{}, 04)
                sect.Sym = s
-               sect.Align = 1
-               state.datsize = Rnd(state.datsize, int64(sect.Align))
-               sect.Vaddr = uint64(state.datsize)
                s.Sect = sect
                s.Type = sym.SRODATA
                s.Value = int64(uint64(state.datsize) - sect.Vaddr)