podman

Форк
0
998 строк · 25.0 Кб
1
// cmd/7l/noop.c, cmd/7l/obj.c, cmd/ld/pass.c from Vita Nuova.
2
// https://code.google.com/p/ken-cc/source/browse/
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 arm64
32

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

41
var complements = []obj.As{
42
	AADD:  ASUB,
43
	AADDW: ASUBW,
44
	ASUB:  AADD,
45
	ASUBW: AADDW,
46
	ACMP:  ACMN,
47
	ACMPW: ACMNW,
48
	ACMN:  ACMP,
49
	ACMNW: ACMPW,
50
}
51

52
func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
53
	// MOV	g_stackguard(g), R1
54
	p = obj.Appendp(p, c.newprog)
55

56
	p.As = AMOVD
57
	p.From.Type = obj.TYPE_MEM
58
	p.From.Reg = REGG
59
	p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
60
	if c.cursym.CFunc() {
61
		p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
62
	}
63
	p.To.Type = obj.TYPE_REG
64
	p.To.Reg = REG_R1
65

66
	// Mark the stack bound check and morestack call async nonpreemptible.
67
	// If we get preempted here, when resumed the preemption request is
68
	// cleared, but we'll still call morestack, which will double the stack
69
	// unnecessarily. See issue #35470.
70
	p = c.ctxt.StartUnsafePoint(p, c.newprog)
71

72
	q := (*obj.Prog)(nil)
73
	if framesize <= objabi.StackSmall {
74
		// small stack: SP < stackguard
75
		//	MOV	SP, R2
76
		//	CMP	stackguard, R2
77
		p = obj.Appendp(p, c.newprog)
78

79
		p.As = AMOVD
80
		p.From.Type = obj.TYPE_REG
81
		p.From.Reg = REGSP
82
		p.To.Type = obj.TYPE_REG
83
		p.To.Reg = REG_R2
84

85
		p = obj.Appendp(p, c.newprog)
86
		p.As = ACMP
87
		p.From.Type = obj.TYPE_REG
88
		p.From.Reg = REG_R1
89
		p.Reg = REG_R2
90
	} else if framesize <= objabi.StackBig {
91
		// large stack: SP-framesize < stackguard-StackSmall
92
		//	SUB	$(framesize-StackSmall), SP, R2
93
		//	CMP	stackguard, R2
94
		p = obj.Appendp(p, c.newprog)
95

96
		p.As = ASUB
97
		p.From.Type = obj.TYPE_CONST
98
		p.From.Offset = int64(framesize) - objabi.StackSmall
99
		p.Reg = REGSP
100
		p.To.Type = obj.TYPE_REG
101
		p.To.Reg = REG_R2
102

103
		p = obj.Appendp(p, c.newprog)
104
		p.As = ACMP
105
		p.From.Type = obj.TYPE_REG
106
		p.From.Reg = REG_R1
107
		p.Reg = REG_R2
108
	} else {
109
		// Such a large stack we need to protect against wraparound
110
		// if SP is close to zero.
111
		//	SP-stackguard+StackGuard < framesize + (StackGuard-StackSmall)
112
		// The +StackGuard on both sides is required to keep the left side positive:
113
		// SP is allowed to be slightly below stackguard. See stack.h.
114
		//	CMP	$StackPreempt, R1
115
		//	BEQ	label_of_call_to_morestack
116
		//	ADD	$StackGuard, SP, R2
117
		//	SUB	R1, R2
118
		//	MOV	$(framesize+(StackGuard-StackSmall)), R3
119
		//	CMP	R3, R2
120
		p = obj.Appendp(p, c.newprog)
121

122
		p.As = ACMP
123
		p.From.Type = obj.TYPE_CONST
124
		p.From.Offset = objabi.StackPreempt
125
		p.Reg = REG_R1
126

127
		p = obj.Appendp(p, c.newprog)
128
		q = p
129
		p.As = ABEQ
130
		p.To.Type = obj.TYPE_BRANCH
131

132
		p = obj.Appendp(p, c.newprog)
133
		p.As = AADD
134
		p.From.Type = obj.TYPE_CONST
135
		p.From.Offset = int64(objabi.StackGuard)
136
		p.Reg = REGSP
137
		p.To.Type = obj.TYPE_REG
138
		p.To.Reg = REG_R2
139

140
		p = obj.Appendp(p, c.newprog)
141
		p.As = ASUB
142
		p.From.Type = obj.TYPE_REG
143
		p.From.Reg = REG_R1
144
		p.To.Type = obj.TYPE_REG
145
		p.To.Reg = REG_R2
146

147
		p = obj.Appendp(p, c.newprog)
148
		p.As = AMOVD
149
		p.From.Type = obj.TYPE_CONST
150
		p.From.Offset = int64(framesize) + (int64(objabi.StackGuard) - objabi.StackSmall)
151
		p.To.Type = obj.TYPE_REG
152
		p.To.Reg = REG_R3
153

154
		p = obj.Appendp(p, c.newprog)
155
		p.As = ACMP
156
		p.From.Type = obj.TYPE_REG
157
		p.From.Reg = REG_R3
158
		p.Reg = REG_R2
159
	}
