aboutsummaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/symtab.go34
-rw-r--r--src/runtime/type.go25
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")