From 20afbe86beda00676a608399638887538bd8f669 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Mon, 6 Jul 2020 14:22:38 -0400 Subject: [PATCH] cmd/oldlink: port bug fixes to old linker This CL ports CL 234105 and CL 240621 to the old linker, which fix critical bugs (runtime crashes). Updates #39049. Updates #39927. Change-Id: I47afc84349119e320d2e60d64b7188a410835d2b Reviewed-on: https://go-review.googlesource.com/c/go/+/241087 Run-TryBot: Cherry Zhang TryBot-Result: Gobot Gobot Reviewed-by: Than McIntosh Reviewed-by: Jeremy Faller --- src/cmd/oldlink/internal/arm/asm.go | 6 ++++- src/cmd/oldlink/internal/ld/decodesym.go | 32 ++++++++++++++--------- src/cmd/oldlink/internal/ld/lib.go | 4 ++- src/cmd/oldlink/internal/ld/pcln.go | 2 +- src/cmd/oldlink/internal/ppc64/asm.go | 6 ++++- src/cmd/oldlink/internal/sym/attribute.go | 6 ++++- 6 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/cmd/oldlink/internal/arm/asm.go b/src/cmd/oldlink/internal/arm/asm.go index 9dc4ca0f2a9379..77338e467292ca 100644 --- a/src/cmd/oldlink/internal/arm/asm.go +++ b/src/cmd/oldlink/internal/arm/asm.go @@ -390,8 +390,12 @@ func trampoline(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol) { offset := (signext24(r.Add&0xffffff) + 2) * 4 var tramp *sym.Symbol for i := 0; ; i++ { - name := r.Sym.Name + fmt.Sprintf("%+d-tramp%d", offset, i) + oName := r.Sym.Name + name := oName + fmt.Sprintf("%+d-tramp%d", offset, i) tramp = ctxt.Syms.Lookup(name, int(r.Sym.Version)) + if oName == "runtime.deferreturn" { + tramp.Attr.Set(sym.AttrDeferReturnTramp, true) + } if tramp.Type == sym.SDYNIMPORT { // don't reuse trampoline defined in other module continue diff --git a/src/cmd/oldlink/internal/ld/decodesym.go b/src/cmd/oldlink/internal/ld/decodesym.go index 0676e94e2c0b27..6c596ec78e1b09 100644 --- a/src/cmd/oldlink/internal/ld/decodesym.go +++ b/src/cmd/oldlink/internal/ld/decodesym.go @@ -11,6 +11,7 @@ import ( "cmd/oldlink/internal/sym" "debug/elf" "fmt" + "log" ) // Decoding the type.* symbols. This has to be in sync with @@ -93,7 +94,7 @@ func decodetypeHasUncommon(arch *sys.Arch, p []byte) bool { func findShlibSection(ctxt *Link, path string, addr uint64) *elf.Section { for _, shlib := range ctxt.Shlibs { if shlib.Path == path { - for _, sect := range shlib.File.Sections { + for _, sect := range shlib.File.Sections[1:] { // skip the NULL section if sect.Addr <= addr && addr <= sect.Addr+sect.Size { return sect } @@ -112,9 +113,15 @@ func decodetypeGcprog(ctxt *Link, s *sym.Symbol) []byte { // A gcprog is a 4-byte uint32 indicating length, followed by // the actual program. progsize := make([]byte, 4) - sect.ReadAt(progsize, int64(addr-sect.Addr)) + _, err := sect.ReadAt(progsize, int64(addr-sect.Addr)) + if err != nil { + log.Fatal(err) + } progbytes := make([]byte, ctxt.Arch.ByteOrder.Uint32(progsize)) - sect.ReadAt(progbytes, int64(addr-sect.Addr+4)) + _, err = sect.ReadAt(progbytes, int64(addr-sect.Addr+4)) + if err != nil { + log.Fatal(err) + } return append(progsize, progbytes...) } Exitf("cannot find gcprog for %s", s.Name) @@ -124,14 +131,6 @@ func decodetypeGcprog(ctxt *Link, s *sym.Symbol) []byte { } func decodetypeGcprogShlib(ctxt *Link, s *sym.Symbol) uint64 { - if ctxt.Arch.Family == sys.ARM64 { - for _, shlib := range ctxt.Shlibs { - if shlib.Path == s.File { - return shlib.gcdataAddresses[s] - } - } - return 0 - } return decodeInuxi(ctxt.Arch, s.P[2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize):], ctxt.Arch.PtrSize) } @@ -141,8 +140,15 @@ func decodetypeGcmask(ctxt *Link, s *sym.Symbol) []byte { ptrdata := decodetypePtrdata(ctxt.Arch, s.P) sect := findShlibSection(ctxt, s.File, addr) if sect != nil { - r := make([]byte, ptrdata/int64(ctxt.Arch.PtrSize)) - sect.ReadAt(r, int64(addr-sect.Addr)) + bits := ptrdata / int64(ctxt.Arch.PtrSize) + r := make([]byte, (bits+7)/8) + // ldshlibsyms avoids closing the ELF file so sect.ReadAt works. + // If we remove this read (and the ones in decodetypeGcprog), we + // can close the file. + _, err := sect.ReadAt(r, int64(addr-sect.Addr)) + if err != nil { + log.Fatal(err) + } return r } Exitf("cannot find gcmask for %s", s.Name) diff --git a/src/cmd/oldlink/internal/ld/lib.go b/src/cmd/oldlink/internal/ld/lib.go index cc42901cb60418..499602f9be03b8 100644 --- a/src/cmd/oldlink/internal/ld/lib.go +++ b/src/cmd/oldlink/internal/ld/lib.go @@ -2010,7 +2010,9 @@ func ldshlibsyms(ctxt *Link, shlib string) { Errorf(nil, "cannot open shared library: %s", libpath) return } - defer f.Close() + // Keep the file open as decodetypeGcprog needs to read from it. + // TODO: fix. Maybe mmap the file. + //defer f.Close() hash, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GOABIHASH_TAG) if err != nil { diff --git a/src/cmd/oldlink/internal/ld/pcln.go b/src/cmd/oldlink/internal/ld/pcln.go index 7d53ab8ad4aa67..ed2e8f9e2b77d5 100644 --- a/src/cmd/oldlink/internal/ld/pcln.go +++ b/src/cmd/oldlink/internal/ld/pcln.go @@ -276,7 +276,7 @@ func (ctxt *Link) pclntab() { // set the resumption point to PC_B. lastWasmAddr = uint32(r.Add) } - if r.Type.IsDirectCall() && r.Sym != nil && r.Sym.Name == "runtime.deferreturn" { + if r.Type.IsDirectCall() && r.Sym != nil && (r.Sym.Name == "runtime.deferreturn" || r.Sym.Attr.DeferReturnTramp()) { if ctxt.Arch.Family == sys.Wasm { deferreturn = lastWasmAddr - 1 } else { diff --git a/src/cmd/oldlink/internal/ppc64/asm.go b/src/cmd/oldlink/internal/ppc64/asm.go index 6b57abf5643e31..612f9aa8d27db5 100644 --- a/src/cmd/oldlink/internal/ppc64/asm.go +++ b/src/cmd/oldlink/internal/ppc64/asm.go @@ -667,7 +667,8 @@ func trampoline(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol) { // target is at some offset within the function. Calls to duff+8 and duff+256 must appear as // distinct trampolines. - name := r.Sym.Name + oName := r.Sym.Name + name := oName if r.Add == 0 { name = name + fmt.Sprintf("-tramp%d", i) } else { @@ -677,6 +678,9 @@ func trampoline(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol) { // Look up the trampoline in case it already exists tramp = ctxt.Syms.Lookup(name, int(r.Sym.Version)) + if oName == "runtime.deferreturn" { + tramp.Attr.Set(sym.AttrDeferReturnTramp, true) + } if tramp.Value == 0 { break } diff --git a/src/cmd/oldlink/internal/sym/attribute.go b/src/cmd/oldlink/internal/sym/attribute.go index 4b69bf32d07f15..773b6a4ee70372 100644 --- a/src/cmd/oldlink/internal/sym/attribute.go +++ b/src/cmd/oldlink/internal/sym/attribute.go @@ -81,7 +81,10 @@ const ( // AttrReadOnly indicates whether the symbol's content (Symbol.P) is backed by // read-only memory. AttrReadOnly - // 19 attributes defined so far. + // AttrDeferReturnTramp indicates the symbol is a trampoline of a deferreturn + // call. + AttrDeferReturnTramp + // 20 attributes defined so far. ) func (a Attribute) DuplicateOK() bool { return a&AttrDuplicateOK != 0 } @@ -103,6 +106,7 @@ func (a Attribute) SubSymbol() bool { return a&AttrSubSymbol != 0 } func (a Attribute) Container() bool { return a&AttrContainer != 0 } func (a Attribute) TopFrame() bool { return a&AttrTopFrame != 0 } func (a Attribute) ReadOnly() bool { return a&AttrReadOnly != 0 } +func (a Attribute) DeferReturnTramp() bool { return a&AttrDeferReturnTramp != 0 } func (a Attribute) CgoExport() bool { return a.CgoExportDynamic() || a.CgoExportStatic()