fix link failure due to relocation overflows on PPC64X
This commit is contained in:
parent
8bda509c5f
commit
d978616527
12
golang.spec
12
golang.spec
@ -91,7 +91,7 @@
|
||||
|
||||
Name: golang
|
||||
Version: 1.7.1
|
||||
Release: 1%{?dist}
|
||||
Release: 2%{?dist}
|
||||
Summary: The Go Programming Language
|
||||
# source tree includes several copies of Mark.Twain-Tom.Sawyer.txt under Public Domain
|
||||
License: BSD and Public Domain
|
||||
@ -133,6 +133,10 @@ Patch213: go1.5beta1-disable-TestGdbPython.patch
|
||||
# later run `go test -a std`. This makes it only use the zoneinfo.zip where needed in tests.
|
||||
Patch215: ./go1.5-zoneinfo_testing_only.patch
|
||||
|
||||
#PPC64X relocation overflow fix
|
||||
Patch216: ppc64x-overflow-1.patch
|
||||
Patch217: ppc64x-overflow-2.patch
|
||||
|
||||
# Having documentation separate was broken
|
||||
Obsoletes: %{name}-docs < 1.1-4
|
||||
|
||||
@ -258,6 +262,9 @@ Summary: Golang shared object libraries
|
||||
|
||||
%patch215 -p1
|
||||
|
||||
%patch216 -p1
|
||||
%patch217 -p1
|
||||
|
||||
%build
|
||||
# print out system information
|
||||
uname -a
|
||||
@ -474,6 +481,9 @@ fi
|
||||
%endif
|
||||
|
||||
%changelog
|
||||
* Fri Sep 23 2016 Jakub Čajka <jcajka@redhat.com> - 1.7.1-2
|
||||
- fix link failure due to relocation overflows on PPC64X
|
||||
|
||||
* Thu Sep 08 2016 Jakub Čajka <jcajka@redhat.com> - 1.7.1-1
|
||||
- rebase to 1.7.1
|
||||
- Resolves: BZ#1374103
|
||||
|
457
ppc64x-overflow-1.patch
Normal file
457
ppc64x-overflow-1.patch
Normal file
@ -0,0 +1,457 @@
|
||||
From d6beea7f9ea1aa2ae5abca7fccb252767820aa13 Mon Sep 17 00:00:00 2001
|
||||
From: Lynn Boger <laboger@linux.vnet.ibm.com>
|
||||
Date: Tue, 26 Jul 2016 08:51:10 -0500
|
||||
Subject: [PATCH] cmd/link: split large elf text sections for ppc64x
|
||||
|
||||
Some applications built with Go on ppc64x with
|
||||
external linking can fail to link with relocation
|
||||
truncation errors, due to the way that the golang
|
||||
compiler generates a single go.o file containing
|
||||
a single large text section to send to the GNU
|
||||
linker. If the size of the single text section is
|
||||
greater than 2^26, this can lead to link errors
|
||||
due to 24 bit offset field in the bl (call)
|
||||
instruction.
|
||||
|
||||
This fix solves the problem by splitting into
|
||||
multiple text sections when this limit is reached.
|
||||
When this is done then the GNU linker can fix the
|
||||
long calls and insert jump tables where needed.
|
||||
---
|
||||
src/cmd/link/internal/ld/data.go | 52 +++++++++++++++++++++++++++++--
|
||||
src/cmd/link/internal/ld/elf.go | 60 ++++++++++++++++++++++++++++++++---
|
||||
src/cmd/link/internal/ld/lib.go | 20 ++++++++++++
|
||||
src/cmd/link/internal/ld/symtab.go | 64 ++++++++++++++++++++++++++++++++++++++
|
||||
src/cmd/link/internal/ppc64/asm.go | 12 ++++---
|
||||
src/runtime/symtab.go | 34 +++++++++++++++-----
|
||||
src/runtime/type.go | 16 +++++++++-
|
||||
7 files changed, 237 insertions(+), 21 deletions(-)
|
||||
|
||||
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
|
||||
index 57a0dad..58ce18c 100644
|
||||
--- a/src/cmd/link/internal/ld/data.go
|
||||
+++ b/src/cmd/link/internal/ld/data.go
|
||||
@@ -527,7 +527,15 @@ func relocsym(s *LSym) {
|
||||
o = Symaddr(r.Sym) + r.Add - int64(r.Sym.Sect.Vaddr)
|
||||
|
||||
case obj.R_ADDROFF:
|
||||
- o = Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr) + r.Add
|
||||
+
|
||||
+ // The method offset tables using this relocation expect the offset to be relative
|
||||
+ // to the start of the first text section, even if there are multiple.
|
||||
+
|
||||
+ if Linkmode == LinkExternal && r.Sym.Sect.Name == ".text" && r.Sym.Sect.Vaddr != Segtext.Vaddr {
|
||||
+ o = Symaddr(r.Sym) - int64(Segtext.Vaddr) + r.Add
|
||||
+ } else {
|
||||
+ o = Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr) + r.Add
|
||||
+ }
|
||||
|
||||
// r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call.
|
||||
case obj.R_CALL, obj.R_GOTPCREL, obj.R_PCREL:
|
||||
@@ -1926,6 +1934,7 @@ func textaddress() {
|
||||
}
|
||||
va := uint64(INITTEXT)
|
||||
sect.Vaddr = va
|
||||
+ n := 1
|
||||
for _, sym := range Ctxt.Textp {
|
||||
sym.Sect = sect
|
||||
if sym.Type&obj.SSUB != 0 {
|
||||
@@ -1948,9 +1957,30 @@ func textaddress() {
|
||||
} else {
|
||||
va += uint64(sym.Size)
|
||||
}
|
||||
+ // On ppc64x a text section should not be larger than 2^26 bytes due to the size of
|
||||
+ // call target offset field in the bl instruction. Splitting into text
|
||||
+ // sections smaller than this limit allows the GNU linker to modify the long calls
|
||||
+ // appropriately. The limit allows for the space for linker tables.
|
||||
+
|
||||
+ // Only break at outermost syms.
|
||||
+
|
||||
+ if sym.Outer == nil && Iself && Linkmode == LinkExternal && SysArch.InFamily(sys.PPC64) && va-sect.Vaddr > uint64(0x1c00000) {
|
||||
+
|
||||
+ // Set the length for the previous text section
|
||||
+ sect.Length = va - sect.Vaddr
|
||||
+
|
||||
+ // Create new section, set the starting Vaddr
|
||||
+ sect = addsection(&Segtext, ".text", 05)
|
||||
+ sect.Vaddr = va
|
||||
+
|
||||
+ // Create a symbol for the start and end of the secondary text section
|
||||
+ Linklookup(Ctxt, fmt.Sprintf("runtime.text.%d", n), 0).Sect = sect
|
||||
+ n++
|
||||
+ }
|
||||
}
|
||||
|
||||
sect.Length = va - sect.Vaddr
|
||||
+ Linklookup(Ctxt, "runtime.etext", 0).Sect = sect
|
||||
}
|
||||
|
||||
// assign addresses
|
||||
@@ -2057,11 +2087,27 @@ func address() {
|
||||
Segdwarf.Filelen = va - Segdwarf.Vaddr
|
||||
|
||||
text := Segtext.Sect
|
||||
+ lasttext := text
|
||||
var rodata *Section
|
||||
if Segrodata.Sect != nil {
|
||||
rodata = Segrodata.Sect
|
||||
} else {
|
||||
- rodata = text.Next
|
||||
+ // Could be multiple .text sections
|
||||
+ n := 1
|
||||
+ for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next {
|
||||
+ if sect.Name != ".text" {
|
||||
+ break
|
||||
+ }
|
||||
+ lasttext = sect
|
||||
+ symname := fmt.Sprintf("runtime.text.%d", n)
|
||||
+ xdefine(symname, obj.STEXT, int64(sect.Vaddr))
|
||||
+ n++
|
||||
+ }
|
||||
+
|
||||
+ rodata = lasttext.Next
|
||||
+ if rodata != nil && rodata.Name != ".rodata" {
|
||||
+ Diag("Unexpected section order in text segment")
|
||||
+ }
|
||||
}
|
||||
var relrodata *Section
|
||||
typelink := rodata.Next
|
||||
@@ -2108,7 +2154,7 @@ func address() {
|
||||
}
|
||||
|
||||
xdefine("runtime.text", obj.STEXT, int64(text.Vaddr))
|
||||
- xdefine("runtime.etext", obj.STEXT, int64(text.Vaddr+text.Length))
|
||||
+ xdefine("runtime.etext", obj.STEXT, int64(lasttext.Vaddr+lasttext.Length))
|
||||
if HEADTYPE == obj.Hwindows {
|
||||
xdefine(".text", obj.STEXT, int64(text.Vaddr))
|
||||
}
|
||||
diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go
|
||||
index 39d3609..ecb00c2 100644
|
||||
--- a/src/cmd/link/internal/ld/elf.go
|
||||
+++ b/src/cmd/link/internal/ld/elf.go
|
||||
@@ -1623,6 +1623,25 @@ func elfshname(name string) *ElfShdr {
|
||||
return nil
|
||||
}
|
||||
|
||||
+// Create an ElfShdr for the section with name.
|
||||
+// A new one is created even if one already exists with
|
||||
+// the same name.
|
||||
+func elfshnamedup(name string) *ElfShdr {
|
||||
+ var off int
|
||||
+ var sh *ElfShdr
|
||||
+
|
||||
+ for i := 0; i < nelfstr; i++ {
|
||||
+ if name == elfstr[i].s {
|
||||
+ off = elfstr[i].off
|
||||
+ sh = newElfShdr(int64(off))
|
||||
+ return sh
|
||||
+ }
|
||||
+ }
|
||||
+ Diag("cannot find elf name %s", name)
|
||||
+ errorexit()
|
||||
+ return nil
|
||||
+}
|
||||
+
|
||||
func elfshalloc(sect *Section) *ElfShdr {
|
||||
sh := elfshname(sect.Name)
|
||||
sect.Elfsect = sh
|
||||
@@ -1630,7 +1649,17 @@ func elfshalloc(sect *Section) *ElfShdr {
|
||||
}
|
||||
|
||||
func elfshbits(sect *Section) *ElfShdr {
|
||||
- sh := elfshalloc(sect)
|
||||
+ var sh *ElfShdr
|
||||
+
|
||||
+ if sect.Name == ".text" {
|
||||
+ if sect.Elfsect == nil {
|
||||
+ sect.Elfsect = elfshnamedup(sect.Name)
|
||||
+ }
|
||||
+ sh = sect.Elfsect
|
||||
+ } else {
|
||||
+ sh = elfshalloc(sect)
|
||||
+ }
|
||||
+
|
||||
// If this section has already been set up as a note, we assume type_ and
|
||||
// flags are already correct, but the other fields still need filling in.
|
||||
if sh.type_ == SHT_NOTE {
|
||||
@@ -1706,6 +1735,15 @@ func elfshreloc(sect *Section) *ElfShdr {
|
||||
}
|
||||
|
||||
sh := elfshname(elfRelType + sect.Name)
|
||||
+
|
||||
+ // There could be multiple text sections but each needs
|
||||
+ // its own .rela.text.
|
||||
+ if sect.Name == ".text" {
|
||||
+ if sh.info != 0 && sh.info != uint32(sect.Elfsect.shnum) {
|
||||
+ sh = elfshnamedup(elfRelType + sect.Name)
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
sh.type_ = uint32(typ)
|
||||
sh.entsize = uint64(SysArch.RegSize) * 2
|
||||
if typ == SHT_RELA {
|
||||
@@ -1776,9 +1814,12 @@ func Elfemitreloc() {
|
||||
Cput(0)
|
||||
}
|
||||
|
||||
- elfrelocsect(Segtext.Sect, Ctxt.Textp)
|
||||
- for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next {
|
||||
- elfrelocsect(sect, datap)
|
||||
+ for sect := Segtext.Sect; sect != nil; sect = sect.Next {
|
||||
+ if sect.Name == ".text" {
|
||||
+ elfrelocsect(sect, Ctxt.Textp)
|
||||
+ } else {
|
||||
+ elfrelocsect(sect, datap)
|
||||
+ }
|
||||
}
|
||||
for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
|
||||
elfrelocsect(sect, datap)
|
||||
@@ -2109,7 +2150,16 @@ func Asmbelfsetup() {
|
||||
elfshname("")
|
||||
|
||||
for sect := Segtext.Sect; sect != nil; sect = sect.Next {
|
||||
- elfshalloc(sect)
|
||||
+
|
||||
+ // There could be multiple .text sections. Instead check the Elfsect
|
||||
+ // field to determine if already has an ElfShdr and if not, create one.
|
||||
+ if sect.Name == ".text" {
|
||||
+ if sect.Elfsect == nil {
|
||||
+ sect.Elfsect = elfshnamedup(sect.Name)
|
||||
+ }
|
||||
+ } else {
|
||||
+ elfshalloc(sect)
|
||||
+ }
|
||||
}
|
||||
for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
|
||||
elfshalloc(sect)
|
||||
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
|
||||
index 14f4fa9..709e7ca 100644
|
||||
--- a/src/cmd/link/internal/ld/lib.go
|
||||
+++ b/src/cmd/link/internal/ld/lib.go
|
||||
@@ -1956,6 +1956,26 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
|
||||
if s.Type == obj.STEXT {
|
||||
put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil)
|
||||
}
|
||||
+ n := 0
|
||||
+
|
||||
+ // Generate base addresses for all text sections if there are multiple
|
||||
+ for sect := Segtext.Sect; sect != nil; sect = sect.Next {
|
||||
+ if n == 0 {
|
||||
+ n++
|
||||
+ continue
|
||||
+ }
|
||||
+ if sect.Name != ".text" {
|
||||
+ break
|
||||
+ }
|
||||
+ s = Linkrlookup(Ctxt, fmt.Sprintf("runtime.text.%d", n), 0)
|
||||
+ if s == nil {
|
||||
+ break
|
||||
+ }
|
||||
+ if s.Type == obj.STEXT {
|
||||
+ put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil)
|
||||
+ }
|
||||
+ n++
|
||||
+ }
|
||||
s = Linklookup(Ctxt, "runtime.etext", 0)
|
||||
if s.Type == obj.STEXT {
|
||||
put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil)
|
||||
diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go
|
||||
index 06d7792..80eb33d 100644
|
||||
--- a/src/cmd/link/internal/ld/symtab.go
|
||||
+++ b/src/cmd/link/internal/ld/symtab.go
|
||||
@@ -315,6 +315,62 @@ func (libs byPkg) Swap(a, b int) {
|
||||
libs[a], libs[b] = libs[b], libs[a]
|
||||
}
|
||||
|
||||
+// Create a table with information on the text sections.
|
||||
+
|
||||
+func textsectionmap() uint32 {
|
||||
+
|
||||
+ t := Linklookup(Ctxt, "runtime.textsectionmap", 0)
|
||||
+ t.Type = obj.SRODATA
|
||||
+ t.Attr |= AttrReachable
|
||||
+ nsections := int64(0)
|
||||
+
|
||||
+ for sect := Segtext.Sect; sect != nil; sect = sect.Next {
|
||||
+ if sect.Name == ".text" {
|
||||
+ nsections++
|
||||
+ } else {
|
||||
+ break
|
||||
+ }
|
||||
+ }
|
||||
+ Symgrow(Ctxt, t, nsections*3*8)
|
||||
+
|
||||
+ off := int64(0)
|
||||
+ n := 0
|
||||
+
|
||||
+ // The vaddr for each text section is the difference between the section's
|
||||
+ // Vaddr and the Vaddr for the first text section as determined at compile
|
||||
+ // time.
|
||||
+
|
||||
+ // The symbol name for the start address of the first text section is
|
||||
+ // runtime.text. Additional text sections are named runtime.text.n where n is the
|
||||
+ // order of creation starting with 1. These symbols provide the section's
|
||||
+ // start address after relocation by the linker.
|
||||
+
|
||||
+ textbase := Segtext.Sect.Vaddr
|
||||
+ for sect := Segtext.Sect; sect != nil; sect = sect.Next {
|
||||
+ if sect.Name != ".text" {
|
||||
+ break
|
||||
+ }
|
||||
+ off = setuintxx(Ctxt, t, off, sect.Vaddr-textbase, int64(SysArch.IntSize))
|
||||
+ off = setuintxx(Ctxt, t, off, sect.Length, int64(SysArch.IntSize))
|
||||
+ if n == 0 {
|
||||
+ s := Linkrlookup(Ctxt, "runtime.text", 0)
|
||||
+ if s == nil {
|
||||
+ Diag("Unable to find symbol runtime.text\n")
|
||||
+ }
|
||||
+ off = setaddr(Ctxt, t, off, s)
|
||||
+
|
||||
+ } else {
|
||||
+ s := Linklookup(Ctxt, fmt.Sprintf("runtime.text.%d", n), 0)
|
||||
+ if s == nil {
|
||||
+ Diag("Unable to find symbol runtime.text.%d\n", n)
|
||||
+ }
|
||||
+ off = setaddr(Ctxt, t, off, s)
|
||||
+ }
|
||||
+ n++
|
||||
+ }
|
||||
+ return uint32(n)
|
||||
+}
|
||||
+
|
||||
func symtab() {
|
||||
dosymtype()
|
||||
|
||||
@@ -489,6 +545,8 @@ func symtab() {
|
||||
adduint(Ctxt, abihashgostr, uint64(hashsym.Size))
|
||||
}
|
||||
|
||||
+ nsections := textsectionmap()
|
||||
+
|
||||
// Information about the layout of the executable image for the
|
||||
// runtime to use. Any changes here must be matched by changes to
|
||||
// the definition of moduledata in runtime/symtab.go.
|
||||
@@ -527,6 +585,12 @@ func symtab() {
|
||||
Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.gcbss", 0))
|
||||
Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.types", 0))
|
||||
Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.etypes", 0))
|
||||
+
|
||||
+ // text section information
|
||||
+ Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.textsectionmap", 0))
|
||||
+ adduint(Ctxt, moduledata, uint64(nsections))
|
||||
+ adduint(Ctxt, moduledata, uint64(nsections))
|
||||
+
|
||||
// The typelinks slice
|
||||
Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.typelink", 0))
|
||||
adduint(Ctxt, moduledata, uint64(ntypelinks))
|
||||
diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go
|
||||
index bd2e23f..ab59fa8 100644
|
||||
--- a/src/cmd/link/internal/ppc64/asm.go
|
||||
+++ b/src/cmd/link/internal/ppc64/asm.go
|
||||
@@ -813,12 +813,14 @@ func asmb() {
|
||||
ld.Asmbelfsetup()
|
||||
}
|
||||
|
||||
- sect := ld.Segtext.Sect
|
||||
- ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
- ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
|
||||
- for sect = sect.Next; sect != nil; sect = sect.Next {
|
||||
+ for sect := ld.Segtext.Sect; sect != nil; sect = sect.Next {
|
||||
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
- ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
|
||||
+ // Might have multiple text sections
|
||||
+ if sect.Name == ".text" {
|
||||
+ ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
|
||||
+ } else {
|
||||
+ ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
|
||||
+ }
|
||||
}
|
||||
|
||||
if ld.Segrodata.Filelen > 0 {
|
||||
diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go
|
||||
index 4f6fae2..23e80ce 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
|
||||
|
||||
modulename string
|
||||
modulehashes []modulehash
|
||||
@@ -226,6 +227,14 @@ type functab struct {
|
||||
funcoff uintptr
|
||||
}
|
||||
|
||||
+// Mapping information for secondary text sections
|
||||
+
|
||||
+type textsect struct {
|
||||
+ vaddr uint64 // prelinked section vaddr
|
||||
+ length uint64 // 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
|
||||
|
||||
@@ -368,12 +377,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 5ef11a4..f641adc 100644
|
||||
--- a/src/runtime/type.go
|
||||
+++ b/src/runtime/type.go
|
||||
@@ -257,7 +257,21 @@ func (t *_type) textOff(off textOff) unsafe.Pointer {
|
||||
}
|
||||
return res
|
||||
}
|
||||
- res := md.text + uintptr(off)
|
||||
+ res := uintptr(0)
|
||||
+
|
||||
+ // Find the text section range that contains the offset to determine the section's base
|
||||
+ // address. In cases where there are multiple text sections, the base address might be
|
||||
+ // relocated by the linker.
|
||||
+
|
||||
+ for i := 0; i < len(md.textsectmap); i++ {
|
||||
+ sectaddr := md.textsectmap[i].vaddr
|
||||
+ sectlen := md.textsectmap[i].length
|
||||
+ if uint64(off) >= sectaddr && uint64(off) <= sectaddr+sectlen {
|
||||
+ res = md.textsectmap[i].baseaddr + uintptr(off) - uintptr(md.textsectmap[i].vaddr)
|
||||
+ break
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
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")
|
150
ppc64x-overflow-2.patch
Normal file
150
ppc64x-overflow-2.patch
Normal file
@ -0,0 +1,150 @@
|
||||
From a5b97a846d70cd8db7f33c24f2b9159f935ce318 Mon Sep 17 00:00:00 2001
|
||||
From: Lynn Boger <laboger@linux.vnet.ibm.com>
|
||||
Date: Tue, 13 Sep 2016 15:13:08 -0500
|
||||
Subject: [PATCH] cmd/compile: large text sections on ppc64le
|
||||
|
||||
Additional fixes as submitted upstream.
|
||||
---
|
||||
src/cmd/link/internal/ld/data.go | 24 ++++++++++++------------
|
||||
src/cmd/link/internal/ld/lib.go | 2 +-
|
||||
src/cmd/link/internal/ld/symtab.go | 2 +-
|
||||
src/runtime/type.go | 28 ++++++++++++++++++----------
|
||||
4 files changed, 32 insertions(+), 24 deletions(-)
|
||||
|
||||
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
|
||||
index 58ce18c..d8e43ff 100644
|
||||
--- a/src/cmd/link/internal/ld/data.go
|
||||
+++ b/src/cmd/link/internal/ld/data.go
|
||||
@@ -531,7 +531,7 @@ func relocsym(s *LSym) {
|
||||
// The method offset tables using this relocation expect the offset to be relative
|
||||
// to the start of the first text section, even if there are multiple.
|
||||
|
||||
- if Linkmode == LinkExternal && r.Sym.Sect.Name == ".text" && r.Sym.Sect.Vaddr != Segtext.Vaddr {
|
||||
+ if r.Sym.Sect.Name == ".text" {
|
||||
o = Symaddr(r.Sym) - int64(Segtext.Vaddr) + r.Add
|
||||
} else {
|
||||
o = Symaddr(r.Sym) - int64(r.Sym.Sect.Vaddr) + r.Add
|
||||
@@ -1928,7 +1928,6 @@ func textaddress() {
|
||||
|
||||
sect.Align = int32(Funcalign)
|
||||
Linklookup(Ctxt, "runtime.text", 0).Sect = sect
|
||||
- Linklookup(Ctxt, "runtime.etext", 0).Sect = sect
|
||||
if HEADTYPE == obj.Hwindows {
|
||||
Linklookup(Ctxt, ".text", 0).Sect = sect
|
||||
}
|
||||
@@ -1964,7 +1963,7 @@ func textaddress() {
|
||||
|
||||
// Only break at outermost syms.
|
||||
|
||||
- if sym.Outer == nil && Iself && Linkmode == LinkExternal && SysArch.InFamily(sys.PPC64) && va-sect.Vaddr > uint64(0x1c00000) {
|
||||
+ if sym.Outer == nil && Iself && Linkmode == LinkExternal && SysArch.InFamily(sys.PPC64) && va-sect.Vaddr > 0x1c00000 {
|
||||
|
||||
// Set the length for the previous text section
|
||||
sect.Length = va - sect.Vaddr
|
||||
@@ -1973,7 +1972,7 @@ func textaddress() {
|
||||
sect = addsection(&Segtext, ".text", 05)
|
||||
sect.Vaddr = va
|
||||
|
||||
- // Create a symbol for the start and end of the secondary text section
|
||||
+ // Create a symbol for the start of the secondary text section
|
||||
Linklookup(Ctxt, fmt.Sprintf("runtime.text.%d", n), 0).Sect = sect
|
||||
n++
|
||||
}
|
||||
@@ -2093,15 +2092,8 @@ func address() {
|
||||
rodata = Segrodata.Sect
|
||||
} else {
|
||||
// Could be multiple .text sections
|
||||
- n := 1
|
||||
- for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next {
|
||||
- if sect.Name != ".text" {
|
||||
- break
|
||||
- }
|
||||
+ for sect := Segtext.Sect.Next; sect != nil && sect.Name == ".text"; sect = sect.Next {
|
||||
lasttext = sect
|
||||
- symname := fmt.Sprintf("runtime.text.%d", n)
|
||||
- xdefine(symname, obj.STEXT, int64(sect.Vaddr))
|
||||
- n++
|
||||
}
|
||||
|
||||
rodata = lasttext.Next
|
||||
@@ -2155,6 +2147,14 @@ func address() {
|
||||
|
||||
xdefine("runtime.text", obj.STEXT, int64(text.Vaddr))
|
||||
xdefine("runtime.etext", obj.STEXT, int64(lasttext.Vaddr+lasttext.Length))
|
||||
+
|
||||
+ n := 1
|
||||
+ for sect := Segtext.Sect.Next; sect != nil && sect.Name == ".text"; sect = sect.Next {
|
||||
+ symname := fmt.Sprintf("runtime.text.%d", n)
|
||||
+ xdefine(symname, obj.STEXT, int64(sect.Vaddr))
|
||||
+ n++
|
||||
+ }
|
||||
+
|
||||
if HEADTYPE == obj.Hwindows {
|
||||
xdefine(".text", obj.STEXT, int64(text.Vaddr))
|
||||
}
|
||||
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
|
||||
index 709e7ca..c37ef92 100644
|
||||
--- a/src/cmd/link/internal/ld/lib.go
|
||||
+++ b/src/cmd/link/internal/ld/lib.go
|
||||
@@ -1958,7 +1958,7 @@ func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
|
||||
}
|
||||
n := 0
|
||||
|
||||
- // Generate base addresses for all text sections if there are multiple
|
||||
+ // Generate base addresses for all text sections if there are multiple.
|
||||
for sect := Segtext.Sect; sect != nil; sect = sect.Next {
|
||||
if n == 0 {
|
||||
n++
|
||||
diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go
|
||||
index 80eb33d..ec26f88 100644
|
||||
--- a/src/cmd/link/internal/ld/symtab.go
|
||||
+++ b/src/cmd/link/internal/ld/symtab.go
|
||||
@@ -331,7 +331,7 @@ func textsectionmap() uint32 {
|
||||
break
|
||||
}
|
||||
}
|
||||
- Symgrow(Ctxt, t, nsections*3*8)
|
||||
+ Symgrow(Ctxt, t, nsections*(2*int64(SysArch.IntSize)+int64(SysArch.PtrSize)))
|
||||
|
||||
off := int64(0)
|
||||
n := 0
|
||||
diff --git a/src/runtime/type.go b/src/runtime/type.go
|
||||
index f641adc..d4df5a9 100644
|
||||
--- a/src/runtime/type.go
|
||||
+++ b/src/runtime/type.go
|
||||
@@ -259,17 +259,25 @@ func (t *_type) textOff(off textOff) unsafe.Pointer {
|
||||
}
|
||||
res := uintptr(0)
|
||||
|
||||
- // Find the text section range that contains the offset to determine the section's base
|
||||
- // address. In cases where there are multiple text sections, the base address might be
|
||||
- // relocated by the linker.
|
||||
-
|
||||
- for i := 0; i < len(md.textsectmap); i++ {
|
||||
- sectaddr := md.textsectmap[i].vaddr
|
||||
- sectlen := md.textsectmap[i].length
|
||||
- if uint64(off) >= sectaddr && uint64(off) <= sectaddr+sectlen {
|
||||
- res = md.textsectmap[i].baseaddr + uintptr(off) - uintptr(md.textsectmap[i].vaddr)
|
||||
- break
|
||||
+ // 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 := 0; i < len(md.textsectmap); i++ {
|
||||
+ sectaddr := md.textsectmap[i].vaddr
|
||||
+ sectlen := md.textsectmap[i].length
|
||||
+ if uint64(off) >= sectaddr && uint64(off) <= sectaddr+sectlen {
|
||||
+ res = md.textsectmap[i].baseaddr + uintptr(off) - uintptr(md.textsectmap[i].vaddr)
|
||||
+ break
|
||||
+ }
|
||||
}
|
||||
+ } else {
|
||||
+ res = md.text + uintptr(off)
|
||||
}
|
||||
|
||||
if res > md.etext {
|
Loading…
Reference in New Issue
Block a user