Skip to content

Commit a9ea91d

Browse files
committed
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 <[email protected]>
1 parent 88e564e commit a9ea91d

File tree

2 files changed

+31
-1
lines changed

2 files changed

+31
-1
lines changed

src/cmd/link/internal/ld/pcln.go

+22
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ func (ctxt *Link) pclntab() {
138138

139139
// Gather some basic stats and info.
140140
var nfunc int32
141+
prevSect := ctxt.Textp[0].Sect
141142
for _, s := range ctxt.Textp {
142143
if !emitPcln(ctxt, s) {
143144
continue
@@ -146,6 +147,14 @@ func (ctxt *Link) pclntab() {
146147
if pclntabFirstFunc == nil {
147148
pclntabFirstFunc = s
148149
}
150+
if s.Sect != prevSect {
151+
// With multiple text sections, the external linker may insert functions
152+
// between the sections, which are not known by Go. This leaves holes in
153+
// the PC range covered by the func table. We need to generate an entry
154+
// to mark the hole.
155+
nfunc++
156+
prevSect = s.Sect
157+
}
149158
}
150159

151160
pclntabNfunc = nfunc
@@ -181,10 +190,23 @@ func (ctxt *Link) pclntab() {
181190
}
182191

183192
nfunc = 0 // repurpose nfunc as a running index
193+
prevFunc := ctxt.Textp[0]
184194
for _, s := range ctxt.Textp {
185195
if !emitPcln(ctxt, s) {
186196
continue
187197
}
198+
199+
if s.Sect != prevFunc.Sect {
200+
// With multiple text sections, there may be a hole here in the address
201+
// space (see the comment above). We use an invalid funcoff value to
202+
// mark the hole.
203+
// See also runtime/symtab.go:findfunc
204+
ftab.SetAddrPlus(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize), prevFunc, prevFunc.Size)
205+
ftab.SetUint(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize)+int64(ctxt.Arch.PtrSize), ^uint64(0))
206+
nfunc++
207+
}
208+
prevFunc = s
209+
188210
pcln := s.FuncInfo
189211
if pcln == nil {
190212
pcln = &pclntabZpcln

src/runtime/symtab.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,15 @@ func findfunc(pc uintptr) funcInfo {
614614
idx++
615615
}
616616
}
617-
return funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[idx].funcoff])), datap}
617+
funcoff := datap.ftab[idx].funcoff
618+
if funcoff == ^uintptr(0) {
619+
// With multiple text sections, there may be functions inserted by the external
620+
// linker that are not known by Go. This means there may be holes in the PC
621+
// range covered by the func table. The invalid funcoff value indicates a hole.
622+
// See also cmd/link/internal/ld/pcln.go:pclntab
623+
return funcInfo{}
624+
}
625+
return funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[funcoff])), datap}
618626
}
619627

620628
type pcvalueCache struct {

0 commit comments

Comments
 (0)