From 87b43088cd736c32f56b864b8185a311d31b1852 Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Fri, 17 Apr 2020 17:23:02 -0400 Subject: [PATCH] [dev.link] cmd/link: refactor section creation in dodata 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 Reviewed-by: Jeremy Faller --- src/cmd/link/internal/ld/data.go | 237 ++++++++++++++----------------- 1 file changed, 104 insertions(+), 133 deletions(-) diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 204c2377943..49f5505f57d 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -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)