From cdfff4d25a01ee1ae269d31a57c1e65ea00249b0 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Wed, 29 Apr 2020 22:00:28 -0400 Subject: [PATCH] [dev.link] cmd/link: use more compact representation for external relocations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, for external relocations, the ExtReloc structure contains all the fields of the relocation. In fact, many of the fields are the same with the original relocation. So, instead, we can just use an index to reference the original relocation and not expand the fields. There is one place where we modify relocation type: changing R_DWARFSECTREF to R_ADDR. Get away with it by changing downstreams. It also makes it easier to retrieve the reloc variant. This reduces some allocation. Linking cmd/compile with external linking, name old alloc/op new alloc/op delta Reloc_GC 34.1MB ± 0% 22.7MB ± 0% -33.30% (p=0.000 n=5+4) Change-Id: Id08a89ed2aee705296886d3b95014b806a0d55cf Reviewed-on: https://go-review.googlesource.com/c/go/+/231217 Run-TryBot: Cherry Zhang TryBot-Result: Gobot Gobot Reviewed-by: Than McIntosh Reviewed-by: Jeremy Faller --- src/cmd/link/internal/amd64/asm.go | 2 +- src/cmd/link/internal/arm/asm.go | 2 +- src/cmd/link/internal/arm64/asm.go | 2 +- src/cmd/link/internal/ld/data.go | 73 +++++++++++--------------- src/cmd/link/internal/loader/loader.go | 33 ++++++------ src/cmd/link/internal/mips/asm.go | 2 +- src/cmd/link/internal/mips64/asm.go | 2 +- src/cmd/link/internal/ppc64/asm.go | 2 +- src/cmd/link/internal/s390x/asm.go | 2 +- src/cmd/link/internal/x86/asm.go | 2 +- 10 files changed, 55 insertions(+), 67 deletions(-) diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go index e1daaec2c73..e2c33b80010 100644 --- a/src/cmd/link/internal/amd64/asm.go +++ b/src/cmd/link/internal/amd64/asm.go @@ -400,7 +400,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool { switch r.Type { default: return false - case objabi.R_ADDR: + case objabi.R_ADDR, objabi.R_DWARFSECREF: if r.Siz == 4 { ctxt.Out.Write64(uint64(elf.R_X86_64_32) | uint64(elfsym)<<32) } else if r.Siz == 8 { diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go index c95de0de2f1..a2024bcedec 100644 --- a/src/cmd/link/internal/arm/asm.go +++ b/src/cmd/link/internal/arm/asm.go @@ -256,7 +256,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool { switch r.Type { default: return false - case objabi.R_ADDR: + case objabi.R_ADDR, objabi.R_DWARFSECREF: if r.Siz == 4 { ctxt.Out.Write32(uint32(elf.R_ARM_ABS32) | uint32(elfsym)<<8) } else { diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go index 2d12fc2f595..dc3e45d6c07 100644 --- a/src/cmd/link/internal/arm64/asm.go +++ b/src/cmd/link/internal/arm64/asm.go @@ -332,7 +332,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool { switch r.Type { default: return false - case objabi.R_ADDR: + case objabi.R_ADDR, objabi.R_DWARFSECREF: switch r.Siz { case 4: ctxt.Out.Write64(uint64(elf.R_AARCH64_ABS32) | uint64(elfsym)<<32) diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index af1b335db7b..102fcabe478 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -224,11 +224,7 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) { var rr loader.ExtReloc needExtReloc := false // will set to true below in case it is needed if target.IsExternal() { - rr.Sym = rs - rr.Type = rt - rr.Off = off - rr.Siz = uint8(siz) - rr.Add = r.Add() + rr.Idx = ri } // TODO(mundaym): remove this special case - see issue 14218. @@ -282,14 +278,14 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) { case objabi.R_TLS_LE: if target.IsExternal() && target.IsElf() { needExtReloc = true - if rr.Sym == 0 { - rr.Sym = syms.Tlsg2 + rr.Xsym = rs + if rr.Xsym == 0 { + rr.Xsym = syms.Tlsg2 } - rr.Xsym = rr.Sym - rr.Xadd = rr.Add + rr.Xadd = r.Add() o = 0 if !target.IsAMD64() { - o = rr.Add + o = r.Add() } break } @@ -313,14 +309,14 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) { case objabi.R_TLS_IE: if target.IsExternal() && target.IsElf() { needExtReloc = true - if rr.Sym == 0 { - rr.Sym = syms.Tlsg2 + rr.Xsym = rs + if rr.Xsym == 0 { + rr.Xsym = syms.Tlsg2 } - rr.Xsym = rr.Sym - rr.Xadd = rr.Add + rr.Xadd = r.Add() o = 0 if !target.IsAMD64() { - o = rr.Add + o = r.Add() } break } @@ -342,7 +338,7 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) { // set up addend for eventual relocation via outer symbol. rs := rs rs, off := foldSubSymbolOffset(ldr, rs) - rr.Xadd = rr.Add + off + rr.Xadd = r.Add() + off rst := ldr.SymType(rs) if rst != sym.SHOSTOBJ && rst != sym.SDYNIMPORT && rst != sym.SUNDEFEXT && ldr.SymSect(rs) == nil { st.err.Errorf(s, "missing section for relocation target %s", ldr.SymName(rs)) @@ -361,7 +357,7 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) { } else if target.IsWindows() { // nothing to do } else if target.IsAIX() { - o = ldr.SymValue(rr.Sym) + rr.Add + o = ldr.SymValue(rs) + r.Add() } else { st.err.Errorf(s, "unhandled pcrel relocation to %s on %v", ldr.SymName(rs), target.HeadType) } @@ -413,17 +409,8 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) { needExtReloc = false } - // PE code emits IMAGE_REL_I386_SECREL and IMAGE_REL_AMD64_SECREL - // for R_DWARFSECREF relocations, while R_ADDR is replaced with - // IMAGE_REL_I386_DIR32, IMAGE_REL_AMD64_ADDR64 and IMAGE_REL_AMD64_ADDR32. - // Do not replace R_DWARFSECREF with R_ADDR for windows - - // let PE code emit correct relocations. - if !target.IsWindows() { - rr.Type = objabi.R_ADDR - } - - rr.Xsym = loader.Sym(ldr.SymSect(rr.Sym).Sym2) - rr.Xadd = rr.Add + ldr.SymValue(rr.Sym) - int64(ldr.SymSect(rr.Sym).Vaddr) + rr.Xsym = loader.Sym(ldr.SymSect(rs).Sym2) + rr.Xadd = r.Add() + ldr.SymValue(rs) - int64(ldr.SymSect(rs).Vaddr) o = rr.Xadd if target.IsElf() && target.IsAMD64() { @@ -455,12 +442,12 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) { case objabi.R_GOTPCREL: if target.IsDynlinkingGo() && target.IsDarwin() && rs != 0 && rst != sym.SCONST { needExtReloc = true - rr.Xadd = rr.Add - rr.Xadd -= int64(rr.Siz) // relative to address after the relocated chunk - rr.Xsym = rr.Sym + rr.Xadd = r.Add() + rr.Xadd -= int64(siz) // relative to address after the relocated chunk + rr.Xsym = rs o = rr.Xadd - o += int64(rr.Siz) + o += int64(siz) break } fallthrough @@ -470,9 +457,9 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) { needExtReloc = true rr.Xadd = 0 if target.IsElf() { - rr.Xadd -= int64(rr.Siz) + rr.Xadd -= int64(siz) } - rr.Xsym = rr.Sym + rr.Xsym = rs o = 0 break } @@ -482,8 +469,8 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) { // set up addend for eventual relocation via outer symbol. rs := rs rs, off := foldSubSymbolOffset(ldr, rs) - rr.Xadd = rr.Add + off - rr.Xadd -= int64(rr.Siz) // relative to address after the relocated chunk + rr.Xadd = r.Add() + off + rr.Xadd -= int64(siz) // relative to address after the relocated chunk rst := ldr.SymType(rs) if rst != sym.SHOSTOBJ && rst != sym.SDYNIMPORT && ldr.SymSect(rs) == nil { st.err.Errorf(s, "missing section for relocation target %s", ldr.SymName(rs)) @@ -496,25 +483,25 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) { o = 0 } } else if target.IsDarwin() { - if rr.Type == objabi.R_CALL { + if rt == objabi.R_CALL { if target.IsExternal() && rst == sym.SDYNIMPORT { if target.IsAMD64() { // AMD64 dynamic relocations are relative to the end of the relocation. - o += int64(rr.Siz) + o += int64(siz) } } else { if rst != sym.SHOSTOBJ { o += int64(uint64(ldr.SymValue(rs)) - ldr.SymSect(rs).Vaddr) } - o -= int64(rr.Off) // relative to section offset, not symbol + o -= int64(off) // relative to section offset, not symbol } } else { - o += int64(rr.Siz) + o += int64(siz) } } else if target.IsWindows() && target.IsAMD64() { // only amd64 needs PCREL // PE/COFF's PC32 relocation uses the address after the relocated // bytes as the base. Compensate by skewing the addend. - o += int64(rr.Siz) + o += int64(siz) } else { st.err.Errorf(s, "unhandled pcrel relocation to %s on %v", ldr.SymName(rs), target.HeadType) } @@ -539,8 +526,8 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) { st.err.Errorf(s, "find XCOFF R_REF with internal linking") } needExtReloc = true - rr.Xsym = rr.Sym - rr.Xadd = rr.Add + rr.Xsym = rs + rr.Xadd = r.Add() // This isn't a real relocation so it must not update // its offset value. diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go index a7b65e3580e..749995bf8e8 100644 --- a/src/cmd/link/internal/loader/loader.go +++ b/src/cmd/link/internal/loader/loader.go @@ -51,11 +51,7 @@ type Reloc struct { // ExtReloc contains the payload for an external relocation. type ExtReloc struct { - Off int32 // offset to rewrite - Siz uint8 // number of bytes to rewrite: 0, 1, 2, or 4 - Type objabi.RelocType // the relocation type - Sym Sym // global index of symbol the reloc addresses - Add int64 // addend + Idx int // index of the original relocation Xsym Sym Xadd int64 } @@ -2763,25 +2759,30 @@ func (l *Loader) convertExtRelocs(dst *sym.Symbol, src Sym) { if int(src) >= len(l.extRelocs) { return } - relocs := l.extRelocs[src] - if len(relocs) == 0 { + extRelocs := l.extRelocs[src] + if len(extRelocs) == 0 { return } if len(dst.R) != 0 { panic("bad") } - dst.R = make([]sym.Reloc, len(relocs)) + dst.R = make([]sym.Reloc, len(extRelocs)) + relocs := l.Relocs(src) for i := range dst.R { - sr := &relocs[i] + er := &extRelocs[i] + sr := relocs.At2(er.Idx) r := &dst.R[i] r.InitExt() - r.Off = sr.Off - r.Siz = sr.Siz - r.Type = sr.Type - r.Sym = l.Syms[sr.Sym] - r.Add = sr.Add - r.Xsym = l.Syms[sr.Xsym] - r.Xadd = sr.Xadd + r.Off = sr.Off() + r.Siz = sr.Siz() + r.Type = sr.Type() + r.Sym = l.Syms[l.ResolveABIAlias(sr.Sym())] + r.Add = sr.Add() + r.Xsym = l.Syms[er.Xsym] + r.Xadd = er.Xadd + if rv := l.RelocVariant(src, er.Idx); rv != 0 { + r.Variant = rv + } } } diff --git a/src/cmd/link/internal/mips/asm.go b/src/cmd/link/internal/mips/asm.go index 53032a7e335..a366e80ea3e 100644 --- a/src/cmd/link/internal/mips/asm.go +++ b/src/cmd/link/internal/mips/asm.go @@ -58,7 +58,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool { switch r.Type { default: return false - case objabi.R_ADDR: + case objabi.R_ADDR, objabi.R_DWARFSECREF: if r.Siz != 4 { return false } diff --git a/src/cmd/link/internal/mips64/asm.go b/src/cmd/link/internal/mips64/asm.go index 33f8b335090..e69db298099 100644 --- a/src/cmd/link/internal/mips64/asm.go +++ b/src/cmd/link/internal/mips64/asm.go @@ -69,7 +69,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool { switch r.Type { default: return false - case objabi.R_ADDR: + case objabi.R_ADDR, objabi.R_DWARFSECREF: switch r.Siz { case 4: ctxt.Out.Write8(uint8(elf.R_MIPS_32)) diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go index 7a5dc565e68..4dc50eab79a 100644 --- a/src/cmd/link/internal/ppc64/asm.go +++ b/src/cmd/link/internal/ppc64/asm.go @@ -457,7 +457,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool { switch r.Type { default: return false - case objabi.R_ADDR: + case objabi.R_ADDR, objabi.R_DWARFSECREF: switch r.Siz { case 4: ctxt.Out.Write64(uint64(elf.R_PPC64_ADDR32) | uint64(elfsym)<<32) diff --git a/src/cmd/link/internal/s390x/asm.go b/src/cmd/link/internal/s390x/asm.go index 4def25868aa..bec7705be58 100644 --- a/src/cmd/link/internal/s390x/asm.go +++ b/src/cmd/link/internal/s390x/asm.go @@ -246,7 +246,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool { case 4: ctxt.Out.Write64(uint64(elf.R_390_TLS_IEENT) | uint64(elfsym)<<32) } - case objabi.R_ADDR: + case objabi.R_ADDR, objabi.R_DWARFSECREF: switch r.Siz { default: return false diff --git a/src/cmd/link/internal/x86/asm.go b/src/cmd/link/internal/x86/asm.go index df704a444d1..21ea5780cbb 100644 --- a/src/cmd/link/internal/x86/asm.go +++ b/src/cmd/link/internal/x86/asm.go @@ -347,7 +347,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool { switch r.Type { default: return false - case objabi.R_ADDR: + case objabi.R_ADDR, objabi.R_DWARFSECREF: if r.Siz == 4 { ctxt.Out.Write32(uint32(elf.R_386_32) | uint32(elfsym)<<8) } else {