// Gather some basic stats and info.
var nfunc int32
+ prevSect := ctxt.Textp[0].Sect
for _, s := range ctxt.Textp {
if !emitPcln(ctxt, s) {
continue
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
}
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
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 {