github.com/bir3/gocompiler@v0.3.205/src/xvendor/golang.org/x/arch/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 "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 }