160

161
	// BLS	do-morestack
162
	bls := obj.Appendp(p, c.newprog)
163
	bls.As = ABLS
164
	bls.To.Type = obj.TYPE_BRANCH
165

166
	end := c.ctxt.EndUnsafePoint(bls, c.newprog, -1)
167

168
	var last *obj.Prog
169
	for last = c.cursym.Func.Text; last.Link != nil; last = last.Link {
170
	}
171

172
	// Now we are at the end of the function, but logically
173
	// we are still in function prologue. We need to fix the
174
	// SP data and PCDATA.
175
	spfix := obj.Appendp(last, c.newprog)
176
	spfix.As = obj.ANOP
177
	spfix.Spadj = -framesize
178

179
	pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
180
	pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
181

182
	// MOV	LR, R3
183
	movlr := obj.Appendp(pcdata, c.newprog)
184
	movlr.As = AMOVD
185
	movlr.From.Type = obj.TYPE_REG
186
	movlr.From.Reg = REGLINK
187
	movlr.To.Type = obj.TYPE_REG
188
	movlr.To.Reg = REG_R3
189
	if q != nil {
190
		q.To.SetTarget(movlr)
191
	}
192
	bls.To.SetTarget(movlr)
193

194
	debug := movlr
195
	if false {
196
		debug = obj.Appendp(debug, c.newprog)
197
		debug.As = AMOVD
198
		debug.From.Type = obj.TYPE_CONST
199
		debug.From.Offset = int64(framesize)
200
		debug.To.Type = obj.TYPE_REG
201
		debug.To.Reg = REGTMP
202
	}
203

204
	// BL	runtime.morestack(SB)
205
	call := obj.Appendp(debug, c.newprog)
206
	call.As = ABL
207
	call.To.Type = obj.TYPE_BRANCH
208
	morestack := "runtime.morestack"
209
	switch {
210
	case c.cursym.CFunc():
211
		morestack = "runtime.morestackc"
212
	case !c.cursym.Func.Text.From.Sym.NeedCtxt():
213
		morestack = "runtime.morestack_noctxt"
214
	}
215
	call.To.Sym = c.ctxt.Lookup(morestack)
216

217
	pcdata = c.ctxt.EndUnsafePoint(call, c.newprog, -1)
218

219
	// B	start
220
	jmp := obj.Appendp(pcdata, c.newprog)
221
	jmp.As = AB
222
	jmp.To.Type = obj.TYPE_BRANCH
223
	jmp.To.SetTarget(c.cursym.Func.Text.Link)
224
	jmp.Spadj = +framesize
225

226
	return end
227
}
228

229
func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
230
	c := ctxt7{ctxt: ctxt, newprog: newprog}
231

232
	p.From.Class = 0
233
	p.To.Class = 0
234

235
	// $0 results in C_ZCON, which matches both C_REG and various
236
	// C_xCON, however the C_REG cases in asmout don't expect a
237
	// constant, so they will use the register fields and assemble
238
	// a R0. To prevent that, rewrite $0 as ZR.
239
	if p.From.Type == obj.TYPE_CONST && p.From.Offset == 0 {
240
		p.From.Type = obj.TYPE_REG
241
		p.From.Reg = REGZERO
242
	}
243
	if p.To.Type == obj.TYPE_CONST && p.To.Offset == 0 {
244
		p.To.Type = obj.TYPE_REG
245
		p.To.Reg = REGZERO
246
	}
247

248
	// Rewrite BR/BL to symbol as TYPE_BRANCH.
249
	switch p.As {
250
	case AB,
251
		ABL,
252
		obj.ARET,
253
		obj.ADUFFZERO,
254
		obj.ADUFFCOPY:
255
		if p.To.Sym != nil {
256
			p.To.Type = obj.TYPE_BRANCH
257
		}
258
		break
259
	}
260

261
	// Rewrite float constants to values stored in memory.
262
	switch p.As {
263
	case AFMOVS:
264
		if p.From.Type == obj.TYPE_FCONST {
265
			f64 := p.From.Val.(float64)
266
			f32 := float32(f64)
267
			if c.chipfloat7(f64) > 0 {
268
				break
269
			}
270
			if math.Float32bits(f32) == 0 {
271
				p.From.Type = obj.TYPE_REG
272
				p.From.Reg = REGZERO
273
				break
274
			}
275
			p.From.Type = obj.TYPE_MEM
276
			p.From.Sym = c.ctxt.Float32Sym(f32)
277
			p.From.Name = obj.NAME_EXTERN
278
			p.From.Offset = 0
279
		}
280

281
	case AFMOVD:
282
		if p.From.Type == obj.TYPE_FCONST {
283
			f64 := p.From.Val.(float64)
284
			if c.chipfloat7(f64) > 0 {
285
				break
286
			}
287
			if math.Float64bits(f64) == 0 {
288
				p.From.Type = obj.TYPE_REG
289
				p.From.Reg = REGZERO
290
				break
291
			}
292
			p.From.Type = obj.TYPE_MEM
293
			p.From.Sym = c.ctxt.Float64Sym(f64)
294
			p.From.Name = obj.NAME_EXTERN
295
			p.From.Offset = 0
296
		}
297

298
		break
299
	}
300

301
	// Rewrite negative immediates as positive immediates with
302
	// complementary instruction.
303
	switch p.As {
304
	case AADD, ASUB, ACMP, ACMN:
305
		if p.From.Type == obj.TYPE_CONST && p.From.Offset < 0 && p.From.Offset != -1<<63 {
306
			p.From.Offset = -p.From.Offset
307
			p.As = complements[p.As]
308
		}
309
	case AADDW, ASUBW, ACMPW, ACMNW:
310
		if p.From.Type == obj.TYPE_CONST && p.From.Offset < 0 && int32(p.From.Offset) != -1<<31 {
311
			p.From.Offset = -p.From.Offset
312
			p.As = complements[p.As]
313
		}
314
	}
315

316
	// For 32-bit logical instruction with constant,
317
	// rewrite the high 32-bit to be a repetition of
318
	// the low 32-bit, so that the BITCON test can be
319
	// shared for both 32-bit and 64-bit. 32-bit ops
320
	// will zero the high 32-bit of the destination
321
	// register anyway.
322
	if isANDWop(p.As) && p.From.Type == obj.TYPE_CONST {
323
		v := p.From.Offset & 0xffffffff
324
		p.From.Offset = v | v<<32
325
	}
326

327
	if c.ctxt.Flag_dynlink {
328
		c.rewriteToUseGot(p)
329
	}
330
}
331

332
// Rewrite p, if necessary, to access global data via the global offset table.
333
func (c *ctxt7) rewriteToUseGot(p *obj.Prog) {
334
	if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
335
		//     ADUFFxxx $offset
336
		// becomes
337
		//     MOVD runtime.duffxxx@GOT, REGTMP
338
		//     ADD $offset, REGTMP
339
		//     CALL REGTMP
340
		var sym *obj.LSym
341
		if p.As == obj.ADUFFZERO {
342
			sym = c.ctxt.Lookup("runtime.duffzero")
343
		} else {
344
			sym = c.ctxt.Lookup("runtime.duffcopy")
345
		}
346
		offset := p.To.Offset
347
		p.As = AMOVD
348
		p.From.Type = obj.TYPE_MEM
349
		p.From.Name = obj.NAME_GOTREF
350
		p.From.Sym = sym
351
		p.To.Type = obj.TYPE_REG
352
		p.To.Reg = REGTMP
353
		p.To.Name = obj.NAME_NONE
354
		p.To.Offset = 0
355
		p.To.Sym = nil
356
		p1 := obj.Appendp(p, c.newprog)
357
		p1.As = AADD
358
		p1.From.Type = obj.TYPE_CONST
359
		p1.From.Offset = offset
360
		p1.To.Type = obj.TYPE_REG
361
		p1.To.Reg = REGTMP
362
		p2 := obj.Appendp(p1, c.newprog)
363
		p2.As = obj.ACALL
364
		p2.To.Type = obj.TYPE_REG
365
		p2.To.Reg = REGTMP
366
	}
367

368
	// We only care about global data: NAME_EXTERN means a global
369
	// symbol in the Go sense, and p.Sym.Local is true for a few
370
	// internally defined symbols.
371
	if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
372
		// MOVD $sym, Rx becomes MOVD sym@GOT, Rx
373
		// MOVD $sym+<off>, Rx becomes MOVD sym@GOT, Rx; ADD <off>, Rx
374
		if p.As != AMOVD {
375
			c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
376
		}
377
		if p.To.Type != obj.TYPE_REG {
378
			c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
379
		}
380
		p.From.Type = obj.TYPE_MEM
381
		p.From.Name = obj.NAME_GOTREF
382
		if p.From.Offset != 0 {
383
			q := obj.Appendp(p, c.newprog)
384
			q.As = AADD
385
			q.From.Type = obj.TYPE_CONST
386
			q.From.Offset = p.From.Offset
387
			q.To = p.To
388
			p.From.Offset = 0
389
		}
390
	}
391
	if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
392
		c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
393
	}
394
	var source *obj.Addr
395
	// MOVx sym, Ry becomes MOVD sym@GOT, REGTMP; MOVx (REGTMP), Ry
396
	// MOVx Ry, sym becomes MOVD sym@GOT, REGTMP; MOVD Ry, (REGTMP)
397
	// An addition may be inserted between the two MOVs if there is an offset.
398
	if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
399
		if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
400
			c.ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
401
		}
402
		source = &p.From
403
	} else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
404
		source = &p.To
405
	} else {
406
		return
407
	}
408
	if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
409
		return
410
	}
411
	if source.Sym.Type == objabi.STLSBSS {
412
		return
413
	}
414
	if source.Type != obj.TYPE_MEM {
415
		c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
416
	}
417
	p1 := obj.Appendp(p, c.newprog)
418
	p2 := obj.Appendp(p1, c.newprog)
419
	p1.As = AMOVD
420
	p1.From.Type = obj.TYPE_MEM
421
	p1.From.Sym = source.Sym
422
	p1.From.Name = obj.NAME_GOTREF
423
	p1.To.Type = obj.TYPE_REG
424
	p1.To.Reg = REGTMP
425

426
	p2.As = p.As
427
	p2.From = p.From
428
	p2.To = p.To
429
	if p.From.Name == obj.NAME_EXTERN {
430
		p2.From.Reg = REGTMP
431
		p2.From.Name = obj.NAME_NONE
432
		p2.From.Sym = nil
433
	} else if p.To.Name == obj.NAME_EXTERN {
434
		p2.To.Reg = REGTMP
435
		p2.To.Name = obj.NAME_NONE
436
		p2.To.Sym = nil
437
	} else {
438
		return
439
	}
440
	obj.Nopout(p)
441
}
442

443
func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
444
	if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
445
		return
446
	}
447

448
	c := ctxt7{ctxt: ctxt, newprog: newprog, cursym: cursym}
449

450
	p := c.cursym.Func.Text
451
	textstksiz := p.To.Offset
452
	if textstksiz == -8 {
453
		// Historical way to mark NOFRAME.
454
		p.From.Sym.Set(obj.AttrNoFrame, true)
455
		textstksiz = 0
456
	}
457
	if textstksiz < 0 {
458
		c.ctxt.Diag("negative frame size %d - did you mean NOFRAME?", textstksiz)
459
	}
460
	if p.From.Sym.NoFrame() {
461
		if textstksiz != 0 {
462
			c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
463
		}
464
	}
465

466
	c.cursym.Func.Args = p.To.Val.(int32)
467
	c.cursym.Func.Locals = int32(textstksiz)
468

469
	/*
470
	 * find leaf subroutines
471
	 */
472
	for p := c.cursym.Func.Text; p != nil; p = p.Link {
473
		switch p.As {
474
		case obj.ATEXT:
475
			p.Mark |= LEAF
476

477
		case ABL,
478
			obj.ADUFFZERO,
479
			obj.ADUFFCOPY:
480
			c.cursym.Func.Text.Mark &^= LEAF
481
		}
482
	}
483

484
	var q *obj.Prog
485
	var q1 *obj.Prog
486
	var retjmp *obj.LSym
487
	for p := c.cursym.Func.Text; p != nil; p = p.Link {
488
		o := p.As
489
		switch o {
490
		case obj.ATEXT:
491
			c.cursym.Func.Text = p
492
			c.autosize = int32(textstksiz)
493

494
			if p.Mark&LEAF != 0 && c.autosize == 0 {
495
				// A leaf function with no locals has no frame.
496
				p.From.Sym.Set(obj.AttrNoFrame, true)
497
			}
498

499
			if !p.From.Sym.NoFrame() {
500
				// If there is a stack frame at all, it includes
501
				// space to save the LR.
502
				c.autosize += 8
503
			}
504

505
			if c.autosize != 0 {
506
				extrasize := int32(0)
507
				if c.autosize%16 == 8 {
508
					// Allocate extra 8 bytes on the frame top to save FP
509
					extrasize = 8
510
				} else if c.autosize&(16-1) == 0 {
511
					// Allocate extra 16 bytes to save FP for the old frame whose size is 8 mod 16
512
					extrasize = 16
513
				} else {
514
					c.ctxt.Diag("%v: unaligned frame size %d - must be 16 aligned", p, c.autosize-8)
515
				}
516
				c.autosize += extrasize
517
				c.cursym.Func.Locals += extrasize
518

519
				// low 32 bits for autosize
520
				// high 32 bits for extrasize
521
				p.To.Offset = int64(c.autosize) | int64(extrasize)<<32
522
			} else {
523
				// NOFRAME
524
				p.To.Offset = 0
525
			}
526

527
			if c.autosize == 0 && c.cursym.Func.Text.Mark&LEAF == 0 {
528
				if c.ctxt.Debugvlog {
529
					c.ctxt.Logf("save suppressed in: %s\n", c.cursym.Func.Text.From.Sym.Name)
530
				}
531
				c.cursym.Func.Text.Mark |= LEAF
532
			}
533

534
			if cursym.Func.Text.Mark&LEAF != 0 {
535
				cursym.Set(obj.AttrLeaf, true)
536
				if p.From.Sym.NoFrame() {
537
					break
538
				}
539
			}
540

541
			if !p.From.Sym.NoSplit() {
542
				p = c.stacksplit(p, c.autosize) // emit split check
543
			}
544

545
			var prologueEnd *obj.Prog
546

547
			aoffset := c.autosize
548
			if aoffset > 0xF0 {
549
				aoffset = 0xF0
550
			}
551

552
			// Frame is non-empty. Make sure to save link register, even if
553
			// it is a leaf function, so that traceback works.
554
			q = p
555
			if c.autosize > aoffset {
556
				// Frame size is too large for a MOVD.W instruction.
557
				// Store link register before decrementing SP, so if a signal comes
558
				// during the execution of the function prologue, the traceback
559
				// code will not see a half-updated stack frame.
560
				// This sequence is not async preemptible, as if we open a frame
561
				// at the current SP, it will clobber the saved LR.
562
				q = c.ctxt.StartUnsafePoint(q, c.newprog)
563

564
				q = obj.Appendp(q, c.newprog)
565
				q.Pos = p.Pos
566
				q.As = ASUB
567
				q.From.Type = obj.TYPE_CONST
568
				q.From.Offset = int64(c.autosize)
569
				q.Reg = REGSP
570
				q.To.Type = obj.TYPE_REG
571
				q.To.Reg = REGTMP
572

573
				prologueEnd = q
574

575
				q = obj.Appendp(q, c.newprog)
576
				q.Pos = p.Pos
577
				q.As = AMOVD
578
				q.From.Type = obj.TYPE_REG
579
				q.From.Reg = REGLINK
580
				q.To.Type = obj.TYPE_MEM
581
				q.To.Reg = REGTMP
582

583
				q1 = obj.Appendp(q, c.newprog)
584
				q1.Pos = p.Pos
585
				q1.As = AMOVD
586
				q1.From.Type = obj.TYPE_REG
587
				q1.From.Reg = REGTMP
588
				q1.To.Type = obj.TYPE_REG
589
				q1.To.Reg = REGSP
590
				q1.Spadj = c.autosize
591

592
				if c.ctxt.Headtype == objabi.Hdarwin {
593
					// iOS does not support SA_ONSTACK. We will run the signal handler
594
					// on the G stack. If we write below SP, it may be clobbered by
595
					// the signal handler. So we save LR after decrementing SP.
596
					q1 = obj.Appendp(q1, c.newprog)
597
					q1.Pos = p.Pos
598
					q1.As = AMOVD
599
					q1.From.Type = obj.TYPE_REG
600
					q1.From.Reg = REGLINK
601
					q1.To.Type = obj.TYPE_MEM
602
					q1.To.Reg = REGSP
603
				}
604

605
				q1 = c.ctxt.EndUnsafePoint(q1, c.newprog, -1)
606
			} else {
607
				// small frame, update SP and save LR in a single MOVD.W instruction
608
				q1 = obj.Appendp(q, c.newprog)
609
				q1.As = AMOVD
610
				q1.Pos = p.Pos
611
				q1.From.Type = obj.TYPE_REG
612
				q1.From.Reg = REGLINK
613
				q1.To.Type = obj.TYPE_MEM
614
				q1.Scond = C_XPRE
615
				q1.To.Offset = int64(-aoffset)
616
				q1.To.Reg = REGSP
617
				q1.Spadj = aoffset
618

619
				prologueEnd = q1
620
			}
621

622
			prologueEnd.Pos = prologueEnd.Pos.WithXlogue(src.PosPrologueEnd)
623

624
			if objabi.Framepointer_enabled {
625
				q1 = obj.Appendp(q1, c.newprog)
626
				q1.Pos = p.Pos
627
				q1.As = AMOVD
628
				q1.From.Type = obj.TYPE_REG
629
				q1.From.Reg = REGFP
630
				q1.To.Type = obj.TYPE_MEM
631
				q1.To.Reg = REGSP
632
				q1.To.Offset = -8
633

634
				q1 = obj.Appendp(q1, c.newprog)
635
				q1.Pos = p.Pos
636
				q1.As = ASUB
637
				q1.From.Type = obj.TYPE_CONST
638
				q1.From.Offset = 8
639
				q1.Reg = REGSP
640
				q1.To.Type = obj.TYPE_REG
641
				q1.To.Reg = REGFP
642
			}
643

644
			if c.cursym.Func.Text.From.Sym.Wrapper() {
645
				// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
646
				//
647
				//	MOV  g_panic(g), R1
648
				//	CBNZ checkargp
649
				// end:
650
				//	NOP
651
				// ... function body ...
652
				// checkargp:
653
				//	MOV  panic_argp(R1), R2
654
				//	ADD  $(autosize+8), RSP, R3
655
				//	CMP  R2, R3
656
				//	BNE  end
657
				//	ADD  $8, RSP, R4
658
				//	MOVD R4, panic_argp(R1)
659
				//	B    end
660
				//
661
				// The NOP is needed to give the jumps somewhere to land.
662
				// It is a liblink NOP, not an ARM64 NOP: it encodes to 0 instruction bytes.
663
				q = q1
664

665
				// MOV g_panic(g), R1
666
				q = obj.Appendp(q, c.newprog)
667
				q.As = AMOVD
668
				q.From.Type = obj.TYPE_MEM
669
				q.From.Reg = REGG
670
				q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic
671
				q.To.Type = obj.TYPE_REG
672
				q.To.Reg = REG_R1
673

674
				// CBNZ R1, checkargp
675
				cbnz := obj.Appendp(q, c.newprog)
676
				cbnz.As = ACBNZ
677
				cbnz.From.Type = obj.TYPE_REG
678
				cbnz.From.Reg = REG_R1
679
				cbnz.To.Type = obj.TYPE_BRANCH
680

681
				// Empty branch target at the top of the function body
682
				end := obj.Appendp(cbnz, c.newprog)
683
				end.As = obj.ANOP
684

685
				// find the end of the function
686
				var last *obj.Prog
687
				for last = end; last.Link != nil; last = last.Link {
688
				}
689

690
				// MOV panic_argp(R1), R2
691
				mov := obj.Appendp(last, c.newprog)
692
				mov.As = AMOVD
693
				mov.From.Type = obj.TYPE_MEM
694
				mov.From.Reg = REG_R1
695
				mov.From.Offset = 0 // Panic.argp
696
				mov.To.Type = obj.TYPE_REG
697
				mov.To.Reg = REG_R2
698

699
				// CBNZ branches to the MOV above
700
				cbnz.To.SetTarget(mov)
701

702
				// ADD $(autosize+8), SP, R3
703
				q = obj.Appendp(mov, c.newprog)
704
				q.As = AADD
705
				q.From.Type = obj.TYPE_CONST
706
				q.From.Offset = int64(c.autosize) + 8
707
				q.Reg = REGSP
708
				q.To.Type = obj.TYPE_REG
709
				q.To.Reg = REG_R3
710

711
				// CMP R2, R3
712
				q = obj.Appendp(q, c.newprog)
713
				q.As = ACMP
714
				q.From.Type = obj.TYPE_REG
715
				q.From.Reg = REG_R2
716
				q.Reg = REG_R3
717

718
				// BNE end
719
				q = obj.Appendp(q, c.newprog)
720
				q.As = ABNE
721
				q.To.Type = obj.TYPE_BRANCH
722
				q.To.SetTarget(end)
723

724
				// ADD $8, SP, R4
725
				q = obj.Appendp(q, c.newprog)
726
				q.As = AADD
727
				q.From.Type = obj.TYPE_CONST
728
				q.From.Offset = 8
729
				q.Reg = REGSP
730
				q.To.Type = obj.TYPE_REG
731
				q.To.Reg = REG_R4
732

733
				// MOV R4, panic_argp(R1)
734
				q = obj.Appendp(q, c.newprog)
735
				q.As = AMOVD
736
				q.From.Type = obj.TYPE_REG
737
				q.From.Reg = REG_R4
738
				q.To.Type = obj.TYPE_MEM
739
				q.To.Reg = REG_R1
740
				q.To.Offset = 0 // Panic.argp
741

742
				// B end
743
				q = obj.Appendp(q, c.newprog)
744
				q.As = AB
745
				q.To.Type = obj.TYPE_BRANCH
746
				q.To.SetTarget(end)
747
			}
748

749
		case obj.ARET:
750
			nocache(p)
751
			if p.From.Type == obj.TYPE_CONST {
752
				c.ctxt.Diag("using BECOME (%v) is not supported!", p)
753
				break
754
			}
755

756
			retjmp = p.To.Sym
757
			p.To = obj.Addr{}
758
			if c.cursym.Func.Text.Mark&LEAF != 0 {
759
				if c.autosize != 0 {
760
					p.As = AADD
761
					p.From.Type = obj.TYPE_CONST
762
					p.From.Offset = int64(c.autosize)
763
					p.To.Type = obj.TYPE_REG
764
					p.To.Reg = REGSP
765
					p.Spadj = -c.autosize
766

767
					if objabi.Framepointer_enabled {
768
						p = obj.Appendp(p, c.newprog)
769
						p.As = ASUB
770
						p.From.Type = obj.TYPE_CONST
771
						p.From.Offset = 8
772
						p.Reg = REGSP
773
						p.To.Type = obj.TYPE_REG
774
						p.To.Reg = REGFP
775
					}
776
				}
777
			} else {
778
				/* want write-back pre-indexed SP+autosize -> SP, loading REGLINK*/
779

780
				if objabi.Framepointer_enabled {
781
					p.As = AMOVD
782
					p.From.Type = obj.TYPE_MEM
783
					p.From.Reg = REGSP
784
					p.From.Offset = -8
785
					p.To.Type = obj.TYPE_REG
786
					p.To.Reg = REGFP
787
					p = obj.Appendp(p, c.newprog)
788
				}
789

790
				aoffset := c.autosize
791

792
				if aoffset <= 0xF0 {
793
					p.As = AMOVD
794
					p.From.Type = obj.TYPE_MEM
795
					p.Scond = C_XPOST
796
					p.From.Offset = int64(aoffset)
797
					p.From.Reg = REGSP
798
					p.To.Type = obj.TYPE_REG
799
					p.To.Reg = REGLINK
800
					p.Spadj = -aoffset
801
				} else {
802
					p.As = AMOVD
803
					p.From.Type = obj.TYPE_MEM
804
					p.From.Offset = 0
805
					p.From.Reg = REGSP
806
					p.To.Type = obj.TYPE_REG
807
					p.To.Reg = REGLINK
808

809
					q = newprog()
810
					q.As = AADD
811
					q.From.Type = obj.TYPE_CONST
812
					q.From.Offset = int64(aoffset)
813
					q.To.Type = obj.TYPE_REG
814
					q.To.Reg = REGSP
815
					q.Link = p.Link
816
					q.Spadj = int32(-q.From.Offset)
817
					q.Pos = p.Pos
818
					p.Link = q
819
					p = q
820
				}
821
			}
822

823
			if p.As != obj.ARET {
824
				q = newprog()
825
				q.Pos = p.Pos
826
				q.Link = p.Link
827
				p.Link = q
828
				p = q
829
			}
830

831
			if retjmp != nil { // retjmp
832
				p.As = AB
833
				p.To.Type = obj.TYPE_BRANCH
834
				p.To.Sym = retjmp
835
				p.Spadj = +c.autosize
836
				break
837
			}
838

839
			p.As = obj.ARET
840
			p.To.Type = obj.TYPE_MEM
841
			p.To.Offset = 0
842
			p.To.Reg = REGLINK
843
			p.Spadj = +c.autosize
844

845
		case AADD, ASUB:
846
			if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
847
				if p.As == AADD {
848
					p.Spadj = int32(-p.From.Offset)
849
				} else {
850
					p.Spadj = int32(+p.From.Offset)
851
				}
852
			}
853

854
		case obj.AGETCALLERPC:
855
			if cursym.Leaf() {
856
				/* MOVD LR, Rd */
857
				p.As = AMOVD
858
				p.From.Type = obj.TYPE_REG
859
				p.From.Reg = REGLINK
860
			} else {
861
				/* MOVD (RSP), Rd */
862
				p.As = AMOVD
863
				p.From.Type = obj.TYPE_MEM
864
				p.From.Reg = REGSP
865
			}
866

867
		case obj.ADUFFCOPY:
868
			if objabi.Framepointer_enabled {
869
				//  ADR	ret_addr, R27
870
				//  STP	(FP, R27), -24(SP)
871
				//  SUB	24, SP, FP
872
				//  DUFFCOPY
873
				// ret_addr:
874
				//  SUB	8, SP, FP
875

876
				q1 := p
877
				// copy DUFFCOPY from q1 to q4
878
				q4 := obj.Appendp(p, c.newprog)
879
				q4.Pos = p.Pos
880
				q4.As = obj.ADUFFCOPY
881
				q4.To = p.To
882

883
				q1.As = AADR
884
				q1.From.Type = obj.TYPE_BRANCH
885
				q1.To.Type = obj.TYPE_REG
886
				q1.To.Reg = REG_R27
887

888
				q2 := obj.Appendp(q1, c.newprog)
889
				q2.Pos = p.Pos
890
				q2.As = ASTP
891
				q2.From.Type = obj.TYPE_REGREG
892
				q2.From.Reg = REGFP
893
				q2.From.Offset = int64(REG_R27)
894
				q2.To.Type = obj.TYPE_MEM
895
				q2.To.Reg = REGSP
896
				q2.To.Offset = -24
897

898
				// maintaine FP for DUFFCOPY
899
				q3 := obj.Appendp(q2, c.newprog)
900
				q3.Pos = p.Pos
901
				q3.As = ASUB
902
				q3.From.Type = obj.TYPE_CONST
903
				q3.From.Offset = 24
904
				q3.Reg = REGSP
905
				q3.To.Type = obj.TYPE_REG
906
				q3.To.Reg = REGFP
907

908
				q5 := obj.Appendp(q4, c.newprog)
909
				q5.Pos = p.Pos
910
				q5.As = ASUB
911
				q5.From.Type = obj.TYPE_CONST
912
				q5.From.Offset = 8
913
				q5.Reg = REGSP
914
				q5.To.Type = obj.TYPE_REG
915
				q5.To.Reg = REGFP
916
				q1.From.SetTarget(q5)
917
				p = q5
918
			}
919

920
		case obj.ADUFFZERO:
921
			if objabi.Framepointer_enabled {
922
				//  ADR	ret_addr, R27
923
				//  STP	(FP, R27), -24(SP)
924
				//  SUB	24, SP, FP
925
				//  DUFFZERO
926
				// ret_addr:
927
				//  SUB	8, SP, FP
928

929
				q1 := p
930
				// copy DUFFZERO from q1 to q4
931
				q4 := obj.Appendp(p, c.newprog)
932
				q4.Pos = p.Pos
933
				q4.As = obj.ADUFFZERO
934
				q4.To = p.To
935

936
				q1.As = AADR
937
				q1.From.Type = obj.TYPE_BRANCH
938
				q1.To.Type = obj.TYPE_REG
939
				q1.To.Reg = REG_R27
940

941
				q2 := obj.Appendp(q1, c.newprog)
942
				q2.Pos = p.Pos
943
				q2.As = ASTP
944
				q2.From.Type = obj.TYPE_REGREG
945
				q2.From.Reg = REGFP
946
				q2.From.Offset = int64(REG_R27)
947
				q2.To.Type = obj.TYPE_MEM
948
				q2.To.Reg = REGSP
949
				q2.To.Offset = -24
950

951
				// maintaine FP for DUFFZERO
952
				q3 := obj.Appendp(q2, c.newprog)
953
				q3.Pos = p.Pos
954
				q3.As = ASUB
955
				q3.From.Type = obj.TYPE_CONST
956
				q3.From.Offset = 24
957
				q3.Reg = REGSP
958
				q3.To.Type = obj.TYPE_REG
959
				q3.To.Reg = REGFP
960

961
				q5 := obj.Appendp(q4, c.newprog)
962
				q5.Pos = p.Pos
963
				q5.As = ASUB
964
				q5.From.Type = obj.TYPE_CONST
965
				q5.From.Offset = 8
966
				q5.Reg = REGSP
967
				q5.To.Type = obj.TYPE_REG
968
				q5.To.Reg = REGFP
969
				q1.From.SetTarget(q5)
970
				p = q5
971
			}
972
		}
973
	}
974
}
975

976
func nocache(p *obj.Prog) {
977
	p.Optab = 0
978
	p.From.Class = 0
979
	p.To.Class = 0
980
}
981

982
var unaryDst = map[obj.As]bool{
983
	AWORD:  true,
984
	ADWORD: true,
985
	ABL:    true,
986
	AB:     true,
987
	ACLREX: true,
988
}
989

990
var Linkarm64 = obj.LinkArch{
991
	Arch:           sys.ArchARM64,
992
	Init:           buildop,
993
	Preprocess:     preprocess,
994
	Assemble:       span7,
995
	Progedit:       progedit,
996
	UnaryDst:       unaryDst,
997
	DWARFRegisters: ARM64DWARFRegisters,
998
}
999

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

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

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

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