1
2
3
4
5 package asm
6
7 import (
8 "bytes"
9 "fmt"
10 "strconv"
11 "text/scanner"
12
13 "cmd/asm/internal/arch"
14 "cmd/asm/internal/flags"
15 "cmd/asm/internal/lex"
16 "cmd/internal/obj"
17 "cmd/internal/obj/x86"
18 "cmd/internal/objabi"
19 "cmd/internal/sys"
20 )
21
22
23
24 var testOut *bytes.Buffer
25
26
27
28 func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) {
29 if cond != "" {
30 switch p.arch.Family {
31 case sys.ARM:
32 if !arch.ARMConditionCodes(prog, cond) {
33 p.errorf("unrecognized condition code .%q", cond)
34 return
35 }
36
37 case sys.ARM64:
38 if !arch.ARM64Suffix(prog, cond) {
39 p.errorf("unrecognized suffix .%q", cond)
40 return
41 }
42
43 case sys.AMD64, sys.I386:
44 if err := x86.ParseSuffix(prog, cond); err != nil {
45 p.errorf("%v", err)
46 return
47 }
48
49 default:
50 p.errorf("unrecognized suffix .%q", cond)
51 return
52 }
53 }
54 if p.firstProg == nil {
55 p.firstProg = prog
56 } else {
57 p.lastProg.Link = prog
58 }
59 p.lastProg = prog
60 if doLabel {
61 p.pc++
62 for _, label := range p.pendingLabels {
63 if p.labels[label] != nil {
64 p.errorf("label %q multiply defined", label)
65 return
66 }
67 p.labels[label] = prog
68 }
69 p.pendingLabels = p.pendingLabels[0:0]
70 }
71 prog.Pc = p.pc
72 if *flags.Debug {
73 fmt.Println(p.lineNum, prog)
74 }
75 if testOut != nil {
76 fmt.Fprintln(testOut, prog)
77 }
78 }
79
80
81 func (p *Parser) validSymbol(pseudo string, addr *obj.Addr, offsetOk bool) bool {
82 if addr.Sym == nil || addr.Name != obj.NAME_EXTERN && addr.Name != obj.NAME_STATIC || addr.Scale != 0 || addr.Reg != 0 {
83 p.errorf("%s symbol %q must be a symbol(SB)", pseudo, symbolName(addr))
84 return false
85 }
86 if !offsetOk && addr.Offset != 0 {
87 p.errorf("%s symbol %q must not be offset from SB", pseudo, symbolName(addr))
88 return false
89 }
90 return true
91 }
92
93
94 func (p *Parser) evalInteger(pseudo string, operands []lex.Token) int64 {
95 addr := p.address(operands)
96 return p.getConstantPseudo(pseudo, &addr)
97 }
98
99
100 func (p *Parser) validImmediate(pseudo string, addr *obj.Addr) bool {
101 if addr.Type != obj.TYPE_CONST || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 {
102 p.errorf("%s: expected immediate constant; found %s", pseudo, obj.Dconv(&emptyProg, addr))
103 return false
104 }
105 return true
106 }
107
108
109
110 func (p *Parser) asmText(operands [][]lex.Token) {
111 if len(operands) != 2 && len(operands) != 3 {
112 p.errorf("expect two or three operands for TEXT")
113 return
114 }
115
116
117
118 p.patch()
119 p.labels = make(map[string]*obj.Prog)
120
121
122
123 nameAddr := p.address(operands[0])
124 if !p.validSymbol("TEXT", &nameAddr, false) {
125 return
126 }
127 name := symbolName(&nameAddr)
128 next := 1
129
130
131 var flag = int64(0)
132 if len(operands) == 3 {
133 flag = p.evalInteger("TEXT", operands[1])
134 next++
135 }
136
137
138
139
140
141 if nameAddr.Sym.ABI() == obj.ABIInternal && flag&obj.NOSPLIT == 0 {
142 p.errorf("TEXT %q: ABIInternal requires NOSPLIT", name)
143 }
144
145
146
147
148
149
150
151 op := operands[next]
152 if len(op) < 2 || op[0].ScanToken != '$' {
153 p.errorf("TEXT %s: frame size must be an immediate constant", name)
154 return
155 }
156 op = op[1:]
157 negative := false
158 if op[0].ScanToken == '-' {
159 negative = true
160 op = op[1:]
161 }
162 if len(op) == 0 || op[0].ScanToken != scanner.Int {
163 p.errorf("TEXT %s: frame size must be an immediate constant", name)
164 return
165 }
166 frameSize := p.positiveAtoi(op[0].String())
167 if negative {
168 frameSize = -frameSize
169 }
170 op = op[1:]
171 argSize := int64(objabi.ArgsSizeUnknown)
172 if len(op) > 0 {
173
174 if len(op) != 2 || op[0].ScanToken != '-' || op[1].ScanToken != scanner.Int {
175 p.errorf("TEXT %s: argument size must be of form -integer", name)
176 return
177 }
178 argSize = p.positiveAtoi(op[1].String())
179 }
180 p.ctxt.InitTextSym(nameAddr.Sym, int(flag))
181 prog := &obj.Prog{
182 Ctxt: p.ctxt,
183 As: obj.ATEXT,
184 Pos: p.pos(),
185 From: nameAddr,
186 To: obj.Addr{
187 Type: obj.TYPE_TEXTSIZE,
188 Offset: frameSize,
189
190 },
191 }
192 nameAddr.Sym.Func().Text = prog
193 prog.To.Val = int32(argSize)
194 p.append(prog, "", true)
195 }
196
197
198
199 func (p *Parser) asmData(operands [][]lex.Token) {
200 if len(operands) != 2 {
201 p.errorf("expect two operands for DATA")
202 return
203 }
204
205
206 op := operands[0]
207 n := len(op)
208 if n < 3 || op[n-2].ScanToken != '/' || op[n-1].ScanToken != scanner.Int {
209 p.errorf("expect /size for DATA argument")
210 return
211 }
212 szop := op[n-1].String()
213 sz, err := strconv.Atoi(szop)
214 if err != nil {
215 p.errorf("bad size for DATA argument: %q", szop)
216 }
217 op = op[:n-2]
218 nameAddr := p.address(op)
219 if !p.validSymbol("DATA", &nameAddr, true) {
220 return
221 }
222 name := symbolName(&nameAddr)
223
224
225 valueAddr := p.address(operands[1])
226 switch valueAddr.Type {
227 case obj.TYPE_CONST, obj.TYPE_FCONST, obj.TYPE_SCONST, obj.TYPE_ADDR:
228
229 default:
230 p.errorf("DATA value must be an immediate constant or address")
231 return
232 }
233
234
235 if lastAddr, ok := p.dataAddr[name]; ok && nameAddr.Offset < lastAddr {
236 p.errorf("overlapping DATA entry for %s", name)
237 return
238 }
239 p.dataAddr[name] = nameAddr.Offset + int64(sz)
240
241 switch valueAddr.Type {
242 case obj.TYPE_CONST:
243 switch sz {
244 case 1, 2, 4, 8:
245 nameAddr.Sym.WriteInt(p.ctxt, nameAddr.Offset, int(sz), valueAddr.Offset)
246 default:
247 p.errorf("bad int size for DATA argument: %d", sz)
248 }
249 case obj.TYPE_FCONST:
250 switch sz {
251 case 4:
252 nameAddr.Sym.WriteFloat32(p.ctxt, nameAddr.Offset, float32(valueAddr.Val.(float64)))
253 case 8:
254 nameAddr.Sym.WriteFloat64(p.ctxt, nameAddr.Offset, valueAddr.Val.(float64))
255 default:
256 p.errorf("bad float size for DATA argument: %d", sz)
257 }
258 case obj.TYPE_SCONST:
259 nameAddr.Sym.WriteString(p.ctxt, nameAddr.Offset, int(sz), valueAddr.Val.(string))
260 case obj.TYPE_ADDR:
261 if sz == p.arch.PtrSize {
262 nameAddr.Sym.WriteAddr(p.ctxt, nameAddr.Offset, int(sz), valueAddr.Sym, valueAddr.Offset)
263 } else {
264 p.errorf("bad addr size for DATA argument: %d", sz)
265 }
266 }
267 }
268
269
270
271
272 func (p *Parser) asmGlobl(operands [][]lex.Token) {
273 if len(operands) != 2 && len(operands) != 3 {
274 p.errorf("expect two or three operands for GLOBL")
275 return
276 }
277
278
279 nameAddr := p.address(operands[0])
280 if !p.validSymbol("GLOBL", &nameAddr, false) {
281 return
282 }
283 next := 1
284
285
286 var flag = int64(0)
287 if len(operands) == 3 {
288 flag = p.evalInteger("GLOBL", operands[1])
289 next++
290 }
291
292
293 addr := p.address(operands[next])
294 if !p.validImmediate("GLOBL", &addr) {
295 return
296 }
297
298
299 p.ctxt.Globl(nameAddr.Sym, addr.Offset, int(flag))
300 }
301
302
303
304 func (p *Parser) asmPCData(operands [][]lex.Token) {
305 if len(operands) != 2 {
306 p.errorf("expect two operands for PCDATA")
307 return
308 }
309
310
311 key := p.address(operands[0])
312 if !p.validImmediate("PCDATA", &key) {
313 return
314 }
315
316
317 value := p.address(operands[1])
318 if !p.validImmediate("PCDATA", &value) {
319 return
320 }
321
322
323 prog := &obj.Prog{
324 Ctxt: p.ctxt,
325 As: obj.APCDATA,
326 Pos: p.pos(),
327 From: key,
328 To: value,
329 }
330 p.append(prog, "", true)
331 }
332
333
334
335 func (p *Parser) asmPCAlign(operands [][]lex.Token) {
336 if len(operands) != 1 {
337 p.errorf("expect one operand for PCALIGN")
338 return
339 }
340
341
342 key := p.address(operands[0])
343 if !p.validImmediate("PCALIGN", &key) {
344 return
345 }
346
347 prog := &obj.Prog{
348 Ctxt: p.ctxt,
349 As: obj.APCALIGN,
350 From: key,
351 }
352 p.append(prog, "", true)
353 }
354
355
356
357 func (p *Parser) asmFuncData(operands [][]lex.Token) {
358 if len(operands) != 2 {
359 p.errorf("expect two operands for FUNCDATA")
360 return
361 }
362
363
364 valueAddr := p.address(operands[0])
365 if !p.validImmediate("FUNCDATA", &valueAddr) {
366 return
367 }
368
369
370 nameAddr := p.address(operands[1])
371 if !p.validSymbol("FUNCDATA", &nameAddr, true) {
372 return
373 }
374
375 prog := &obj.Prog{
376 Ctxt: p.ctxt,
377 As: obj.AFUNCDATA,
378 Pos: p.pos(),
379 From: valueAddr,
380 To: nameAddr,
381 }
382 p.append(prog, "", true)
383 }
384
385
386
387
388
389 func (p *Parser) asmJump(op obj.As, cond string, a []obj.Addr) {
390 var target *obj.Addr
391 prog := &obj.Prog{
392 Ctxt: p.ctxt,
393 Pos: p.pos(),
394 As: op,
395 }
396 switch len(a) {
397 case 0:
398 if p.arch.Family == sys.Wasm {
399 target = &obj.Addr{Type: obj.TYPE_NONE}
400 break
401 }
402 p.errorf("wrong number of arguments to %s instruction", op)
403 return
404 case 1:
405 target = &a[0]
406 case 2:
407
408 target = &a[1]
409 prog.From = a[0]
410 case 3:
411 if p.arch.Family == sys.PPC64 {
412
413
414 target = &a[2]
415 prog.From = obj.Addr{
416 Type: obj.TYPE_CONST,
417 Offset: p.getConstant(prog, op, &a[0]),
418 }
419 reg := int16(p.getConstant(prog, op, &a[1]))
420 reg, ok := p.arch.RegisterNumber("R", reg)
421 if !ok {
422 p.errorf("bad register number %d", reg)
423 return
424 }
425 prog.Reg = reg
426 break
427 }
428 if p.arch.Family == sys.MIPS || p.arch.Family == sys.MIPS64 || p.arch.Family == sys.RISCV64 {
429
430
431 target = &a[2]
432 prog.From = a[0]
433 prog.Reg = p.getRegister(prog, op, &a[1])
434 break
435 }
436 if p.arch.Family == sys.S390X {
437
438 target = &a[2]
439 prog.From = a[0]
440 if a[1].Reg != 0 {
441
442 prog.Reg = p.getRegister(prog, op, &a[1])
443 } else {
444
445 prog.SetFrom3(a[1])
446 }
447 break
448 }
449 if p.arch.Family == sys.ARM64 {
450
451
452 if a[0].Type != obj.TYPE_CONST {
453 p.errorf("%s: expected immediate constant; found %s", op, obj.Dconv(prog, &a[0]))
454 return
455 }
456 prog.From = a[0]
457 prog.Reg = p.getRegister(prog, op, &a[1])
458 target = &a[2]
459 break
460 }
461 p.errorf("wrong number of arguments to %s instruction", op)
462 return
463 case 4:
464 if p.arch.Family == sys.S390X {
465
466 prog.From = a[0]
467 prog.Reg = p.getRegister(prog, op, &a[1])
468 prog.SetFrom3(a[2])
469 target = &a[3]
470 break
471 }
472 p.errorf("wrong number of arguments to %s instruction", op)
473 return
474 default:
475 p.errorf("wrong number of arguments to %s instruction", op)
476 return
477 }
478 switch {
479 case target.Type == obj.TYPE_BRANCH:
480
481 prog.To = obj.Addr{
482 Type: obj.TYPE_BRANCH,
483 Offset: p.pc + 1 + target.Offset,
484 }
485 case target.Type == obj.TYPE_REG:
486
487 prog.To = *target
488 case target.Type == obj.TYPE_MEM && (target.Name == obj.NAME_EXTERN || target.Name == obj.NAME_STATIC):
489
490 prog.To = *target
491 case target.Type == obj.TYPE_INDIR && (target.Name == obj.NAME_EXTERN || target.Name == obj.NAME_STATIC):
492
493 prog.To = *target
494 prog.To.Type = obj.TYPE_INDIR
495 case target.Type == obj.TYPE_MEM && target.Reg == 0 && target.Offset == 0:
496
497 if target.Sym == nil {
498
499 return
500 }
501 targetProg := p.labels[target.Sym.Name]
502 if targetProg == nil {
503 p.toPatch = append(p.toPatch, Patch{prog, target.Sym.Name})
504 } else {
505 p.branch(prog, targetProg)
506 }
507 case target.Type == obj.TYPE_MEM && target.Name == obj.NAME_NONE:
508
509 prog.To = *target
510
511 if p.arch.Family == sys.PPC64 && target.Offset == 0 {
512 prog.To.Type = obj.TYPE_REG
513 }
514 case target.Type == obj.TYPE_CONST:
515
516 prog.To = a[0]
517 case target.Type == obj.TYPE_NONE:
518
519 default:
520 p.errorf("cannot assemble jump %+v", target)
521 return
522 }
523
524 p.append(prog, cond, true)
525 }
526
527 func (p *Parser) patch() {
528 for _, patch := range p.toPatch {
529 targetProg := p.labels[patch.label]
530 if targetProg == nil {
531 p.errorf("undefined label %s", patch.label)
532 return
533 }
534 p.branch(patch.prog, targetProg)
535 }
536 p.toPatch = p.toPatch[:0]
537 }
538
539 func (p *Parser) branch(jmp, target *obj.Prog) {
540 jmp.To = obj.Addr{
541 Type: obj.TYPE_BRANCH,
542 Index: 0,
543 }
544 jmp.To.Val = target
545 }
546
547
548
549 func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
550
551 prog := &obj.Prog{
552 Ctxt: p.ctxt,
553 Pos: p.pos(),
554 As: op,
555 }
556 switch len(a) {
557 case 0:
558
559 case 1:
560 if p.arch.UnaryDst[op] || op == obj.ARET || op == obj.AGETCALLERPC {
561
562 prog.To = a[0]
563 } else {
564 prog.From = a[0]
565
566 }
567 if p.arch.Family == sys.PPC64 && arch.IsPPC64NEG(op) {
568
569 prog.To = a[0]
570 prog.From = a[0]
571 break
572 }
573 case 2:
574 if p.arch.Family == sys.ARM {
575 if arch.IsARMCMP(op) {
576 prog.From = a[0]
577 prog.Reg = p.getRegister(prog, op, &a[1])
578 break
579 }
580
581 if arch.IsARMFloatCmp(op) {
582 prog.From = a[0]
583 prog.Reg = p.getRegister(prog, op, &a[1])
584 break
585 }
586 } else if p.arch.Family == sys.ARM64 && arch.IsARM64CMP(op) {
587 prog.From = a[0]
588 prog.Reg = p.getRegister(prog, op, &a[1])
589 break
590 } else if p.arch.Family == sys.MIPS || p.arch.Family == sys.MIPS64 {
591 if arch.IsMIPSCMP(op) || arch.IsMIPSMUL(op) {
592 prog.From = a[0]
593 prog.Reg = p.getRegister(prog, op, &a[1])
594 break
595 }
596 }
597 prog.From = a[0]
598 prog.To = a[1]
599 case 3:
600 switch p.arch.Family {
601 case sys.MIPS, sys.MIPS64:
602 prog.From = a[0]
603 prog.Reg = p.getRegister(prog, op, &a[1])
604 prog.To = a[2]
605 case sys.ARM:
606
607 if arch.IsARMSTREX(op) {
608
612 prog.From = a[1]
613 prog.Reg = p.getRegister(prog, op, &a[0])
614 prog.To = a[2]
615 break
616 }
617 if arch.IsARMBFX(op) {
618
619 prog.From = a[0]
620 prog.SetFrom3(a[1])
621 prog.To = a[2]
622 break
623 }
624
625 prog.From = a[0]
626 prog.Reg = p.getRegister(prog, op, &a[1])
627 prog.To = a[2]
628 case sys.AMD64:
629 prog.From = a[0]
630 prog.SetFrom3(a[1])
631 prog.To = a[2]
632 case sys.ARM64:
633 switch {
634 case arch.IsARM64STLXR(op):
635
636 prog.From = a[0]
637 prog.To = a[1]
638 if a[2].Type != obj.TYPE_REG {
639 p.errorf("invalid addressing modes for third operand to %s instruction, must be register", op)
640 return
641 }
642 prog.RegTo2 = a[2].Reg
643 case arch.IsARM64TBL(op):
644
645 prog.From = a[0]
646 prog.SetFrom3(a[1])
647 prog.To = a[2]
648 case arch.IsARM64CASP(op):
649 prog.From = a[0]
650 prog.To = a[1]
651
652
653 if (a[0].Type != obj.TYPE_REGREG) || (a[2].Type != obj.TYPE_REGREG) {
654 p.errorf("invalid addressing modes for 1st or 3rd operand to %s instruction, must be register pair", op)
655 return
656 }
657
658
659 prog.SetTo2(a[2])
660 default:
661 prog.From = a[0]
662 prog.Reg = p.getRegister(prog, op, &a[1])
663 prog.To = a[2]
664 }
665 case sys.I386:
666 prog.From = a[0]
667 prog.SetFrom3(a[1])
668 prog.To = a[2]
669 case sys.PPC64:
670 if arch.IsPPC64CMP(op) {
671
672 prog.From = a[0]
673 prog.Reg = p.getRegister(prog, op, &a[2])
674 prog.To = a[1]
675 break
676 }
677
678
679
680
681
682 switch a[1].Type {
683 case obj.TYPE_REG:
684 prog.From = a[0]
685 prog.Reg = p.getRegister(prog, op, &a[1])
686 prog.To = a[2]
687 case obj.TYPE_CONST:
688 prog.From = a[0]
689 prog.SetFrom3(a[1])
690 prog.To = a[2]
691 default:
692 p.errorf("invalid addressing modes for %s instruction", op)
693 return
694 }
695 case sys.RISCV64:
696
697 if arch.IsRISCV64AMO(op) {
698 prog.From = a[0]
699 prog.To = a[1]
700 if a[2].Type != obj.TYPE_REG {
701 p.errorf("invalid addressing modes for third operand to %s instruction, must be register", op)
702 return
703 }
704 prog.RegTo2 = a[2].Reg
705 break
706 }
707 prog.From = a[0]
708 prog.Reg = p.getRegister(prog, op, &a[1])
709 prog.To = a[2]
710 case sys.S390X:
711 prog.From = a[0]
712 if a[1].Type == obj.TYPE_REG {
713 prog.Reg = p.getRegister(prog, op, &a[1])
714 } else {
715 prog.SetFrom3(a[1])
716 }
717 prog.To = a[2]
718 default:
719 p.errorf("TODO: implement three-operand instructions for this architecture")
720 return
721 }
722 case 4:
723 if p.arch.Family == sys.ARM {
724 if arch.IsARMBFX(op) {
725
726 prog.From = a[0]
727 prog.SetFrom3(a[1])
728 prog.Reg = p.getRegister(prog, op, &a[2])
729 prog.To = a[3]
730 break
731 }
732 if arch.IsARMMULA(op) {
733
734 p.getRegister(prog, op, &a[0])
735 r1 := p.getRegister(prog, op, &a[1])
736 r2 := p.getRegister(prog, op, &a[2])
737 p.getRegister(prog, op, &a[3])
738 prog.From = a[0]
739 prog.To = a[3]
740 prog.To.Type = obj.TYPE_REGREG2
741 prog.To.Offset = int64(r2)
742 prog.Reg = r1
743 break
744 }
745 }
746 if p.arch.Family == sys.AMD64 {
747 prog.From = a[0]
748 prog.SetRestArgs([]obj.Addr{a[1], a[2]})
749 prog.To = a[3]
750 break
751 }
752 if p.arch.Family == sys.ARM64 {
753 prog.From = a[0]
754 prog.Reg = p.getRegister(prog, op, &a[1])
755 prog.SetFrom3(a[2])
756 prog.To = a[3]
757 break
758 }
759 if p.arch.Family == sys.PPC64 {
760 if arch.IsPPC64RLD(op) {
761 prog.From = a[0]
762 prog.Reg = p.getRegister(prog, op, &a[1])
763 prog.SetFrom3(a[2])
764 prog.To = a[3]
765 break
766 } else if arch.IsPPC64ISEL(op) {
767
768 prog.SetFrom3(a[2])
769 prog.From = a[0]
770 prog.Reg = p.getRegister(prog, op, &a[1])
771 prog.To = a[3]
772 break
773 }
774
775
776
777
778
779 if a[1].Type == obj.TYPE_REG {
780 prog.From = a[0]
781 prog.Reg = p.getRegister(prog, op, &a[1])
782 prog.SetFrom3(a[2])
783 prog.To = a[3]
784 break
785 } else if a[1].Type == obj.TYPE_CONST {
786 prog.From = a[0]
787 prog.Reg = p.getRegister(prog, op, &a[2])
788 prog.SetFrom3(a[1])
789 prog.To = a[3]
790 break
791 } else {
792 p.errorf("invalid addressing modes for %s instruction", op)
793 return
794 }
795 }
796 if p.arch.Family == sys.S390X {
797 if a[1].Type != obj.TYPE_REG {
798 p.errorf("second operand must be a register in %s instruction", op)
799 return
800 }
801 prog.From = a[0]
802 prog.Reg = p.getRegister(prog, op, &a[1])
803 prog.SetFrom3(a[2])
804 prog.To = a[3]
805 break
806 }
807 p.errorf("can't handle %s instruction with 4 operands", op)
808 return
809 case 5:
810 if p.arch.Family == sys.PPC64 {
811 prog.From = a[0]
812
813 prog.Reg = p.getRegister(prog, op, &a[1])
814 prog.SetRestArgs([]obj.Addr{a[2], a[3]})
815 prog.To = a[4]
816 break
817 }
818 if p.arch.Family == sys.AMD64 {
819 prog.From = a[0]
820 prog.SetRestArgs([]obj.Addr{a[1], a[2], a[3]})
821 prog.To = a[4]
822 break
823 }
824 if p.arch.Family == sys.S390X {
825 prog.From = a[0]
826 prog.SetRestArgs([]obj.Addr{a[1], a[2], a[3]})
827 prog.To = a[4]
828 break
829 }
830 p.errorf("can't handle %s instruction with 5 operands", op)
831 return
832 case 6:
833 if p.arch.Family == sys.ARM && arch.IsARMMRC(op) {
834
835 prog.To.Type = obj.TYPE_CONST
836 x0 := p.getConstant(prog, op, &a[0])
837 x1 := p.getConstant(prog, op, &a[1])
838 x2 := int64(p.getRegister(prog, op, &a[2]))
839 x3 := int64(p.getRegister(prog, op, &a[3]))
840 x4 := int64(p.getRegister(prog, op, &a[4]))
841 x5 := p.getConstant(prog, op, &a[5])
842
843 offset, MRC, ok := arch.ARMMRCOffset(op, cond, x0, x1, x2, x3, x4, x5)
844 if !ok {
845 p.errorf("unrecognized condition code .%q", cond)
846 }
847 prog.To.Offset = offset
848 cond = ""
849 prog.As = MRC
850 break
851 }
852 fallthrough
853 default:
854 p.errorf("can't handle %s instruction with %d operands", op, len(a))
855 return
856 }
857
858 p.append(prog, cond, true)
859 }
860
861
862 func newAddr(x obj.Addr) *obj.Addr {
863 p := new(obj.Addr)
864 *p = x
865 return p
866 }
867
868
869 func symbolName(addr *obj.Addr) string {
870 if addr.Sym != nil {
871 return addr.Sym.Name
872 }
873 return "<erroneous symbol>"
874 }
875
876 var emptyProg obj.Prog
877
878
879 func (p *Parser) getConstantPseudo(pseudo string, addr *obj.Addr) int64 {
880 if addr.Type != obj.TYPE_MEM || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 {
881 p.errorf("%s: expected integer constant; found %s", pseudo, obj.Dconv(&emptyProg, addr))
882 }
883 return addr.Offset
884 }
885
886
887 func (p *Parser) getConstant(prog *obj.Prog, op obj.As, addr *obj.Addr) int64 {
888 if addr.Type != obj.TYPE_MEM || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 {
889 p.errorf("%s: expected integer constant; found %s", op, obj.Dconv(prog, addr))
890 }
891 return addr.Offset
892 }
893
894
895 func (p *Parser) getImmediate(prog *obj.Prog, op obj.As, addr *obj.Addr) int64 {
896 if addr.Type != obj.TYPE_CONST || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 {
897 p.errorf("%s: expected immediate constant; found %s", op, obj.Dconv(prog, addr))
898 }
899 return addr.Offset
900 }
901
902
903 func (p *Parser) getRegister(prog *obj.Prog, op obj.As, addr *obj.Addr) int16 {
904 if addr.Type != obj.TYPE_REG || addr.Offset != 0 || addr.Name != 0 || addr.Index != 0 {
905 p.errorf("%s: expected register; found %s", op, obj.Dconv(prog, addr))
906 }
907 return addr.Reg
908 }
909
View as plain text