From: Cherry Zhang Date: Sun, 26 Apr 2020 05:42:55 +0000 (-0400) Subject: [dev.link] cmd/link: support external linking in new reloc implementation X-Git-Tag: go1.15beta1~259^2^2~19 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=095d2a453265acea44bea04620258f1ae5bb12bc;p=gostls13.git [dev.link] cmd/link: support external linking in new reloc implementation Support external linking for the new reloc pass as well, and enable it on AMD64 and 386. Change-Id: Ia71aec3d7c14e9d661e0748d2e988f29f220d1e1 Reviewed-on: https://go-review.googlesource.com/c/go/+/230308 Run-TryBot: Cherry Zhang TryBot-Result: Gobot Gobot Reviewed-by: Jeremy Faller Reviewed-by: Than McIntosh --- diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 187f915a82..d895c62f39 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -120,6 +120,20 @@ func trampoline(ctxt *Link, s loader.Sym) { } +// foldSubSymbolOffset computes the offset of symbol s to its top-level outer +// symbol. Returns the top-level symbol and the offset. +// This is used in generating external relocations. +func foldSubSymbolOffset(ldr *loader.Loader, s loader.Sym) (loader.Sym, int64) { + outer := ldr.OuterSym(s) + off := int64(0) + for outer != 0 { + off += ldr.SymValue(s) - ldr.SymValue(outer) + s = outer + outer = ldr.OuterSym(s) + } + return s, off +} + // relocsym resolve relocations in "s", updating the symbol's content // in "P". // The main loop walks through the list of relocations attached to "s" @@ -141,6 +155,7 @@ func relocsym(target *Target, ldr *loader.Loader, err *ErrorReporter, syms *Arch if relocs.Count() == 0 { return } + var extRelocs []loader.ExtReloc for ri := 0; ri < relocs.Count(); ri++ { r := relocs.At2(ri) off := r.Off() @@ -200,9 +215,14 @@ func relocsym(target *Target, ldr *loader.Loader, err *ErrorReporter, syms *Arch err.Errorf(s, "unreachable sym in relocation: %s", ldr.SymName(rs)) } + var rr loader.ExtReloc + needExtReloc := false // will set to true below in case it is needed if target.IsExternal() { - panic("external linking not implemented") - //r.InitExt() + rr.Sym = rs + rr.Type = rt + rr.Off = off + rr.Siz = uint8(siz) + rr.Add = r.Add() } // TODO(mundaym): remove this special case - see issue 14218. @@ -239,19 +259,19 @@ func relocsym(target *Target, ldr *loader.Loader, err *ErrorReporter, syms *Arch err.Errorf(s, "unknown reloc to %v: %d (%s)", ldr.SymName(rs), rt, sym.RelocName(target.Arch, rt)) } case objabi.R_TLS_LE: - //if target.IsExternal() && target.IsElf() { - // r.Done = false - // if r.Sym == nil { - // r.Sym = syms.Tlsg - // } - // r.Xsym = r.Sym - // r.Xadd = r.Add - // o = 0 - // if !target.IsAMD64() { - // o = r.Add - // } - // break - //} + if target.IsExternal() && target.IsElf() { + needExtReloc = true + if rr.Sym == 0 { + rr.Sym = syms.Tlsg2 + } + rr.Xsym = rr.Sym + rr.Xadd = rr.Add + o = 0 + if !target.IsAMD64() { + o = rr.Add + } + break + } if target.IsElf() && target.IsARM() { // On ELF ARM, the thread pointer is 8 bytes before @@ -270,19 +290,19 @@ func relocsym(target *Target, ldr *loader.Loader, err *ErrorReporter, syms *Arch log.Fatalf("unexpected R_TLS_LE relocation for %v", target.HeadType) } case objabi.R_TLS_IE: - //if target.IsExternal() && target.IsElf() { - // r.Done = false - // if r.Sym == nil { - // r.Sym = syms.Tlsg - // } - // r.Xsym = r.Sym - // r.Xadd = r.Add - // o = 0 - // if !target.IsAMD64() { - // o = r.Add - // } - // break - //} + if target.IsExternal() && target.IsElf() { + needExtReloc = true + if rr.Sym == 0 { + rr.Sym = syms.Tlsg2 + } + rr.Xsym = rr.Sym + rr.Xadd = rr.Add + o = 0 + if !target.IsAMD64() { + o = rr.Add + } + break + } if target.IsPIE() && target.IsElf() { // We are linking the final executable, so we // can optimize any TLS IE relocation to LE. @@ -295,42 +315,38 @@ func relocsym(target *Target, ldr *loader.Loader, err *ErrorReporter, syms *Arch log.Fatalf("cannot handle R_TLS_IE (sym %s) when linking internally", ldr.SymName(s)) } case objabi.R_ADDR: - //if target.IsExternal() && r.Sym.Type != sym.SCONST { - // r.Done = false - // - // // set up addend for eventual relocation via outer symbol. - // rs := r.Sym - // - // r.Xadd = r.Add - // for rs.Outer != nil { - // r.Xadd += Symaddr(rs) - Symaddr(rs.Outer) - // rs = rs.Outer - // } - // - // if rs.Type != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Type != sym.SUNDEFEXT && rs.Sect == nil { - // Errorf(s, "missing section for relocation target %s", rs.Name) - // } - // r.Xsym = rs - // - // o = r.Xadd - // if target.IsElf() { - // if target.IsAMD64() { - // o = 0 - // } - // } else if target.IsDarwin() { - // if rs.Type != sym.SHOSTOBJ { - // o += Symaddr(rs) - // } - // } else if target.IsWindows() { - // // nothing to do - // } else if target.IsAIX() { - // o = Symaddr(r.Sym) + r.Add - // } else { - // Errorf(s, "unhandled pcrel relocation to %s on %v", rs.Name, target.HeadType) - // } - // - // break - //} + if target.IsExternal() && rst != sym.SCONST { + needExtReloc = true + + // set up addend for eventual relocation via outer symbol. + rs := rs + rs, off := foldSubSymbolOffset(ldr, rs) + rr.Xadd = rr.Add + off + rst := ldr.SymType(rs) + if rst != sym.SHOSTOBJ && rst != sym.SDYNIMPORT && rst != sym.SUNDEFEXT && ldr.SymSect(rs) == nil { + err.Errorf(s, "missing section for relocation target %s", ldr.SymName(rs)) + } + rr.Xsym = rs + + o = rr.Xadd + if target.IsElf() { + if target.IsAMD64() { + o = 0 + } + } else if target.IsDarwin() { + if ldr.SymType(rs) != sym.SHOSTOBJ { + o += ldr.SymValue(rs) + } + } else if target.IsWindows() { + // nothing to do + } else if target.IsAIX() { + o = ldr.SymValue(rr.Sym) + rr.Add + } else { + err.Errorf(s, "unhandled pcrel relocation to %s on %v", ldr.SymName(rs), target.HeadType) + } + + break + } // On AIX, a second relocation must be done by the loader, // as section addresses can change once loaded. @@ -343,6 +359,7 @@ func relocsym(target *Target, ldr *loader.Loader, err *ErrorReporter, syms *Arch // symbol which isn't in .data. However, as .text has the // same address once loaded, this is possible. if ldr.SymSect(s).Seg == &Segdata { + panic("not implemented") //Xcoffadddynrel(target, ldr, err, s, &r) // XXX } } @@ -363,36 +380,36 @@ func relocsym(target *Target, ldr *loader.Loader, err *ErrorReporter, syms *Arch err.Errorf(s, "missing DWARF section for relocation target %s", ldr.SymName(rs)) } - //if target.IsExternal() { - // r.Done = false - // - // // On most platforms, the external linker needs to adjust DWARF references - // // as it combines DWARF sections. However, on Darwin, dsymutil does the - // // DWARF linking, and it understands how to follow section offsets. - // // Leaving in the relocation records confuses it (see - // // https://golang.org/issue/22068) so drop them for Darwin. - // if target.IsDarwin() { - // r.Done = true - // } - // - // // 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() { - // r.Type = objabi.R_ADDR - // } - // - // r.Xsym = r.Sym.Sect.Sym - // r.Xadd = r.Add + Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr) - // - // o = r.Xadd - // if target.IsElf() && target.IsAMD64() { - // o = 0 - // } - // break - //} + if target.IsExternal() { + needExtReloc = true + + // On most platforms, the external linker needs to adjust DWARF references + // as it combines DWARF sections. However, on Darwin, dsymutil does the + // DWARF linking, and it understands how to follow section offsets. + // Leaving in the relocation records confuses it (see + // https://golang.org/issue/22068) so drop them for Darwin. + if target.IsDarwin() { + 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) + + o = rr.Xadd + if target.IsElf() && target.IsAMD64() { + o = 0 + } + break + } o = ldr.SymValue(rs) + r.Add() - int64(ldr.SymSect(rs).Vaddr) case objabi.R_WEAKADDROFF, objabi.R_METHODOFF: if !ldr.AttrReachable(rs) { @@ -415,78 +432,74 @@ func relocsym(target *Target, ldr *loader.Loader, err *ErrorReporter, syms *Arch // r.Sym() can be 0 when CALL $(constant) is transformed from absolute PC to relative PC call. case objabi.R_GOTPCREL: - //if target.IsDynlinkingGo() && target.IsDarwin() && r.Sym != nil && r.Sym.Type != sym.SCONST { - // r.Done = false - // r.Xadd = r.Add - // r.Xadd -= int64(r.Siz) // relative to address after the relocated chunk - // r.Xsym = r.Sym - // - // o = r.Xadd - // o += int64(r.Siz) - // break - //} + 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 + + o = rr.Xadd + o += int64(rr.Siz) + break + } fallthrough case objabi.R_CALL, objabi.R_PCREL: - //if target.IsExternal() && r.Sym != nil && r.Sym.Type == sym.SUNDEFEXT { - // // pass through to the external linker. - // r.Done = false - // r.Xadd = 0 - // if target.IsElf() { - // r.Xadd -= int64(r.Siz) - // } - // r.Xsym = r.Sym - // o = 0 - // break - //} - //if target.IsExternal() && r.Sym != nil && r.Sym.Type != sym.SCONST && (r.Sym.Sect != s.Sect || r.Type == objabi.R_GOTPCREL) { - // r.Done = false - // - // // set up addend for eventual relocation via outer symbol. - // rs := r.Sym - // - // r.Xadd = r.Add - // for rs.Outer != nil { - // r.Xadd += Symaddr(rs) - Symaddr(rs.Outer) - // rs = rs.Outer - // } - // - // r.Xadd -= int64(r.Siz) // relative to address after the relocated chunk - // if rs.Type != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Sect == nil { - // Errorf(s, "missing section for relocation target %s", rs.Name) - // } - // r.Xsym = rs - // - // o = r.Xadd - // if target.IsElf() { - // if target.IsAMD64() { - // o = 0 - // } - // } else if target.IsDarwin() { - // if r.Type == objabi.R_CALL { - // if target.IsExternal() && rs.Type == sym.SDYNIMPORT { - // if target.IsAMD64() { - // // AMD64 dynamic relocations are relative to the end of the relocation. - // o += int64(r.Siz) - // } - // } else { - // if rs.Type != sym.SHOSTOBJ { - // o += int64(uint64(Symaddr(rs)) - rs.Sect.Vaddr) - // } - // o -= int64(r.Off) // relative to section offset, not symbol - // } - // } else { - // o += int64(r.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(r.Siz) - // } else { - // Errorf(s, "unhandled pcrel relocation to %s on %v", rs.Name, target.HeadType) - // } - // - // break - //} + if target.IsExternal() && rs != 0 && rst == sym.SUNDEFEXT { + // pass through to the external linker. + needExtReloc = true + rr.Xadd = 0 + if target.IsElf() { + rr.Xadd -= int64(rr.Siz) + } + rr.Xsym = rr.Sym + o = 0 + break + } + if target.IsExternal() && rs != 0 && rst != sym.SCONST && (ldr.SymSect(rs) != ldr.SymSect(s) || rt == objabi.R_GOTPCREL) { + needExtReloc = true + + // 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 + rst := ldr.SymType(rs) + if rst != sym.SHOSTOBJ && rst != sym.SDYNIMPORT && ldr.SymSect(rs) == nil { + err.Errorf(s, "missing section for relocation target %s", ldr.SymName(rs)) + } + rr.Xsym = rs + + o = rr.Xadd + if target.IsElf() { + if target.IsAMD64() { + o = 0 + } + } else if target.IsDarwin() { + if rr.Type == 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) + } + } 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 + } + } else { + o += int64(rr.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) + } else { + err.Errorf(s, "unhandled pcrel relocation to %s on %v", ldr.SymName(rs), target.HeadType) + } + + break + } o = 0 if rs != 0 { @@ -504,9 +517,9 @@ func relocsym(target *Target, ldr *loader.Loader, err *ErrorReporter, syms *Arch if !target.IsExternal() { err.Errorf(s, "find XCOFF R_REF with internal linking") } - //r.Xsym = r.Sym - //r.Xadd = r.Add - //r.Done = false + needExtReloc = true + rr.Xsym = rr.Sym + rr.Xadd = rr.Add // This isn't a real relocation so it must not update // its offset value. @@ -548,6 +561,13 @@ func relocsym(target *Target, ldr *loader.Loader, err *ErrorReporter, syms *Arch case 8: target.Arch.ByteOrder.PutUint64(P[off:], uint64(o)) } + + if needExtReloc { + extRelocs = append(extRelocs, rr) + } + } + if len(extRelocs) != 0 { + ldr.SetExtRelocs(s, extRelocs) } } @@ -557,6 +577,9 @@ func (ctxt *Link) reloc() { ldr := ctxt.loader reporter := &ctxt.ErrorReporter syms := &ctxt.ArchSyms + if ctxt.IsExternal() { + ldr.InitExtRelocs() + } wg.Add(3) go func() { if !ctxt.IsWasm() { // On Wasm, text relocations are applied in Asmb2. diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index 1484ade313..2cac61c08c 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go @@ -326,14 +326,14 @@ func Main(arch *sys.Arch, theArch Arch) { ctxt.loader.InitOutData() thearch.Asmb(ctxt, ctxt.loader) - newreloc := ctxt.IsInternal() && (ctxt.IsAMD64() || ctxt.Is386()) + newreloc := ctxt.IsAMD64() || ctxt.Is386() if newreloc { bench.Start("reloc") ctxt.reloc() bench.Start("loadlibfull") // We don't need relocations at this point. - // An exception is Windows, see pe.go:addPEBaseRelocSym - needReloc := ctxt.IsWindows() + // An exception is internal linking on Windows, see pe.go:addPEBaseRelocSym + needReloc := ctxt.IsWindows() && ctxt.IsInternal() ctxt.loadlibfull(symGroupType, needReloc) // XXX do it here for now } else { bench.Start("loadlibfull") diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go index 4fcdc1a661..e3dec5feee 100644 --- a/src/cmd/link/internal/loader/loader.go +++ b/src/cmd/link/internal/loader/loader.go @@ -49,6 +49,17 @@ type Reloc struct { Sym Sym // global index of symbol the reloc addresses } +// 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 + Xsym Sym + Xadd int64 +} + // Reloc2 holds a "handle" to access a relocation record from an // object file. type Reloc2 struct { @@ -216,7 +227,8 @@ type Loader struct { sects []*sym.Section // sections symSects []uint16 // symbol's section, index to sects array - outdata [][]byte // symbol's data in the output buffer + outdata [][]byte // symbol's data in the output buffer + extRelocs [][]ExtReloc // symbol's external relocations itablink map[Sym]struct{} // itablink[j] defined if j is go.itablink.* @@ -1108,6 +1120,16 @@ func (l *Loader) InitOutData() { l.outdata = make([][]byte, l.extStart) } +// SetExtRelocs sets the section of the i-th symbol. i is global index. +func (l *Loader) SetExtRelocs(i Sym, relocs []ExtReloc) { + l.extRelocs[i] = relocs +} + +// InitExtRelocs initialize the slice used to store external relocations. +func (l *Loader) InitExtRelocs() { + l.extRelocs = make([][]ExtReloc, l.NSym()) +} + // SymAlign returns the alignment for a symbol. func (l *Loader) SymAlign(i Sym) int32 { // If an alignment has been recorded, return that. @@ -2072,6 +2094,8 @@ func (l *Loader) LoadFull(arch *sys.Arch, syms *sym.Symbols, needReloc bool) { l.convertRelocations(i, &relocs, s, false) } + l.convertExtRelocs(s, i) + // Copy data s.P = pp.data @@ -2632,6 +2656,8 @@ func loadObjFull(l *Loader, r *oReader, needReloc bool) { l.convertRelocations(gi, &relocs, s, false) } + l.convertExtRelocs(s, gi) + // Aux symbol info auxs := r.Auxs(i) for j := range auxs { @@ -2697,6 +2723,33 @@ func (l *Loader) convertRelocations(symIdx Sym, src *Relocs, dst *sym.Symbol, st } } +// Convert external relocations to sym.Relocs on symbol dst. +func (l *Loader) convertExtRelocs(dst *sym.Symbol, src Sym) { + if int(src) >= len(l.extRelocs) { + return + } + relocs := l.extRelocs[src] + if len(relocs) == 0 { + return + } + if len(dst.R) != 0 { + panic("bad") + } + dst.R = make([]sym.Reloc, len(relocs)) + for i := range dst.R { + sr := &relocs[i] + 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 + } +} + // relocId is essentially a tuple identifying the Rth // relocation of symbol S. type relocId struct {