Home | History | Annotate | Download | only in armasm
      1 // Copyright 2014 The Go Authors.  All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package armasm
      6 
      7 import (
      8 	"bytes"
      9 	"fmt"
     10 	"strings"
     11 )
     12 
     13 var saveDot = strings.NewReplacer(
     14 	".F16", "_dot_F16",
     15 	".F32", "_dot_F32",
     16 	".F64", "_dot_F64",
     17 	".S32", "_dot_S32",
     18 	".U32", "_dot_U32",
     19 	".FXS", "_dot_S",
     20 	".FXU", "_dot_U",
     21 	".32", "_dot_32",
     22 )
     23 
     24 // GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils.
     25 // This form typically matches the syntax defined in the ARM Reference Manual.
     26 func GNUSyntax(inst Inst) string {
     27 	var buf bytes.Buffer
     28 	op := inst.Op.String()
     29 	op = saveDot.Replace(op)
     30 	op = strings.Replace(op, ".", "", -1)
     31 	op = strings.Replace(op, "_dot_", ".", -1)
     32 	op = strings.ToLower(op)
     33 	buf.WriteString(op)
     34 	sep := " "
     35 	for i, arg := range inst.Args {
     36 		if arg == nil {
     37 			break
     38 		}
     39 		text := gnuArg(&inst, i, arg)
     40 		if text == "" {
     41 			continue
     42 		}
     43 		buf.WriteString(sep)
     44 		sep = ", "
     45 		buf.WriteString(text)
     46 	}
     47 	return buf.String()
     48 }
     49 
     50 func gnuArg(inst *Inst, argIndex int, arg Arg) string {
     51 	switch inst.Op &^ 15 {
     52 	case LDRD_EQ, LDREXD_EQ, STRD_EQ:
     53 		if argIndex == 1 {
     54 			// second argument in consecutive pair not printed
     55 			return ""
     56 		}
     57 	case STREXD_EQ:
     58 		if argIndex == 2 {
     59 			// second argument in consecutive pair not printed
     60 			return ""
     61 		}
     62 	}
     63 
     64 	switch arg := arg.(type) {
     65 	case Imm:
     66 		switch inst.Op &^ 15 {
     67 		case BKPT_EQ:
     68 			return fmt.Sprintf("%#04x", uint32(arg))
     69 		case SVC_EQ:
     70 			return fmt.Sprintf("%#08x", uint32(arg))
     71 		}
     72 		return fmt.Sprintf("#%d", int32(arg))
     73 
     74 	case ImmAlt:
     75 		return fmt.Sprintf("#%d, %d", arg.Val, arg.Rot)
     76 
     77 	case Mem:
     78 		R := gnuArg(inst, -1, arg.Base)
     79 		X := ""
     80 		if arg.Sign != 0 {
     81 			X = ""
     82 			if arg.Sign < 0 {
     83 				X = "-"
     84 			}
     85 			X += gnuArg(inst, -1, arg.Index)
     86 			if arg.Shift == ShiftLeft && arg.Count == 0 {
     87 				// nothing
     88 			} else if arg.Shift == RotateRightExt {
     89 				X += ", rrx"
     90 			} else {
     91 				X += fmt.Sprintf(", %s #%d", strings.ToLower(arg.Shift.String()), arg.Count)
     92 			}
     93 		} else {
     94 			X = fmt.Sprintf("#%d", arg.Offset)
     95 		}
     96 
     97 		switch arg.Mode {
     98 		case AddrOffset:
     99 			if X == "#0" {
    100 				return fmt.Sprintf("[%s]", R)
    101 			}
    102 			return fmt.Sprintf("[%s, %s]", R, X)
    103 		case AddrPreIndex:
    104 			return fmt.Sprintf("[%s, %s]!", R, X)
    105 		case AddrPostIndex:
    106 			return fmt.Sprintf("[%s], %s", R, X)
    107 		case AddrLDM:
    108 			if X == "#0" {
    109 				return R
    110 			}
    111 		case AddrLDM_WB:
    112 			if X == "#0" {
    113 				return R + "!"
    114 			}
    115 		}
    116 		return fmt.Sprintf("[%s Mode(%d) %s]", R, int(arg.Mode), X)
    117 
    118 	case PCRel:
    119 		return fmt.Sprintf(".%+#x", int32(arg)+4)
    120 
    121 	case Reg:
    122 		switch inst.Op &^ 15 {
    123 		case LDREX_EQ:
    124 			if argIndex == 0 {
    125 				return fmt.Sprintf("r%d", int32(arg))
    126 			}
    127 		}
    128 		switch arg {
    129 		case R10:
    130 			return "sl"
    131 		case R11:
    132 			return "fp"
    133 		case R12:
    134 			return "ip"
    135 		}
    136 
    137 	case RegList:
    138 		var buf bytes.Buffer
    139 		fmt.Fprintf(&buf, "{")
    140 		sep := ""
    141 		for i := 0; i < 16; i++ {
    142 			if arg&(1<<uint(i)) != 0 {
    143 				fmt.Fprintf(&buf, "%s%s", sep, gnuArg(inst, -1, Reg(i)))
    144 				sep = ", "
    145 			}
    146 		}
    147 		fmt.Fprintf(&buf, "}")
    148 		return buf.String()
    149 
    150 	case RegShift:
    151 		if arg.Shift == ShiftLeft && arg.Count == 0 {
    152 			return gnuArg(inst, -1, arg.Reg)
    153 		}
    154 		if arg.Shift == RotateRightExt {
    155 			return gnuArg(inst, -1, arg.Reg) + ", rrx"
    156 		}
    157 		return fmt.Sprintf("%s, %s #%d", gnuArg(inst, -1, arg.Reg), strings.ToLower(arg.Shift.String()), arg.Count)
    158 
    159 	case RegShiftReg:
    160 		return fmt.Sprintf("%s, %s %s", gnuArg(inst, -1, arg.Reg), strings.ToLower(arg.Shift.String()), gnuArg(inst, -1, arg.RegCount))
    161 
    162 	}
    163 	return strings.ToLower(arg.String())
    164 }
    165