github.com/akaros/go-akaros@v0.0.0-20181004170632-85005d477eab/src/cmd/internal/rsc.io/arm/armasm/plan9x.go (about)

     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  	"strings"
    13  )
    14  
    15  // Plan9Syntax returns the Go assembler syntax for the instruction.
    16  // The syntax was originally defined by Plan 9.
    17  // The pc is the program counter of the instruction, used for expanding
    18  // PC-relative addresses into absolute ones.
    19  // The symname function queries the symbol table for the program
    20  // being disassembled. Given a target address it returns the name and base
    21  // address of the symbol containing the target, if any; otherwise it returns "", 0.
    22  // The reader r should read from the text segment using text addresses
    23  // as offsets; it is used to display pc-relative loads as constant loads.
    24  func Plan9Syntax(inst Inst, pc uint64, symname func(uint64) (string, uint64), text io.ReaderAt) string {
    25  	if symname == nil {
    26  		symname = func(uint64) (string, uint64) { return "", 0 }
    27  	}
    28  
    29  	var args []string
    30  	for _, a := range inst.Args {
    31  		if a == nil {
    32  			break
    33  		}
    34  		args = append(args, plan9Arg(&inst, pc, symname, a))
    35  	}
    36  
    37  	op := inst.Op.String()
    38  
    39  	switch inst.Op &^ 15 {
    40  	case LDR_EQ, LDRB_EQ, LDRH_EQ:
    41  		// Check for RET
    42  		reg, _ := inst.Args[0].(Reg)
    43  		mem, _ := inst.Args[1].(Mem)
    44  		if inst.Op&^15 == LDR_EQ && reg == R15 && mem.Base == SP && mem.Sign == 0 && mem.Mode == AddrPostIndex {
    45  			return fmt.Sprintf("RET%s #%d", op[3:], mem.Offset)
    46  		}
    47  
    48  		// Check for PC-relative load.
    49  		if mem.Base == PC && mem.Sign == 0 && mem.Mode == AddrOffset && text != nil {
    50  			addr := uint32(pc) + 8 + uint32(mem.Offset)
    51  			buf := make([]byte, 4)
    52  			switch inst.Op &^ 15 {
    53  			case LDRB_EQ:
    54  				if _, err := text.ReadAt(buf[:1], int64(addr)); err != nil {
    55  					break
    56  				}
    57  				args[1] = fmt.Sprintf("$%#x", buf[0])
    58  
    59  			case LDRH_EQ:
    60  				if _, err := text.ReadAt(buf[:2], int64(addr)); err != nil {
    61  					break
    62  				}
    63  				args[1] = fmt.Sprintf("$%#x", binary.LittleEndian.Uint16(buf))
    64  
    65  			case LDR_EQ:
    66  				if _, err := text.ReadAt(buf, int64(addr)); err != nil {
    67  					break
    68  				}
    69  				x := binary.LittleEndian.Uint32(buf)
    70  				if s, base := symname(uint64(x)); s != "" && uint64(x) == base {
    71  					args[1] = fmt.Sprintf("$%s(SB)", s)
    72  				} else {
    73  					args[1] = fmt.Sprintf("$%#x", x)
    74  				}
    75  			}
    76  		}
    77  	}
    78  
    79  	// Move addressing mode into opcode suffix.
    80  	suffix := ""
    81  	switch inst.Op &^ 15 {
    82  	case LDR_EQ, LDRB_EQ, LDRH_EQ, STR_EQ, STRB_EQ, STRH_EQ:
    83  		mem, _ := inst.Args[1].(Mem)
    84  		switch mem.Mode {
    85  		case AddrOffset, AddrLDM:
    86  			// no suffix
    87  		case AddrPreIndex, AddrLDM_WB:
    88  			suffix = ".W"
    89  		case AddrPostIndex:
    90  			suffix = ".P"
    91  		}
    92  		off := ""
    93  		if mem.Offset != 0 {
    94  			off = fmt.Sprintf("%#x", mem.Offset)
    95  		}
    96  		base := fmt.Sprintf("(R%d)", int(mem.Base))
    97  		index := ""
    98  		if mem.Sign != 0 {
    99  			sign := ""
   100  			if mem.Sign < 0 {
   101  				sign = ""
   102  			}
   103  			shift := ""
   104  			if mem.Count != 0 {
   105  				shift = fmt.Sprintf("%s%d", plan9Shift[mem.Shift], mem.Count)
   106  			}
   107  			index = fmt.Sprintf("(%sR%d%s)", sign, int(mem.Index), shift)
   108  		}
   109  		args[1] = off + base + index
   110  	}
   111  
   112  	// Reverse args, placing dest last.
   113  	for i, j := 0, len(args)-1; i < j; i, j = i+1, j-1 {
   114  		args[i], args[j] = args[j], args[i]
   115  	}
   116  
   117  	switch inst.Op &^ 15 {
   118  	case MOV_EQ:
   119  		op = "MOVW" + op[3:]
   120  
   121  	case LDR_EQ:
   122  		op = "MOVW" + op[3:] + suffix
   123  	case LDRB_EQ:
   124  		op = "MOVB" + op[4:] + suffix
   125  	case LDRH_EQ:
   126  		op = "MOVH" + op[4:] + suffix
   127  
   128  	case STR_EQ:
   129  		op = "MOVW" + op[3:] + suffix
   130  		args[0], args[1] = args[1], args[0]
   131  	case STRB_EQ:
   132  		op = "MOVB" + op[4:] + suffix
   133  		args[0], args[1] = args[1], args[0]
   134  	case STRH_EQ:
   135  		op = "MOVH" + op[4:] + suffix
   136  		args[0], args[1] = args[1], args[0]
   137  	}
   138  
   139  	if args != nil {
   140  		op += " " + strings.Join(args, ", ")
   141  	}
   142  
   143  	return op
   144  }
   145  
   146  // assembler syntax for the various shifts.
   147  // @x> is a lie; the assembler uses @> 0
   148  // instead of @x> 1, but i wanted to be clear that it
   149  // was a different operation (rotate right extended, not rotate right).
   150  var plan9Shift = []string{"<<", ">>", "->", "@>", "@x>"}
   151  
   152  func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string {
   153  	switch a := arg.(type) {
   154  	case Endian:
   155  
   156  	case Imm:
   157  		return fmt.Sprintf("$%d", int(a))
   158  
   159  	case Mem:
   160  
   161  	case PCRel:
   162  		addr := uint32(pc) + 8 + uint32(a)
   163  		if s, base := symname(uint64(addr)); s != "" && uint64(addr) == base {
   164  			return fmt.Sprintf("%s(SB)", s)
   165  		}
   166  		return fmt.Sprintf("%#x", addr)
   167  
   168  	case Reg:
   169  		if a < 16 {
   170  			return fmt.Sprintf("R%d", int(a))
   171  		}
   172  
   173  	case RegList:
   174  		var buf bytes.Buffer
   175  		start := -2
   176  		end := -2
   177  		fmt.Fprintf(&buf, "[")
   178  		flush := func() {
   179  			if start >= 0 {
   180  				if buf.Len() > 1 {
   181  					fmt.Fprintf(&buf, ",")
   182  				}
   183  				if start == end {
   184  					fmt.Fprintf(&buf, "R%d", start)
   185  				} else {
   186  					fmt.Fprintf(&buf, "R%d-R%d", start, end)
   187  				}
   188  			}
   189  		}
   190  		for i := 0; i < 16; i++ {
   191  			if a&(1<<uint(i)) != 0 {
   192  				if i == end+1 {
   193  					end++
   194  					continue
   195  				}
   196  				start = i
   197  				end = i
   198  			}
   199  		}
   200  		flush()
   201  		fmt.Fprintf(&buf, "]")
   202  		return buf.String()
   203  
   204  	case RegShift:
   205  		return fmt.Sprintf("R%d%s$%d", int(a.Reg), plan9Shift[a.Shift], int(a.Count))
   206  
   207  	case RegShiftReg:
   208  		return fmt.Sprintf("R%d%sR%d", int(a.Reg), plan9Shift[a.Shift], int(a.RegCount))
   209  	}
   210  	return strings.ToUpper(arg.String())
   211  }