1
0
mirror of https://github.com/golang/go synced 2024-11-23 03:50:03 -07:00

cmd/link, runtime: skip holes in func table

On PPC64 when external linking, for large binaries we split the
text section to multiple sections, so the external linking may
insert trampolines between sections. These trampolines are within
the address range covered by the func table, but not known by Go.
This causes runtime.findfunc to return a wrong function if the
given PC is from such trampolines.

In this CL, we generate a marker between text sections where
there could potentially be a hole in the func table. At run time,
we skip the hole if we see such a marker.

Fixes #37216.

Change-Id: I95ab3875a84b357dbaa65a4ed339a19282257ce0
Reviewed-on: https://go-review.googlesource.com/c/go/+/219717
Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
Cherry Zhang 2020-02-16 16:18:04 -05:00
parent 88e564edb1
commit a9ea91d571
2 changed files with 31 additions and 1 deletions

View File

@ -138,6 +138,7 @@ func (ctxt *Link) pclntab() {
// Gather some basic stats and info.
var nfunc int32
prevSect := ctxt.Textp[0].Sect
for _, s := range ctxt.Textp {
if !emitPcln(ctxt, s) {
continue
@ -146,6 +147,14 @@ func (ctxt *Link) pclntab() {
if pclntabFirstFunc == nil {
pclntabFirstFunc = s
}
if s.Sect != prevSect {
// With multiple text sections, the external linker may insert functions
// between the sections, which are not known by Go. This leaves holes in
// the PC range covered by the func table. We need to generate an entry
// to mark the hole.
nfunc++
prevSect = s.Sect
}
}
pclntabNfunc = nfunc
@ -181,10 +190,23 @@ func (ctxt *Link) pclntab() {
}
nfunc = 0 // repurpose nfunc as a running index
prevFunc := ctxt.Textp[0]
for _, s := range ctxt.Textp {
if !emitPcln(ctxt, s) {
continue
}
if s.Sect != prevFunc.Sect {
// With multiple text sections, there may be a hole here in the address
// space (see the comment above). We use an invalid funcoff value to
// mark the hole.
// See also runtime/symtab.go:findfunc
ftab.SetAddrPlus(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize), prevFunc, prevFunc.Size)
ftab.SetUint(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize)+int64(ctxt.Arch.PtrSize), ^uint64(0))
nfunc++
}
prevFunc = s
pcln := s.FuncInfo
if pcln == nil {
pcln = &pclntabZpcln

View File

@ -614,7 +614,15 @@ func findfunc(pc uintptr) funcInfo {
idx++
}
}
return funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[idx].funcoff])), datap}
funcoff := datap.ftab[idx].funcoff
if funcoff == ^uintptr(0) {
// With multiple text sections, there may be functions inserted by the external
// linker that are not known by Go. This means there may be holes in the PC
// range covered by the func table. The invalid funcoff value indicates a hole.
// See also cmd/link/internal/ld/pcln.go:pclntab
return funcInfo{}
}
return funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[funcoff])), datap}
}
type pcvalueCache struct {