1
0
mirror of https://github.com/golang/go synced 2024-11-23 17:30:02 -07:00

cmd/link: fix trampoline generation for aix/ppc64

This commit fixes trampoline generation on aix/ppc64 which must use TOC
symbols.
It also adds a size to runtime.text.X symbols to prevent ld from moving
them, like runtime.text.

Change-Id: Ida033ec20ad8d7b7fb3faeb0ec4fa7bc4ce86b7e
Reviewed-on: https://go-review.googlesource.com/c/go/+/164009
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
Clément Chigot 2019-02-20 16:48:43 +01:00 committed by Ian Lance Taylor
parent d06704a3c2
commit cb8054a6b6
4 changed files with 95 additions and 33 deletions

View File

@ -1990,6 +1990,10 @@ func (ctxt *Link) textaddress() {
// lay down trampolines after each function
for ; ntramps < len(ctxt.tramps); ntramps++ {
tramp := ctxt.tramps[ntramps]
if ctxt.HeadType == objabi.Haix && strings.HasPrefix(tramp.Name, "runtime.text.") {
// Already set in assignAddress
continue
}
sect, n, va = assignAddress(ctxt, sect, n, tramp, va, true)
}
}
@ -2030,10 +2034,6 @@ func assignAddress(ctxt *Link, sect *sym.Section, n int, s *sym.Symbol, va uint6
} else {
va = uint64(Rnd(int64(va), int64(Funcalign)))
}
s.Value = 0
for sub := s; sub != nil; sub = sub.Sub {
sub.Value += int64(va)
}
funcsize := uint64(MINFUNC) // spacing required for findfunctab
if s.Size > MINFUNC {
@ -2049,7 +2049,7 @@ func assignAddress(ctxt *Link, sect *sym.Section, n int, s *sym.Symbol, va uint6
// Only break at outermost syms.
if ctxt.Arch.InFamily(sys.PPC64) && s.Outer == nil && ctxt.IsELF && ctxt.LinkMode == LinkExternal && va-sect.Vaddr+funcsize+maxSizeTrampolinesPPC64(s, isTramp) > 0x1c00000 {
if ctxt.Arch.InFamily(sys.PPC64) && s.Outer == nil && ctxt.LinkMode == LinkExternal && va-sect.Vaddr+funcsize+maxSizeTrampolinesPPC64(s, isTramp) > 0x1c00000 {
// Set the length for the previous text section
sect.Length = va - sect.Vaddr
@ -2059,9 +2059,35 @@ func assignAddress(ctxt *Link, sect *sym.Section, n int, s *sym.Symbol, va uint6
s.Sect = sect
// Create a symbol for the start of the secondary text sections
ctxt.Syms.Lookup(fmt.Sprintf("runtime.text.%d", n), 0).Sect = sect
ntext := ctxt.Syms.Lookup(fmt.Sprintf("runtime.text.%d", n), 0)
ntext.Sect = sect
if ctxt.HeadType == objabi.Haix {
// runtime.text.X must be a real symbol on AIX.
// Assign its address directly in order to be the
// first symbol of this new section.
ntext.Type = sym.STEXT
ntext.Size = int64(MINFUNC)
ntext.Attr |= sym.AttrReachable
ntext.Attr |= sym.AttrOnList
ctxt.tramps = append(ctxt.tramps, ntext)
ntext.Value = int64(va)
va += uint64(ntext.Size)
if s.Align != 0 {
va = uint64(Rnd(int64(va), int64(s.Align)))
} else {
va = uint64(Rnd(int64(va), int64(Funcalign)))
}
}
n++
}
s.Value = 0
for sub := s; sub != nil; sub = sub.Sub {
sub.Value += int64(va)
}
va += funcsize
return sect, n, va
@ -2247,7 +2273,11 @@ func (ctxt *Link) address() []*sym.Segment {
break
}
symname := fmt.Sprintf("runtime.text.%d", n)
ctxt.xdefine(symname, sym.STEXT, int64(sect.Vaddr))
if ctxt.HeadType != objabi.Haix || ctxt.LinkMode != LinkExternal {
// Addresses are already set on AIX with external linker
// because these symbols are part of their sections.
ctxt.xdefine(symname, sym.STEXT, int64(sect.Vaddr))
}
n++
}

View File

@ -2176,7 +2176,8 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
n++
continue
}
if sect.Name != ".text" {
if sect.Name != ".text" || (ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
// On AIX, runtime.text.X are symbols already in the symtab.
break
}
s = ctxt.Syms.ROLookup(fmt.Sprintf("runtime.text.%d", n), 0)

View File

@ -777,7 +777,11 @@ func (f *xcoffFile) writeSymbolFunc(ctxt *Link, x *sym.Symbol) []xcoffSym {
syms := []xcoffSym{}
// Check if a new file is detected.
if x.File == "" { // Undefined global symbol
if strings.Contains(x.Name, "-tramp") || strings.HasPrefix(x.Name, "runtime.text.") {
// Trampoline don't have a FILE so there are considered
// in the current file.
// Same goes for runtime.text.X symbols.
} else if x.File == "" { // Undefined global symbol
// If this happens, the algorithme must be redone.
if currSymSrcFile.name != "" {
Exitf("undefined global symbol found inside another file")
@ -860,7 +864,7 @@ func putaixsym(ctxt *Link, x *sym.Symbol, str string, t SymbolType, addr int64,
return
case TextSym:
if x.FuncInfo != nil {
if x.FuncInfo != nil || strings.Contains(x.Name, "-tramp") || strings.HasPrefix(x.Name, "runtime.text.") {
// Function within a file
syms = xfile.writeSymbolFunc(ctxt, x)
} else {

View File

@ -694,7 +694,7 @@ func trampoline(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol) {
ld.Errorf(s, "unexpected trampoline for shared or dynamic linking\n")
} else {
ctxt.AddTramp(tramp)
gentramp(ctxt.Arch, ctxt.LinkMode, tramp, r.Sym, r.Add)
gentramp(ctxt, tramp, r.Sym, r.Add)
}
}
r.Sym = tramp
@ -706,40 +706,67 @@ func trampoline(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol) {
}
}
func gentramp(arch *sys.Arch, linkmode ld.LinkMode, tramp, target *sym.Symbol, offset int64) {
// Used for default build mode for an executable
// Address of the call target is generated using
// relocation and doesn't depend on r2 (TOC).
func gentramp(ctxt *ld.Link, tramp, target *sym.Symbol, offset int64) {
tramp.Size = 16 // 4 instructions
tramp.P = make([]byte, tramp.Size)
t := ld.Symaddr(target) + offset
o1 := uint32(0x3fe00000) // lis r31,targetaddr hi
o2 := uint32(0x3bff0000) // addi r31,targetaddr lo
// With external linking, the target address must be
// relocated using LO and HA
if linkmode == ld.LinkExternal {
var o1, o2 uint32
if ctxt.HeadType == objabi.Haix {
// On AIX, the address is retrieved with a TOC symbol.
// For internal linking, the "Linux" way might still be used.
// However, all text symbols are accessed with a TOC symbol as
// text relocations aren't supposed to be possible.
// So, keep using the external linking way to be more AIX friendly.
o1 = uint32(0x3fe20000) // lis r2, toctargetaddr hi
o2 = uint32(0xebff0000) // ld r31, toctargetaddr lo
toctramp := ctxt.Syms.Lookup("TOC."+tramp.Name, 0)
toctramp.Type = sym.SXCOFFTOC
toctramp.Attr |= sym.AttrReachable
toctramp.AddAddr(ctxt.Arch, target)
tr := tramp.AddRel()
tr.Off = 0
tr.Type = objabi.R_ADDRPOWER
tr.Type = objabi.R_ADDRPOWER_TOCREL_DS
tr.Siz = 8 // generates 2 relocations: HA + LO
tr.Sym = target
tr.Sym = toctramp
tr.Add = offset
} else {
// adjustment needed if lo has sign bit set
// when using addi to compute address
val := uint32((t & 0xffff0000) >> 16)
if t&0x8000 != 0 {
val += 1
// Used for default build mode for an executable
// Address of the call target is generated using
// relocation and doesn't depend on r2 (TOC).
o1 = uint32(0x3fe00000) // lis r31,targetaddr hi
o2 = uint32(0x3bff0000) // addi r31,targetaddr lo
// With external linking, the target address must be
// relocated using LO and HA
if ctxt.LinkMode == ld.LinkExternal {
tr := tramp.AddRel()
tr.Off = 0
tr.Type = objabi.R_ADDRPOWER
tr.Siz = 8 // generates 2 relocations: HA + LO
tr.Sym = target
tr.Add = offset
} else {
// adjustment needed if lo has sign bit set
// when using addi to compute address
val := uint32((t & 0xffff0000) >> 16)
if t&0x8000 != 0 {
val += 1
}
o1 |= val // hi part of addr
o2 |= uint32(t & 0xffff) // lo part of addr
}
o1 |= val // hi part of addr
o2 |= uint32(t & 0xffff) // lo part of addr
}
o3 := uint32(0x7fe903a6) // mtctr r31
o4 := uint32(0x4e800420) // bctr
arch.ByteOrder.PutUint32(tramp.P, o1)
arch.ByteOrder.PutUint32(tramp.P[4:], o2)
arch.ByteOrder.PutUint32(tramp.P[8:], o3)
arch.ByteOrder.PutUint32(tramp.P[12:], o4)
ctxt.Arch.ByteOrder.PutUint32(tramp.P, o1)
ctxt.Arch.ByteOrder.PutUint32(tramp.P[4:], o2)
ctxt.Arch.ByteOrder.PutUint32(tramp.P[8:], o3)
ctxt.Arch.ByteOrder.PutUint32(tramp.P[12:], o4)
}
func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {