podman

Форк
0
784 строки · 20.2 Кб
1
// Derived from Inferno utils/5c/swt.c
2
// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5c/swt.c
3
//
4
//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
5
//	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
6
//	Portions Copyright © 1997-1999 Vita Nuova Limited
7
//	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
8
//	Portions Copyright © 2004,2006 Bruce Ellis
9
//	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
10
//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
11
//	Portions Copyright © 2009 The Go Authors. All rights reserved.
12
//
13
// Permission is hereby granted, free of charge, to any person obtaining a copy
14
// of this software and associated documentation files (the "Software"), to deal
15
// in the Software without restriction, including without limitation the rights
16
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
// copies of the Software, and to permit persons to whom the Software is
18
// furnished to do so, subject to the following conditions:
19
//
20
// The above copyright notice and this permission notice shall be included in
21
// all copies or substantial portions of the Software.
22
//
23
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
26
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29
// THE SOFTWARE.
30

31
package arm
32

33
import (
34
	"github.com/twitchyliquid64/golang-asm/obj"
35
	"github.com/twitchyliquid64/golang-asm/objabi"
36
	"github.com/twitchyliquid64/golang-asm/sys"
37
)
38

39
var progedit_tlsfallback *obj.LSym
40

41
func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
42
	p.From.Class = 0
43
	p.To.Class = 0
44

45
	c := ctxt5{ctxt: ctxt, newprog: newprog}
46

47
	// Rewrite B/BL to symbol as TYPE_BRANCH.
48
	switch p.As {
49
	case AB, ABL, obj.ADUFFZERO, obj.ADUFFCOPY:
50
		if p.To.Type == obj.TYPE_MEM && (p.To.Name == obj.NAME_EXTERN || p.To.Name == obj.NAME_STATIC) && p.To.Sym != nil {
51
			p.To.Type = obj.TYPE_BRANCH
52
		}
53
	}
54

55
	// Replace TLS register fetches on older ARM processors.
56
	switch p.As {
57
	// Treat MRC 15, 0, <reg>, C13, C0, 3 specially.
58
	case AMRC:
59
		if p.To.Offset&0xffff0fff == 0xee1d0f70 {
60
			// Because the instruction might be rewritten to a BL which returns in R0
61
			// the register must be zero.
62
			if p.To.Offset&0xf000 != 0 {
63
				ctxt.Diag("%v: TLS MRC instruction must write to R0 as it might get translated into a BL instruction", p.Line())
64
			}
65

66
			if objabi.GOARM < 7 {
67
				// Replace it with BL runtime.read_tls_fallback(SB) for ARM CPUs that lack the tls extension.
68
				if progedit_tlsfallback == nil {
69
					progedit_tlsfallback = ctxt.Lookup("runtime.read_tls_fallback")
70
				}
71

72
				// MOVW	LR, R11
73
				p.As = AMOVW
74

75
				p.From.Type = obj.TYPE_REG
76
				p.From.Reg = REGLINK
77
				p.To.Type = obj.TYPE_REG
78
				p.To.Reg = REGTMP
79

80
				// BL	runtime.read_tls_fallback(SB)
81
				p = obj.Appendp(p, newprog)
82

83
				p.As = ABL
84
				p.To.Type = obj.TYPE_BRANCH
85
				p.To.Sym = progedit_tlsfallback
86
				p.To.Offset = 0
87

88
				// MOVW	R11, LR
89
				p = obj.Appendp(p, newprog)
90

91
				p.As = AMOVW
92
				p.From.Type = obj.TYPE_REG
93
				p.From.Reg = REGTMP
94
				p.To.Type = obj.TYPE_REG
95
				p.To.Reg = REGLINK
96
				break
97
			}
98
		}
99

100
		// Otherwise, MRC/MCR instructions need no further treatment.
101
		p.As = AWORD
102
	}
103

104
	// Rewrite float constants to values stored in memory.
105
	switch p.As {
106
	case AMOVF:
107
		if p.From.Type == obj.TYPE_FCONST && c.chipfloat5(p.From.Val.(float64)) < 0 && (c.chipzero5(p.From.Val.(float64)) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) {
108
			f32 := float32(p.From.Val.(float64))
109
			p.From.Type = obj.TYPE_MEM
110
			p.From.Sym = ctxt.Float32Sym(f32)
111
			p.From.Name = obj.NAME_EXTERN
112
			p.From.Offset = 0
113
		}
114

115
	case AMOVD:
116
		if p.From.Type == obj.TYPE_FCONST && c.chipfloat5(p.From.Val.(float64)) < 0 && (c.chipzero5(p.From.Val.(float64)) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) {
117
			p.From.Type = obj.TYPE_MEM
118
			p.From.Sym = ctxt.Float64Sym(p.From.Val.(float64))
119
			p.From.Name = obj.NAME_EXTERN
120
			p.From.Offset = 0
121
		}
122
	}
123

124
	if ctxt.Flag_dynlink {
125
		c.rewriteToUseGot(p)
126
	}
127
}
128

129
// Rewrite p, if necessary, to access global data via the global offset table.
130
func (c *ctxt5) rewriteToUseGot(p *obj.Prog) {
131
	if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
132
		//     ADUFFxxx $offset
133
		// becomes
134
		//     MOVW runtime.duffxxx@GOT, R9
135
		//     ADD $offset, R9
136
		//     CALL (R9)
137
		var sym *obj.LSym
138
		if p.As == obj.ADUFFZERO {
139
			sym = c.ctxt.Lookup("runtime.duffzero")
140
		} else {
141
			sym = c.ctxt.Lookup("runtime.duffcopy")
142
		}
143
		offset := p.To.Offset
144
		p.As = AMOVW
145
		p.From.Type = obj.TYPE_MEM
146
		p.From.Name = obj.NAME_GOTREF
147
		p.From.Sym = sym
148
		p.To.Type = obj.TYPE_REG
149
		p.To.Reg = REG_R9
150
		p.To.Name = obj.NAME_NONE
151
		p.To.Offset = 0
152
		p.To.Sym = nil
153
		p1 := obj.Appendp(p, c.newprog)
154
		p1.As = AADD
155
		p1.From.Type = obj.TYPE_CONST
156
		p1.From.Offset = offset
157
		p1.To.Type = obj.TYPE_REG
158
		p1.To.Reg = REG_R9
159
		p2 := obj.Appendp(p1, c.newprog)
160
		p2.As = obj.ACALL
161
		p2.To.Type = obj.TYPE_MEM
162
		p2.To.Reg = REG_R9
163
		return
164
	}
165

166
	// We only care about global data: NAME_EXTERN means a global
167
	// symbol in the Go sense, and p.Sym.Local is true for a few
168
	// internally defined symbols.
169
	if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
170
		// MOVW $sym, Rx becomes MOVW sym@GOT, Rx
171
		// MOVW $sym+<off>, Rx becomes MOVW sym@GOT, Rx; ADD <off>, Rx
172
		if p.As != AMOVW {
173
			c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
174
		}
175
		if p.To.Type != obj.TYPE_REG {
176
			c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
177
		}
178
		p.From.Type = obj.TYPE_MEM
179
		p.From.Name = obj.NAME_GOTREF
180
		if p.From.Offset != 0 {
181
			q := obj.Appendp(p, c.newprog)
182
			q.As = AADD
183
			q.From.Type = obj.TYPE_CONST
184
			q.From.Offset = p.From.Offset
185
			q.To = p.To
186
			p.From.Offset = 0
187
		}
188
	}
189
	if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
190
		c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
191
	}
192
	var source *obj.Addr
193
	// MOVx sym, Ry becomes MOVW sym@GOT, R9; MOVx (R9), Ry
194
	// MOVx Ry, sym becomes MOVW sym@GOT, R9; MOVx Ry, (R9)
195
	// An addition may be inserted between the two MOVs if there is an offset.
196
	if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
197
		if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
198
			c.ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
199
		}
200
		source = &p.From
201
	} else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
202
		source = &p.To
203
	} else {
204
		return
205
	}
206
	if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
207
		return
208
	}
209
	if source.Sym.Type == objabi.STLSBSS {
210
		return
211
	}
212
	if source.Type != obj.TYPE_MEM {
213
		c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
214
	}
215
	p1 := obj.Appendp(p, c.newprog)
216
	p2 := obj.Appendp(p1, c.newprog)
217

218
	p1.As = AMOVW
219
	p1.From.Type = obj.TYPE_MEM
220
	p1.From.Sym = source.Sym
221
	p1.From.Name = obj.NAME_GOTREF
222
	p1.To.Type = obj.TYPE_REG
223
	p1.To.Reg = REG_R9
224

225
	p2.As = p.As
226
	p2.From = p.From
227
	p2.To = p.To
228
	if p.From.Name == obj.NAME_EXTERN {
229
		p2.From.Reg = REG_R9
230
		p2.From.Name = obj.NAME_NONE
231
		p2.From.Sym = nil
232
	} else if p.To.Name == obj.NAME_EXTERN {
233
		p2.To.Reg = REG_R9
234
		p2.To.Name = obj.NAME_NONE
235
		p2.To.Sym = nil
236
	} else {
237
		return
238
	}
239
	obj.Nopout(p)
240
}
241

242
// Prog.mark
243
const (
244
	FOLL  = 1 << 0
245
	LABEL = 1 << 1
246
	LEAF  = 1 << 2
247
)
248

249
func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
250
	autosize := int32(0)
251

252
	if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
253
		return
254
	}
255

256
	c := ctxt5{ctxt: ctxt, cursym: cursym, newprog: newprog}
257

258
	p := c.cursym.Func.Text
259
	autoffset := int32(p.To.Offset)
260
	if autoffset == -4 {
261
		// Historical way to mark NOFRAME.
262
		p.From.Sym.Set(obj.AttrNoFrame, true)
263
		autoffset = 0
264
	}
265
	if autoffset < 0 || autoffset%4 != 0 {
266
		c.ctxt.Diag("frame size %d not 0 or a positive multiple of 4", autoffset)
267
	}
268
	if p.From.Sym.NoFrame() {
269
		if autoffset != 0 {
270
			c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", autoffset)
271
		}
272
	}
273

274
	cursym.Func.Locals = autoffset
275
	cursym.Func.Args = p.To.Val.(int32)
276

277
	/*
278
	 * find leaf subroutines
279
	 */
280
	for p := cursym.Func.Text; p != nil; p = p.Link {
281
		switch p.As {
282
		case obj.ATEXT:
283
			p.Mark |= LEAF
284

285
		case ADIV, ADIVU, AMOD, AMODU:
286
			cursym.Func.Text.Mark &^= LEAF
287

288
		case ABL,
289
			ABX,
290
			obj.ADUFFZERO,
291
			obj.ADUFFCOPY:
292
			cursym.Func.Text.Mark &^= LEAF
293
		}
294
	}
295

296
	var q2 *obj.Prog
