mirror of
https://github.com/golang/go
synced 2024-11-23 14:50:07 -07:00
cmd/compile: prevent 387+float32+pie from clobbering registers
The 387 port needs to load a floating-point control word from a global location to implement float32 arithmetic. When compiling with -pie, loading that control word clobbers an integer register. If that register had something important in it, boom. Fix by using LEAL to materialize the address of the global location first. LEAL with -pie works because the destination register is used as the scratch register. 387 support is about to go away (#40255), so this will need to be backported to have any effect. No test. I have one, but it requires building with -pie, which requires cgo. Our testing infrastructure doesn't make that easy. Not worth it for a port which is about to vanish. Fixes #41503 Change-Id: I140f9fc8fdce4e74a52c2c046e2bd30ae476d295 Reviewed-on: https://go-review.googlesource.com/c/go/+/257277 Run-TryBot: Keith Randall <khr@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com> Reviewed-by: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Trust: Keith Randall <khr@golang.org>
This commit is contained in:
parent
f765dcbd5c
commit
ea106cc07a
@ -139,12 +139,18 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) {
|
|||||||
// Set precision if needed. 64 bits is the default.
|
// Set precision if needed. 64 bits is the default.
|
||||||
switch v.Op {
|
switch v.Op {
|
||||||
case ssa.Op386ADDSS, ssa.Op386SUBSS, ssa.Op386MULSS, ssa.Op386DIVSS:
|
case ssa.Op386ADDSS, ssa.Op386SUBSS, ssa.Op386MULSS, ssa.Op386DIVSS:
|
||||||
p := s.Prog(x86.AFSTCW)
|
// Save AX so we can use it as scratch space.
|
||||||
|
p := s.Prog(x86.AMOVL)
|
||||||
|
p.From.Type = obj.TYPE_REG
|
||||||
|
p.From.Reg = x86.REG_AX
|
||||||
s.AddrScratch(&p.To)
|
s.AddrScratch(&p.To)
|
||||||
p = s.Prog(x86.AFLDCW)
|
// Install a 32-bit version of the control word.
|
||||||
p.From.Type = obj.TYPE_MEM
|
installControlWord(s, gc.ControlWord32, x86.REG_AX)
|
||||||
p.From.Name = obj.NAME_EXTERN
|
// Restore AX.
|
||||||
p.From.Sym = gc.ControlWord32
|
p = s.Prog(x86.AMOVL)
|
||||||
|
s.AddrScratch(&p.From)
|
||||||
|
p.To.Type = obj.TYPE_REG
|
||||||
|
p.To.Reg = x86.REG_AX
|
||||||
}
|
}
|
||||||
|
|
||||||
var op obj.As
|
var op obj.As
|
||||||
@ -167,8 +173,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) {
|
|||||||
// Restore precision if needed.
|
// Restore precision if needed.
|
||||||
switch v.Op {
|
switch v.Op {
|
||||||
case ssa.Op386ADDSS, ssa.Op386SUBSS, ssa.Op386MULSS, ssa.Op386DIVSS:
|
case ssa.Op386ADDSS, ssa.Op386SUBSS, ssa.Op386MULSS, ssa.Op386DIVSS:
|
||||||
p := s.Prog(x86.AFLDCW)
|
restoreControlWord(s)
|
||||||
s.AddrScratch(&p.From)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case ssa.Op386UCOMISS, ssa.Op386UCOMISD:
|
case ssa.Op386UCOMISS, ssa.Op386UCOMISD:
|
||||||
@ -225,19 +230,11 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) {
|
|||||||
case ssa.Op386CVTTSD2SL, ssa.Op386CVTTSS2SL:
|
case ssa.Op386CVTTSD2SL, ssa.Op386CVTTSS2SL:
|
||||||
push(s, v.Args[0])
|
push(s, v.Args[0])
|
||||||
|
|
||||||
// Save control word.
|
|
||||||
p := s.Prog(x86.AFSTCW)
|
|
||||||
s.AddrScratch(&p.To)
|
|
||||||
p.To.Offset += 4
|
|
||||||
|
|
||||||
// Load control word which truncates (rounds towards zero).
|
// Load control word which truncates (rounds towards zero).
|
||||||
p = s.Prog(x86.AFLDCW)
|
installControlWord(s, gc.ControlWord64trunc, v.Reg())
|
||||||
p.From.Type = obj.TYPE_MEM
|
|
||||||
p.From.Name = obj.NAME_EXTERN
|
|
||||||
p.From.Sym = gc.ControlWord64trunc
|
|
||||||
|
|
||||||
// Now do the conversion.
|
// Now do the conversion.
|
||||||
p = s.Prog(x86.AFMOVLP)
|
p := s.Prog(x86.AFMOVLP)
|
||||||
p.From.Type = obj.TYPE_REG
|
p.From.Type = obj.TYPE_REG
|
||||||
p.From.Reg = x86.REG_F0
|
p.From.Reg = x86.REG_F0
|
||||||
s.AddrScratch(&p.To)
|
s.AddrScratch(&p.To)
|
||||||
@ -247,9 +244,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) {
|
|||||||
p.To.Reg = v.Reg()
|
p.To.Reg = v.Reg()
|
||||||
|
|
||||||
// Restore control word.
|
// Restore control word.
|
||||||
p = s.Prog(x86.AFLDCW)
|
restoreControlWord(s)
|
||||||
s.AddrScratch(&p.From)
|
|
||||||
p.From.Offset += 4
|
|
||||||
|
|
||||||
case ssa.Op386CVTSS2SD:
|
case ssa.Op386CVTSS2SD:
|
||||||
// float32 -> float64 is a nop
|
// float32 -> float64 is a nop
|
||||||
@ -373,3 +368,36 @@ func ssaGenBlock387(s *gc.SSAGenState, b, next *ssa.Block) {
|
|||||||
|
|
||||||
ssaGenBlock(s, b, next)
|
ssaGenBlock(s, b, next)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// installControlWord saves the current floating-point control
|
||||||
|
// word and installs a new one loaded from cw.
|
||||||
|
// scratchReg must be an unused register.
|
||||||
|
// This call must be paired with restoreControlWord.
|
||||||
|
// Bytes 4-5 of the scratch space (s.AddrScratch) are used between
|
||||||
|
// this call and restoreControlWord.
|
||||||
|
func installControlWord(s *gc.SSAGenState, cw *obj.LSym, scratchReg int16) {
|
||||||
|
// Save current control word.
|
||||||
|
p := s.Prog(x86.AFSTCW)
|
||||||
|
s.AddrScratch(&p.To)
|
||||||
|
p.To.Offset += 4
|
||||||
|
|
||||||
|
// Materialize address of new control word.
|
||||||
|
// Note: this must be a seperate instruction to handle PIE correctly.
|
||||||
|
// See issue 41503.
|
||||||
|
p = s.Prog(x86.ALEAL)
|
||||||
|
p.From.Type = obj.TYPE_MEM
|
||||||
|
p.From.Name = obj.NAME_EXTERN
|
||||||
|
p.From.Sym = cw
|
||||||
|
p.To.Type = obj.TYPE_REG
|
||||||
|
p.To.Reg = scratchReg
|
||||||
|
|
||||||
|
// Load replacement control word.
|
||||||
|
p = s.Prog(x86.AFLDCW)
|
||||||
|
p.From.Type = obj.TYPE_MEM
|
||||||
|
p.From.Reg = scratchReg
|
||||||
|
}
|
||||||
|
func restoreControlWord(s *gc.SSAGenState) {
|
||||||
|
p := s.Prog(x86.AFLDCW)
|
||||||
|
s.AddrScratch(&p.From)
|
||||||
|
p.From.Offset += 4
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user