// 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
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)
C_GOK
C_ADDR
C_GOTADDR
+ C_TOCADDR
C_TLS_LE
C_TLS_IE
C_TEXTSIZE
"DACON",
"SBRA",
"LBRA",
+ "LBRAPIC",
"SAUTO",
"LAUTO",
"SEXT",
"GOK",
"ADDR",
"GOTADDR",
+ "TOCADDR",
"TLS_LE",
"TLS_IE",
"TEXTSIZE",
{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},
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 {
}
}
- //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]
// 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 {
/* 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
}
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 {
} 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
}
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)
}
}
// 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
}
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
})
xfile.genDynSym(ctxt)
+
+ for _, s := range ctxt.Syms.Allsym {
+ if strings.HasPrefix(s.Name, "TOC.") {
+ s.Type = sym.SXCOFFTOC
+ }
+ }
}
// Loader section
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)
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
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:
SNOPTRDATA
SINITARR
SDATA
+ SXCOFFTOC
SBSS
SNOPTRBSS
STLSBSS
- SXCOFFTOC
SXREF
SMACHOSYMSTR
SMACHOSYMTAB
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) {