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
|
Name: golang
|
||||||
Version: 1.7.1
|
Version: 1.7.1
|
||||||
Release: 1%{?dist}
|
Release: 2%{?dist}
|
||||||
Summary: The Go Programming Language
|
Summary: The Go Programming Language
|
||||||
# source tree includes several copies of Mark.Twain-Tom.Sawyer.txt under Public Domain
|
# source tree includes several copies of Mark.Twain-Tom.Sawyer.txt under Public Domain
|
||||||
License: BSD and 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.
|
# 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
|
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
|
# Having documentation separate was broken
|
||||||
Obsoletes: %{name}-docs < 1.1-4
|
Obsoletes: %{name}-docs < 1.1-4
|
||||||
|
|
||||||
@ -258,6 +262,9 @@ Summary: Golang shared object libraries
|
|||||||
|
|
||||||
%patch215 -p1
|
%patch215 -p1
|
||||||
|
|
||||||
|
%patch216 -p1
|
||||||
|
%patch217 -p1
|
||||||
|
|
||||||
%build
|
%build
|
||||||
# print out system information
|
# print out system information
|
||||||
uname -a
|
uname -a
|
||||||
@ -474,6 +481,9 @@ fi
|
|||||||
%endif
|
%endif
|
||||||
|
|
||||||
%changelog
|
%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
|
* Thu Sep 08 2016 Jakub Čajka <jcajka@redhat.com> - 1.7.1-1
|
||||||
- rebase to 1.7.1
|
- rebase to 1.7.1
|
||||||
- Resolves: BZ#1374103
|
- 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