]> Cypherpunks repositories - gostls13.git/commitdiff
cmd: fix symbols addressing for aix/ppc64
authorClément Chigot <clement.chigot@atos.net>
Fri, 23 Nov 2018 13:20:19 +0000 (14:20 +0100)
committerIan Lance Taylor <iant@golang.org>
Tue, 27 Nov 2018 21:06:16 +0000 (21:06 +0000)
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>
12 files changed:
src/cmd/internal/obj/link.go
src/cmd/internal/obj/objfile.go
src/cmd/internal/obj/ppc64/a.out.go
src/cmd/internal/obj/ppc64/anames9.go
src/cmd/internal/obj/ppc64/asm9.go
src/cmd/internal/obj/ppc64/obj9.go
src/cmd/internal/obj/util.go
src/cmd/link/internal/ld/data.go
src/cmd/link/internal/ld/xcoff.go
src/cmd/link/internal/ppc64/asm.go
src/cmd/link/internal/sym/symkind.go
src/cmd/link/internal/sym/symkind_string.go

index 2989831a0a63bddc833faeaeda5881138659989e..6cff335ddfab25964c16aecc12c13f4c0678dc9d 100644 (file)
@@ -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
index 94334d8361b5ed42f163a869f02b2ebcd3d4d96c..4fbaafe3474fc61cca458aafb64f6ab9bf82c305 100644 (file)
@@ -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)
index 3c374579ec6a946ba0cb444bc2472b1c38475fc1..0fd9c81039140a7ea7f5ca728ed24016e7ffb6c3 100644 (file)
@@ -391,6 +391,7 @@ const (
        C_GOK
        C_ADDR
        C_GOTADDR
+       C_TOCADDR
        C_TLS_LE
        C_TLS_IE
        C_TEXTSIZE
index 6ec7b7b5183265887497d598893f8ae3f9da3e3b..4699a15d3bec9963077365265cf1212daddfc24a 100644 (file)
@@ -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",
index a36565c9fd463b7b7cf455c0804f6776e32e1325..51a9a18601347efa3c20ffeb9f3641deeef6bde9 100644 (file)
@@ -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
index 7a07b5058c3c11bb570be1aa4c0043d82ba2b8fe..a9928742deaa6f348fdd9b04d94f3058f24e0240 100644 (file)
@@ -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 {
index da938c998a2dd263685cc7d56d6d7dfc667a4b8c..46c3d7b17bbd1a635cdb2f699caf1b989a1d4eb7 100644 (file)
@@ -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
 }
index 39746f5a4f0ec4ad132fc2f0b58dce75f407701a..ffa20bb637574509a40cd21eb1d1a89dd7e71584 100644 (file)
@@ -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)
                                }
                        }
index e77e2d8b80876724ef2f9b6a092f10ab3396db9e..a82bbb65dfa4723bc2541d9a082de7d83afafb4b 100644 (file)
@@ -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
index 4a974a546b2872d1b3c710c61c2c82396f9adc80..4f5d8b55398bc6653d4f34efc4d34ea29537e237 100644 (file)
@@ -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:
index 6e1e1b58a1f71d82157121a7a2309f542d322097..82e4b9eda48c443a9894bf7bef527bda734f9c26 100644 (file)
@@ -89,10 +89,10 @@ const (
        SNOPTRDATA
        SINITARR
        SDATA
+       SXCOFFTOC
        SBSS
        SNOPTRBSS
        STLSBSS
-       SXCOFFTOC
        SXREF
        SMACHOSYMSTR
        SMACHOSYMTAB
index 4da6c656f7bab951348b91f91434fb279f0c5146..9c8e1569f6bd1fff5837aa2cb5adc079ce519ebd 100644 (file)
@@ -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) {