mirror of
https://github.com/golang/go
synced 2024-11-24 10:00:12 -07: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
@ -4575,6 +4575,11 @@ func asmins(ctxt *obj.Link, p *obj.Prog) {
|
||||
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 {
|
||||
|
@ -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.
|
||||
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 {
|
||||
// ADUFFxxx $offset
|
||||
// becomes
|
||||
// MOVQ runtime.duffxxx@GOT, R15
|
||||
// ADDQ $offset, R15
|
||||
// CALL R15
|
||||
// $MOV runtime.duffxxx@GOT, $reg
|
||||
// $ADD $offset, $reg
|
||||
// CALL $reg
|
||||
var sym *obj.LSym
|
||||
if p.As == obj.ADUFFZERO {
|
||||
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)
|
||||
}
|
||||
offset := p.To.Offset
|
||||
p.As = AMOVQ
|
||||
p.As = mov
|
||||
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_R15
|
||||
p.To.Reg = reg
|
||||
p.To.Offset = 0
|
||||
p.To.Sym = nil
|
||||
p1 := obj.Appendp(ctxt, p)
|
||||
p1.As = AADDQ
|
||||
p1.As = add
|
||||
p1.From.Type = obj.TYPE_CONST
|
||||
p1.From.Offset = offset
|
||||
p1.To.Type = obj.TYPE_REG
|
||||
p1.To.Reg = REG_R15
|
||||
p1.To.Reg = reg
|
||||
p2 := obj.Appendp(ctxt, p1)
|
||||
p2.As = obj.ACALL
|
||||
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
|
||||
// symbol in the Go sense, and p.Sym.Local is true for a few
|
||||
// internally defined symbols.
|
||||
if p.As == ALEAQ && 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
|
||||
p.As = AMOVQ
|
||||
if p.As == lea && p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
|
||||
// $LEA sym, Rx becomes $MOV $sym, Rx which will be rewritten below
|
||||
p.As = mov
|
||||
p.From.Type = obj.TYPE_ADDR
|
||||
}
|
||||
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
|
||||
// MOVQ $sym+<off>, Rx becomes MOVQ sym@GOT, Rx; ADDQ <off>, Rx
|
||||
if p.As != AMOVQ {
|
||||
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)
|
||||
// $MOV $sym, Rx becomes $MOV sym@GOT, Rx
|
||||
// $MOV $sym+<off>, Rx becomes $MOV sym@GOT, Rx; $ADD <off>, Rx
|
||||
// On 386 only, more complicated things like PUSHL $sym become $MOV sym@GOT, CX; PUSHL CX
|
||||
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)
|
||||
}
|
||||
cmplxdest = true
|
||||
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.Name = obj.NAME_GOTREF
|
||||
q := p
|
||||
if p.From.Offset != 0 {
|
||||
q := obj.Appendp(ctxt, p)
|
||||
q.As = AADDQ
|
||||
q = obj.Appendp(ctxt, p)
|
||||
q.As = add
|
||||
q.From.Type = obj.TYPE_CONST
|
||||
q.From.Offset = p.From.Offset
|
||||
q.To = p.To
|
||||
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 {
|
||||
ctxt.Diag("don't know how to handle %v with -dynlink", p)
|
||||
}
|
||||
var source *obj.Addr
|
||||
// MOVx sym, Ry becomes MOVW sym@GOT, R15; MOVx (R15), Ry
|
||||
// MOVx Ry, sym becomes MOVW sym@GOT, R15; MOVx Ry, (R15)
|
||||
// MOVx sym, Ry becomes $MOV sym@GOT, R15; MOVx (R15), Ry
|
||||
// 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.
|
||||
if p.From.Name == obj.NAME_EXTERN && !p.From.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 {
|
||||
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
|
||||
}
|
||||
if source.Type != obj.TYPE_MEM {
|
||||
@ -406,22 +471,22 @@ func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog) {
|
||||
p1 := obj.Appendp(ctxt, p)
|
||||
p2 := obj.Appendp(ctxt, p1)
|
||||
|
||||
p1.As = AMOVQ
|
||||
p1.As = mov
|
||||
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_R15
|
||||
p1.To.Reg = reg
|
||||
|
||||
p2.As = p.As
|
||||
p2.From = p.From
|
||||
p2.To = p.To
|
||||
if p.From.Name == obj.NAME_EXTERN {
|
||||
p2.From.Reg = REG_R15
|
||||
p2.From.Reg = reg
|
||||
p2.From.Name = obj.NAME_NONE
|
||||
p2.From.Sym = nil
|
||||
} 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.Sym = nil
|
||||
} else {
|
||||
|
@ -267,8 +267,29 @@ func elfreloc1(r *ld.Reloc, sectoff int64) int {
|
||||
return -1
|
||||
}
|
||||
|
||||
case obj.R_CALL,
|
||||
obj.R_PCREL:
|
||||
case obj.R_GOTPCREL:
|
||||
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 {
|
||||
ld.Thearch.Lput(ld.R_386_PC32 | uint32(elfsym)<<8)
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user