Skip to content

Commit 69dcdbd

Browse files
committed
cmd/internal/obj/mips: mark unsafe points
For async preemption, we will be using REGTMP as a temporary register in injected call on MIPS, which will clobber it. So any code that uses REGTMP is not safe for async preemption. In the assembler backend, we expand a Prog to multiple machine instructions and use REGTMP as a temporary register if necessary. These need to be marked unsafe. In fact, most of the multi-instruction Progs use REGTMP, so we mark all of them, except ones that are whitelisted. Change-Id: Ic00ae5589683c2c9525abdaee076d884df6b0d1e Reviewed-on: https://go-review.googlesource.com/c/go/+/203718 Run-TryBot: Cherry Zhang <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Keith Randall <[email protected]>
1 parent 1b0b980 commit 69dcdbd

File tree

2 files changed

+62
-20
lines changed

2 files changed

+62
-20
lines changed

src/cmd/internal/obj/mips/asm0.go

+56-20
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,20 @@ type Optab struct {
7272
flag uint8
7373
}
7474

75+
const (
76+
// Optab.flag
77+
NOTUSETMP = 1 << iota // p expands to multiple instructions, but does NOT use REGTMP
78+
)
79+
7580
var optab = []Optab{
7681
{obj.ATEXT, C_LEXT, C_NONE, C_TEXTSIZE, 0, 0, 0, sys.MIPS64, 0},
7782
{obj.ATEXT, C_ADDR, C_NONE, C_TEXTSIZE, 0, 0, 0, 0, 0},
7883

7984
{AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
8085
{AMOVV, C_REG, C_NONE, C_REG, 1, 4, 0, sys.MIPS64, 0},
81-
{AMOVB, C_REG, C_NONE, C_REG, 12, 8, 0, 0, 0},
86+
{AMOVB, C_REG, C_NONE, C_REG, 12, 8, 0, 0, NOTUSETMP},
8287
{AMOVBU, C_REG, C_NONE, C_REG, 13, 4, 0, 0, 0},
83-
{AMOVWU, C_REG, C_NONE, C_REG, 14, 8, 0, sys.MIPS64, 0},
88+
{AMOVWU, C_REG, C_NONE, C_REG, 14, 8, 0, sys.MIPS64, NOTUSETMP},
8489

8590
{ASUB, C_REG, C_REG, C_REG, 2, 4, 0, 0, 0},
8691
{ASUBV, C_REG, C_REG, C_REG, 2, 4, 0, sys.MIPS64, 0},
@@ -182,11 +187,11 @@ var optab = []Optab{
182187
{AMOVB, C_REG, C_NONE, C_ADDR, 50, 12, 0, sys.MIPS64, 0},
183188
{AMOVBU, C_REG, C_NONE, C_ADDR, 50, 8, 0, sys.MIPS, 0},
184189
{AMOVBU, C_REG, C_NONE, C_ADDR, 50, 12, 0, sys.MIPS64, 0},
185-
{AMOVW, C_REG, C_NONE, C_TLS, 53, 8, 0, 0, 0},
186-
{AMOVWU, C_REG, C_NONE, C_TLS, 53, 8, 0, sys.MIPS64, 0},
187-
{AMOVV, C_REG, C_NONE, C_TLS, 53, 8, 0, sys.MIPS64, 0},
188-
{AMOVB, C_REG, C_NONE, C_TLS, 53, 8, 0, 0, 0},
189-
{AMOVBU, C_REG, C_NONE, C_TLS, 53, 8, 0, 0, 0},
190+
{AMOVW, C_REG, C_NONE, C_TLS, 53, 8, 0, 0, NOTUSETMP},
191+
{AMOVWU, C_REG, C_NONE, C_TLS, 53, 8, 0, sys.MIPS64, NOTUSETMP},
192+
{AMOVV, C_REG, C_NONE, C_TLS, 53, 8, 0, sys.MIPS64, NOTUSETMP},
193+
{AMOVB, C_REG, C_NONE, C_TLS, 53, 8, 0, 0, NOTUSETMP},
194+
{AMOVBU, C_REG, C_NONE, C_TLS, 53, 8, 0, 0, NOTUSETMP},
190195

191196
{AMOVW, C_LEXT, C_NONE, C_REG, 36, 12, REGSB, sys.MIPS64, 0},
192197
{AMOVWU, C_LEXT, C_NONE, C_REG, 36, 12, REGSB, sys.MIPS64, 0},
@@ -211,33 +216,33 @@ var optab = []Optab{
211216
{AMOVB, C_ADDR, C_NONE, C_REG, 51, 12, 0, sys.MIPS64, 0},
212217
{AMOVBU, C_ADDR, C_NONE, C_REG, 51, 8, 0, sys.MIPS, 0},
213218
{AMOVBU, C_ADDR, C_NONE, C_REG, 51, 12, 0, sys.MIPS64, 0},
214-
{AMOVW, C_TLS, C_NONE, C_REG, 54, 8, 0, 0, 0},
215-
{AMOVWU, C_TLS, C_NONE, C_REG, 54, 8, 0, sys.MIPS64, 0},
216-
{AMOVV, C_TLS, C_NONE, C_REG, 54, 8, 0, sys.MIPS64, 0},
217-
{AMOVB, C_TLS, C_NONE, C_REG, 54, 8, 0, 0, 0},
218-
{AMOVBU, C_TLS, C_NONE, C_REG, 54, 8, 0, 0, 0},
219+
{AMOVW, C_TLS, C_NONE, C_REG, 54, 8, 0, 0, NOTUSETMP},
220+
{AMOVWU, C_TLS, C_NONE, C_REG, 54, 8, 0, sys.MIPS64, NOTUSETMP},
221+
{AMOVV, C_TLS, C_NONE, C_REG, 54, 8, 0, sys.MIPS64, NOTUSETMP},
222+
{AMOVB, C_TLS, C_NONE, C_REG, 54, 8, 0, 0, NOTUSETMP},
223+
{AMOVBU, C_TLS, C_NONE, C_REG, 54, 8, 0, 0, NOTUSETMP},
219224

220225
{AMOVW, C_SECON, C_NONE, C_REG, 3, 4, REGSB, sys.MIPS64, 0},
221226
{AMOVV, C_SECON, C_NONE, C_REG, 3, 4, REGSB, sys.MIPS64, 0},
222227
{AMOVW, C_SACON, C_NONE, C_REG, 3, 4, REGSP, 0, 0},
223228
{AMOVV, C_SACON, C_NONE, C_REG, 3, 4, REGSP, sys.MIPS64, 0},
224-
{AMOVW, C_LECON, C_NONE, C_REG, 52, 8, REGSB, sys.MIPS, 0},
225-
{AMOVW, C_LECON, C_NONE, C_REG, 52, 12, REGSB, sys.MIPS64, 0},
226-
{AMOVV, C_LECON, C_NONE, C_REG, 52, 12, REGSB, sys.MIPS64, 0},
229+
{AMOVW, C_LECON, C_NONE, C_REG, 52, 8, REGSB, sys.MIPS, NOTUSETMP},
230+
{AMOVW, C_LECON, C_NONE, C_REG, 52, 12, REGSB, sys.MIPS64, NOTUSETMP},
231+
{AMOVV, C_LECON, C_NONE, C_REG, 52, 12, REGSB, sys.MIPS64, NOTUSETMP},
227232

228233
{AMOVW, C_LACON, C_NONE, C_REG, 26, 12, REGSP, 0, 0},
229234
{AMOVV, C_LACON, C_NONE, C_REG, 26, 12, REGSP, sys.MIPS64, 0},
230235
{AMOVW, C_ADDCON, C_NONE, C_REG, 3, 4, REGZERO, 0, 0},
231236
{AMOVV, C_ADDCON, C_NONE, C_REG, 3, 4, REGZERO, sys.MIPS64, 0},
232237
{AMOVW, C_ANDCON, C_NONE, C_REG, 3, 4, REGZERO, 0, 0},
233238
{AMOVV, C_ANDCON, C_NONE, C_REG, 3, 4, REGZERO, sys.MIPS64, 0},
234-
{AMOVW, C_STCON, C_NONE, C_REG, 55, 8, 0, 0, 0},
235-
{AMOVV, C_STCON, C_NONE, C_REG, 55, 8, 0, sys.MIPS64, 0},
239+
{AMOVW, C_STCON, C_NONE, C_REG, 55, 8, 0, 0, NOTUSETMP},
240+
{AMOVV, C_STCON, C_NONE, C_REG, 55, 8, 0, sys.MIPS64, NOTUSETMP},
236241

237242
{AMOVW, C_UCON, C_NONE, C_REG, 24, 4, 0, 0, 0},
238243
{AMOVV, C_UCON, C_NONE, C_REG, 24, 4, 0, sys.MIPS64, 0},
239-
{AMOVW, C_LCON, C_NONE, C_REG, 19, 8, 0, 0, 0},
240-
{AMOVV, C_LCON, C_NONE, C_REG, 19, 8, 0, sys.MIPS64, 0},
244+
{AMOVW, C_LCON, C_NONE, C_REG, 19, 8, 0, 0, NOTUSETMP},
245+
{AMOVV, C_LCON, C_NONE, C_REG, 19, 8, 0, sys.MIPS64, NOTUSETMP},
241246

242247
{AMOVW, C_HI, C_NONE, C_REG, 20, 4, 0, 0, 0},
243248
{AMOVV, C_HI, C_NONE, C_REG, 20, 4, 0, sys.MIPS64, 0},
@@ -292,7 +297,7 @@ var optab = []Optab{
292297
{ABEQ, C_REG, C_REG, C_SBRA, 6, 4, 0, 0, 0},
293298
{ABEQ, C_REG, C_NONE, C_SBRA, 6, 4, 0, 0, 0},
294299
{ABLEZ, C_REG, C_NONE, C_SBRA, 6, 4, 0, 0, 0},
295-
{ABFPT, C_NONE, C_NONE, C_SBRA, 6, 8, 0, 0, 0},
300+
{ABFPT, C_NONE, C_NONE, C_SBRA, 6, 8, 0, 0, NOTUSETMP},
296301

297302
{AJMP, C_NONE, C_NONE, C_LBRA, 11, 4, 0, 0, 0},
298303
{AJAL, C_NONE, C_NONE, C_LBRA, 11, 4, 0, 0, 0},
@@ -506,6 +511,23 @@ func span0(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
506511
bp = bp[4:]
507512
}
508513
}
514+
515+
// Mark nonpreemptible instruction sequences.
516+
// We use REGTMP as a scratch register during call injection,
517+
// so instruction sequences that use REGTMP are unsafe to
518+
// preempt asynchronously.
519+
obj.MarkUnsafePoints(c.ctxt, c.cursym.Func.Text, c.newprog, c.isUnsafePoint)
520+
}
521+
522+
// Return whether p is an unsafe point.
523+
func (c *ctxt0) isUnsafePoint(p *obj.Prog) bool {
524+
if p.From.Reg == REGTMP || p.To.Reg == REGTMP || p.Reg == REGTMP {
525+
return true
526+
}
527+
// Most of the multi-instruction sequence uses REGTMP, except
528+
// ones marked safe.
529+
o := c.oplook(p)
530+
return o.size > 4 && o.flag&NOTUSETMP == 0
509531
}
510532

511533
func isint32(v int64) bool {
@@ -1253,6 +1275,8 @@ func (c *ctxt0) asmout(p *obj.Prog, o *Optab, out []uint32) {
12531275
}
12541276

12551277
case 12: /* movbs r,r */
1278+
// NOTE: this case does not use REGTMP. If it ever does,
1279+
// remove the NOTUSETMP flag in optab.
12561280
v := 16
12571281
if p.As == AMOVB {
12581282
v = 24
@@ -1268,6 +1292,8 @@ func (c *ctxt0) asmout(p *obj.Prog, o *Optab, out []uint32) {
12681292
}
12691293

12701294
case 14: /* movwu r,r */
1295+
// NOTE: this case does not use REGTMP. If it ever does,
1296+
// remove the NOTUSETMP flag in optab.
12711297
o1 = OP_SRR(c.opirr(-ASLLV), uint32(0), uint32(p.From.Reg), uint32(p.To.Reg))
12721298
o2 = OP_SRR(c.opirr(-ASRLV), uint32(0), uint32(p.To.Reg), uint32(p.To.Reg))
12731299

@@ -1309,6 +1335,8 @@ func (c *ctxt0) asmout(p *obj.Prog, o *Optab, out []uint32) {
13091335
rel.Type = objabi.R_CALLIND
13101336

13111337
case 19: /* mov $lcon,r ==> lu+or */
1338+
// NOTE: this case does not use REGTMP. If it ever does,
1339+
// remove the NOTUSETMP flag in optab.
13121340
v := c.regoff(&p.From)
13131341
o1 = OP_IRR(c.opirr(ALUI), uint32(v>>16), uint32(REGZERO), uint32(p.To.Reg))
13141342
o2 = OP_IRR(c.opirr(AOR), uint32(v), uint32(p.To.Reg), uint32(p.To.Reg))
@@ -1539,6 +1567,8 @@ func (c *ctxt0) asmout(p *obj.Prog, o *Optab, out []uint32) {
15391567
}
15401568

15411569
case 52: /* mov $lext, r ==> lu + add REGSB, r + add */
1570+
// NOTE: this case does not use REGTMP. If it ever does,
1571+
// remove the NOTUSETMP flag in optab.
15421572
o1 = OP_IRR(c.opirr(ALUI), uint32(0), uint32(REGZERO), uint32(p.To.Reg))
15431573
rel := obj.Addrel(c.cursym)
15441574
rel.Off = int32(c.pc)
@@ -1563,6 +1593,8 @@ func (c *ctxt0) asmout(p *obj.Prog, o *Optab, out []uint32) {
15631593
case 53: /* mov r, tlsvar ==> rdhwr + sw o(r3) */
15641594
// clobbers R3 !
15651595
// load thread pointer with RDHWR, R3 is used for fast kernel emulation on Linux
1596+
// NOTE: this case does not use REGTMP. If it ever does,
1597+
// remove the NOTUSETMP flag in optab.
15661598
o1 = (037<<26 + 073) | (29 << 11) | (3 << 16) // rdhwr $29, r3
15671599
o2 = OP_IRR(c.opirr(p.As), uint32(0), uint32(REG_R3), uint32(p.From.Reg))
15681600
rel := obj.Addrel(c.cursym)
@@ -1574,6 +1606,8 @@ func (c *ctxt0) asmout(p *obj.Prog, o *Optab, out []uint32) {
15741606

15751607
case 54: /* mov tlsvar, r ==> rdhwr + lw o(r3) */
15761608
// clobbers R3 !
1609+
// NOTE: this case does not use REGTMP. If it ever does,
1610+
// remove the NOTUSETMP flag in optab.
15771611
o1 = (037<<26 + 073) | (29 << 11) | (3 << 16) // rdhwr $29, r3
15781612
o2 = OP_IRR(c.opirr(-p.As), uint32(0), uint32(REG_R3), uint32(p.To.Reg))
15791613
rel := obj.Addrel(c.cursym)
@@ -1585,6 +1619,8 @@ func (c *ctxt0) asmout(p *obj.Prog, o *Optab, out []uint32) {
15851619

15861620
case 55: /* mov $tlsvar, r ==> rdhwr + add */
15871621
// clobbers R3 !
1622+
// NOTE: this case does not use REGTMP. If it ever does,
1623+
// remove the NOTUSETMP flag in optab.
15881624
o1 = (037<<26 + 073) | (29 << 11) | (3 << 16) // rdhwr $29, r3
15891625
o2 = OP_IRR(c.opirr(add), uint32(0), uint32(REG_R3), uint32(p.To.Reg))
15901626
rel := obj.Addrel(c.cursym)

src/cmd/internal/obj/mips/obj0.go

+6
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,10 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
339339
// Store link register before decrement SP, so if a signal comes
340340
// during the execution of the function prologue, the traceback
341341
// code will not see a half-updated stack frame.
342+
// This sequence is not async preemptible, as if we open a frame
343+
// at the current SP, it will clobber the saved LR.
344+
q = c.ctxt.StartUnsafePoint(q, c.newprog)
345+
342346
q = obj.Appendp(q, newprog)
343347
q.As = mov
344348
q.Pos = p.Pos
@@ -356,6 +360,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
356360
q.To.Type = obj.TYPE_REG
357361
q.To.Reg = REGSP
358362
q.Spadj = +autosize
363+
364+
q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
359365
}
360366

361367
if c.cursym.Func.Text.From.Sym.Wrapper() && c.cursym.Func.Text.Mark&LEAF == 0 {

0 commit comments

Comments
 (0)