Skip to content

Commit ea106cc

Browse files
committed
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 <[email protected]> Reviewed-by: Cherry Zhang <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]> TryBot-Result: Go Bot <[email protected]> Trust: Keith Randall <[email protected]>
1 parent f765dcb commit ea106cc

File tree

1 file changed

+48
-20
lines changed
  • src/cmd/compile/internal/x86

1 file changed

+48
-20
lines changed

src/cmd/compile/internal/x86/387.go

+48-20
Original file line numberDiff line numberDiff line change
@@ -139,12 +139,18 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) {
139139
// Set precision if needed. 64 bits is the default.
140140
switch v.Op {
141141
case ssa.Op386ADDSS, ssa.Op386SUBSS, ssa.Op386MULSS, ssa.Op386DIVSS:
142-
p := s.Prog(x86.AFSTCW)
142+
// Save AX so we can use it as scratch space.
143+
p := s.Prog(x86.AMOVL)
144+
p.From.Type = obj.TYPE_REG
145+
p.From.Reg = x86.REG_AX
143146
s.AddrScratch(&p.To)
144-
p = s.Prog(x86.AFLDCW)
145-
p.From.Type = obj.TYPE_MEM
146-
p.From.Name = obj.NAME_EXTERN
147-
p.From.Sym = gc.ControlWord32
147+
// Install a 32-bit version of the control word.
148+
installControlWord(s, gc.ControlWord32, x86.REG_AX)
149+
// Restore AX.
150+
p = s.Prog(x86.AMOVL)
151+
s.AddrScratch(&p.From)
152+
p.To.Type = obj.TYPE_REG
153+
p.To.Reg = x86.REG_AX
148154
}
149155

150156
var op obj.As
@@ -167,8 +173,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) {
167173
// Restore precision if needed.
168174
switch v.Op {
169175
case ssa.Op386ADDSS, ssa.Op386SUBSS, ssa.Op386MULSS, ssa.Op386DIVSS:
170-
p := s.Prog(x86.AFLDCW)
171-
s.AddrScratch(&p.From)
176+
restoreControlWord(s)
172177
}
173178

174179
case ssa.Op386UCOMISS, ssa.Op386UCOMISD:
@@ -225,19 +230,11 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) {
225230
case ssa.Op386CVTTSD2SL, ssa.Op386CVTTSS2SL:
226231
push(s, v.Args[0])
227232

228-
// Save control word.
229-
p := s.Prog(x86.AFSTCW)
230-
s.AddrScratch(&p.To)
231-
p.To.Offset += 4
232-
233233
// Load control word which truncates (rounds towards zero).
234-
p = s.Prog(x86.AFLDCW)
235-
p.From.Type = obj.TYPE_MEM
236-
p.From.Name = obj.NAME_EXTERN
237-
p.From.Sym = gc.ControlWord64trunc
234+
installControlWord(s, gc.ControlWord64trunc, v.Reg())
238235

239236
// Now do the conversion.
240-
p = s.Prog(x86.AFMOVLP)
237+
p := s.Prog(x86.AFMOVLP)
241238
p.From.Type = obj.TYPE_REG
242239
p.From.Reg = x86.REG_F0
243240
s.AddrScratch(&p.To)
@@ -247,9 +244,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) {
247244
p.To.Reg = v.Reg()
248245

249246
// Restore control word.
250-
p = s.Prog(x86.AFLDCW)
251-
s.AddrScratch(&p.From)
252-
p.From.Offset += 4
247+
restoreControlWord(s)
253248

254249
case ssa.Op386CVTSS2SD:
255250
// float32 -> float64 is a nop
@@ -373,3 +368,36 @@ func ssaGenBlock387(s *gc.SSAGenState, b, next *ssa.Block) {
373368

374369
ssaGenBlock(s, b, next)
375370
}
371+
372+
// installControlWord saves the current floating-point control
373+
// word and installs a new one loaded from cw.
374+
// scratchReg must be an unused register.
375+
// This call must be paired with restoreControlWord.
376+
// Bytes 4-5 of the scratch space (s.AddrScratch) are used between
377+
// this call and restoreControlWord.
378+
func installControlWord(s *gc.SSAGenState, cw *obj.LSym, scratchReg int16) {
379+
// Save current control word.
380+
p := s.Prog(x86.AFSTCW)
381+
s.AddrScratch(&p.To)
382+
p.To.Offset += 4
383+
384+
// Materialize address of new control word.
385+
// Note: this must be a seperate instruction to handle PIE correctly.
386+
// See issue 41503.
387+
p = s.Prog(x86.ALEAL)
388+
p.From.Type = obj.TYPE_MEM
389+
p.From.Name = obj.NAME_EXTERN
390+
p.From.Sym = cw
391+
p.To.Type = obj.TYPE_REG
392+
p.To.Reg = scratchReg
393+
394+
// Load replacement control word.
395+
p = s.Prog(x86.AFLDCW)
396+
p.From.Type = obj.TYPE_MEM
397+
p.From.Reg = scratchReg
398+
}
399+
func restoreControlWord(s *gc.SSAGenState) {
400+
p := s.Prog(x86.AFLDCW)
401+
s.AddrScratch(&p.From)
402+
p.From.Offset += 4
403+
}

0 commit comments

Comments
 (0)