|  | // Copyright 2014 The Go Authors.  All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package armasm | 
|  |  | 
|  | import ( | 
|  | "bytes" | 
|  | "fmt" | 
|  | "strings" | 
|  | ) | 
|  |  | 
|  | var saveDot = strings.NewReplacer( | 
|  | ".F16", "_dot_F16", | 
|  | ".F32", "_dot_F32", | 
|  | ".F64", "_dot_F64", | 
|  | ".S32", "_dot_S32", | 
|  | ".U32", "_dot_U32", | 
|  | ".FXS", "_dot_S", | 
|  | ".FXU", "_dot_U", | 
|  | ".32", "_dot_32", | 
|  | ) | 
|  |  | 
|  | // GNUSyntax returns the GNU assembler syntax for the instruction, as defined by GNU binutils. | 
|  | // This form typically matches the syntax defined in the ARM Reference Manual. | 
|  | func GNUSyntax(inst Inst) string { | 
|  | var buf bytes.Buffer | 
|  | op := inst.Op.String() | 
|  | op = saveDot.Replace(op) | 
|  | op = strings.Replace(op, ".", "", -1) | 
|  | op = strings.Replace(op, "_dot_", ".", -1) | 
|  | op = strings.ToLower(op) | 
|  | buf.WriteString(op) | 
|  | sep := " " | 
|  | for i, arg := range inst.Args { | 
|  | if arg == nil { | 
|  | break | 
|  | } | 
|  | text := gnuArg(&inst, i, arg) | 
|  | if text == "" { | 
|  | continue | 
|  | } | 
|  | buf.WriteString(sep) | 
|  | sep = ", " | 
|  | buf.WriteString(text) | 
|  | } | 
|  | return buf.String() | 
|  | } | 
|  |  | 
|  | func gnuArg(inst *Inst, argIndex int, arg Arg) string { | 
|  | switch inst.Op &^ 15 { | 
|  | case LDRD_EQ, LDREXD_EQ, STRD_EQ: | 
|  | if argIndex == 1 { | 
|  | // second argument in consecutive pair not printed | 
|  | return "" | 
|  | } | 
|  | case STREXD_EQ: | 
|  | if argIndex == 2 { | 
|  | // second argument in consecutive pair not printed | 
|  | return "" | 
|  | } | 
|  | } | 
|  |  | 
|  | switch arg := arg.(type) { | 
|  | case Imm: | 
|  | switch inst.Op &^ 15 { | 
|  | case BKPT_EQ: | 
|  | return fmt.Sprintf("%#04x", uint32(arg)) | 
|  | case SVC_EQ: | 
|  | return fmt.Sprintf("%#08x", uint32(arg)) | 
|  | } | 
|  | return fmt.Sprintf("#%d", int32(arg)) | 
|  |  | 
|  | case ImmAlt: | 
|  | return fmt.Sprintf("#%d, %d", arg.Val, arg.Rot) | 
|  |  | 
|  | case Mem: | 
|  | R := gnuArg(inst, -1, arg.Base) | 
|  | X := "" | 
|  | if arg.Sign != 0 { | 
|  | X = "" | 
|  | if arg.Sign < 0 { | 
|  | X = "-" | 
|  | } | 
|  | X += gnuArg(inst, -1, arg.Index) | 
|  | if arg.Shift == ShiftLeft && arg.Count == 0 { | 
|  | // nothing | 
|  | } else if arg.Shift == RotateRightExt { | 
|  | X += ", rrx" | 
|  | } else { | 
|  | X += fmt.Sprintf(", %s #%d", strings.ToLower(arg.Shift.String()), arg.Count) | 
|  | } | 
|  | } else { | 
|  | X = fmt.Sprintf("#%d", arg.Offset) | 
|  | } | 
|  |  | 
|  | switch arg.Mode { | 
|  | case AddrOffset: | 
|  | if X == "#0" { | 
|  | return fmt.Sprintf("[%s]", R) | 
|  | } | 
|  | return fmt.Sprintf("[%s, %s]", R, X) | 
|  | case AddrPreIndex: | 
|  | return fmt.Sprintf("[%s, %s]!", R, X) | 
|  | case AddrPostIndex: | 
|  | return fmt.Sprintf("[%s], %s", R, X) | 
|  | case AddrLDM: | 
|  | if X == "#0" { | 
|  | return R | 
|  | } | 
|  | case AddrLDM_WB: | 
|  | if X == "#0" { | 
|  | return R + "!" | 
|  | } | 
|  | } | 
|  | return fmt.Sprintf("[%s Mode(%d) %s]", R, int(arg.Mode), X) | 
|  |  | 
|  | case PCRel: | 
|  | return fmt.Sprintf(".%+#x", int32(arg)+4) | 
|  |  | 
|  | case Reg: | 
|  | switch inst.Op &^ 15 { | 
|  | case LDREX_EQ: | 
|  | if argIndex == 0 { | 
|  | return fmt.Sprintf("r%d", int32(arg)) | 
|  | } | 
|  | } | 
|  | switch arg { | 
|  | case R10: | 
|  | return "sl" | 
|  | case R11: | 
|  | return "fp" | 
|  | case R12: | 
|  | return "ip" | 
|  | } | 
|  |  | 
|  | case RegList: | 
|  | var buf bytes.Buffer | 
|  | fmt.Fprintf(&buf, "{") | 
|  | sep := "" | 
|  | for i := 0; i < 16; i++ { | 
|  | if arg&(1<<uint(i)) != 0 { | 
|  | fmt.Fprintf(&buf, "%s%s", sep, gnuArg(inst, -1, Reg(i))) | 
|  | sep = ", " | 
|  | } | 
|  | } | 
|  | fmt.Fprintf(&buf, "}") | 
|  | return buf.String() | 
|  |  | 
|  | case RegShift: | 
|  | if arg.Shift == ShiftLeft && arg.Count == 0 { | 
|  | return gnuArg(inst, -1, arg.Reg) | 
|  | } | 
|  | if arg.Shift == RotateRightExt { | 
|  | return gnuArg(inst, -1, arg.Reg) + ", rrx" | 
|  | } | 
|  | return fmt.Sprintf("%s, %s #%d", gnuArg(inst, -1, arg.Reg), strings.ToLower(arg.Shift.String()), arg.Count) | 
|  |  | 
|  | case RegShiftReg: | 
|  | return fmt.Sprintf("%s, %s %s", gnuArg(inst, -1, arg.Reg), strings.ToLower(arg.Shift.String()), gnuArg(inst, -1, arg.RegCount)) | 
|  |  | 
|  | } | 
|  | return strings.ToLower(arg.String()) | 
|  | } |