mirror of https://github.com/golang/go.git
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: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
b41cdc4a59
commit
4295ed9bef
|
|
@ -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
|
||||
ldr.symndx = 1 // .data
|
||||
} 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) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue