...

Source file src/cmd/vendor/golang.org/x/arch/arm/armasm/plan9x.go

     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		"encoding/binary"
    10		"fmt"
    11		"io"
    12		"math"
    13		"strings"
    14	)
    15	
    16	// GoSyntax returns the Go assembler syntax for the instruction.
    17	// The syntax was originally defined by Plan 9.
    18	// The pc is the program counter of the instruction, used for expanding
    19	// PC-relative addresses into absolute ones.
    20	// The symname function queries the symbol table for the program
    21	// being disassembled. Given a target address it returns the name and base
    22	// address of the symbol containing the target, if any; otherwise it returns "", 0.
    23	// The reader r should read from the text segment using text addresses
    24	// as offsets; it is used to display pc-relative loads as constant loads.
    25	func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text io.ReaderAt) string {
    26		if symname == nil {
    27			symname = func(uint64) (string, uint64) { return "", 0 }
    28		}
    29	
    30		var args []string
    31		for _, a := range inst.Args {
    32			if a == nil {
    33				break
    34			}
    35			args = append(args, plan9Arg(&inst, pc, symname, a))
    36		}
    37	
    38		op := inst.Op.String()
    39	
    40		switch inst.Op &^ 15 {
    41		case LDR_EQ, LDRB_EQ, LDRH_EQ, LDRSB_EQ, LDRSH_EQ, VLDR_EQ:
    42			// Check for RET
    43			reg, _ := inst.Args[0].(Reg)
    44			mem, _ := inst.Args[1].(Mem)
    45			if inst.Op&^15 == LDR_EQ && reg == R15 && mem.Base == SP && mem.Sign == 0 && mem.Mode == AddrPostIndex {
    46				return fmt.Sprintf("RET%s #%d", op[3:], mem.Offset)
    47			}
    48	
    49			// Check for PC-relative load.
    50			if mem.Base == PC && mem.Sign == 0 && mem.Mode == AddrOffset && text != nil {
    51				addr := uint32(pc) + 8 + uint32(mem.Offset)
    52				buf := make([]byte, 8)
    53				switch inst.Op &^ 15 {
    54				case LDRB_EQ, LDRSB_EQ:
    55					if _, err := text.ReadAt(buf[:1], int64(addr)); err != nil {
    56						break
    57					}
    58					args[1] = fmt.Sprintf("$%#x", buf[0])
    59	
    60				case LDRH_EQ, LDRSH_EQ:
    61					if _, err := text.ReadAt(buf[:2], int64(addr)); err != nil {
    62						break
    63					}
    64					args[1] = fmt.Sprintf("$%#x", binary.LittleEndian.Uint16(buf))
    65	
    66				case LDR_EQ:
    67					if _, err := text.ReadAt(buf[:4], int64(addr)); err != nil {
    68						break
    69					}
    70					x := binary.LittleEndian.Uint32(buf)
    71					if s, base := symname(uint64(x)); s != "" && uint64(x) == base {
    72						args[1] = fmt.Sprintf("$%s(SB)", s)
    73					} else {
    74						args[1] = fmt.Sprintf("$%#x", x)
    75					}
    76	
    77				case VLDR_EQ:
    78					switch {
    79					case strings.HasPrefix(args[0], "D"): // VLDR.F64
    80						if _, err := text.ReadAt(buf, int64(addr)); err != nil {
    81							break
    82						}
    83						args[1] = fmt.Sprintf("$%f", math.Float64frombits(binary.LittleEndian.Uint64(buf)))
    84					case strings.HasPrefix(args[0], "S"): // VLDR.F32
    85						if _, err := text.ReadAt(buf[:4], int64(addr)); err != nil {
    86							break
    87						}
    88						args[1] = fmt.Sprintf("$%f", math.Float32frombits(binary.LittleEndian.Uint32(buf)))
    89					default:
    90						panic(fmt.Sprintf("wrong FP register: %v", inst))
    91					}
    92				}
    93			}
    94		}
    95	
    96		// Move addressing mode into opcode suffix.
    97		suffix := ""
    98		switch inst.Op &^ 15 {
    99		case PLD, PLI, PLD_W:
   100			if mem, ok := inst.Args[0].(Mem); ok {
   101				args[0], suffix = memOpTrans(mem)
   102			} else {
   103				panic(fmt.Sprintf("illegal instruction: %v", inst))
   104			}
   105		case LDR_EQ, LDRB_EQ, LDRSB_EQ, LDRH_EQ, LDRSH_EQ, STR_EQ, STRB_EQ, STRH_EQ, VLDR_EQ, VSTR_EQ, LDREX_EQ, LDREXH_EQ, LDREXB_EQ:
   106			if mem, ok := inst.Args[1].(Mem); ok {
   107				args[1], suffix = memOpTrans(mem)
   108			} else {
   109				panic(fmt.Sprintf("illegal instruction: %v", inst))
   110			}
   111		case SWP_EQ, SWP_B_EQ, STREX_EQ, STREXB_EQ, STREXH_EQ:
   112			if mem, ok := inst.Args[2].(Mem); ok {
   113				args[2], suffix = memOpTrans(mem)
   114			} else {
   115				panic(fmt.Sprintf("illegal instruction: %v", inst))
   116			}
   117		}
   118	
   119		// Reverse args, placing dest last.
   120		for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
   121			args[i], args[j] = args[j], args[i]
   122		}
   123		// For MLA-like instructions, the addend is the third operand.
   124		switch inst.Op &^ 15 {
   125		case SMLAWT_EQ, SMLAWB_EQ, MLA_EQ, MLA_S_EQ, MLS_EQ, SMMLA_EQ, SMMLS_EQ, SMLABB_EQ, SMLATB_EQ, SMLABT_EQ, SMLATT_EQ, SMLAD_EQ, SMLAD_X_EQ, SMLSD_EQ, SMLSD_X_EQ:
   126			args = []string{args[1], args[2], args[0], args[3]}
   127		}
   128		// For STREX like instructions, the memory operands comes first.
   129		switch inst.Op &^ 15 {
   130		case STREX_EQ, STREXB_EQ, STREXH_EQ, SWP_EQ, SWP_B_EQ:
   131			args = []string{args[1], args[0], args[2]}
   132		}
   133	
   134		// special process for FP instructions
   135		op, args = fpTrans(&inst, op, args)
   136	
   137		// LDR/STR like instructions -> MOV like
   138		switch inst.Op &^ 15 {
   139		case MOV_EQ:
   140			op = "MOVW" + op[3:]
   141		case LDR_EQ, MSR_EQ, MRS_EQ:
   142			op = "MOVW" + op[3:] + suffix
   143		case VMRS_EQ, VMSR_EQ:
   144			op = "MOVW" + op[4:] + suffix
   145		case LDRB_EQ, UXTB_EQ:
   146			op = "MOVBU" + op[4:] + suffix
   147		case LDRSB_EQ:
   148			op = "MOVBS" + op[5:] + suffix
   149		case SXTB_EQ:
   150			op = "MOVBS" + op[4:] + suffix
   151		case LDRH_EQ, UXTH_EQ:
   152			op = "MOVHU" + op[4:] + suffix
   153		case LDRSH_EQ:
   154			op = "MOVHS" + op[5:] + suffix
   155		case SXTH_EQ:
   156			op = "MOVHS" + op[4:] + suffix
   157		case STR_EQ:
   158			op = "MOVW" + op[3:] + suffix
   159			args[0], args[1] = args[1], args[0]
   160		case STRB_EQ:
   161			op = "MOVB" + op[4:] + suffix
   162			args[0], args[1] = args[1], args[0]
   163		case STRH_EQ:
   164			op = "MOVH" + op[4:] + suffix
   165			args[0], args[1] = args[1], args[0]
   166		case VSTR_EQ:
   167			args[0], args[1] = args[1], args[0]
   168		default:
   169			op = op + suffix
   170		}
   171	
   172		if args != nil {
   173			op += " " + strings.Join(args, ", ")
   174		}
   175	
   176		return op
   177	}
   178	
   179	// assembler syntax for the various shifts.
   180	// @x> is a lie; the assembler uses @> 0
   181	// instead of @x> 1, but i wanted to be clear that it
   182	// was a different operation (rotate right extended, not rotate right).
   183	var plan9Shift = []string{"<<", ">>", "->", "@>", "@x>"}
   184	
   185	func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string {
   186		switch a := arg.(type) {
   187		case Endian:
   188	
   189		case Imm:
   190			return fmt.Sprintf("$%d", uint32(a))
   191	
   192		case Mem:
   193	
   194		case PCRel:
   195			addr := uint32(pc) + 8 + uint32(a)
   196			if s, base := symname(uint64(addr)); s != "" && uint64(addr) == base {
   197				return fmt.Sprintf("%s(SB)", s)
   198			}
   199			return fmt.Sprintf("%#x", addr)
   200	
   201		case Reg:
   202			if a < 16 {
   203				return fmt.Sprintf("R%d", int(a))
   204			}
   205	
   206		case RegList:
   207			var buf bytes.Buffer
   208			start := -2
   209			end := -2
   210			fmt.Fprintf(&buf, "[")
   211			flush := func() {
   212				if start >= 0 {
   213					if buf.Len() > 1 {
   214						fmt.Fprintf(&buf, ",")
   215					}
   216					if start == end {
   217						fmt.Fprintf(&buf, "R%d", start)
   218					} else {
   219						fmt.Fprintf(&buf, "R%d-R%d", start, end)
   220					}
   221					start = -2
   222					end = -2
   223				}
   224			}
   225			for i := 0; i < 16; i++ {
   226				if a&(1<<uint(i)) != 0 {
   227					if i == end+1 {
   228						end++
   229						continue
   230					}
   231					start = i
   232					end = i
   233				} else {
   234					flush()
   235				}
   236			}
   237			flush()
   238			fmt.Fprintf(&buf, "]")
   239			return buf.String()
   240	
   241		case RegShift:
   242			return fmt.Sprintf("R%d%s$%d", int(a.Reg), plan9Shift[a.Shift], int(a.Count))
   243	
   244		case RegShiftReg:
   245			return fmt.Sprintf("R%d%sR%d", int(a.Reg), plan9Shift[a.Shift], int(a.RegCount))
   246		}
   247		return strings.ToUpper(arg.String())
   248	}
   249	
   250	// convert memory operand from GNU syntax to Plan 9 syntax, for example,
   251	// [r5] -> (R5)
   252	// [r6, #4080] -> 0xff0(R6)
   253	// [r2, r0, ror #1] -> (R2)(R0@>1)
   254	// inst [r2, -r0, ror #1] -> INST.U (R2)(R0@>1)
   255	// input:
   256	//   a memory operand
   257	// return values:
   258	//   corresponding memory operand in Plan 9 syntax
   259	//   .W/.P/.U suffix
   260	func memOpTrans(mem Mem) (string, string) {
   261		suffix := ""
   262		switch mem.Mode {
   263		case AddrOffset, AddrLDM:
   264			// no suffix
   265		case AddrPreIndex, AddrLDM_WB:
   266			suffix = ".W"
   267		case AddrPostIndex:
   268			suffix = ".P"
   269		}
   270		off := ""
   271		if mem.Offset != 0 {
   272			off = fmt.Sprintf("%#x", mem.Offset)
   273		}
   274		base := fmt.Sprintf("(R%d)", int(mem.Base))
   275		index := ""
   276		if mem.Sign != 0 {
   277			sign := ""
   278			if mem.Sign < 0 {
   279				suffix += ".U"
   280			}
   281			shift := ""
   282			if mem.Count != 0 {
   283				shift = fmt.Sprintf("%s%d", plan9Shift[mem.Shift], mem.Count)
   284			}
   285			index = fmt.Sprintf("(%sR%d%s)", sign, int(mem.Index), shift)
   286		}
   287		return off + base + index, suffix
   288	}
   289	
   290	type goFPInfo struct {
   291		op        Op
   292		transArgs []int  // indexes of arguments which need transformation
   293		gnuName   string // instruction name in GNU syntax
   294		goName    string // instruction name in Plan 9 syntax
   295	}
   296	
   297	var fpInst []goFPInfo = []goFPInfo{
   298		{VADD_EQ_F32, []int{2, 1, 0}, "VADD", "ADDF"},
   299		{VADD_EQ_F64, []int{2, 1, 0}, "VADD", "ADDD"},
   300		{VSUB_EQ_F32, []int{2, 1, 0}, "VSUB", "SUBF"},
   301		{VSUB_EQ_F64, []int{2, 1, 0}, "VSUB", "SUBD"},
   302		{VMUL_EQ_F32, []int{2, 1, 0}, "VMUL", "MULF"},
   303		{VMUL_EQ_F64, []int{2, 1, 0}, "VMUL", "MULD"},
   304		{VNMUL_EQ_F32, []int{2, 1, 0}, "VNMUL", "NMULF"},
   305		{VNMUL_EQ_F64, []int{2, 1, 0}, "VNMUL", "NMULD"},
   306		{VMLA_EQ_F32, []int{2, 1, 0}, "VMLA", "MULAF"},
   307		{VMLA_EQ_F64, []int{2, 1, 0}, "VMLA", "MULAD"},
   308		{VMLS_EQ_F32, []int{2, 1, 0}, "VMLS", "MULSF"},
   309		{VMLS_EQ_F64, []int{2, 1, 0}, "VMLS", "MULSD"},
   310		{VNMLA_EQ_F32, []int{2, 1, 0}, "VNMLA", "NMULAF"},
   311		{VNMLA_EQ_F64, []int{2, 1, 0}, "VNMLA", "NMULAD"},
   312		{VNMLS_EQ_F32, []int{2, 1, 0}, "VNMLS", "NMULSF"},
   313		{VNMLS_EQ_F64, []int{2, 1, 0}, "VNMLS", "NMULSD"},
   314		{VDIV_EQ_F32, []int{2, 1, 0}, "VDIV", "DIVF"},
   315		{VDIV_EQ_F64, []int{2, 1, 0}, "VDIV", "DIVD"},
   316		{VNEG_EQ_F32, []int{1, 0}, "VNEG", "NEGF"},
   317		{VNEG_EQ_F64, []int{1, 0}, "VNEG", "NEGD"},
   318		{VABS_EQ_F32, []int{1, 0}, "VABS", "ABSF"},
   319		{VABS_EQ_F64, []int{1, 0}, "VABS", "ABSD"},
   320		{VSQRT_EQ_F32, []int{1, 0}, "VSQRT", "SQRTF"},
   321		{VSQRT_EQ_F64, []int{1, 0}, "VSQRT", "SQRTD"},
   322		{VCMP_EQ_F32, []int{1, 0}, "VCMP", "CMPF"},
   323		{VCMP_EQ_F64, []int{1, 0}, "VCMP", "CMPD"},
   324		{VCMP_E_EQ_F32, []int{1, 0}, "VCMP.E", "CMPF"},
   325		{VCMP_E_EQ_F64, []int{1, 0}, "VCMP.E", "CMPD"},
   326		{VLDR_EQ, []int{1}, "VLDR", "MOV"},
   327		{VSTR_EQ, []int{1}, "VSTR", "MOV"},
   328		{VMOV_EQ_F32, []int{1, 0}, "VMOV", "MOVF"},
   329		{VMOV_EQ_F64, []int{1, 0}, "VMOV", "MOVD"},
   330		{VMOV_EQ_32, []int{1, 0}, "VMOV", "MOVW"},
   331		{VMOV_EQ, []int{1, 0}, "VMOV", "MOVW"},
   332		{VCVT_EQ_F64_F32, []int{1, 0}, "VCVT", "MOVFD"},
   333		{VCVT_EQ_F32_F64, []int{1, 0}, "VCVT", "MOVDF"},
   334		{VCVT_EQ_F32_U32, []int{1, 0}, "VCVT", "MOVWF.U"},
   335		{VCVT_EQ_F32_S32, []int{1, 0}, "VCVT", "MOVWF"},
   336		{VCVT_EQ_S32_F32, []int{1, 0}, "VCVT", "MOVFW"},
   337		{VCVT_EQ_U32_F32, []int{1, 0}, "VCVT", "MOVFW.U"},
   338		{VCVT_EQ_F64_U32, []int{1, 0}, "VCVT", "MOVWD.U"},
   339		{VCVT_EQ_F64_S32, []int{1, 0}, "VCVT", "MOVWD"},
   340		{VCVT_EQ_S32_F64, []int{1, 0}, "VCVT", "MOVDW"},
   341		{VCVT_EQ_U32_F64, []int{1, 0}, "VCVT", "MOVDW.U"},
   342	}
   343	
   344	// convert FP instructions from GNU syntax to Plan 9 syntax, for example,
   345	// vadd.f32 s0, s3, s4 -> ADDF F0, S3, F2
   346	// vsub.f64 d0, d2, d4 -> SUBD F0, F2, F4
   347	// vldr s2, [r11] -> MOVF (R11), F1
   348	// inputs: instruction name and arguments in GNU syntax
   349	// return values: corresponding instruction name and arguments in Plan 9 syntax
   350	func fpTrans(inst *Inst, op string, args []string) (string, []string) {
   351		for _, fp := range fpInst {
   352			if inst.Op&^15 == fp.op {
   353				// remove gnu syntax suffixes
   354				op = strings.Replace(op, ".F32", "", -1)
   355				op = strings.Replace(op, ".F64", "", -1)
   356				op = strings.Replace(op, ".S32", "", -1)
   357				op = strings.Replace(op, ".U32", "", -1)
   358				op = strings.Replace(op, ".32", "", -1)
   359				// compose op name
   360				if fp.op == VLDR_EQ || fp.op == VSTR_EQ {
   361					switch {
   362					case strings.HasPrefix(args[fp.transArgs[0]], "D"):
   363						op = "MOVD" + op[len(fp.gnuName):]
   364					case strings.HasPrefix(args[fp.transArgs[0]], "S"):
   365						op = "MOVF" + op[len(fp.gnuName):]
   366					default:
   367						panic(fmt.Sprintf("wrong FP register: %v", inst))
   368					}
   369				} else {
   370					op = fp.goName + op[len(fp.gnuName):]
   371				}
   372				// transform registers
   373				for ix, ri := range fp.transArgs {
   374					switch {
   375					case strings.HasSuffix(args[ri], "[1]"): // MOVW Rx, Dy[1]
   376						break
   377					case strings.HasSuffix(args[ri], "[0]"): // Dx[0] -> Fx
   378						args[ri] = strings.Replace(args[ri], "[0]", "", -1)
   379						fallthrough
   380					case strings.HasPrefix(args[ri], "D"): // Dx -> Fx
   381						args[ri] = "F" + args[ri][1:]
   382					case strings.HasPrefix(args[ri], "S"):
   383						if inst.Args[ix].(Reg)&1 == 0 { // Sx -> Fy, y = x/2, if x is even
   384							args[ri] = fmt.Sprintf("F%d", (inst.Args[ix].(Reg)-S0)/2)
   385						}
   386					case strings.HasPrefix(args[ri], "$"): // CMPF/CMPD $0, Fx
   387						break
   388					case strings.HasPrefix(args[ri], "R"): // MOVW Rx, Dy[1]
   389						break
   390					default:
   391						panic(fmt.Sprintf("wrong FP register: %v", inst))
   392					}
   393				}
   394				break
   395			}
   396		}
   397		return op, args
   398	}
   399	

View as plain text