mirror of
https://github.com/golang/go.git
synced 2025-11-01 17:20:56 +00:00
cmd/internal/obj/x86, cmd/link: enable access to global data via GOT when -dynlink on 386
Change-Id: I97504a11291ee60e656efb7704e37387e864d74f Reviewed-on: https://go-review.googlesource.com/16385 Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
cb0393866a
commit
342f17eaf7
3 changed files with 120 additions and 29 deletions
|
|
@ -4575,6 +4575,11 @@ func asmins(ctxt *obj.Link, p *obj.Prog) {
|
||||||
r.Add += int64(r.Off) - p.Pc + int64(r.Siz)
|
r.Add += int64(r.Off) - p.Pc + int64(r.Siz)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if r.Type == obj.R_GOTPCREL && p.Mode == 32 {
|
||||||
|
// On 386, R_GOTPCREL makes the same assumptions as R_PCREL.
|
||||||
|
r.Add += int64(r.Off) - p.Pc + int64(r.Siz)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.Mode == 64 && ctxt.Headtype == obj.Hnacl && p.As != ACMPL && p.As != ACMPQ && p.To.Type == obj.TYPE_REG {
|
if p.Mode == 64 && ctxt.Headtype == obj.Hnacl && p.As != ACMPL && p.As != ACMPQ && p.To.Type == obj.TYPE_REG {
|
||||||
|
|
|
||||||
|
|
@ -319,12 +319,25 @@ func progedit(ctxt *obj.Link, p *obj.Prog) {
|
||||||
|
|
||||||
// Rewrite p, if necessary, to access global data via the global offset table.
|
// Rewrite p, if necessary, to access global data via the global offset table.
|
||||||
func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
|
func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
|
||||||
|
var add, lea, mov, reg int16
|
||||||
|
if p.Mode == 64 {
|
||||||
|
add = AADDQ
|
||||||
|
lea = ALEAQ
|
||||||
|
mov = AMOVQ
|
||||||
|
reg = REG_R15
|
||||||
|
} else {
|
||||||
|
add = AADDL
|
||||||
|
lea = ALEAL
|
||||||
|
mov = AMOVL
|
||||||
|
reg = REG_CX
|
||||||
|
}
|
||||||
|
|
||||||
if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
|
if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
|
||||||
// ADUFFxxx $offset
|
// ADUFFxxx $offset
|
||||||
// becomes
|
// becomes
|
||||||
// MOVQ runtime.duffxxx@GOT, R15
|
// $MOV runtime.duffxxx@GOT, $reg
|
||||||
// ADDQ $offset, R15
|
// $ADD $offset, $reg
|
||||||
// CALL R15
|
// CALL $reg
|
||||||
var sym *obj.LSym
|
var sym *obj.LSym
|
||||||
if p.As == obj.ADUFFZERO {
|
if p.As == obj.ADUFFZERO {
|
||||||
sym = obj.Linklookup(ctxt, "runtime.duffzero", 0)
|
sym = obj.Linklookup(ctxt, "runtime.duffzero", 0)
|
||||||
|
|
@ -332,60 +345,78 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
|
||||||
sym = obj.Linklookup(ctxt, "runtime.duffcopy", 0)
|
sym = obj.Linklookup(ctxt, "runtime.duffcopy", 0)
|
||||||
}
|
}
|
||||||
offset := p.To.Offset
|
offset := p.To.Offset
|
||||||
p.As = AMOVQ
|
p.As = mov
|
||||||
p.From.Type = obj.TYPE_MEM
|
p.From.Type = obj.TYPE_MEM
|
||||||
p.From.Name = obj.NAME_GOTREF
|
p.From.Name = obj.NAME_GOTREF
|
||||||
p.From.Sym = sym
|
p.From.Sym = sym
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
p.To.Reg = REG_R15
|
p.To.Reg = reg
|
||||||
p.To.Offset = 0
|
p.To.Offset = 0
|
||||||
p.To.Sym = nil
|
p.To.Sym = nil
|
||||||
p1 := obj.Appendp(ctxt, p)
|
p1 := obj.Appendp(ctxt, p)
|
||||||
p1.As = AADDQ
|
p1.As = add
|
||||||
p1.From.Type = obj.TYPE_CONST
|
p1.From.Type = obj.TYPE_CONST
|
||||||
p1.From.Offset = offset
|
p1.From.Offset = offset
|
||||||
p1.To.Type = obj.TYPE_REG
|
p1.To.Type = obj.TYPE_REG
|
||||||
p1.To.Reg = REG_R15
|
p1.To.Reg = reg
|
||||||
p2 := obj.Appendp(ctxt, p1)
|
p2 := obj.Appendp(ctxt, p1)
|
||||||
p2.As = obj.ACALL
|
p2.As = obj.ACALL
|
||||||
p2.To.Type = obj.TYPE_REG
|
p2.To.Type = obj.TYPE_REG
|
||||||
p2.To.Reg = REG_R15
|
p2.To.Reg = reg
|
||||||
}
|
}
|
||||||
|
|
||||||
// We only care about global data: NAME_EXTERN means a global
|
// 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
|
// symbol in the Go sense, and p.Sym.Local is true for a few
|
||||||
// internally defined symbols.
|
// internally defined symbols.
|
||||||
if p.As == ALEAQ && p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
|
if p.As == lea && p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
|
||||||
// LEAQ sym, Rx becomes MOVQ $sym, Rx which will be rewritten below
|
// $LEA sym, Rx becomes $MOV $sym, Rx which will be rewritten below
|
||||||
p.As = AMOVQ
|
p.As = mov
|
||||||
p.From.Type = obj.TYPE_ADDR
|
p.From.Type = obj.TYPE_ADDR
|
||||||
}
|
}
|
||||||
if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
|
if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
|
||||||
// MOVQ $sym, Rx becomes MOVQ sym@GOT, Rx
|
// $MOV $sym, Rx becomes $MOV sym@GOT, Rx
|
||||||
// MOVQ $sym+<off>, Rx becomes MOVQ sym@GOT, Rx; ADDQ <off>, Rx
|
// $MOV $sym+<off>, Rx becomes $MOV sym@GOT, Rx; $ADD <off>, Rx
|
||||||
if p.As != AMOVQ {
|
// On 386 only, more complicated things like PUSHL $sym become $MOV sym@GOT, CX; PUSHL CX
|
||||||
ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
|
cmplxdest := false
|
||||||
|
pAs := p.As
|
||||||
|
var dest obj.Addr
|
||||||
|
if p.To.Type != obj.TYPE_REG || pAs != mov {
|
||||||
|
if p.Mode == 64 {
|
||||||
|
ctxt.Diag("do not know how to handle LEA-type insn to non-register in %v with -dynlink", p)
|
||||||
}
|
}
|
||||||
if p.To.Type != obj.TYPE_REG {
|
cmplxdest = true
|
||||||
ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
|
dest = p.To
|
||||||
|
p.As = mov
|
||||||
|
p.To.Type = obj.TYPE_REG
|
||||||
|
p.To.Reg = REG_CX
|
||||||
|
p.To.Sym = nil
|
||||||
|
p.To.Name = obj.NAME_NONE
|
||||||
}
|
}
|
||||||
p.From.Type = obj.TYPE_MEM
|
p.From.Type = obj.TYPE_MEM
|
||||||
p.From.Name = obj.NAME_GOTREF
|
p.From.Name = obj.NAME_GOTREF
|
||||||
|
q := p
|
||||||
if p.From.Offset != 0 {
|
if p.From.Offset != 0 {
|
||||||
q := obj.Appendp(ctxt, p)
|
q = obj.Appendp(ctxt, p)
|
||||||
q.As = AADDQ
|
q.As = add
|
||||||
q.From.Type = obj.TYPE_CONST
|
q.From.Type = obj.TYPE_CONST
|
||||||
q.From.Offset = p.From.Offset
|
q.From.Offset = p.From.Offset
|
||||||
q.To = p.To
|
q.To = p.To
|
||||||
p.From.Offset = 0
|
p.From.Offset = 0
|
||||||
}
|
}
|
||||||
|
if cmplxdest {
|
||||||
|
q = obj.Appendp(ctxt, q)
|
||||||
|
q.As = pAs
|
||||||
|
q.To = dest
|
||||||
|
q.From.Type = obj.TYPE_REG
|
||||||
|
q.From.Reg = REG_CX
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN {
|
if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN {
|
||||||
ctxt.Diag("don't know how to handle %v with -dynlink", p)
|
ctxt.Diag("don't know how to handle %v with -dynlink", p)
|
||||||
}
|
}
|
||||||
var source *obj.Addr
|
var source *obj.Addr
|
||||||
// MOVx sym, Ry becomes MOVW sym@GOT, R15; MOVx (R15), Ry
|
// MOVx sym, Ry becomes $MOV sym@GOT, R15; MOVx (R15), Ry
|
||||||
// MOVx Ry, sym becomes MOVW sym@GOT, R15; MOVx Ry, (R15)
|
// MOVx Ry, sym becomes $MOV sym@GOT, R15; MOVx Ry, (R15)
|
||||||
// An addition may be inserted between the two MOVs if there is an offset.
|
// 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.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
|
||||||
if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local {
|
if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local {
|
||||||
|
|
@ -397,7 +428,41 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
|
||||||
} else {
|
} else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
|
if p.As == obj.ACALL {
|
||||||
|
// When dynlinking on 386, almost any call might end up being a call
|
||||||
|
// to a PLT, so make sure the GOT pointer is loaded into BX.
|
||||||
|
// RegTo2 is set on the replacement call insn to stop it being
|
||||||
|
// processed when it is in turn passed to progedit.
|
||||||
|
if p.Mode == 64 || (p.To.Sym != nil && p.To.Sym.Local) || p.RegTo2 != 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p1 := obj.Appendp(ctxt, p)
|
||||||
|
p2 := obj.Appendp(ctxt, p1)
|
||||||
|
|
||||||
|
p1.As = ALEAL
|
||||||
|
p1.From.Type = obj.TYPE_MEM
|
||||||
|
p1.From.Name = obj.NAME_STATIC
|
||||||
|
p1.From.Sym = obj.Linklookup(ctxt, "_GLOBAL_OFFSET_TABLE_", 0)
|
||||||
|
p1.To.Type = obj.TYPE_REG
|
||||||
|
p1.To.Reg = REG_BX
|
||||||
|
|
||||||
|
p2.As = p.As
|
||||||
|
p2.Scond = p.Scond
|
||||||
|
p2.From = p.From
|
||||||
|
p2.From3 = p.From3
|
||||||
|
p2.Reg = p.Reg
|
||||||
|
p2.To = p.To
|
||||||
|
// p.To.Type was set to TYPE_BRANCH above, but that makes checkaddr
|
||||||
|
// in ../pass.go complain, so set it back to TYPE_MEM here, until p2
|
||||||
|
// itself gets passed to progedit.
|
||||||
|
p2.To.Type = obj.TYPE_MEM
|
||||||
|
p2.RegTo2 = 1
|
||||||
|
|
||||||
|
obj.Nopout(p)
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ARET || p.As == obj.AJMP {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if source.Type != obj.TYPE_MEM {
|
if source.Type != obj.TYPE_MEM {
|
||||||
|
|
@ -406,22 +471,22 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
|
||||||
p1 := obj.Appendp(ctxt, p)
|
p1 := obj.Appendp(ctxt, p)
|
||||||
p2 := obj.Appendp(ctxt, p1)
|
p2 := obj.Appendp(ctxt, p1)
|
||||||
|
|
||||||
p1.As = AMOVQ
|
p1.As = mov
|
||||||
p1.From.Type = obj.TYPE_MEM
|
p1.From.Type = obj.TYPE_MEM
|
||||||
p1.From.Sym = source.Sym
|
p1.From.Sym = source.Sym
|
||||||
p1.From.Name = obj.NAME_GOTREF
|
p1.From.Name = obj.NAME_GOTREF
|
||||||
p1.To.Type = obj.TYPE_REG
|
p1.To.Type = obj.TYPE_REG
|
||||||
p1.To.Reg = REG_R15
|
p1.To.Reg = reg
|
||||||
|
|
||||||
p2.As = p.As
|
p2.As = p.As
|
||||||
p2.From = p.From
|
p2.From = p.From
|
||||||
p2.To = p.To
|
p2.To = p.To
|
||||||
if p.From.Name == obj.NAME_EXTERN {
|
if p.From.Name == obj.NAME_EXTERN {
|
||||||
p2.From.Reg = REG_R15
|
p2.From.Reg = reg
|
||||||
p2.From.Name = obj.NAME_NONE
|
p2.From.Name = obj.NAME_NONE
|
||||||
p2.From.Sym = nil
|
p2.From.Sym = nil
|
||||||
} else if p.To.Name == obj.NAME_EXTERN {
|
} else if p.To.Name == obj.NAME_EXTERN {
|
||||||
p2.To.Reg = REG_R15
|
p2.To.Reg = reg
|
||||||
p2.To.Name = obj.NAME_NONE
|
p2.To.Name = obj.NAME_NONE
|
||||||
p2.To.Sym = nil
|
p2.To.Sym = nil
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -267,8 +267,29 @@ func elfreloc1(r *ld.Reloc, sectoff int64) int {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
case obj.R_CALL,
|
case obj.R_GOTPCREL:
|
||||||
obj.R_PCREL:
|
if r.Siz == 4 {
|
||||||
|
ld.Thearch.Lput(ld.R_386_GOTPC)
|
||||||
|
if r.Xsym.Name != "_GLOBAL_OFFSET_TABLE_" {
|
||||||
|
ld.Thearch.Lput(uint32(sectoff))
|
||||||
|
ld.Thearch.Lput(ld.R_386_GOT32 | uint32(elfsym)<<8)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
case obj.R_CALL:
|
||||||
|
if r.Siz == 4 {
|
||||||
|
if r.Xsym.Type == obj.SDYNIMPORT {
|
||||||
|
ld.Thearch.Lput(ld.R_386_PLT32 | uint32(elfsym)<<8)
|
||||||
|
} else {
|
||||||
|
ld.Thearch.Lput(ld.R_386_PC32 | uint32(elfsym)<<8)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
case obj.R_PCREL:
|
||||||
if r.Siz == 4 {
|
if r.Siz == 4 {
|
||||||
ld.Thearch.Lput(ld.R_386_PC32 | uint32(elfsym)<<8)
|
ld.Thearch.Lput(ld.R_386_PC32 | uint32(elfsym)<<8)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue