From e6ceb92e1ce8cd722922abeef7f350273692ccc9 Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Sun, 5 Jul 2015 21:49:11 +1200 Subject: [PATCH] cmd/internal/obj/arm: access global data via GOT on arm when -dynlink Change-Id: I88034611f56cc06bb47b0c431075cc78ca8dbb09 Reviewed-on: https://go-review.googlesource.com/14188 Reviewed-by: Ian Lance Taylor --- src/cmd/internal/obj/arm/asm5.go | 11 ++- src/cmd/internal/obj/arm/obj5.go | 117 +++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 2 deletions(-) diff --git a/src/cmd/internal/obj/arm/asm5.go b/src/cmd/internal/obj/arm/asm5.go index 3bf4a31729..87ebc842ef 100644 --- a/src/cmd/internal/obj/arm/asm5.go +++ b/src/cmd/internal/obj/arm/asm5.go @@ -981,6 +981,7 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int { return C_NONE case obj.TYPE_REG: + ctxt.Instoffset = 0 if REG_R0 <= a.Reg && a.Reg <= REG_R15 { return C_REG } @@ -1010,6 +1011,7 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int { case obj.TYPE_MEM: switch a.Name { case obj.NAME_EXTERN, + obj.NAME_GOTREF, obj.NAME_STATIC: if a.Sym == nil || a.Sym.Name == "" { fmt.Printf("null sym external\n") @@ -1130,6 +1132,7 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int { return C_LCON case obj.NAME_EXTERN, + obj.NAME_GOTREF, obj.NAME_STATIC: s := a.Sym if s == nil { @@ -1589,7 +1592,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) { aclass(ctxt, &p.To) if ctxt.Instoffset != 0 { - ctxt.Diag("%v: doesn't support BL offset(REG) where offset != 0", p) + ctxt.Diag("%v: doesn't support BL offset(REG) with non-zero offset %d", p, ctxt.Instoffset) } o1 = oprrr(ctxt, ABL, int(p.Scond)) o1 |= (uint32(p.To.Reg) & 15) << 0 @@ -1644,7 +1647,11 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) { rel.Add = p.To.Offset if ctxt.Flag_shared != 0 { - rel.Type = obj.R_PCREL + if p.To.Name == obj.NAME_GOTREF { + rel.Type = obj.R_GOTPCREL + } else { + rel.Type = obj.R_PCREL + } rel.Add += ctxt.Pc - p.Rel.Pc - 8 } else { rel.Type = obj.R_ADDR diff --git a/src/cmd/internal/obj/arm/obj5.go b/src/cmd/internal/obj/arm/obj5.go index 00ab13ccc3..ae045049ee 100644 --- a/src/cmd/internal/obj/arm/obj5.go +++ b/src/cmd/internal/obj/arm/obj5.go @@ -129,6 +129,123 @@ func progedit(ctxt *obj.Link, p *obj.Prog) { p.From.Offset = 0 } } + + if ctxt.Flag_dynlink { + rewriteToUseGot(ctxt, p) + } +} + +// Rewrite p, if necessary, to access global data via the global offset table. +func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) { + if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO { + // ADUFFxxx $offset + // becomes + // MOVW runtime.duffxxx@GOT, R9 + // ADD $offset, R9 + // CALL (R9) + var sym *obj.LSym + if p.As == obj.ADUFFZERO { + sym = obj.Linklookup(ctxt, "runtime.duffzero", 0) + } else { + sym = obj.Linklookup(ctxt, "runtime.duffcopy", 0) + } + offset := p.To.Offset + p.As = AMOVW + p.From.Type = obj.TYPE_MEM + p.From.Name = obj.NAME_GOTREF + p.From.Sym = sym + p.To.Type = obj.TYPE_REG + p.To.Reg = REG_R9 + p.To.Name = obj.NAME_NONE + p.To.Offset = 0 + p.To.Sym = nil + p1 := obj.Appendp(ctxt, p) + p1.As = AADD + p1.From.Type = obj.TYPE_CONST + p1.From.Offset = offset + p1.To.Type = obj.TYPE_REG + p1.To.Reg = REG_R9 + p2 := obj.Appendp(ctxt, p1) + p2.As = obj.ACALL + p2.To.Type = obj.TYPE_MEM + p2.To.Reg = REG_R9 + return + } + + // We only care about global data: NAME_EXTERN means a global + // symbol in the Go sense, and p.Sym.Local is true for a few + // internally defined symbols. + if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local { + // MOVW $sym, Rx becomes MOVW sym@GOT, Rx + // MOVW $sym+, Rx becomes MOVW sym@GOT, Rx; ADD , Rx + if p.As != AMOVW { + ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p) + } + if p.To.Type != obj.TYPE_REG { + ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p) + } + p.From.Type = obj.TYPE_MEM + p.From.Name = obj.NAME_GOTREF + if p.From.Offset != 0 { + q := obj.Appendp(ctxt, p) + q.As = AADD + q.From.Type = obj.TYPE_CONST + q.From.Offset = p.From.Offset + q.To = p.To + p.From.Offset = 0 + } + } + if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN { + ctxt.Diag("don't know how to handle %v with -dynlink", p) + } + var source *obj.Addr + // MOVx sym, Ry becomes MOVW sym@GOT, R9; MOVx (R9), Ry + // MOVx Ry, sym becomes MOVW sym@GOT, R9; MOVx Ry, (R9) + // An addition may be inserted between the two MOVs if there is an offset. + if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local { + if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local { + ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p) + } + source = &p.From + } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local { + source = &p.To + } else { + return + } + if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP { + return + } + if source.Sym.Type == obj.STLSBSS { + return + } + if source.Type != obj.TYPE_MEM { + ctxt.Diag("don't know how to handle %v with -dynlink", p) + } + p1 := obj.Appendp(ctxt, p) + p2 := obj.Appendp(ctxt, p1) + + p1.As = AMOVW + p1.From.Type = obj.TYPE_MEM + p1.From.Sym = source.Sym + p1.From.Name = obj.NAME_GOTREF + p1.To.Type = obj.TYPE_REG + p1.To.Reg = REG_R9 + + p2.As = p.As + p2.From = p.From + p2.To = p.To + if p.From.Name == obj.NAME_EXTERN { + p2.From.Reg = REG_R9 + p2.From.Name = obj.NAME_NONE + p2.From.Sym = nil + } else if p.To.Name == obj.NAME_EXTERN { + p2.To.Reg = REG_R9 + p2.To.Name = obj.NAME_NONE + p2.To.Sym = nil + } else { + return + } + obj.Nopout(p) } // Prog.mark -- 2.48.1