diff options
Diffstat (limited to 'src/runtime')
| -rw-r--r-- | src/runtime/symtab.go | 34 | ||||
| -rw-r--r-- | src/runtime/type.go | 25 |
2 files changed, 51 insertions, 8 deletions
diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index 87b478a885..c1cca7037d 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -195,8 +195,9 @@ type moduledata struct { end, gcdata, gcbss uintptr types, etypes uintptr - typelinks []int32 // offsets from types - itablinks []*itab + textsectmap []textsect + typelinks []int32 // offsets from types + itablinks []*itab ptab []ptabEntry @@ -228,6 +229,14 @@ type functab struct { funcoff uintptr } +// Mapping information for secondary text sections + +type textsect struct { + vaddr uintptr // prelinked section vaddr + length uintptr // section length + baseaddr uintptr // relocated section address +} + const minfunc = 16 // minimum function size const pcbucketsize = 256 * minfunc // size of bucket in the pc->func lookup table @@ -370,12 +379,23 @@ func findfunc(pc uintptr) *_func { ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{}))) idx := ffb.idx + uint32(ffb.subbuckets[i]) if pc < datap.ftab[idx].entry { - throw("findfunc: bad findfunctab entry") - } - // linear search to find func with pc >= entry. - for datap.ftab[idx+1].entry <= pc { - idx++ + // If there are multiple text sections then the buckets for the secondary + // text sections will be off because the addresses in those text sections + // were relocated to higher addresses. Search back to find it. + + for datap.ftab[idx].entry > pc && idx > 0 { + idx-- + } + if idx == 0 { + throw("findfunc: bad findfunctab entry idx") + } + } else { + + // linear search to find func with pc >= entry. + for datap.ftab[idx+1].entry <= pc { + idx++ + } } return (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[idx].funcoff])) } diff --git a/src/runtime/type.go b/src/runtime/type.go index 0467c77400..7f7849d5a0 100644 --- a/src/runtime/type.go +++ b/src/runtime/type.go @@ -257,7 +257,30 @@ func (t *_type) textOff(off textOff) unsafe.Pointer { } return res } - res := md.text + uintptr(off) + res := uintptr(0) + + // The text, or instruction stream is generated as one large buffer. The off (offset) for a method is + // its offset within this buffer. If the total text size gets too large, there can be issues on platforms like ppc64 if + // the target of calls are too far for the call instruction. To resolve the large text issue, the text is split + // into multiple text sections to allow the linker to generate long calls when necessary. When this happens, the vaddr + // for each text section is set to its offset within the text. Each method's offset is compared against the section + // vaddrs and sizes to determine the containing section. Then the section relative offset is added to the section's + // relocated baseaddr to compute the method addess. + + if len(md.textsectmap) > 1 { + for i := range md.textsectmap { + sectaddr := md.textsectmap[i].vaddr + sectlen := md.textsectmap[i].length + if uintptr(off) >= sectaddr && uintptr(off) <= sectaddr+sectlen { + res = md.textsectmap[i].baseaddr + uintptr(off) - uintptr(md.textsectmap[i].vaddr) + break + } + } + } else { + // single text section + res = md.text + uintptr(off) + } + if res > md.etext { println("runtime: textOff", hex(off), "out of range", hex(md.text), "-", hex(md.etext)) throw("runtime: text offset out of range") |