297
	for p := cursym.Func.Text; p != nil; p = p.Link {
298
		o := p.As
299
		switch o {
300
		case obj.ATEXT:
301
			autosize = autoffset
302

303
			if p.Mark&LEAF != 0 && autosize == 0 {
304
				// A leaf function with no locals has no frame.
305
				p.From.Sym.Set(obj.AttrNoFrame, true)
306
			}
307

308
			if !p.From.Sym.NoFrame() {
309
				// If there is a stack frame at all, it includes
310
				// space to save the LR.
311
				autosize += 4
312
			}
313

314
			if autosize == 0 && cursym.Func.Text.Mark&LEAF == 0 {
315
				// A very few functions that do not return to their caller
316
				// are not identified as leaves but still have no frame.
317
				if ctxt.Debugvlog {
318
					ctxt.Logf("save suppressed in: %s\n", cursym.Name)
319
				}
320

321
				cursym.Func.Text.Mark |= LEAF
322
			}
323

324
			// FP offsets need an updated p.To.Offset.
325
			p.To.Offset = int64(autosize) - 4
326

327
			if cursym.Func.Text.Mark&LEAF != 0 {
328
				cursym.Set(obj.AttrLeaf, true)
329
				if p.From.Sym.NoFrame() {
330
					break
331
				}
332
			}
333

334
			if !p.From.Sym.NoSplit() {
335
				p = c.stacksplit(p, autosize) // emit split check
336
			}
337

338
			// MOVW.W		R14,$-autosize(SP)
339
			p = obj.Appendp(p, c.newprog)
340

341
			p.As = AMOVW
342
			p.Scond |= C_WBIT
343
			p.From.Type = obj.TYPE_REG
344
			p.From.Reg = REGLINK
345
			p.To.Type = obj.TYPE_MEM
346
			p.To.Offset = int64(-autosize)
347
			p.To.Reg = REGSP
348
			p.Spadj = autosize
349

350
			if cursym.Func.Text.From.Sym.Wrapper() {
351
				// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
352
				//
353
				//	MOVW g_panic(g), R1
354
				//	CMP  $0, R1
355
				//	B.NE checkargp
356
				// end:
357
				//	NOP
358
				// ... function ...
359
				// checkargp:
360
				//	MOVW panic_argp(R1), R2
361
				//	ADD  $(autosize+4), R13, R3
362
				//	CMP  R2, R3
363
				//	B.NE end
364
				//	ADD  $4, R13, R4
365
				//	MOVW R4, panic_argp(R1)
366
				//	B    end
367
				//
368
				// The NOP is needed to give the jumps somewhere to land.
369
				// It is a liblink NOP, not an ARM NOP: it encodes to 0 instruction bytes.
370

371
				p = obj.Appendp(p, newprog)
372
				p.As = AMOVW
373
				p.From.Type = obj.TYPE_MEM
374
				p.From.Reg = REGG
375
				p.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // G.panic
376
				p.To.Type = obj.TYPE_REG
377
				p.To.Reg = REG_R1
378

379
				p = obj.Appendp(p, newprog)
380
				p.As = ACMP
381
				p.From.Type = obj.TYPE_CONST
382
				p.From.Offset = 0
383
				p.Reg = REG_R1
384

385
				// B.NE checkargp
386
				bne := obj.Appendp(p, newprog)
387
				bne.As = ABNE
388
				bne.To.Type = obj.TYPE_BRANCH
389

390
				// end: NOP
391
				end := obj.Appendp(bne, newprog)
392
				end.As = obj.ANOP
393

394
				// find end of function
395
				var last *obj.Prog
396
				for last = end; last.Link != nil; last = last.Link {
397
				}
398

399
				// MOVW panic_argp(R1), R2
400
				mov := obj.Appendp(last, newprog)
401
				mov.As = AMOVW
402
				mov.From.Type = obj.TYPE_MEM
403
				mov.From.Reg = REG_R1
404
				mov.From.Offset = 0 // Panic.argp
405
				mov.To.Type = obj.TYPE_REG
406
				mov.To.Reg = REG_R2
407

408
				// B.NE branch target is MOVW above
409
				bne.To.SetTarget(mov)
410

411
				// ADD $(autosize+4), R13, R3
412
				p = obj.Appendp(mov, newprog)
413
				p.As = AADD
414
				p.From.Type = obj.TYPE_CONST
415
				p.From.Offset = int64(autosize) + 4
416
				p.Reg = REG_R13
417
				p.To.Type = obj.TYPE_REG
418
				p.To.Reg = REG_R3
419

420
				// CMP R2, R3
421
				p = obj.Appendp(p, newprog)
422
				p.As = ACMP
423
				p.From.Type = obj.TYPE_REG
424
				p.From.Reg = REG_R2
425
				p.Reg = REG_R3
426

427
				// B.NE end
428
				p = obj.Appendp(p, newprog)
429
				p.As = ABNE
430
				p.To.Type = obj.TYPE_BRANCH
431
				p.To.SetTarget(end)
432

433
				// ADD $4, R13, R4
434
				p = obj.Appendp(p, newprog)
435
				p.As = AADD
436
				p.From.Type = obj.TYPE_CONST
437
				p.From.Offset = 4
438
				p.Reg = REG_R13
439
				p.To.Type = obj.TYPE_REG
440
				p.To.Reg = REG_R4
441

442
				// MOVW R4, panic_argp(R1)
443
				p = obj.Appendp(p, newprog)
444
				p.As = AMOVW
445
				p.From.Type = obj.TYPE_REG
446
				p.From.Reg = REG_R4
447
				p.To.Type = obj.TYPE_MEM
448
				p.To.Reg = REG_R1
449
				p.To.Offset = 0 // Panic.argp
450

451
				// B end
452
				p = obj.Appendp(p, newprog)
453
				p.As = AB
454
				p.To.Type = obj.TYPE_BRANCH
455
				p.To.SetTarget(end)
456

457
				// reset for subsequent passes
458
				p = end
459
			}
460

461
		case obj.ARET:
462
			nocache(p)
463
			if cursym.Func.Text.Mark&LEAF != 0 {
464
				if autosize == 0 {
465
					p.As = AB
466
					p.From = obj.Addr{}
467
					if p.To.Sym != nil { // retjmp
468
						p.To.Type = obj.TYPE_BRANCH
469
					} else {
470
						p.To.Type = obj.TYPE_MEM
471
						p.To.Offset = 0
472
						p.To.Reg = REGLINK
473
					}
474

475
					break
476
				}
477
			}
478

479
			p.As = AMOVW
480
			p.Scond |= C_PBIT
481
			p.From.Type = obj.TYPE_MEM
482
			p.From.Offset = int64(autosize)
483
			p.From.Reg = REGSP
484
			p.To.Type = obj.TYPE_REG
485
			p.To.Reg = REGPC
486

487
			// If there are instructions following
488
			// this ARET, they come from a branch
489
			// with the same stackframe, so no spadj.
490
			if p.To.Sym != nil { // retjmp
491
				p.To.Reg = REGLINK
492
				q2 = obj.Appendp(p, newprog)
493
				q2.As = AB
494
				q2.To.Type = obj.TYPE_BRANCH
495
				q2.To.Sym = p.To.Sym
496
				p.To.Sym = nil
497
				p = q2
498
			}
499

500
		case AADD:
501
			if p.From.Type == obj.TYPE_CONST && p.From.Reg == 0 && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP {
502
				p.Spadj = int32(-p.From.Offset)
503
			}
504

505
		case ASUB:
506
			if p.From.Type == obj.TYPE_CONST && p.From.Reg == 0 && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP {
507
				p.Spadj = int32(p.From.Offset)
508
			}
509

510
		case ADIV, ADIVU, AMOD, AMODU:
511
			if cursym.Func.Text.From.Sym.NoSplit() {
512
				ctxt.Diag("cannot divide in NOSPLIT function")
513
			}
514
			const debugdivmod = false
515
			if debugdivmod {
516
				break
517
			}
518
			if p.From.Type != obj.TYPE_REG {
519
				break
520
			}
521
			if p.To.Type != obj.TYPE_REG {
522
				break
523
			}
524

525
			// Make copy because we overwrite p below.
526
			q1 := *p
527
			if q1.Reg == REGTMP || q1.Reg == 0 && q1.To.Reg == REGTMP {
528
				ctxt.Diag("div already using REGTMP: %v", p)
529
			}
530

531
			/* MOV m(g),REGTMP */
532
			p.As = AMOVW
533
			p.Pos = q1.Pos
534
			p.From.Type = obj.TYPE_MEM
535
			p.From.Reg = REGG
536
			p.From.Offset = 6 * 4 // offset of g.m
537
			p.Reg = 0
538
			p.To.Type = obj.TYPE_REG
539
			p.To.Reg = REGTMP
540

541
			/* MOV a,m_divmod(REGTMP) */
542
			p = obj.Appendp(p, newprog)
543
			p.As = AMOVW
544
			p.Pos = q1.Pos
545
			p.From.Type = obj.TYPE_REG
546
			p.From.Reg = q1.From.Reg
547
			p.To.Type = obj.TYPE_MEM
548
			p.To.Reg = REGTMP
549
			p.To.Offset = 8 * 4 // offset of m.divmod
550

551
			/* MOV b, R8 */
552
			p = obj.Appendp(p, newprog)
553
			p.As = AMOVW
554
			p.Pos = q1.Pos
555
			p.From.Type = obj.TYPE_REG
556
			p.From.Reg = q1.Reg
557
			if q1.Reg == 0 {
558
				p.From.Reg = q1.To.Reg
559
			}
560
			p.To.Type = obj.TYPE_REG
561
			p.To.Reg = REG_R8
562
			p.To.Offset = 0
563

564
			/* CALL appropriate */
565
			p = obj.Appendp(p, newprog)
566
			p.As = ABL
567
			p.Pos = q1.Pos
568
			p.To.Type = obj.TYPE_BRANCH
569
			switch o {
570
			case ADIV:
571
				p.To.Sym = symdiv
572
			case ADIVU:
573
				p.To.Sym = symdivu
574
			case AMOD:
575
				p.To.Sym = symmod
576
			case AMODU:
577
				p.To.Sym = symmodu
578
			}
579

580
			/* MOV REGTMP, b */
581
			p = obj.Appendp(p, newprog)
582
			p.As = AMOVW
583
			p.Pos = q1.Pos
584
			p.From.Type = obj.TYPE_REG
585
			p.From.Reg = REGTMP
586
			p.From.Offset = 0
587
			p.To.Type = obj.TYPE_REG
588
			p.To.Reg = q1.To.Reg
589

590
		case AMOVW:
591
			if (p.Scond&C_WBIT != 0) && p.To.Type == obj.TYPE_MEM && p.To.Reg == REGSP {
592
				p.Spadj = int32(-p.To.Offset)
593
			}
594
			if (p.Scond&C_PBIT != 0) && p.From.Type == obj.TYPE_MEM && p.From.Reg == REGSP && p.To.Reg != REGPC {
595
				p.Spadj = int32(-p.From.Offset)
596
			}
597
			if p.From.Type == obj.TYPE_ADDR && p.From.Reg == REGSP && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP {
598
				p.Spadj = int32(-p.From.Offset)
599
			}
600

601
		case obj.AGETCALLERPC:
602
			if cursym.Leaf() {
603
				/* MOVW LR, Rd */
604
				p.As = AMOVW
605
				p.From.Type = obj.TYPE_REG
606
				p.From.Reg = REGLINK
607
			} else {
608
				/* MOVW (RSP), Rd */
609
				p.As = AMOVW
610
				p.From.Type = obj.TYPE_MEM
611
				p.From.Reg = REGSP
612
			}
613
		}
614
	}
615
}
616

617
func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
618
	// MOVW g_stackguard(g), R1
619
	p = obj.Appendp(p, c.newprog)
620

621
	p.As = AMOVW
622
	p.From.Type = obj.TYPE_MEM
623
	p.From.Reg = REGG
624
	p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
625
	if c.cursym.CFunc() {
626
		p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
627
	}
628
	p.To.Type = obj.TYPE_REG
629
	p.To.Reg = REG_R1
630

631
	// Mark the stack bound check and morestack call async nonpreemptible.
632
	// If we get preempted here, when resumed the preemption request is
633
	// cleared, but we'll still call morestack, which will double the stack
634
	// unnecessarily. See issue #35470.
635
	p = c.ctxt.StartUnsafePoint(p, c.newprog)
636

637
	if framesize <= objabi.StackSmall {
638
		// small stack: SP < stackguard
639
		//	CMP	stackguard, SP
640
		p = obj.Appendp(p, c.newprog)
641

642
		p.As = ACMP
643
		p.From.Type = obj.TYPE_REG
644
		p.From.Reg = REG_R1
645
		p.Reg = REGSP
646
	} else if framesize <= objabi.StackBig {
647
		// large stack: SP-framesize < stackguard-StackSmall
648
		//	MOVW $-(framesize-StackSmall)(SP), R2
649
		//	CMP stackguard, R2
650
		p = obj.Appendp(p, c.newprog)
651

652
		p.As = AMOVW
653
		p.From.Type = obj.TYPE_ADDR
654
		p.From.Reg = REGSP
655
		p.From.Offset = -(int64(framesize) - objabi.StackSmall)
656
		p.To.Type = obj.TYPE_REG
657
		p.To.Reg = REG_R2
658

659
		p = obj.Appendp(p, c.newprog)
660
		p.As = ACMP
661
		p.From.Type = obj.TYPE_REG
662
		p.From.Reg = REG_R1
663
		p.Reg = REG_R2
664
	} else {
665
		// Such a large stack we need to protect against wraparound
666
		// if SP is close to zero.
667
		//	SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall)
668
		// The +StackGuard on both sides is required to keep the left side positive:
669
		// SP is allowed to be slightly below stackguard. See stack.h.
670
		//	CMP     $StackPreempt, R1
671
		//	MOVW.NE $StackGuard(SP), R2
672
		//	SUB.NE  R1, R2
673
		//	MOVW.NE $(framesize+(StackGuard-StackSmall)), R3
674
		//	CMP.NE  R3, R2
675
		p = obj.Appendp(p, c.newprog)
676

677
		p.As = ACMP
678
		p.From.Type = obj.TYPE_CONST
679
		p.From.Offset = int64(uint32(objabi.StackPreempt & (1<<32 - 1)))
680
		p.Reg = REG_R1
681

682
		p = obj.Appendp(p, c.newprog)
683
		p.As = AMOVW
684
		p.From.Type = obj.TYPE_ADDR
685
		p.From.Reg = REGSP
686
		p.From.Offset = int64(objabi.StackGuard)
687
		p.To.Type = obj.TYPE_REG
688
		p.To.Reg = REG_R2
689
		p.Scond = C_SCOND_NE
690

691
		p = obj.Appendp(p, c.newprog)
692
		p.As = ASUB
693
		p.From.Type = obj.TYPE_REG
694
		p.From.Reg = REG_R1
695
		p.To.Type = obj.TYPE_REG
696
		p.To.Reg = REG_R2
697
		p.Scond = C_SCOND_NE
698

699
		p = obj.Appendp(p, c.newprog)
700
		p.As = AMOVW
701
		p.From.Type = obj.TYPE_ADDR
702
		p.From.Offset = int64(framesize) + (int64(objabi.StackGuard) - objabi.StackSmall)
703
		p.To.Type = obj.TYPE_REG
704
		p.To.Reg = REG_R3
705
		p.Scond = C_SCOND_NE
706

707
		p = obj.Appendp(p, c.newprog)
708
		p.As = ACMP
709
		p.From.Type = obj.TYPE_REG
710
		p.From.Reg = REG_R3
711
		p.Reg = REG_R2
712
		p.Scond = C_SCOND_NE
713
	}
714

715
	// BLS call-to-morestack
716
	bls := obj.Appendp(p, c.newprog)
717
	bls.As = ABLS
718
	bls.To.Type = obj.TYPE_BRANCH
719

720
	end := c.ctxt.EndUnsafePoint(bls, c.newprog, -1)
721

722
	var last *obj.Prog
723
	for last = c.cursym.Func.Text; last.Link != nil; last = last.Link {
724
	}
725

726
	// Now we are at the end of the function, but logically
727
	// we are still in function prologue. We need to fix the
728
	// SP data and PCDATA.
729
	spfix := obj.Appendp(last, c.newprog)
730
	spfix.As = obj.ANOP
731
	spfix.Spadj = -framesize
732

733
	pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
734
	pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
735

736
	// MOVW	LR, R3
737
	movw := obj.Appendp(pcdata, c.newprog)
738
	movw.As = AMOVW
739
	movw.From.Type = obj.TYPE_REG
740
	movw.From.Reg = REGLINK
741
	movw.To.Type = obj.TYPE_REG
742
	movw.To.Reg = REG_R3
743

744
	bls.To.SetTarget(movw)
745

746
	// BL runtime.morestack
747
	call := obj.Appendp(movw, c.newprog)
748
	call.As = obj.ACALL
749
	call.To.Type = obj.TYPE_BRANCH
750
	morestack := "runtime.morestack"
751
	switch {
752
	case c.cursym.CFunc():
753
		morestack = "runtime.morestackc"
754
	case !c.cursym.Func.Text.From.Sym.NeedCtxt():
755
		morestack = "runtime.morestack_noctxt"
756
	}
757
	call.To.Sym = c.ctxt.Lookup(morestack)
758

759
	pcdata = c.ctxt.EndUnsafePoint(call, c.newprog, -1)
760

761
	// B start
762
	b := obj.Appendp(pcdata, c.newprog)
763
	b.As = obj.AJMP
764
	b.To.Type = obj.TYPE_BRANCH
765
	b.To.SetTarget(c.cursym.Func.Text.Link)
766
	b.Spadj = +framesize
767

768
	return end
769
}
770

771
var unaryDst = map[obj.As]bool{
772
	ASWI:  true,
773
	AWORD: true,
774
}
775

776
var Linkarm = obj.LinkArch{
777
	Arch:           sys.ArchARM,
778
	Init:           buildop,
779
	Preprocess:     preprocess,
780
	Assemble:       span5,
781
	Progedit:       progedit,
782
	UnaryDst:       unaryDst,
783
	DWARFRegisters: ARMDWARFRegisters,
784
}
785

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.