Commit 4295ed9b authored by Clément Chigot's avatar Clément Chigot Committed by Ian Lance Taylor

cmd: fix symbols addressing for aix/ppc64

This commit changes the code generated for addressing symbols on AIX
operating system.

On AIX, every symbol accesses must be done via another symbol near the TOC,
named TOC anchor or TOC entry. This TOC anchor is a pointer to the symbol
address.
During Progedit function, when a symbol access is detected, its instructions
are modified to create a load on its TOC anchor and retrieve the symbol.

Change-Id: I00cf8f49c13004bc99fa8af13d549a709320f797
Reviewed-on: https://go-review.googlesource.com/c/151039
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
parent b41cdc4a
......@@ -214,6 +214,8 @@ const (
// Indicates auto that was optimized away, but whose type
// we want to preserve in the DWARF debug info.
NAME_DELETED_AUTO
// Indicates that this is a reference to a TOC anchor.
NAME_TOCREF
)
//go:generate stringer -type AddrType
......
......@@ -98,6 +98,17 @@ func WriteObjFile(ctxt *Link, b *bufio.Writer) {
w.writeRefs(s)
w.addLengths(s)
}
if ctxt.Headtype == objabi.Haix {
// Data must be sorted to keep a constant order in TOC symbols.
// As they are created during Progedit, two symbols can be switched between
// two different compilations. Therefore, BuildID will be different.
// TODO: find a better place and optimize to only sort TOC symbols
SortSlice(ctxt.Data, func(i, j int) bool {
return ctxt.Data[i].Name < ctxt.Data[j].Name
})
}
for _, s := range ctxt.Data {
w.writeRefs(s)
w.addLengths(s)
......
......@@ -391,6 +391,7 @@ const (
C_GOK
C_ADDR
C_GOTADDR
C_TOCADDR
C_TLS_LE
C_TLS_IE
C_TEXTSIZE
......
......@@ -26,6 +26,7 @@ var cnames9 = []string{
"DACON",
"SBRA",
"LBRA",
"LBRAPIC",
"SAUTO",
"LAUTO",
"SEXT",
......@@ -42,6 +43,7 @@ var cnames9 = []string{
"GOK",
"ADDR",
"GOTADDR",
"TOCADDR",
"TLS_LE",
"TLS_IE",
"TEXTSIZE",
......
......@@ -287,6 +287,7 @@ var optab = []Optab{
{AMOVD, C_TLS_IE, C_NONE, C_NONE, C_REG, 80, 8, 0},
{AMOVD, C_GOTADDR, C_NONE, C_NONE, C_REG, 81, 8, 0},
{AMOVD, C_TOCADDR, C_NONE, C_NONE, C_REG, 95, 8, 0},
/* load constant */
{AMOVD, C_SECON, C_NONE, C_NONE, C_REG, 3, 4, REGSB},
......@@ -846,6 +847,9 @@ func (c *ctxt9) aclass(a *obj.Addr) int {
case obj.NAME_GOTREF:
return C_GOTADDR
case obj.NAME_TOCREF:
return C_TOCADDR
case obj.NAME_AUTO:
c.instoffset = int64(c.autosize) + a.Offset
if c.instoffset >= -BIG && c.instoffset < BIG {
......@@ -1019,7 +1023,7 @@ func (c *ctxt9) oplook(p *obj.Prog) *Optab {
}
}
//print("oplook %v %d %d %d %d\n", p, a1, a2, a3, a4);
// c.ctxt.Logf("oplook %v %d %d %d %d\n", p, a1, a2, a3, a4)
ops := oprange[p.As&obj.AMask]
c1 := &xcmp[a1]
c3 := &xcmp[a3]
......@@ -2207,6 +2211,10 @@ func (c *ctxt9) opform(insn uint32) int {
// Encode instructions and create relocation for accessing s+d according to the
// instruction op with source or destination (as appropriate) register reg.
func (c *ctxt9) symbolAccess(s *obj.LSym, d int64, reg int16, op uint32) (o1, o2 uint32) {
if c.ctxt.Headtype == objabi.Haix {
// Every symbol accesses must be made via a TOC anchor.
c.ctxt.Diag("symbolAccess called for %s", s.Name)
}
var base uint32
form := c.opform(op)
if c.ctxt.Flag_shared {
......@@ -3647,6 +3655,24 @@ func (c *ctxt9) asmout(p *obj.Prog, o *Optab, out []uint32) {
/* operand order: RA, RB, CY, RT */
cy := int(c.regoff(p.GetFrom3()))
o1 = AOP_Z23I(c.oprrr(p.As), uint32(p.To.Reg), uint32(p.From.Reg), uint32(p.Reg), uint32(cy))
case 95: /* Retrieve TOC symbol */
v := c.vregoff(&p.To)
if v != 0 {
c.ctxt.Diag("invalid offset against TOC slot %v", p)
}
if c.opform(c.opload(p.As)) != DS_FORM {
c.ctxt.Diag("invalid form for a TOC access in %v", p)
}
o1 = AOP_IRR(OP_ADDIS, uint32(p.To.Reg), REG_R2, 0)
o2 = AOP_IRR(c.opload(AMOVD), uint32(p.To.Reg), uint32(p.To.Reg), 0)
rel := obj.Addrel(c.cursym)
rel.Off = int32(c.pc)
rel.Siz = 8
rel.Sym = p.From.Sym
rel.Type = objabi.R_ADDRPOWER_TOCREL_DS
}
out[0] = o1
......
......@@ -108,9 +108,122 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
}
if c.ctxt.Flag_dynlink {
c.rewriteToUseGot(p)
} else if c.ctxt.Headtype == objabi.Haix {
c.rewriteToUseTOC(p)
}
}
// Rewrite p, if necessary, to access a symbol using its TOC anchor.
func (c *ctxt9) rewriteToUseTOC(p *obj.Prog) {
if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
return
}
var source *obj.Addr
if p.From.Name == obj.NAME_EXTERN || p.From.Name == obj.NAME_STATIC {
if p.From.Type == obj.TYPE_ADDR {
if p.As == ADWORD {
// ADWORD $sym doesn't need TOC anchor
return
}
if p.As != AMOVD {
c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v", p)
return
}
if p.To.Type != obj.TYPE_REG {
c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v", p)
return
}
} else if p.From.Type != obj.TYPE_MEM {
c.ctxt.Diag("do not know how to handle %v without TYPE_MEM", p)
return
}
source = &p.From
} else if p.To.Name == obj.NAME_EXTERN || p.To.Name == obj.NAME_STATIC {
if p.To.Type != obj.TYPE_MEM {
c.ctxt.Diag("do not know how to handle %v without TYPE_MEM", p)
return
}
if source != nil {
c.ctxt.Diag("cannot handle symbols on both sides in %v", p)
return
}
source = &p.To
} else {
return
}
if source.Sym == nil {
c.ctxt.Diag("do not know how to handle nil symbol in %v", p)
return
}
if source.Sym.Type == objabi.STLSBSS {
return
}
// Retrieve or create the TOC anchor.
symtoc := c.ctxt.LookupInit("TOC."+source.Sym.Name, func(s *obj.LSym) {
s.Type = objabi.SDATA
s.Set(obj.AttrDuplicateOK, true)
c.ctxt.Data = append(c.ctxt.Data, s)
s.WriteAddr(c.ctxt, 0, 8, source.Sym, 0)
})
if source.Type == obj.TYPE_ADDR {
// MOVD $sym, Rx becomes MOVD symtoc, Rx
// MOVD $sym+<off>, Rx becomes MOVD symtoc, Rx; ADD <off>, Rx
p.From.Type = obj.TYPE_MEM
p.From.Sym = symtoc
p.From.Name = obj.NAME_TOCREF
if p.From.Offset != 0 {
q := obj.Appendp(p, c.newprog)
q.As = AADD
q.From.Type = obj.TYPE_CONST
q.From.Offset = p.From.Offset
p.From.Offset = 0
q.To = p.To
}
return
}
// MOVx sym, Ry becomes MOVD symtoc, REGTMP; MOVx (REGTMP), Ry
// MOVx Ry, sym becomes MOVD symtoc, REGTMP; MOVx Ry, (REGTMP)
// An addition may be inserted between the two MOVs if there is an offset.
q := obj.Appendp(p, c.newprog)
q.As = AMOVD
q.From.Type = obj.TYPE_MEM
q.From.Sym = symtoc
q.From.Name = obj.NAME_TOCREF
q.To.Type = obj.TYPE_REG
q.To.Reg = REGTMP
q = obj.Appendp(q, c.newprog)
q.As = p.As
q.From = p.From
q.To = p.To
if p.From.Name != obj.NAME_NONE {
q.From.Type = obj.TYPE_MEM
q.From.Reg = REGTMP
q.From.Name = obj.NAME_NONE
q.From.Sym = nil
} else if p.To.Name != obj.NAME_NONE {
q.To.Type = obj.TYPE_MEM
q.To.Reg = REGTMP
q.To.Name = obj.NAME_NONE
q.To.Sym = nil
} else {
c.ctxt.Diag("unreachable case in rewriteToUseTOC with %v", p)
}
obj.Nopout(p)
}
// Rewrite p, if necessary, to access global data via the global offset table.
func (c *ctxt9) rewriteToUseGot(p *obj.Prog) {
if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
......
......@@ -372,6 +372,17 @@ func Mconv(a *Addr) string {
} else {
str = fmt.Sprintf("%s(%s)", offConv(a.Offset), reg)
}
case NAME_TOCREF:
reg := "SB"
if a.Reg != REG_NONE {
reg = Rconv(int(a.Reg))
}
if a.Sym != nil {
str = fmt.Sprintf("%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg)
} else {
str = fmt.Sprintf("%s(%s)", offConv(a.Offset), reg)
}
}
return str
}
......
......@@ -314,14 +314,18 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
break
}
// On AIX, if a relocated symbol is in .data, a second relocation
// must be done by the loader, as the section .data will be moved.
// On AIX, a second relocation must be done by the loader,
// as section addresses can change once loaded.
// The "default" symbol address is still needed by the loader so
// the current relocation can't be skipped.
if ctxt.HeadType == objabi.Haix && r.Sym.Type != sym.SDYNIMPORT && r.Sym.Sect.Seg == &Segdata {
// It's not possible to make a loader relocation to a DWARF section.
// FIXME
if s.Sect.Seg != &Segdwarf {
if ctxt.HeadType == objabi.Haix && r.Sym.Type != sym.SDYNIMPORT {
// It's not possible to make a loader relocation in a
// symbol which is not inside .data section.
// FIXME: It should be forbidden to have R_ADDR from a
// symbol which isn't in .data. However, as .text has the
// same address once loaded, this is possible.
if s.Sect.Seg == &Segdata {
Xcoffadddynrel(ctxt, s, r)
}
}
......
......@@ -913,8 +913,8 @@ func (f *xcoffFile) adddynimpsym(ctxt *Link, s *sym.Symbol) {
// Xcoffadddynrel adds a dynamic relocation in a XCOFF file.
// This relocation will be made by the loader.
func Xcoffadddynrel(ctxt *Link, s *sym.Symbol, r *sym.Reloc) bool {
if s.Type <= sym.SPCLNTAB && r.Sym.Type >= sym.SELFSECT && r.Sym.Type <= sym.SXREF {
Errorf(s, "cannot have a relocation in a text section with a data symbol: %s ", r.Sym.Name)
if s.Type <= sym.SPCLNTAB {
Errorf(s, "cannot have a relocation to %s in a text section symbol", r.Sym.Name)
return false
}
......@@ -936,9 +936,22 @@ func Xcoffadddynrel(ctxt *Link, s *sym.Symbol, r *sym.Reloc) bool {
break
}
}
} else if s.Type == sym.SDATA && r.Sym.Type >= sym.SELFSECT && r.Sym.Type <= sym.SXREF {
// .data to .data relocation
} else if s.Type == sym.SDATA {
switch r.Sym.Sect.Seg {
default:
Errorf(s, "unknown segment for .loader relocation with symbol %s", r.Sym.Name)
case &Segtext:
case &Segrodata:
ldr.symndx = 0 // .text
case &Segdata:
if r.Sym.Type == sym.SBSS || r.Sym.Type == sym.SNOPTRBSS {
ldr.symndx = 2 // .bss
} else {
ldr.symndx = 1 // .data
}
}
} else {
Errorf(s, "unexpected type for .loader relocation R_ADDR for symbol %s: %s to %s", r.Sym.Name, s.Type, r.Sym.Type)
return false
......@@ -1009,6 +1022,12 @@ func (ctxt *Link) doxcoff() {
})
xfile.genDynSym(ctxt)
for _, s := range ctxt.Syms.Allsym {
if strings.HasPrefix(s.Name, "TOC.") {
s.Type = sym.SXCOFFTOC
}
}
}
// Loader section
......
......@@ -489,7 +489,40 @@ func symtoc(ctxt *ld.Link, s *sym.Symbol) int64 {
return toc.Value
}
func archreloctoc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) int64 {
var o1, o2 uint32
o1 = uint32(val >> 32)
o2 = uint32(val)
t := ld.Symaddr(r.Sym) + r.Add - ctxt.Syms.ROLookup("TOC", 0).Value // sym addr
if t != int64(int32(t)) {
ld.Errorf(s, "TOC relocation for %s is too big to relocate %s: 0x%x", s.Name, r.Sym, t)
}
if t&0x8000 != 0 {
t += 0x10000
}
o1 |= uint32((t >> 16) & 0xFFFF)
switch r.Type {
case objabi.R_ADDRPOWER_TOCREL_DS:
if t&3 != 0 {
ld.Errorf(s, "bad DS reloc for %s: %d", s.Name, ld.Symaddr(r.Sym))
}
o2 |= uint32(t) & 0xFFFC
default:
return -1
}
return int64(o1)<<32 | int64(o2)
}
func archrelocaddr(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) int64 {
if ctxt.HeadType == objabi.Haix {
ld.Errorf(s, "archrelocaddr called for %s relocation\n", r.Sym.Name)
}
var o1, o2 uint32
if ctxt.Arch.ByteOrder == binary.BigEndian {
o1 = uint32(val >> 32)
......@@ -508,7 +541,7 @@ func archrelocaddr(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) int64
t := ld.Symaddr(r.Sym) + r.Add
if t < 0 || t >= 1<<31 {
ld.Errorf(s, "relocation for %s is too big (>=2G): %d", s.Name, ld.Symaddr(r.Sym))
ld.Errorf(s, "relocation for %s is too big (>=2G): 0x%x", s.Name, ld.Symaddr(r.Sym))
}
if t&0x8000 != 0 {
t += 0x10000
......@@ -682,6 +715,8 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bo
return r.Add, true
case objabi.R_GOTOFF:
return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true
case objabi.R_ADDRPOWER_TOCREL, objabi.R_ADDRPOWER_TOCREL_DS:
return archreloctoc(ctxt, r, s, val), true
case objabi.R_ADDRPOWER, objabi.R_ADDRPOWER_DS:
return archrelocaddr(ctxt, r, s, val), true
case objabi.R_CALLPOWER:
......
......@@ -89,10 +89,10 @@ const (
SNOPTRDATA
SINITARR
SDATA
SXCOFFTOC
SBSS
SNOPTRBSS
STLSBSS
SXCOFFTOC
SXREF
SMACHOSYMSTR
SMACHOSYMTAB
......
......@@ -4,9 +4,9 @@ package sym
import "strconv"
const _SymKind_name = "SxxxSTEXTSELFRXSECTSTYPESSTRINGSGOSTRINGSGOFUNCSGCBITSSRODATASFUNCTABSELFROSECTSMACHOPLTSTYPERELROSSTRINGRELROSGOSTRINGRELROSGOFUNCRELROSGCBITSRELROSRODATARELROSFUNCTABRELROSTYPELINKSITABLINKSSYMTABSPCLNTABSELFSECTSMACHOSMACHOGOTSWINDOWSSELFGOTSNOPTRDATASINITARRSDATASBSSSNOPTRBSSSTLSBSSSXCOFFTOCSXREFSMACHOSYMSTRSMACHOSYMTABSMACHOINDIRECTPLTSMACHOINDIRECTGOTSFILEPATHSCONSTSDYNIMPORTSHOSTOBJSDWARFSECTSDWARFINFOSDWARFRANGESDWARFLOCSDWARFMISCSABIALIAS"
const _SymKind_name = "SxxxSTEXTSELFRXSECTSTYPESSTRINGSGOSTRINGSGOFUNCSGCBITSSRODATASFUNCTABSELFROSECTSMACHOPLTSTYPERELROSSTRINGRELROSGOSTRINGRELROSGOFUNCRELROSGCBITSRELROSRODATARELROSFUNCTABRELROSTYPELINKSITABLINKSSYMTABSPCLNTABSELFSECTSMACHOSMACHOGOTSWINDOWSSELFGOTSNOPTRDATASINITARRSDATASXCOFFTOCSBSSSNOPTRBSSSTLSBSSSXREFSMACHOSYMSTRSMACHOSYMTABSMACHOINDIRECTPLTSMACHOINDIRECTGOTSFILEPATHSCONSTSDYNIMPORTSHOSTOBJSDWARFSECTSDWARFINFOSDWARFRANGESDWARFLOCSDWARFMISCSABIALIAS"
var _SymKind_index = [...]uint16{0, 4, 9, 19, 24, 31, 40, 47, 54, 61, 69, 79, 88, 98, 110, 124, 136, 148, 160, 173, 182, 191, 198, 206, 214, 220, 229, 237, 244, 254, 262, 267, 271, 280, 287, 296, 301, 313, 325, 342, 359, 368, 374, 384, 392, 402, 412, 423, 432, 442, 451}
var _SymKind_index = [...]uint16{0, 4, 9, 19, 24, 31, 40, 47, 54, 61, 69, 79, 88, 98, 110, 124, 136, 148, 160, 173, 182, 191, 198, 206, 214, 220, 229, 237, 244, 254, 262, 267, 276, 280, 289, 296, 301, 313, 325, 342, 359, 368, 374, 384, 392, 402, 412, 423, 432, 442, 451}
func (i SymKind) String() string {
if i >= SymKind(len(_SymKind_index)-1) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment