Skip to content

Commit 1667b35

Browse files
committed
[dev.link] cmd/link: directly use loader.ExtReloc in ELF relocation generation
Convert the part that uses relocations to use loader.ExtReloc directly. It still uses sym.Symbols for now, but not sym.Relocs. This reduces some memory usage: linking cmd/compile with external linking, name old allocs/op new allocs/op delta Loadlibfull_GC 52.2MB ± 0% 13.9MB ± 0% -73.40% (p=0.008 n=5+5) name old live-B new live-B delta Loadlibfull_GC 75.5M ± 0% 61.9M ± 0% -18.02% (p=0.008 n=5+5) Change-Id: I317ecbf516063c42b255b2caba310ea6281342d7 Reviewed-on: https://go-review.googlesource.com/c/go/+/231319 Reviewed-by: Jeremy Faller <[email protected]> Reviewed-by: Than McIntosh <[email protected]>
1 parent 7aa6e0f commit 1667b35

File tree

7 files changed

+144
-47
lines changed

7 files changed

+144
-47
lines changed

src/cmd/link/internal/amd64/asm.go

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -393,36 +393,38 @@ func adddynrel2(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, s load
393393
return false
394394
}
395395

396-
func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
396+
func elfreloc2(ctxt *ld.Link, ldr *loader.Loader, s loader.Sym, r loader.ExtRelocView, sectoff int64) bool {
397397
ctxt.Out.Write64(uint64(sectoff))
398398

399-
elfsym := ld.ElfSymForReloc(ctxt, r.Xsym)
400-
switch r.Type {
399+
xsym := ldr.Syms[r.Xsym]
400+
elfsym := ld.ElfSymForReloc(ctxt, xsym)
401+
siz := r.Siz()
402+
switch r.Type() {
401403
default:
402404
return false
403405
case objabi.R_ADDR, objabi.R_DWARFSECREF:
404-
if r.Siz == 4 {
406+
if siz == 4 {
405407
ctxt.Out.Write64(uint64(elf.R_X86_64_32) | uint64(elfsym)<<32)
406-
} else if r.Siz == 8 {
408+
} else if siz == 8 {
407409
ctxt.Out.Write64(uint64(elf.R_X86_64_64) | uint64(elfsym)<<32)
408410
} else {
409411
return false
410412
}
411413
case objabi.R_TLS_LE:
412-
if r.Siz == 4 {
414+
if siz == 4 {
413415
ctxt.Out.Write64(uint64(elf.R_X86_64_TPOFF32) | uint64(elfsym)<<32)
414416
} else {
415417
return false
416418
}
417419
case objabi.R_TLS_IE:
418-
if r.Siz == 4 {
420+
if siz == 4 {
419421
ctxt.Out.Write64(uint64(elf.R_X86_64_GOTTPOFF) | uint64(elfsym)<<32)
420422
} else {
421423
return false
422424
}
423425
case objabi.R_CALL:
424-
if r.Siz == 4 {
425-
if r.Xsym.Type == sym.SDYNIMPORT {
426+
if siz == 4 {
427+
if xsym.Type == sym.SDYNIMPORT {
426428
if ctxt.DynlinkingGo() {
427429
ctxt.Out.Write64(uint64(elf.R_X86_64_PLT32) | uint64(elfsym)<<32)
428430
} else {
@@ -435,8 +437,8 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
435437
return false
436438
}
437439
case objabi.R_PCREL:
438-
if r.Siz == 4 {
439-
if r.Xsym.Type == sym.SDYNIMPORT && r.Xsym.ElfType() == elf.STT_FUNC {
440+
if siz == 4 {
441+
if xsym.Type == sym.SDYNIMPORT && xsym.ElfType() == elf.STT_FUNC {
440442
ctxt.Out.Write64(uint64(elf.R_X86_64_PLT32) | uint64(elfsym)<<32)
441443
} else {
442444
ctxt.Out.Write64(uint64(elf.R_X86_64_PC32) | uint64(elfsym)<<32)
@@ -445,7 +447,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
445447
return false
446448
}
447449
case objabi.R_GOTPCREL:
448-
if r.Siz == 4 {
450+
if siz == 4 {
449451
ctxt.Out.Write64(uint64(elf.R_X86_64_GOTPCREL) | uint64(elfsym)<<32)
450452
} else {
451453
return false

src/cmd/link/internal/amd64/obj.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func Init() (*sys.Arch, ld.Arch) {
5252
Archrelocvariant: archrelocvariant,
5353
Asmb: asmb,
5454
Asmb2: asmb2,
55-
Elfreloc1: elfreloc1,
55+
Elfreloc2: elfreloc2,
5656
Elfsetupplt: elfsetupplt,
5757
Gentext2: gentext2,
5858
Machoreloc1: machoreloc1,

src/cmd/link/internal/ld/elf.go

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1374,6 +1374,11 @@ func elfshreloc(arch *sys.Arch, sect *sym.Section) *ElfShdr {
13741374
}
13751375

13761376
func elfrelocsect(ctxt *Link, sect *sym.Section, syms []*sym.Symbol) {
1377+
if !ctxt.IsAMD64() {
1378+
elfrelocsect2(ctxt, sect, syms)
1379+
return
1380+
}
1381+
13771382
// If main section is SHT_NOBITS, nothing to relocate.
13781383
// Also nothing to relocate in .shstrtab.
13791384
if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
@@ -1394,6 +1399,7 @@ func elfrelocsect(ctxt *Link, sect *sym.Section, syms []*sym.Symbol) {
13941399
}
13951400
}
13961401

1402+
ldr := ctxt.loader
13971403
eaddr := int32(sect.Vaddr + sect.Length)
13981404
for _, s := range syms {
13991405
if !s.Attr.Reachable() {
@@ -1402,24 +1408,23 @@ func elfrelocsect(ctxt *Link, sect *sym.Section, syms []*sym.Symbol) {
14021408
if s.Value >= int64(eaddr) {
14031409
break
14041410
}
1405-
for ri := range s.R {
1406-
r := &s.R[ri]
1407-
if r.Done {
1408-
continue
1409-
}
1410-
if r.Xsym == nil {
1411-
Errorf(s, "missing xsym in relocation %#v %#v", r.Sym.Name, s)
1411+
i := loader.Sym(s.SymIdx)
1412+
relocs := ldr.ExtRelocs(i)
1413+
for ri := 0; ri < relocs.Count(); ri++ {
1414+
r := relocs.At(ri)
1415+
if r.Xsym == 0 {
1416+
Errorf(s, "missing xsym in relocation %v", ldr.SymName(r.Sym()))
14121417
continue
14131418
}
1414-
esr := ElfSymForReloc(ctxt, r.Xsym)
1419+
esr := ElfSymForReloc(ctxt, ldr.Syms[r.Xsym])
14151420
if esr == 0 {
1416-
Errorf(s, "reloc %d (%s) to non-elf symbol %s (outer=%s) %d (%s)", r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Sym.Name, r.Xsym.Name, r.Sym.Type, r.Sym.Type)
1421+
Errorf(s, "reloc %d (%s) to non-elf symbol %s (outer=%s) %d (%s)", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), ldr.Syms[r.Sym()].Name, ldr.Syms[r.Xsym].Name, ldr.Syms[r.Sym()].Type, ldr.Syms[r.Sym()].Type)
14171422
}
1418-
if !r.Xsym.Attr.Reachable() {
1419-
Errorf(s, "unreachable reloc %d (%s) target %v", r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Xsym.Name)
1423+
if !ldr.AttrReachable(r.Xsym) {
1424+
Errorf(s, "unreachable reloc %d (%s) target %v", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), ldr.Syms[r.Xsym].Name)
14201425
}
1421-
if !thearch.Elfreloc1(ctxt, r, int64(uint64(s.Value+int64(r.Off))-sect.Vaddr)) {
1422-
Errorf(s, "unsupported obj reloc %d (%s)/%d to %s", r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Siz, r.Sym.Name)
1426+
if !thearch.Elfreloc2(ctxt, ldr, i, r, int64(uint64(s.Value+int64(r.Off()))-sect.Vaddr)) {
1427+
Errorf(s, "unsupported obj reloc %d (%s)/%d to %s", r.Type(), sym.RelocName(ctxt.Arch, r.Type()), r.Siz(), ldr.Syms[r.Sym()].Name)
14231428
}
14241429
}
14251430
}

src/cmd/link/internal/ld/elf2.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,57 @@ func elfsetstring(s *sym.Symbol, str string, off int) {
2323
elfstr[nelfstr].off = off
2424
nelfstr++
2525
}
26+
27+
func elfrelocsect2(ctxt *Link, sect *sym.Section, syms []*sym.Symbol) {
28+
// If main section is SHT_NOBITS, nothing to relocate.
29+
// Also nothing to relocate in .shstrtab.
30+
if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
31+
return
32+
}
33+
if sect.Name == ".shstrtab" {
34+
return
35+
}
36+
37+
sect.Reloff = uint64(ctxt.Out.Offset())
38+
for i, s := range syms {
39+
if !s.Attr.Reachable() {
40+
continue
41+
}
42+
if uint64(s.Value) >= sect.Vaddr {
43+
syms = syms[i:]
44+
break
45+
}
46+
}
47+
48+
eaddr := int32(sect.Vaddr + sect.Length)
49+
for _, s := range syms {
50+
if !s.Attr.Reachable() {
51+
continue
52+
}
53+
if s.Value >= int64(eaddr) {
54+
break
55+
}
56+
for ri := range s.R {
57+
r := &s.R[ri]
58+
if r.Done {
59+
continue
60+
}
61+
if r.Xsym == nil {
62+
Errorf(s, "missing xsym in relocation %#v %#v", r.Sym.Name, s)
63+
continue
64+
}
65+
esr := ElfSymForReloc(ctxt, r.Xsym)
66+
if esr == 0 {
67+
Errorf(s, "reloc %d (%s) to non-elf symbol %s (outer=%s) %d (%s)", r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Sym.Name, r.Xsym.Name, r.Sym.Type, r.Sym.Type)
68+
}
69+
if !r.Xsym.Attr.Reachable() {
70+
Errorf(s, "unreachable reloc %d (%s) target %v", r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Xsym.Name)
71+
}
72+
if !thearch.Elfreloc1(ctxt, r, int64(uint64(s.Value+int64(r.Off))-sect.Vaddr)) {
73+
Errorf(s, "unsupported obj reloc %d (%s)/%d to %s", r.Type, sym.RelocName(ctxt.Arch, r.Type), r.Siz, r.Sym.Name)
74+
}
75+
}
76+
}
77+
78+
sect.Rellen = uint64(ctxt.Out.Offset()) - sect.Reloff
79+
}

src/cmd/link/internal/ld/lib.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,7 @@ type Arch struct {
270270
Asmb2 func(*Link)
271271

272272
Elfreloc1 func(*Link, *sym.Reloc, int64) bool
273+
Elfreloc2 func(*Link, *loader.Loader, loader.Sym, loader.ExtRelocView, int64) bool
273274
Elfsetupplt func(ctxt *Link, plt, gotplt *loader.SymbolBuilder, dynamic loader.Sym)
274275
Gentext func(*Link)
275276
Gentext2 func(*Link, *loader.Loader)
@@ -2825,9 +2826,9 @@ func addToTextp(ctxt *Link) {
28252826
ctxt.Textp = textp
28262827
}
28272828

2828-
func (ctxt *Link) loadlibfull(symGroupType []sym.SymKind, needReloc bool) {
2829+
func (ctxt *Link) loadlibfull(symGroupType []sym.SymKind, needReloc, needExtReloc bool) {
28292830
// Load full symbol contents, resolve indexed references.
2830-
ctxt.loader.LoadFull(ctxt.Arch, ctxt.Syms, needReloc)
2831+
ctxt.loader.LoadFull(ctxt.Arch, ctxt.Syms, needReloc, needExtReloc)
28312832

28322833
// Convert ctxt.Moduledata2 to ctxt.Moduledata, etc
28332834
if ctxt.Moduledata2 != 0 {

src/cmd/link/internal/ld/main.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -335,10 +335,13 @@ func Main(arch *sys.Arch, theArch Arch) {
335335
// An exception is internal linking on Windows, see pe.go:addPEBaseRelocSym
336336
// Wasm is another exception, where it applies text relocations in Asmb2.
337337
needReloc := (ctxt.IsWindows() && ctxt.IsInternal()) || ctxt.IsWasm()
338-
ctxt.loadlibfull(symGroupType, needReloc) // XXX do it here for now
338+
// On AMD64 ELF, we directly use the loader's ExtRelocs, so we don't
339+
// need conversion. Otherwise we do.
340+
needExtReloc := ctxt.IsExternal() && !(ctxt.IsAMD64() && ctxt.IsELF)
341+
ctxt.loadlibfull(symGroupType, needReloc, needExtReloc) // XXX do it here for now
339342
} else {
340343
bench.Start("loadlibfull")
341-
ctxt.loadlibfull(symGroupType, true) // XXX do it here for now
344+
ctxt.loadlibfull(symGroupType, true, false) // XXX do it here for now
342345
bench.Start("reloc")
343346
ctxt.reloc2()
344347
}

src/cmd/link/internal/loader/loader.go

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@ type ExtReloc struct {
5656
Xadd int64
5757
}
5858

59+
// ExtRelocView is a view of an external relocation.
60+
// It is intended to be constructed on the fly, such as ExtRelocs.At.
61+
// It is not the data structure used to store the payload internally.
62+
type ExtRelocView struct {
63+
Reloc2
64+
*ExtReloc
65+
}
66+
5967
// Reloc2 holds a "handle" to access a relocation record from an
6068
// object file.
6169
type Reloc2 struct {
@@ -1116,7 +1124,7 @@ func (l *Loader) InitOutData() {
11161124
l.outdata = make([][]byte, l.extStart)
11171125
}
11181126

1119-
// SetExtRelocs sets the section of the i-th symbol. i is global index.
1127+
// SetExtRelocs sets the external relocations of the i-th symbol. i is global index.
11201128
func (l *Loader) SetExtRelocs(i Sym, relocs []ExtReloc) {
11211129
l.extRelocs[i] = relocs
11221130
}
@@ -1699,6 +1707,24 @@ func (l *Loader) relocs(r *oReader, li int) Relocs {
16991707
}
17001708
}
17011709

1710+
// ExtRelocs returns the external relocations of the i-th symbol.
1711+
func (l *Loader) ExtRelocs(i Sym) ExtRelocs {
1712+
return ExtRelocs{l.Relocs(i), l.extRelocs[i]}
1713+
}
1714+
1715+
// ExtRelocs represents the set of external relocations of a symbol.
1716+
type ExtRelocs struct {
1717+
rs Relocs
1718+
es []ExtReloc
1719+
}
1720+
1721+
func (ers ExtRelocs) Count() int { return len(ers.es) }
1722+
1723+
func (ers ExtRelocs) At(j int) ExtRelocView {
1724+
i := ers.es[j].Idx
1725+
return ExtRelocView{ers.rs.At2(i), &ers.es[j]}
1726+
}
1727+
17021728
// RelocByOff implements sort.Interface for sorting relocations by offset.
17031729

17041730
type RelocByOff []Reloc
@@ -2033,7 +2059,7 @@ func (l *Loader) preprocess(arch *sys.Arch, s Sym, name string) {
20332059
}
20342060

20352061
// Load full contents.
2036-
func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols, needReloc bool) {
2062+
func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols, needReloc, needExtReloc bool) {
20372063
// create all Symbols first.
20382064
l.growSyms(l.NSym())
20392065
l.growSects(l.NSym())
@@ -2047,7 +2073,7 @@ func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols, needReloc bool) {
20472073

20482074
nr := 0 // total number of sym.Reloc's we'll need
20492075
for _, o := range l.objs[1:] {
2050-
nr += loadObjSyms(l, syms, o.r, needReloc)
2076+
nr += loadObjSyms(l, syms, o.r, needReloc, needExtReloc)
20512077
}
20522078

20532079
// Make a first pass through the external symbols, making
@@ -2063,7 +2089,7 @@ func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols, needReloc bool) {
20632089
if needReloc {
20642090
nr += len(pp.relocs)
20652091
}
2066-
if int(i) < len(l.extRelocs) {
2092+
if needExtReloc && int(i) < len(l.extRelocs) {
20672093
nr += len(l.extRelocs[i])
20682094
}
20692095
// create and install the sym.Symbol here so that l.Syms will
@@ -2079,7 +2105,7 @@ func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols, needReloc bool) {
20792105
// allocate a single large slab of relocations for all live symbols
20802106
if nr != 0 {
20812107
l.relocBatch = make([]sym.Reloc, nr)
2082-
if len(l.extRelocs) != 0 {
2108+
if needExtReloc {
20832109
l.relocExtBatch = make([]sym.RelocExt, nr)
20842110
}
20852111
}
@@ -2102,8 +2128,9 @@ func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols, needReloc bool) {
21022128
relocs := l.Relocs(i)
21032129
l.convertRelocations(i, &relocs, s, false)
21042130
}
2105-
2106-
l.convertExtRelocs(s, i)
2131+
if needExtReloc {
2132+
l.convertExtRelocs(s, i)
2133+
}
21072134

21082135
// Copy data
21092136
s.P = pp.data
@@ -2114,7 +2141,7 @@ func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols, needReloc bool) {
21142141

21152142
// load contents of defined symbols
21162143
for _, o := range l.objs[1:] {
2117-
loadObjFull(l, o.r, needReloc)
2144+
loadObjFull(l, o.r, needReloc, needExtReloc)
21182145
}
21192146

21202147
// Sanity check: we should have consumed all batched allocations.
@@ -2170,17 +2197,21 @@ func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols, needReloc bool) {
21702197
l.plt = nil
21712198
l.got = nil
21722199
l.dynid = nil
2173-
l.relocVariant = nil
2174-
l.extRelocs = nil
2200+
if needExtReloc { // converted to sym.Relocs, drop loader references
2201+
l.relocVariant = nil
2202+
l.extRelocs = nil
2203+
}
21752204

21762205
// Drop fields that are no longer needed.
21772206
for _, i := range l.extReader.syms {
21782207
pp := l.getPayload(i)
21792208
pp.name = ""
2180-
pp.relocs = nil
2181-
pp.reltypes = nil
21822209
pp.auxs = nil
21832210
pp.data = nil
2211+
if needExtReloc {
2212+
pp.relocs = nil
2213+
pp.reltypes = nil
2214+
}
21842215
}
21852216
}
21862217

@@ -2450,7 +2481,7 @@ func topLevelSym(sname string, skind sym.SymKind) bool {
24502481
// loadObjSyms creates sym.Symbol objects for the live Syms in the
24512482
// object corresponding to object reader "r". Return value is the
24522483
// number of sym.Reloc entries required for all the new symbols.
2453-
func loadObjSyms(l *Loader, syms *sym.Symbols, r *oReader, needReloc bool) int {
2484+
func loadObjSyms(l *Loader, syms *sym.Symbols, r *oReader, needReloc, needExtReloc bool) int {
24542485
nr := 0
24552486
for i, n := 0, r.NSym()+r.NNonpkgdef(); i < n; i++ {
24562487
gi := r.syms[i]
@@ -2483,7 +2514,7 @@ func loadObjSyms(l *Loader, syms *sym.Symbols, r *oReader, needReloc bool) int {
24832514
if needReloc {
24842515
nr += r.NReloc(i)
24852516
}
2486-
if int(gi) < len(l.extRelocs) {
2517+
if needExtReloc && int(gi) < len(l.extRelocs) {
24872518
nr += len(l.extRelocs[gi])
24882519
}
24892520
}
@@ -2690,7 +2721,7 @@ func (l *Loader) FreeSym(i Sym) {
26902721
}
26912722
}
26922723

2693-
func loadObjFull(l *Loader, r *oReader, needReloc bool) {
2724+
func loadObjFull(l *Loader, r *oReader, needReloc, needExtReloc bool) {
26942725
for i, n := 0, r.NSym()+r.NNonpkgdef(); i < n; i++ {
26952726
// A symbol may be a dup or overwritten. In this case, its
26962727
// content will actually be provided by a different object
@@ -2722,8 +2753,9 @@ func loadObjFull(l *Loader, r *oReader, needReloc bool) {
27222753
l.relocBatch = batch[relocs.Count():]
27232754
l.convertRelocations(gi, &relocs, s, false)
27242755
}
2725-
2726-
l.convertExtRelocs(s, gi)
2756+
if needExtReloc {
2757+
l.convertExtRelocs(s, gi)
2758+
}
27272759

27282760
// Aux symbol info
27292761
auxs := r.Auxs(i)

0 commit comments

Comments
 (0)