Home | History | Annotate | Download | only in ppc64asm
      1 // Copyright 2015 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 ppc64asm
      6 
      7 import (
      8 	"fmt"
      9 	"strings"
     10 )
     11 
     12 // GoSyntax returns the Go assembler syntax for the instruction.
     13 // The pc is the program counter of the first instruction, used for expanding
     14 // PC-relative addresses into absolute ones.
     15 // The symname function queries the symbol table for the program
     16 // being disassembled. It returns the name and base address of the symbol
     17 // containing the target, if any; otherwise it returns "", 0.
     18 func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64)) string {
     19 	if symname == nil {
     20 		symname = func(uint64) (string, uint64) { return "", 0 }
     21 	}
     22 	if inst.Op == 0 {
     23 		return "?"
     24 	}
     25 	var args []string
     26 	for i, a := range inst.Args[:] {
     27 		if a == nil {
     28 			break
     29 		}
     30 		if s := plan9Arg(&inst, i, pc, a, symname); s != "" {
     31 			args = append(args, s)
     32 		}
     33 	}
     34 	var op string
     35 	op = plan9OpMap[inst.Op]
     36 	if op == "" {
     37 		op = strings.ToUpper(inst.Op.String())
     38 	}
     39 	// laid out the instruction
     40 	switch inst.Op {
     41 	default: // dst, sA, sB, ...
     42 		if len(args) == 0 {
     43 			return op
     44 		} else if len(args) == 1 {
     45 			return fmt.Sprintf("%s %s", op, args[0])
     46 		}
     47 		args = append(args, args[0])
     48 		return op + " " + strings.Join(args[1:], ", ")
     49 	// store instructions always have the memory operand at the end, no need to reorder
     50 	case STB, STBU, STBX, STBUX,
     51 		STH, STHU, STHX, STHUX,
     52 		STW, STWU, STWX, STWUX,
     53 		STD, STDU, STDX, STDUX,
     54 		STQ,
     55 		STHBRX, STWBRX:
     56 		return op + " " + strings.Join(args, ", ")
     57 	// branch instructions needs additional handling
     58 	case BCLR:
     59 		if int(inst.Args[0].(Imm))&20 == 20 { // unconditional
     60 			return "RET"
     61 		}
     62 		return op + " " + strings.Join(args, ", ")
     63 	case BC:
     64 		if int(inst.Args[0].(Imm))&0x1c == 12 { // jump on cond bit set
     65 			return fmt.Sprintf("B%s %s", args[1], args[2])
     66 		} else if int(inst.Args[0].(Imm))&0x1c == 4 && revCondMap[args[1]] != "" { // jump on cond bit not set
     67 			return fmt.Sprintf("B%s %s", revCondMap[args[1]], args[2])
     68 		}
     69 		return op + " " + strings.Join(args, ", ")
     70 	case BCCTR:
     71 		if int(inst.Args[0].(Imm))&20 == 20 { // unconditional
     72 			return "BR (CTR)"
     73 		}
     74 		return op + " " + strings.Join(args, ", ")
     75 	case BCCTRL:
     76 		if int(inst.Args[0].(Imm))&20 == 20 { // unconditional
     77 			return "BL (CTR)"
     78 		}
     79 		return op + " " + strings.Join(args, ", ")
     80 	case BCA, BCL, BCLA, BCLRL, BCTAR, BCTARL:
     81 		return op + " " + strings.Join(args, ", ")
     82 	}
     83 }
     84 
     85 // plan9Arg formats arg (which is the argIndex's arg in inst) according to Plan 9 rules.
     86 // NOTE: because Plan9Syntax is the only caller of this func, and it receives a copy
     87 //       of inst, it's ok to modify inst.Args here.
     88 func plan9Arg(inst *Inst, argIndex int, pc uint64, arg Arg, symname func(uint64) (string, uint64)) string {
     89 	// special cases for load/store instructions
     90 	if _, ok := arg.(Offset); ok {
     91 		if argIndex+1 == len(inst.Args) || inst.Args[argIndex+1] == nil {
     92 			panic(fmt.Errorf("wrong table: offset not followed by register"))
     93 		}
     94 	}
     95 	switch arg := arg.(type) {
     96 	case Reg:
     97 		if isLoadStoreOp(inst.Op) && argIndex == 1 && arg == R0 {
     98 			return "0"
     99 		}
    100 		if arg == R30 {
    101 			return "g"
    102 		}
    103 		return strings.ToUpper(arg.String())
    104 	case CondReg:
    105 		if arg == CR0 && strings.HasPrefix(inst.Op.String(), "cmp") {
    106 			return "" // don't show cr0 for cmp instructions
    107 		} else if arg >= CR0 {
    108 			return fmt.Sprintf("CR%d", int(arg-CR0))
    109 		}
    110 		bit := [4]string{"LT", "GT", "EQ", "SO"}[(arg-Cond0LT)%4]
    111 		if arg <= Cond0SO {
    112 			return bit
    113 		}
    114 		return fmt.Sprintf("4*CR%d+%s", int(arg-Cond0LT)/4, bit)
    115 	case Imm:
    116 		return fmt.Sprintf("$%d", arg)
    117 	case SpReg:
    118 		switch arg {
    119 		case 8:
    120 			return "LR"
    121 		case 9:
    122 			return "CTR"
    123 		}
    124 		return fmt.Sprintf("SPR(%d)", int(arg))
    125 	case PCRel:
    126 		addr := pc + uint64(int64(arg))
    127 		if s, base := symname(addr); s != "" && base == addr {
    128 			return fmt.Sprintf("%s(SB)", s)
    129 		}
    130 		return fmt.Sprintf("%#x", addr)
    131 	case Label:
    132 		return fmt.Sprintf("%#x", int(arg))
    133 	case Offset:
    134 		reg := inst.Args[argIndex+1].(Reg)
    135 		removeArg(inst, argIndex+1)
    136 		if reg == R0 {
    137 			return fmt.Sprintf("%d(0)", int(arg))
    138 		}
    139 		return fmt.Sprintf("%d(R%d)", int(arg), reg-R0)
    140 	}
    141 	return fmt.Sprintf("???(%v)", arg)
    142 }
    143 
    144 // revCondMap maps a conditional register bit to its inverse, if possible.
    145 var revCondMap = map[string]string{
    146 	"LT": "GE", "GT": "LE", "EQ": "NE",
    147 }
    148 
    149 // plan9OpMap maps an Op to its Plan 9 mnemonics, if different than its GNU mnemonics.
    150 var plan9OpMap = map[Op]string{
    151 	LWARX: "LWAR", STWCX_: "STWCCC",
    152 	LDARX: "LDAR", STDCX_: "STDCCC",
    153 	LHARX: "LHAR", STHCX_: "STHCCC",
    154 	LBARX: "LBAR", STBCX_: "STBCCC",
    155 	ADDI: "ADD",
    156 	ADD_: "ADDCC",
    157 	LBZ:  "MOVBZ", STB: "MOVB",
    158 	LBZU: "MOVBZU", STBU: "MOVBU", // TODO(minux): indexed forms are not handled
    159 	LHZ: "MOVHZ", LHA: "MOVH", STH: "MOVH",
    160 	LHZU: "MOVHZU", STHU: "MOVHU",
    161 	LI:  "MOVD",
    162 	LIS: "ADDIS",
    163 	LWZ: "MOVWZ", LWA: "MOVW", STW: "MOVW",
    164 	LWZU: "MOVWZU", STWU: "MOVWU",
    165 	LD: "MOVD", STD: "MOVD",
    166 	LDU: "MOVDU", STDU: "MOVDU",
    167 	MTSPR: "MOVD", MFSPR: "MOVD", // the width is ambiguous for SPRs
    168 	B:     "BR",
    169 	BL:    "CALL",
    170 	CMPLD: "CMPU", CMPLW: "CMPWU",
    171 	CMPD: "CMP", CMPW: "CMPW",
    172 }
    173