// inserts the displacement from the place being relocated to the address of the
        // the relocated symbol instead of just its address.
        R_ADDRPOWER_PCREL
+
+       // R_ADDRPOWER_TOCREL relocates two D-form instructions like R_ADDRPOWER, but
+       // inserts the offset from the TOC to the address of the the relocated symbol
+       // rather than the symbol's address.
+       R_ADDRPOWER_TOCREL
+
+       // R_ADDRPOWER_TOCREL relocates a D-form, DS-form instruction sequence like
+       // R_ADDRPOWER_DS but inserts the offset from the TOC to the address of the the
+       // relocated symbol rather than the symbol's address.
+       R_ADDRPOWER_TOCREL_DS
 )
 
 type Auto struct {
 
 // Encode instructions and create relocation for accessing s+d according to the
 // instruction op with source or destination (as appropriate) register reg.
 func symbolAccess(ctxt *obj.Link, s *obj.LSym, d int64, reg int16, op int32) (o1, o2 uint32) {
+       var base uint32
        form := opform(ctxt, op)
-       o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, 0)
+       if ctxt.Flag_shared != 0 {
+               base = REG_R2
+       } else {
+               base = REG_R0
+       }
+       o1 = AOP_IRR(OP_ADDIS, REGTMP, base, 0)
        o2 = AOP_IRR(uint32(op), uint32(reg), REGTMP, 0)
        rel := obj.Addrel(ctxt.Cursym)
        rel.Off = int32(ctxt.Pc)
        rel.Siz = 8
        rel.Sym = s
        rel.Add = d
-       switch form {
-       case D_FORM:
-               rel.Type = obj.R_ADDRPOWER
-       case DS_FORM:
-               rel.Type = obj.R_ADDRPOWER_DS
+       if ctxt.Flag_shared != 0 {
+               switch form {
+               case D_FORM:
+                       rel.Type = obj.R_ADDRPOWER_TOCREL
+               case DS_FORM:
+                       rel.Type = obj.R_ADDRPOWER_TOCREL_DS
+               }
+
+       } else {
+               switch form {
+               case D_FORM:
+                       rel.Type = obj.R_ADDRPOWER
+               case DS_FORM:
+                       rel.Type = obj.R_ADDRPOWER_DS
+               }
        }
        return
 }
 
                ld.Thearch.Vput(ld.R_PPC64_REL16_LO | uint64(elfsym)<<32)
                r.Xadd += 4
 
+       case obj.R_ADDRPOWER_TOCREL:
+               ld.Thearch.Vput(ld.R_PPC64_TOC16_HA | uint64(elfsym)<<32)
+               ld.Thearch.Vput(uint64(r.Xadd))
+               ld.Thearch.Vput(uint64(sectoff + 4))
+               ld.Thearch.Vput(ld.R_PPC64_TOC16_LO | uint64(elfsym)<<32)
+
+       case obj.R_ADDRPOWER_TOCREL_DS:
+               ld.Thearch.Vput(ld.R_PPC64_TOC16_HA | uint64(elfsym)<<32)
+               ld.Thearch.Vput(uint64(r.Xadd))
+               ld.Thearch.Vput(uint64(sectoff + 4))
+               ld.Thearch.Vput(ld.R_PPC64_TOC16_LO_DS | uint64(elfsym)<<32)
+
        case obj.R_CALLPOWER:
                if r.Siz != 4 {
                        return -1
 
                case obj.R_ADDRPOWER,
                        obj.R_ADDRPOWER_DS,
+                       obj.R_ADDRPOWER_TOCREL,
+                       obj.R_ADDRPOWER_TOCREL_DS,
                        obj.R_ADDRPOWER_PCREL:
                        r.Done = 0