aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCherry Zhang <cherryyz@google.com>2020-02-16 16:18:04 -0500
committerCherry Zhang <cherryyz@google.com>2020-02-18 17:55:23 +0000
commita9ea91d571b75d27a49e07f3604b8faa7a48525d (patch)
tree2cecbedadf03184ce0430c131081a7dd1b558aaa
parent88e564edb13f1596c12ad16d5fd3c7ac7deac855 (diff)
downloadgo-a9ea91d571b75d27a49e07f3604b8faa7a48525d.tar.gz
go-a9ea91d571b75d27a49e07f3604b8faa7a48525d.zip
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>
-rw-r--r--src/cmd/link/internal/ld/pcln.go22
-rw-r--r--src/runtime/symtab.go10
2 files changed, 31 insertions, 1 deletions
diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go
index db44c0292e..3e8135c959 100644
--- a/src/cmd/link/internal/ld/pcln.go
+++ b/src/cmd/link/internal/ld/pcln.go
@@ -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
diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go
index ddcf231929..a6e08d7214 100644
--- a/src/runtime/symtab.go
+++ b/src/runtime/symtab.go
@@ -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 {