[dev.link] cmd/link: use more compact representation for external relocations

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 <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
This commit is contained in:
Cherry Zhang 2020-04-29 22:00:28 -04:00
parent ca290169ab
commit cdfff4d25a
10 changed files with 55 additions and 67 deletions

View File

@ -400,7 +400,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
switch r.Type { switch r.Type {
default: default:
return false return false
case objabi.R_ADDR: case objabi.R_ADDR, objabi.R_DWARFSECREF:
if r.Siz == 4 { if r.Siz == 4 {
ctxt.Out.Write64(uint64(elf.R_X86_64_32) | uint64(elfsym)<<32) ctxt.Out.Write64(uint64(elf.R_X86_64_32) | uint64(elfsym)<<32)
} else if r.Siz == 8 { } else if r.Siz == 8 {

View File

@ -256,7 +256,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
switch r.Type { switch r.Type {
default: default:
return false return false
case objabi.R_ADDR: case objabi.R_ADDR, objabi.R_DWARFSECREF:
if r.Siz == 4 { if r.Siz == 4 {
ctxt.Out.Write32(uint32(elf.R_ARM_ABS32) | uint32(elfsym)<<8) ctxt.Out.Write32(uint32(elf.R_ARM_ABS32) | uint32(elfsym)<<8)
} else { } else {

View File

@ -332,7 +332,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
switch r.Type { switch r.Type {
default: default:
return false return false
case objabi.R_ADDR: case objabi.R_ADDR, objabi.R_DWARFSECREF:
switch r.Siz { switch r.Siz {
case 4: case 4:
ctxt.Out.Write64(uint64(elf.R_AARCH64_ABS32) | uint64(elfsym)<<32) ctxt.Out.Write64(uint64(elf.R_AARCH64_ABS32) | uint64(elfsym)<<32)

View File

@ -224,11 +224,7 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) {
var rr loader.ExtReloc var rr loader.ExtReloc
needExtReloc := false // will set to true below in case it is needed needExtReloc := false // will set to true below in case it is needed
if target.IsExternal() { if target.IsExternal() {
rr.Sym = rs rr.Idx = ri
rr.Type = rt
rr.Off = off
rr.Siz = uint8(siz)
rr.Add = r.Add()
} }
// TODO(mundaym): remove this special case - see issue 14218. // 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: case objabi.R_TLS_LE:
if target.IsExternal() && target.IsElf() { if target.IsExternal() && target.IsElf() {
needExtReloc = true needExtReloc = true
if rr.Sym == 0 { rr.Xsym = rs
rr.Sym = syms.Tlsg2 if rr.Xsym == 0 {
rr.Xsym = syms.Tlsg2
} }
rr.Xsym = rr.Sym rr.Xadd = r.Add()
rr.Xadd = rr.Add
o = 0 o = 0
if !target.IsAMD64() { if !target.IsAMD64() {
o = rr.Add o = r.Add()
} }
break break
} }
@ -313,14 +309,14 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) {
case objabi.R_TLS_IE: case objabi.R_TLS_IE:
if target.IsExternal() && target.IsElf() { if target.IsExternal() && target.IsElf() {
needExtReloc = true needExtReloc = true
if rr.Sym == 0 { rr.Xsym = rs
rr.Sym = syms.Tlsg2 if rr.Xsym == 0 {
rr.Xsym = syms.Tlsg2
} }
rr.Xsym = rr.Sym rr.Xadd = r.Add()
rr.Xadd = rr.Add
o = 0 o = 0
if !target.IsAMD64() { if !target.IsAMD64() {
o = rr.Add o = r.Add()
} }
break break
} }
@ -342,7 +338,7 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) {
// set up addend for eventual relocation via outer symbol. // set up addend for eventual relocation via outer symbol.
rs := rs rs := rs
rs, off := foldSubSymbolOffset(ldr, rs) rs, off := foldSubSymbolOffset(ldr, rs)
rr.Xadd = rr.Add + off rr.Xadd = r.Add() + off
rst := ldr.SymType(rs) rst := ldr.SymType(rs)
if rst != sym.SHOSTOBJ && rst != sym.SDYNIMPORT && rst != sym.SUNDEFEXT && ldr.SymSect(rs) == nil { 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)) 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() { } else if target.IsWindows() {
// nothing to do // nothing to do
} else if target.IsAIX() { } else if target.IsAIX() {
o = ldr.SymValue(rr.Sym) + rr.Add o = ldr.SymValue(rs) + r.Add()
} else { } else {
st.err.Errorf(s, "unhandled pcrel relocation to %s on %v", ldr.SymName(rs), target.HeadType) 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 needExtReloc = false
} }
// PE code emits IMAGE_REL_I386_SECREL and IMAGE_REL_AMD64_SECREL rr.Xsym = loader.Sym(ldr.SymSect(rs).Sym2)
// for R_DWARFSECREF relocations, while R_ADDR is replaced with rr.Xadd = r.Add() + ldr.SymValue(rs) - int64(ldr.SymSect(rs).Vaddr)
// 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)
o = rr.Xadd o = rr.Xadd
if target.IsElf() && target.IsAMD64() { if target.IsElf() && target.IsAMD64() {
@ -455,12 +442,12 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) {
case objabi.R_GOTPCREL: case objabi.R_GOTPCREL:
if target.IsDynlinkingGo() && target.IsDarwin() && rs != 0 && rst != sym.SCONST { if target.IsDynlinkingGo() && target.IsDarwin() && rs != 0 && rst != sym.SCONST {
needExtReloc = true needExtReloc = true
rr.Xadd = rr.Add rr.Xadd = r.Add()
rr.Xadd -= int64(rr.Siz) // relative to address after the relocated chunk rr.Xadd -= int64(siz) // relative to address after the relocated chunk
rr.Xsym = rr.Sym rr.Xsym = rs
o = rr.Xadd o = rr.Xadd
o += int64(rr.Siz) o += int64(siz)
break break
} }
fallthrough fallthrough
@ -470,9 +457,9 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) {
needExtReloc = true needExtReloc = true
rr.Xadd = 0 rr.Xadd = 0
if target.IsElf() { if target.IsElf() {
rr.Xadd -= int64(rr.Siz) rr.Xadd -= int64(siz)
} }
rr.Xsym = rr.Sym rr.Xsym = rs
o = 0 o = 0
break break
} }
@ -482,8 +469,8 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) {
// set up addend for eventual relocation via outer symbol. // set up addend for eventual relocation via outer symbol.
rs := rs rs := rs
rs, off := foldSubSymbolOffset(ldr, rs) rs, off := foldSubSymbolOffset(ldr, rs)
rr.Xadd = rr.Add + off rr.Xadd = r.Add() + off
rr.Xadd -= int64(rr.Siz) // relative to address after the relocated chunk rr.Xadd -= int64(siz) // relative to address after the relocated chunk
rst := ldr.SymType(rs) rst := ldr.SymType(rs)
if rst != sym.SHOSTOBJ && rst != sym.SDYNIMPORT && ldr.SymSect(rs) == nil { if rst != sym.SHOSTOBJ && rst != sym.SDYNIMPORT && ldr.SymSect(rs) == nil {
st.err.Errorf(s, "missing section for relocation target %s", ldr.SymName(rs)) 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 o = 0
} }
} else if target.IsDarwin() { } else if target.IsDarwin() {
if rr.Type == objabi.R_CALL { if rt == objabi.R_CALL {
if target.IsExternal() && rst == sym.SDYNIMPORT { if target.IsExternal() && rst == sym.SDYNIMPORT {
if target.IsAMD64() { if target.IsAMD64() {
// AMD64 dynamic relocations are relative to the end of the relocation. // AMD64 dynamic relocations are relative to the end of the relocation.
o += int64(rr.Siz) o += int64(siz)
} }
} else { } else {
if rst != sym.SHOSTOBJ { if rst != sym.SHOSTOBJ {
o += int64(uint64(ldr.SymValue(rs)) - ldr.SymSect(rs).Vaddr) 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 { } else {
o += int64(rr.Siz) o += int64(siz)
} }
} else if target.IsWindows() && target.IsAMD64() { // only amd64 needs PCREL } else if target.IsWindows() && target.IsAMD64() { // only amd64 needs PCREL
// PE/COFF's PC32 relocation uses the address after the relocated // PE/COFF's PC32 relocation uses the address after the relocated
// bytes as the base. Compensate by skewing the addend. // bytes as the base. Compensate by skewing the addend.
o += int64(rr.Siz) o += int64(siz)
} else { } else {
st.err.Errorf(s, "unhandled pcrel relocation to %s on %v", ldr.SymName(rs), target.HeadType) 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") st.err.Errorf(s, "find XCOFF R_REF with internal linking")
} }
needExtReloc = true needExtReloc = true
rr.Xsym = rr.Sym rr.Xsym = rs
rr.Xadd = rr.Add rr.Xadd = r.Add()
// This isn't a real relocation so it must not update // This isn't a real relocation so it must not update
// its offset value. // its offset value.

View File

@ -51,11 +51,7 @@ type Reloc struct {
// ExtReloc contains the payload for an external relocation. // ExtReloc contains the payload for an external relocation.
type ExtReloc struct { type ExtReloc struct {
Off int32 // offset to rewrite Idx int // index of the original relocation
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
Xsym Sym Xsym Sym
Xadd int64 Xadd int64
} }
@ -2763,25 +2759,30 @@ func (l *Loader) convertExtRelocs(dst *sym.Symbol, src Sym) {
if int(src) >= len(l.extRelocs) { if int(src) >= len(l.extRelocs) {
return return
} }
relocs := l.extRelocs[src] extRelocs := l.extRelocs[src]
if len(relocs) == 0 { if len(extRelocs) == 0 {
return return
} }
if len(dst.R) != 0 { if len(dst.R) != 0 {
panic("bad") 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 { for i := range dst.R {
sr := &relocs[i] er := &extRelocs[i]
sr := relocs.At2(er.Idx)
r := &dst.R[i] r := &dst.R[i]
r.InitExt() r.InitExt()
r.Off = sr.Off r.Off = sr.Off()
r.Siz = sr.Siz r.Siz = sr.Siz()
r.Type = sr.Type r.Type = sr.Type()
r.Sym = l.Syms[sr.Sym] r.Sym = l.Syms[l.ResolveABIAlias(sr.Sym())]
r.Add = sr.Add r.Add = sr.Add()
r.Xsym = l.Syms[sr.Xsym] r.Xsym = l.Syms[er.Xsym]
r.Xadd = sr.Xadd r.Xadd = er.Xadd
if rv := l.RelocVariant(src, er.Idx); rv != 0 {
r.Variant = rv
}
} }
} }

View File

@ -58,7 +58,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
switch r.Type { switch r.Type {
default: default:
return false return false
case objabi.R_ADDR: case objabi.R_ADDR, objabi.R_DWARFSECREF:
if r.Siz != 4 { if r.Siz != 4 {
return false return false
} }

View File

@ -69,7 +69,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
switch r.Type { switch r.Type {
default: default:
return false return false
case objabi.R_ADDR: case objabi.R_ADDR, objabi.R_DWARFSECREF:
switch r.Siz { switch r.Siz {
case 4: case 4:
ctxt.Out.Write8(uint8(elf.R_MIPS_32)) ctxt.Out.Write8(uint8(elf.R_MIPS_32))

View File

@ -457,7 +457,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
switch r.Type { switch r.Type {
default: default:
return false return false
case objabi.R_ADDR: case objabi.R_ADDR, objabi.R_DWARFSECREF:
switch r.Siz { switch r.Siz {
case 4: case 4:
ctxt.Out.Write64(uint64(elf.R_PPC64_ADDR32) | uint64(elfsym)<<32) ctxt.Out.Write64(uint64(elf.R_PPC64_ADDR32) | uint64(elfsym)<<32)

View File

@ -246,7 +246,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
case 4: case 4:
ctxt.Out.Write64(uint64(elf.R_390_TLS_IEENT) | uint64(elfsym)<<32) 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 { switch r.Siz {
default: default:
return false return false

View File

@ -347,7 +347,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
switch r.Type { switch r.Type {
default: default:
return false return false
case objabi.R_ADDR: case objabi.R_ADDR, objabi.R_DWARFSECREF:
if r.Siz == 4 { if r.Siz == 4 {
ctxt.Out.Write32(uint32(elf.R_386_32) | uint32(elfsym)<<8) ctxt.Out.Write32(uint32(elf.R_386_32) | uint32(elfsym)<<8)
} else { } else {