From 3e8975172f0cf72be89d5bbeb46dd3084faa9b06 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Sat, 25 Apr 2020 14:17:10 -0400 Subject: [PATCH] [dev.link] cmd/link: convert dwarfcompress to using the loader Change-Id: I34f806b54e8e0985a30ef38ea4324352aabfc845 Reviewed-on: https://go-review.googlesource.com/c/go/+/229995 Run-TryBot: Cherry Zhang TryBot-Result: Gobot Gobot Reviewed-by: Than McIntosh Reviewed-by: Jeremy Faller --- src/cmd/link/internal/ld/data.go | 654 ++++++++++++++--------------- src/cmd/link/internal/ld/data2.go | 443 +++++++++++++++++++ src/cmd/link/internal/ld/dwarf2.go | 59 +-- src/cmd/link/internal/ld/errors.go | 50 ++- src/cmd/link/internal/ld/lib.go | 2 +- src/cmd/link/internal/ld/main.go | 4 +- 6 files changed, 839 insertions(+), 373 deletions(-) diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 40d07199fa..1fd048e10d 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -120,139 +120,139 @@ func trampoline(ctxt *Link, s loader.Sym) { } -// relocsym resolve relocations in "s". The main loop walks through -// the list of relocations attached to "s" and resolves them where -// applicable. Relocations are often architecture-specific, requiring -// calls into the 'archreloc' and/or 'archrelocvariant' functions for -// the architecture. When external linking is in effect, it may not be -// possible to completely resolve the address/offset for a symbol, in -// which case the goal is to lay the groundwork for turning a given -// relocation into an external reloc (to be applied by the external -// linker). For more on how relocations work in general, see +// relocsym resolve relocations in "s", updating the symbol's content +// in "P". +// The main loop walks through the list of relocations attached to "s" +// and resolves them where applicable. Relocations are often +// architecture-specific, requiring calls into the 'archreloc' and/or +// 'archrelocvariant' functions for the architecture. When external +// linking is in effect, it may not be possible to completely resolve +// the address/offset for a symbol, in which case the goal is to lay +// the groundwork for turning a given relocation into an external reloc +// (to be applied by the external linker). For more on how relocations +// work in general, see // // "Linkers and Loaders", by John R. Levine (Morgan Kaufmann, 1999), ch. 7 // // This is a performance-critical function for the linker; be careful // to avoid introducing unnecessary allocations in the main loop. -// TODO: This function is called in parallel. When the Loader wavefront -// reaches here, calls into the loader need to be parallel as well. -func relocsym(target *Target, ldr *loader.Loader, err *ErrorReporter, syms *ArchSyms, s *sym.Symbol) { - if len(s.R) == 0 { +func relocsym(target *Target, ldr *loader.Loader, err *ErrorReporter, syms *ArchSyms, s loader.Sym, P []byte) { + relocs := ldr.Relocs(s) + if relocs.Count() == 0 { return } - if target.IsWasm() && s.Attr.ReadOnly() { - // The symbol's content is backed by read-only memory. - // Copy it to writable memory to apply relocations. - // Only need to do this on Wasm. On other platforms we - // apply relocations to the output buffer, which is - // always writeable. - s.P = append([]byte(nil), s.P...) - // No need to unset AttrReadOnly because it will not be used. - } - for ri := int32(0); ri < int32(len(s.R)); ri++ { - r := &s.R[ri] - if r.Done { - // Relocation already processed by an earlier phase. - continue + for ri := 0; ri < relocs.Count(); ri++ { + r := relocs.At2(ri) + off := r.Off() + siz := int32(r.Siz()) + rs := r.Sym() + if rs != 0 { + rs = ldr.ResolveABIAlias(rs) } - r.Done = true - off := r.Off - siz := int32(r.Siz) - if off < 0 || off+siz > int32(len(s.P)) { + rt := r.Type() + if off < 0 || off+siz > int32(len(P)) { rname := "" - if r.Sym != nil { - rname = r.Sym.Name + if rs != 0 { + rname = ldr.SymName(rs) } - Errorf(s, "invalid relocation %s: %d+%d not in [%d,%d)", rname, off, siz, 0, len(s.P)) + err.Errorf(s, "invalid relocation %s: %d+%d not in [%d,%d)", rname, off, siz, 0, len(P)) continue } - if r.Sym != nil && ((r.Sym.Type == sym.Sxxx && !r.Sym.Attr.VisibilityHidden()) || r.Sym.Type == sym.SXREF) { + var rst sym.SymKind + if rs != 0 { + rst = ldr.SymType(rs) + } + + if rs != 0 && ((rst == sym.Sxxx && !ldr.AttrVisibilityHidden(rs)) || rst == sym.SXREF) { // When putting the runtime but not main into a shared library // these symbols are undefined and that's OK. if target.IsShared() || target.IsPlugin() { - if r.Sym.Name == "main.main" || (!target.IsPlugin() && r.Sym.Name == "main..inittask") { - r.Sym.Type = sym.SDYNIMPORT - } else if strings.HasPrefix(r.Sym.Name, "go.info.") { + if ldr.SymName(rs) == "main.main" || (!target.IsPlugin() && ldr.SymName(rs) == "main..inittask") { + sb := ldr.MakeSymbolUpdater(rs) + sb.SetType(sym.SDYNIMPORT) + } else if strings.HasPrefix(ldr.SymName(rs), "go.info.") { // Skip go.info symbols. They are only needed to communicate // DWARF info between the compiler and linker. continue } } else { - err.errorUnresolved(s, r) + err.errorUnresolved(ldr, s, rs) continue } } - if r.Type >= objabi.ElfRelocOffset { + if rt >= objabi.ElfRelocOffset { continue } - if r.Siz == 0 { // informational relocation - no work to do + if siz == 0 { // informational relocation - no work to do continue } // We need to be able to reference dynimport symbols when linking against // shared libraries, and Solaris, Darwin and AIX need it always - if !target.IsSolaris() && !target.IsDarwin() && !target.IsAIX() && r.Sym != nil && r.Sym.Type == sym.SDYNIMPORT && !target.IsDynlinkingGo() && !r.Sym.Attr.SubSymbol() { - if !(target.IsPPC64() && target.IsExternal() && r.Sym.Name == ".TOC.") { - Errorf(s, "unhandled relocation for %s (type %d (%s) rtype %d (%s))", r.Sym.Name, r.Sym.Type, r.Sym.Type, r.Type, sym.RelocName(target.Arch, r.Type)) + if !target.IsSolaris() && !target.IsDarwin() && !target.IsAIX() && rs != 0 && rst == sym.SDYNIMPORT && !target.IsDynlinkingGo() && !ldr.AttrSubSymbol(rs) { + if !(target.IsPPC64() && target.IsExternal() && ldr.SymName(rs) == ".TOC.") { + err.Errorf(s, "unhandled relocation for %s (type %d (%s) rtype %d (%s))", ldr.SymName(rs), rst, rst, rt, sym.RelocName(target.Arch, rt)) } } - if r.Sym != nil && r.Sym.Type != sym.STLSBSS && r.Type != objabi.R_WEAKADDROFF && !r.Sym.Attr.Reachable() { - Errorf(s, "unreachable sym in relocation: %s", r.Sym.Name) + if rs != 0 && rst != sym.STLSBSS && rt != objabi.R_WEAKADDROFF && rt != objabi.R_METHODOFF && !ldr.AttrReachable(rs) { + err.Errorf(s, "unreachable sym in relocation: %s", ldr.SymName(rs)) } if target.IsExternal() { - r.InitExt() + panic("external linking not implemented") + //r.InitExt() } // TODO(mundaym): remove this special case - see issue 14218. - if target.IsS390X() { - switch r.Type { - case objabi.R_PCRELDBL: - r.InitExt() - r.Type = objabi.R_PCREL - r.Variant = sym.RV_390_DBL - case objabi.R_CALL: - r.InitExt() - r.Variant = sym.RV_390_DBL - } - } + //if target.IsS390X() { + // switch r.Type { + // case objabi.R_PCRELDBL: + // r.InitExt() + // r.Type = objabi.R_PCREL + // r.Variant = sym.RV_390_DBL + // case objabi.R_CALL: + // r.InitExt() + // r.Variant = sym.RV_390_DBL + // } + //} var o int64 - switch r.Type { + switch rt { default: - switch siz { - default: - Errorf(s, "bad reloc size %#x for %s", uint32(siz), r.Sym.Name) - case 1: - o = int64(s.P[off]) - case 2: - o = int64(target.Arch.ByteOrder.Uint16(s.P[off:])) - case 4: - o = int64(target.Arch.ByteOrder.Uint32(s.P[off:])) - case 8: - o = int64(target.Arch.ByteOrder.Uint64(s.P[off:])) - } - if offset, ok := thearch.Archreloc(target, syms, r, s, o); ok { - o = offset - } else { - Errorf(s, "unknown reloc to %v: %d (%s)", r.Sym.Name, r.Type, sym.RelocName(target.Arch, r.Type)) - } + panic("not implemented") + //switch siz { + //default: + // err.Errorf(s, "bad reloc size %#x for %s", uint32(siz), ldr.SymName(rs)) + //case 1: + // o = int64(P[off]) + //case 2: + // o = int64(target.Arch.ByteOrder.Uint16(P[off:])) + //case 4: + // o = int64(target.Arch.ByteOrder.Uint32(P[off:])) + //case 8: + // o = int64(target.Arch.ByteOrder.Uint64(P[off:])) + //} + //if out, ok := thearch.Archreloc(ldr, target, syms, &r, s, o); ok { + // o = out + //} else { + // 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() { + // 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.IsElf() && target.IsARM() { // On ELF ARM, the thread pointer is 8 bytes before @@ -262,96 +262,94 @@ func relocsym(target *Target, ldr *loader.Loader, err *ErrorReporter, syms *Arch // ELF on ARM (or maybe Glibc on ARM); it is not // related to the fact that our own TLS storage happens // to take up 8 bytes. - o = 8 + r.Sym.Value + o = 8 + ldr.SymValue(rs) } else if target.IsElf() || target.IsPlan9() || target.IsDarwin() { - o = int64(syms.Tlsoffset) + r.Add + o = int64(syms.Tlsoffset) + r.Add() } else if target.IsWindows() { - o = r.Add + o = r.Add() } else { 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.IsPIE() && target.IsElf() { - // We are linking the final executable, so we - // can optimize any TLS IE relocation to LE. - if thearch.TLSIEtoLE == nil { - log.Fatalf("internal linking of TLS IE not supported on %v", target.Arch.Family) - } - thearch.TLSIEtoLE(s, int(off), int(r.Siz)) - o = int64(syms.Tlsoffset) - // TODO: o += r.Add when !target.IsAmd64()? - // Why do we treat r.Add differently on AMD64? - // Is the external linker using Xadd at all? - } else { - log.Fatalf("cannot handle R_TLS_IE (sym %s) when linking internally", s.Name) - } + panic("not implemented") + //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.IsPIE() && target.IsElf() { + // // We are linking the final executable, so we + // // can optimize any TLS IE relocation to LE. + // if thearch.TLSIEtoLE == nil { + // log.Fatalf("internal linking of TLS IE not supported on %v", target.Arch.Family) + // } + // thearch.TLSIEtoLE(ldr, s, int(off), int(siz)) + // o = int64(syms.Tlsoffset) + //} else { + // 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() && 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 + //} // On AIX, a second relocation must be done by the loader, // as section addresses can change once loaded. // The "default" symbol address is still needed by the loader so // the current relocation can't be skipped. - if target.IsAIX() && r.Sym.Type != sym.SDYNIMPORT { + if target.IsAIX() && rst != sym.SDYNIMPORT { // It's not possible to make a loader relocation in a // symbol which is not inside .data section. // FIXME: It should be forbidden to have R_ADDR from a // symbol which isn't in .data. However, as .text has the // same address once loaded, this is possible. - if s.Sect.Seg == &Segdata { - Xcoffadddynrel(target, ldr, s, r) + if ldr.SymSect(s).Seg == &Segdata { + //Xcoffadddynrel(target, ldr, err, s, &r) // XXX } } - o = Symaddr(r.Sym) + r.Add + o = ldr.SymValue(rs) + r.Add() // On amd64, 4-byte offsets will be sign-extended, so it is impossible to // access more than 2GB of static data; fail at link time is better than @@ -359,217 +357,198 @@ func relocsym(target *Target, ldr *loader.Loader, err *ErrorReporter, syms *Arch // Instead of special casing only amd64, we treat this as an error on all // 64-bit architectures so as to be future-proof. if int32(o) < 0 && target.Arch.PtrSize > 4 && siz == 4 { - Errorf(s, "non-pc-relative relocation address for %s is too big: %#x (%#x + %#x)", r.Sym.Name, uint64(o), Symaddr(r.Sym), r.Add) + err.Errorf(s, "non-pc-relative relocation address for %s is too big: %#x (%#x + %#x)", ldr.SymName(rs), uint64(o), ldr.SymValue(rs), r.Add()) errorexit() } case objabi.R_DWARFSECREF: - if r.Sym.Sect == nil { - Errorf(s, "missing DWARF section for relocation target %s", r.Sym.Name) - } - - 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 - } - o = Symaddr(r.Sym) + r.Add - int64(r.Sym.Sect.Vaddr) - case objabi.R_WEAKADDROFF: - if !r.Sym.Attr.Reachable() { + if ldr.SymSect(rs) == nil { + 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 + //} + o = ldr.SymValue(rs) + r.Add() - int64(ldr.SymSect(rs).Vaddr) + case objabi.R_WEAKADDROFF, objabi.R_METHODOFF: + if !ldr.AttrReachable(rs) { continue } fallthrough case objabi.R_ADDROFF: // The method offset tables using this relocation expect the offset to be relative // to the start of the first text section, even if there are multiple. - if r.Sym.Sect.Name == ".text" { - o = Symaddr(r.Sym) - int64(Segtext.Sections[0].Vaddr) + r.Add + if ldr.SymSect(rs).Name == ".text" { + o = ldr.SymValue(rs) - int64(Segtext.Sections[0].Vaddr) + r.Add() } else { - o = Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr) + r.Add + o = ldr.SymValue(rs) - int64(ldr.SymSect(rs).Vaddr) + r.Add() } case objabi.R_ADDRCUOFF: // debug_range and debug_loc elements use this relocation type to get an // offset from the start of the compile unit. - o = Symaddr(r.Sym) + r.Add - Symaddr(ldr.Syms[r.Sym.Unit.Textp2[0]]) + o = ldr.SymValue(rs) + r.Add() - ldr.SymValue(loader.Sym(ldr.SymUnit(rs).Textp2[0])) - // r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call. + // 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() && 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 + //} 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() && 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 + //} o = 0 - if r.Sym != nil { - o += Symaddr(r.Sym) + if rs != 0 { + o = ldr.SymValue(rs) } - o += r.Add - (s.Value + int64(r.Off) + int64(r.Siz)) + o += r.Add() - (ldr.SymValue(s) + int64(off) + int64(siz)) case objabi.R_SIZE: - o = r.Sym.Size + r.Add + o = ldr.SymSize(rs) + r.Add() case objabi.R_XCOFFREF: if !target.IsAIX() { - Errorf(s, "find XCOFF R_REF on non-XCOFF files") + err.Errorf(s, "find XCOFF R_REF on non-XCOFF files") } if !target.IsExternal() { - Errorf(s, "find XCOFF R_REF with internal linking") + err.Errorf(s, "find XCOFF R_REF with internal linking") } - r.Xsym = r.Sym - r.Xadd = r.Add - r.Done = false + //r.Xsym = r.Sym + //r.Xadd = r.Add + //r.Done = false // This isn't a real relocation so it must not update // its offset value. continue case objabi.R_DWARFFILEREF: - // The final file index is saved in r.Add in dwarf.go:writelines. - o = r.Add + // We don't renumber files in dwarf.go:writelines anymore. + continue } - if target.IsPPC64() || target.IsS390X() { - r.InitExt() - if r.Variant != sym.RV_NONE { - o = thearch.Archrelocvariant(target, syms, r, s, o) - } - } + //if target.IsPPC64() || target.IsS390X() { + // r.InitExt() + // if r.Variant != sym.RV_NONE { + // o = thearch.Archrelocvariant(ldr, target, syms, &r, s, o) + // } + //} - if false { - nam := "" - var addr int64 - if r.Sym != nil { - nam = r.Sym.Name - addr = Symaddr(r.Sym) - } - xnam := "" - if r.Xsym != nil { - xnam = r.Xsym.Name - } - fmt.Printf("relocate %s %#x (%#x+%#x, size %d) => %s %#x +%#x (xsym: %s +%#x) [type %d (%s)/%d, %x]\n", s.Name, s.Value+int64(off), s.Value, r.Off, r.Siz, nam, addr, r.Add, xnam, r.Xadd, r.Type, sym.RelocName(target.Arch, r.Type), r.Variant, o) - } switch siz { default: - Errorf(s, "bad reloc size %#x for %s", uint32(siz), r.Sym.Name) - fallthrough - - // TODO(rsc): Remove. + err.Errorf(s, "bad reloc size %#x for %s", uint32(siz), ldr.SymName(rs)) case 1: - s.P[off] = byte(int8(o)) + P[off] = byte(int8(o)) case 2: if o != int64(int16(o)) { - Errorf(s, "relocation address for %s is too big: %#x", r.Sym.Name, o) + err.Errorf(s, "relocation address for %s is too big: %#x", ldr.SymName(rs), o) } - i16 := int16(o) - target.Arch.ByteOrder.PutUint16(s.P[off:], uint16(i16)) + target.Arch.ByteOrder.PutUint16(P[off:], uint16(o)) case 4: - if r.Type == objabi.R_PCREL || r.Type == objabi.R_CALL { + if rt == objabi.R_PCREL || rt == objabi.R_CALL { if o != int64(int32(o)) { - Errorf(s, "pc-relative relocation address for %s is too big: %#x", r.Sym.Name, o) + err.Errorf(s, "pc-relative relocation address for %s is too big: %#x", ldr.SymName(rs), o) } } else { if o != int64(int32(o)) && o != int64(uint32(o)) { - Errorf(s, "non-pc-relative relocation address for %s is too big: %#x", r.Sym.Name, uint64(o)) + err.Errorf(s, "non-pc-relative relocation address for %s is too big: %#x", ldr.SymName(rs), uint64(o)) } } - - fl := int32(o) - target.Arch.ByteOrder.PutUint32(s.P[off:], uint32(fl)) + target.Arch.ByteOrder.PutUint32(P[off:], uint32(o)) case 8: - target.Arch.ByteOrder.PutUint64(s.P[off:], uint64(o)) + target.Arch.ByteOrder.PutUint64(P[off:], uint64(o)) } } } @@ -584,21 +563,21 @@ func (ctxt *Link) reloc() { go func() { if !ctxt.IsWasm() { // On Wasm, text relocations are applied in Asmb2. for _, s := range ctxt.Textp { - relocsym(target, ldr, reporter, syms, s) + relocsym2(target, ldr, reporter, syms, s) } } wg.Done() }() go func() { for _, s := range ctxt.datap { - relocsym(target, ldr, reporter, syms, s) + relocsym2(target, ldr, reporter, syms, s) } wg.Done() }() go func() { for _, si := range dwarfp { for _, s := range si.syms { - relocsym(target, ldr, reporter, syms, s) + relocsym2(target, ldr, reporter, syms, s) } } wg.Done() @@ -2478,10 +2457,11 @@ func (ctxt *Link) AddTramp(s *loader.SymbolBuilder) { // compressSyms compresses syms and returns the contents of the // compressed section. If the section would get larger, it returns nil. -func compressSyms(ctxt *Link, syms []*sym.Symbol) []byte { +func compressSyms(ctxt *Link, syms []loader.Sym) []byte { + ldr := ctxt.loader var total int64 for _, sym := range syms { - total += sym.Size + total += ldr.SymSize(sym) } var buf bytes.Buffer @@ -2501,23 +2481,22 @@ func compressSyms(ctxt *Link, syms []*sym.Symbol) []byte { log.Fatalf("NewWriterLevel failed: %s", err) } target := &ctxt.Target - ldr := ctxt.loader reporter := &ctxt.ErrorReporter archSyms := &ctxt.ArchSyms for _, s := range syms { - // s.P may be read-only. Apply relocations in a + // Symbol data may be read-only. Apply relocations in a // temporary buffer, and immediately write it out. - oldP := s.P - wasReadOnly := s.Attr.ReadOnly() - if len(s.R) != 0 && wasReadOnly { - relocbuf = append(relocbuf[:0], s.P...) - s.P = relocbuf - } - relocsym(target, ldr, reporter, archSyms, s) - if _, err := z.Write(s.P); err != nil { + P := ldr.Data(s) + relocs := ldr.Relocs(s) + if relocs.Count() != 0 { + relocbuf = append(relocbuf[:0], P...) + P = relocbuf + } + relocsym(target, ldr, reporter, archSyms, s, P) + if _, err := z.Write(P); err != nil { log.Fatalf("compression failed: %s", err) } - for i := s.Size - int64(len(s.P)); i > 0; { + for i := ldr.SymSize(s) - int64(len(P)); i > 0; { b := zeros[:] if i < int64(len(b)) { b = b[:i] @@ -2528,15 +2507,6 @@ func compressSyms(ctxt *Link, syms []*sym.Symbol) []byte { } i -= int64(n) } - // Restore s.P if a temporary buffer was used. If compression - // is not beneficial, we'll go back to use the uncompressed - // contents, in which case we still need s.P. - if len(s.R) != 0 && wasReadOnly { - s.P = oldP - for i := range s.R { - s.R[i].Done = false - } - } } if err := z.Close(); err != nil { log.Fatalf("compression failed: %s", err) diff --git a/src/cmd/link/internal/ld/data2.go b/src/cmd/link/internal/ld/data2.go index 033fe75068..79badd5fdd 100644 --- a/src/cmd/link/internal/ld/data2.go +++ b/src/cmd/link/internal/ld/data2.go @@ -5,7 +5,11 @@ package ld import ( + "cmd/internal/objabi" + "cmd/link/internal/loader" "cmd/link/internal/sym" + "fmt" + "log" "strings" ) @@ -49,3 +53,442 @@ func symalign(s *sym.Symbol) int32 { s.Align = align return align } + +func relocsym2(target *Target, ldr *loader.Loader, err *ErrorReporter, syms *ArchSyms, s *sym.Symbol) { + if len(s.R) == 0 { + return + } + if target.IsWasm() && s.Attr.ReadOnly() { + // The symbol's content is backed by read-only memory. + // Copy it to writable memory to apply relocations. + // Only need to do this on Wasm. On other platforms we + // apply relocations to the output buffer, which is + // always writeable. + s.P = append([]byte(nil), s.P...) + // No need to unset AttrReadOnly because it will not be used. + } + for ri := int32(0); ri < int32(len(s.R)); ri++ { + r := &s.R[ri] + if r.Done { + // Relocation already processed by an earlier phase. + continue + } + r.Done = true + off := r.Off + siz := int32(r.Siz) + if off < 0 || off+siz > int32(len(s.P)) { + rname := "" + if r.Sym != nil { + rname = r.Sym.Name + } + Errorf(s, "invalid relocation %s: %d+%d not in [%d,%d)", rname, off, siz, 0, len(s.P)) + continue + } + + if r.Sym != nil && ((r.Sym.Type == sym.Sxxx && !r.Sym.Attr.VisibilityHidden()) || r.Sym.Type == sym.SXREF) { + // When putting the runtime but not main into a shared library + // these symbols are undefined and that's OK. + if target.IsShared() || target.IsPlugin() { + if r.Sym.Name == "main.main" || (!target.IsPlugin() && r.Sym.Name == "main..inittask") { + r.Sym.Type = sym.SDYNIMPORT + } else if strings.HasPrefix(r.Sym.Name, "go.info.") { + // Skip go.info symbols. They are only needed to communicate + // DWARF info between the compiler and linker. + continue + } + } else { + err.errorUnresolved2(s, r) + continue + } + } + + if r.Type >= objabi.ElfRelocOffset { + continue + } + if r.Siz == 0 { // informational relocation - no work to do + continue + } + + // We need to be able to reference dynimport symbols when linking against + // shared libraries, and Solaris, Darwin and AIX need it always + if !target.IsSolaris() && !target.IsDarwin() && !target.IsAIX() && r.Sym != nil && r.Sym.Type == sym.SDYNIMPORT && !target.IsDynlinkingGo() && !r.Sym.Attr.SubSymbol() { + if !(target.IsPPC64() && target.IsExternal() && r.Sym.Name == ".TOC.") { + Errorf(s, "unhandled relocation for %s (type %d (%s) rtype %d (%s))", r.Sym.Name, r.Sym.Type, r.Sym.Type, r.Type, sym.RelocName(target.Arch, r.Type)) + } + } + if r.Sym != nil && r.Sym.Type != sym.STLSBSS && r.Type != objabi.R_WEAKADDROFF && !r.Sym.Attr.Reachable() { + Errorf(s, "unreachable sym in relocation: %s", r.Sym.Name) + } + + if target.IsExternal() { + r.InitExt() + } + + // TODO(mundaym): remove this special case - see issue 14218. + if target.IsS390X() { + switch r.Type { + case objabi.R_PCRELDBL: + r.InitExt() + r.Type = objabi.R_PCREL + r.Variant = sym.RV_390_DBL + case objabi.R_CALL: + r.InitExt() + r.Variant = sym.RV_390_DBL + } + } + + var o int64 + switch r.Type { + default: + switch siz { + default: + Errorf(s, "bad reloc size %#x for %s", uint32(siz), r.Sym.Name) + case 1: + o = int64(s.P[off]) + case 2: + o = int64(target.Arch.ByteOrder.Uint16(s.P[off:])) + case 4: + o = int64(target.Arch.ByteOrder.Uint32(s.P[off:])) + case 8: + o = int64(target.Arch.ByteOrder.Uint64(s.P[off:])) + } + if offset, ok := thearch.Archreloc(target, syms, r, s, o); ok { + o = offset + } else { + Errorf(s, "unknown reloc to %v: %d (%s)", r.Sym.Name, r.Type, sym.RelocName(target.Arch, r.Type)) + } + 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.IsElf() && target.IsARM() { + // On ELF ARM, the thread pointer is 8 bytes before + // the start of the thread-local data block, so add 8 + // to the actual TLS offset (r->sym->value). + // This 8 seems to be a fundamental constant of + // ELF on ARM (or maybe Glibc on ARM); it is not + // related to the fact that our own TLS storage happens + // to take up 8 bytes. + o = 8 + r.Sym.Value + } else if target.IsElf() || target.IsPlan9() || target.IsDarwin() { + o = int64(syms.Tlsoffset) + r.Add + } else if target.IsWindows() { + o = r.Add + } else { + 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.IsPIE() && target.IsElf() { + // We are linking the final executable, so we + // can optimize any TLS IE relocation to LE. + if thearch.TLSIEtoLE == nil { + log.Fatalf("internal linking of TLS IE not supported on %v", target.Arch.Family) + } + thearch.TLSIEtoLE(s, int(off), int(r.Siz)) + o = int64(syms.Tlsoffset) + // TODO: o += r.Add when !target.IsAmd64()? + // Why do we treat r.Add differently on AMD64? + // Is the external linker using Xadd at all? + } else { + log.Fatalf("cannot handle R_TLS_IE (sym %s) when linking internally", s.Name) + } + 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 + } + + // On AIX, a second relocation must be done by the loader, + // as section addresses can change once loaded. + // The "default" symbol address is still needed by the loader so + // the current relocation can't be skipped. + if target.IsAIX() && r.Sym.Type != sym.SDYNIMPORT { + // It's not possible to make a loader relocation in a + // symbol which is not inside .data section. + // FIXME: It should be forbidden to have R_ADDR from a + // symbol which isn't in .data. However, as .text has the + // same address once loaded, this is possible. + if s.Sect.Seg == &Segdata { + Xcoffadddynrel(target, ldr, s, r) + } + } + + o = Symaddr(r.Sym) + r.Add + + // On amd64, 4-byte offsets will be sign-extended, so it is impossible to + // access more than 2GB of static data; fail at link time is better than + // fail at runtime. See https://golang.org/issue/7980. + // Instead of special casing only amd64, we treat this as an error on all + // 64-bit architectures so as to be future-proof. + if int32(o) < 0 && target.Arch.PtrSize > 4 && siz == 4 { + Errorf(s, "non-pc-relative relocation address for %s is too big: %#x (%#x + %#x)", r.Sym.Name, uint64(o), Symaddr(r.Sym), r.Add) + errorexit() + } + case objabi.R_DWARFSECREF: + if r.Sym.Sect == nil { + Errorf(s, "missing DWARF section for relocation target %s", r.Sym.Name) + } + + 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 + } + o = Symaddr(r.Sym) + r.Add - int64(r.Sym.Sect.Vaddr) + case objabi.R_WEAKADDROFF: + if !r.Sym.Attr.Reachable() { + continue + } + fallthrough + case objabi.R_ADDROFF: + // The method offset tables using this relocation expect the offset to be relative + // to the start of the first text section, even if there are multiple. + if r.Sym.Sect.Name == ".text" { + o = Symaddr(r.Sym) - int64(Segtext.Sections[0].Vaddr) + r.Add + } else { + o = Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr) + r.Add + } + + case objabi.R_ADDRCUOFF: + // debug_range and debug_loc elements use this relocation type to get an + // offset from the start of the compile unit. + o = Symaddr(r.Sym) + r.Add - Symaddr(ldr.Syms[r.Sym.Unit.Textp2[0]]) + + // r->sym can be null 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 + } + 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 + } + + o = 0 + if r.Sym != nil { + o += Symaddr(r.Sym) + } + + o += r.Add - (s.Value + int64(r.Off) + int64(r.Siz)) + case objabi.R_SIZE: + o = r.Sym.Size + r.Add + + case objabi.R_XCOFFREF: + if !target.IsAIX() { + Errorf(s, "find XCOFF R_REF on non-XCOFF files") + } + if !target.IsExternal() { + Errorf(s, "find XCOFF R_REF with internal linking") + } + r.Xsym = r.Sym + r.Xadd = r.Add + r.Done = false + + // This isn't a real relocation so it must not update + // its offset value. + continue + + case objabi.R_DWARFFILEREF: + // The final file index is saved in r.Add in dwarf.go:writelines. + o = r.Add + } + + if target.IsPPC64() || target.IsS390X() { + r.InitExt() + if r.Variant != sym.RV_NONE { + o = thearch.Archrelocvariant(target, syms, r, s, o) + } + } + + if false { + nam := "" + var addr int64 + if r.Sym != nil { + nam = r.Sym.Name + addr = Symaddr(r.Sym) + } + xnam := "" + if r.Xsym != nil { + xnam = r.Xsym.Name + } + fmt.Printf("relocate %s %#x (%#x+%#x, size %d) => %s %#x +%#x (xsym: %s +%#x) [type %d (%s)/%d, %x]\n", s.Name, s.Value+int64(off), s.Value, r.Off, r.Siz, nam, addr, r.Add, xnam, r.Xadd, r.Type, sym.RelocName(target.Arch, r.Type), r.Variant, o) + } + switch siz { + default: + Errorf(s, "bad reloc size %#x for %s", uint32(siz), r.Sym.Name) + fallthrough + + // TODO(rsc): Remove. + case 1: + s.P[off] = byte(int8(o)) + case 2: + if o != int64(int16(o)) { + Errorf(s, "relocation address for %s is too big: %#x", r.Sym.Name, o) + } + i16 := int16(o) + target.Arch.ByteOrder.PutUint16(s.P[off:], uint16(i16)) + case 4: + if r.Type == objabi.R_PCREL || r.Type == objabi.R_CALL { + if o != int64(int32(o)) { + Errorf(s, "pc-relative relocation address for %s is too big: %#x", r.Sym.Name, o) + } + } else { + if o != int64(int32(o)) && o != int64(uint32(o)) { + Errorf(s, "non-pc-relative relocation address for %s is too big: %#x", r.Sym.Name, uint64(o)) + } + } + + fl := int32(o) + target.Arch.ByteOrder.PutUint32(s.P[off:], uint32(fl)) + case 8: + target.Arch.ByteOrder.PutUint64(s.P[off:], uint64(o)) + } + } +} + diff --git a/src/cmd/link/internal/ld/dwarf2.go b/src/cmd/link/internal/ld/dwarf2.go index 4bd52f5105..336122800b 100644 --- a/src/cmd/link/internal/ld/dwarf2.go +++ b/src/cmd/link/internal/ld/dwarf2.go @@ -101,20 +101,20 @@ func dwarfcompress(ctxt *Link) { type compressedSect struct { index int compressed []byte - syms []*sym.Symbol + syms []loader.Sym } - supported := ctxt.IsELF || ctxt.HeadType == objabi.Hwindows || ctxt.HeadType == objabi.Hdarwin - if !ctxt.compressDWARF || !supported || ctxt.LinkMode != LinkInternal { + supported := ctxt.IsELF || ctxt.IsWindows() || ctxt.IsDarwin() + if !ctxt.compressDWARF || !supported || ctxt.IsExternal() { return } var compressedCount int resChannel := make(chan compressedSect) - for i := range dwarfp { - go func(resIndex int, syms []*sym.Symbol) { + for i := range dwarfp2 { + go func(resIndex int, syms []loader.Sym) { resChannel <- compressedSect{resIndex, compressSyms(ctxt, syms), syms} - }(compressedCount, dwarfp[i].syms) + }(compressedCount, dwarfp2[i].syms) compressedCount++ } res := make([]compressedSect, compressedCount) @@ -123,46 +123,55 @@ func dwarfcompress(ctxt *Link) { res[r.index] = r } - var newDwarfp []dwarfSecInfo2 + ldr := ctxt.loader + var newDwarfp []dwarfSecInfo Segdwarf.Sections = Segdwarf.Sections[:0] for _, z := range res { s := z.syms[0] if z.compressed == nil { // Compression didn't help. - ds := dwarfSecInfo2{syms: z.syms} + ds := dwarfSecInfo{syms: z.syms} newDwarfp = append(newDwarfp, ds) - Segdwarf.Sections = append(Segdwarf.Sections, s.Sect) + Segdwarf.Sections = append(Segdwarf.Sections, ldr.SymSect(s)) } else { - compressedSegName := ".zdebug_" + s.Sect.Name[len(".debug_"):] + compressedSegName := ".zdebug_" + ldr.SymSect(s).Name[len(".debug_"):] sect := addsection(ctxt.loader, ctxt.Arch, &Segdwarf, compressedSegName, 04) + sect.Align = 1 sect.Length = uint64(len(z.compressed)) - newSym := ctxt.Syms.Lookup(compressedSegName, 0) - newSym.P = z.compressed - newSym.Size = int64(len(z.compressed)) - newSym.Sect = sect - ds := dwarfSecInfo2{syms: []*sym.Symbol{newSym}} + newSym := ldr.CreateSymForUpdate(compressedSegName, 0) + newSym.SetReachable(true) + newSym.SetData(z.compressed) + newSym.SetSize(int64(len(z.compressed))) + ldr.SetSymSect(newSym.Sym(), sect) + ds := dwarfSecInfo{syms: []loader.Sym{newSym.Sym()}} newDwarfp = append(newDwarfp, ds) + + // compressed symbols are no longer needed. + for _, s := range z.syms { + ldr.SetAttrReachable(s, false) + } } } - dwarfp = newDwarfp + dwarfp2 = newDwarfp // Re-compute the locations of the compressed DWARF symbols // and sections, since the layout of these within the file is // based on Section.Vaddr and Symbol.Value. pos := Segdwarf.Vaddr var prevSect *sym.Section - for _, si := range dwarfp { + for _, si := range dwarfp2 { for _, s := range si.syms { - s.Value = int64(pos) - if s.Sect != prevSect { - s.Sect.Vaddr = uint64(s.Value) - prevSect = s.Sect + ldr.SetSymValue(s, int64(pos)) + sect := ldr.SymSect(s) + if sect != prevSect { + sect.Vaddr = uint64(pos) + prevSect = sect } - if s.Sub != nil { - log.Fatalf("%s: unexpected sub-symbols", s) + if ldr.SubSym(s) != 0 { + log.Fatalf("%s: unexpected sub-symbols", ldr.SymName(s)) } - pos += uint64(s.Size) - if ctxt.HeadType == objabi.Hwindows { + pos += uint64(ldr.SymSize(s)) + if ctxt.IsWindows() { pos = uint64(Rnd(int64(pos), PEFILEALIGN)) } } diff --git a/src/cmd/link/internal/ld/errors.go b/src/cmd/link/internal/ld/errors.go index 61289b4798..c2c191d058 100644 --- a/src/cmd/link/internal/ld/errors.go +++ b/src/cmd/link/internal/ld/errors.go @@ -11,6 +11,11 @@ import ( ) type unresolvedSymKey struct { + from loader.Sym // Symbol that referenced unresolved "to" + to loader.Sym // Unresolved symbol referenced by "from" +} + +type unresolvedSymKey2 struct { from *sym.Symbol // Symbol that referenced unresolved "to" to *sym.Symbol // Unresolved symbol referenced by "from" } @@ -23,20 +28,59 @@ type ErrorReporter struct { loader.ErrorReporter unresOnce sync.Once unresSyms map[unresolvedSymKey]bool + unresSyms2 map[unresolvedSymKey2]bool unresMutex sync.Mutex lookup lookupFn SymName symNameFn } -// errorUnresolved prints unresolved symbol error for r.Sym that is referenced from s. -func (reporter *ErrorReporter) errorUnresolved(s *sym.Symbol, r *sym.Reloc) { +// errorUnresolved prints unresolved symbol error for rs that is referenced from s. +func (reporter *ErrorReporter) errorUnresolved(ldr *loader.Loader, s, rs loader.Sym) { reporter.unresOnce.Do(func() { reporter.unresSyms = make(map[unresolvedSymKey]bool) }) - k := unresolvedSymKey{from: s, to: r.Sym} + k := unresolvedSymKey{from: s, to: rs} reporter.unresMutex.Lock() defer reporter.unresMutex.Unlock() if !reporter.unresSyms[k] { reporter.unresSyms[k] = true + name := ldr.SymName(rs) + + // Try to find symbol under another ABI. + var reqABI, haveABI obj.ABI + haveABI = ^obj.ABI(0) + reqABI, ok := sym.VersionToABI(ldr.SymVersion(rs)) + if ok { + for abi := obj.ABI(0); abi < obj.ABICount; abi++ { + v := sym.ABIToVersion(abi) + if v == -1 { + continue + } + if rs1 := ldr.Lookup(name, v); rs1 != 0 && ldr.SymType(rs1) != sym.Sxxx && ldr.SymType(rs1) != sym.SXREF { + haveABI = abi + } + } + } + + // Give a special error message for main symbol (see #24809). + if name == "main.main" { + reporter.Errorf(s, "function main is undeclared in the main package") + } else if haveABI != ^obj.ABI(0) { + reporter.Errorf(s, "relocation target %s not defined for %s (but is defined for %s)", name, reqABI, haveABI) + } else { + reporter.Errorf(s, "relocation target %s not defined", name) + } + } +} + +// errorUnresolved2 prints unresolved symbol error for r.Sym that is referenced from s. +func (reporter *ErrorReporter) errorUnresolved2(s *sym.Symbol, r *sym.Reloc) { + reporter.unresOnce.Do(func() { reporter.unresSyms2 = make(map[unresolvedSymKey2]bool) }) + + k := unresolvedSymKey2{from: s, to: r.Sym} + reporter.unresMutex.Lock() + defer reporter.unresMutex.Unlock() + if !reporter.unresSyms2[k] { + reporter.unresSyms2[k] = true // Try to find symbol under another ABI. var reqABI, haveABI obj.ABI diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index a43aff22ee..7264f9383e 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -2897,7 +2897,7 @@ func (ctxt *Link) loadlibfull(symGroupType []sym.SymKind) { if t != sym.Sxxx { s := ctxt.loader.Syms[i] if s == nil { - panic(fmt.Sprintf("nil sym for symGroupType t=%s entry %d", t.String(), i)) + continue // in dwarfcompress we drop compressed DWARF symbols } s.Type = t } diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index 14856c160f..6c5a18c359 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go @@ -302,12 +302,12 @@ func Main(arch *sys.Arch, theArch Arch) { ctxt.dodata2(symGroupType) bench.Start("address") order := ctxt.address() - bench.Start("loadlibfull") - ctxt.loadlibfull(symGroupType) // XXX do it here for now bench.Start("dwarfcompress") dwarfcompress(ctxt) bench.Start("layout") filesize := ctxt.layout(order) + bench.Start("loadlibfull") + ctxt.loadlibfull(symGroupType) // XXX do it here for now // Write out the output file. // It is split into two parts (Asmb and Asmb2). The first -- 2.50.0