plan9x.go (7267B)
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 x86asm 6 7 import ( 8 "fmt" 9 "strings" 10 ) 11 12 type SymLookup func(uint64) (string, uint64) 13 14 // GoSyntax returns the Go assembler syntax for the instruction. 15 // The syntax was originally defined by Plan 9. 16 // The pc is the program counter of the instruction, used for expanding 17 // PC-relative addresses into absolute ones. 18 // The symname function queries the symbol table for the program 19 // being disassembled. Given a target address it returns the name and base 20 // address of the symbol containing the target, if any; otherwise it returns "", 0. 21 func GoSyntax(inst Inst, pc uint64, symname SymLookup) string { 22 if symname == nil { 23 symname = func(uint64) (string, uint64) { return "", 0 } 24 } 25 var args []string 26 for i := len(inst.Args) - 1; i >= 0; i-- { 27 a := inst.Args[i] 28 if a == nil { 29 continue 30 } 31 args = append(args, plan9Arg(&inst, pc, symname, a)) 32 } 33 34 var rep string 35 var last Prefix 36 for _, p := range inst.Prefix { 37 if p == 0 || p.IsREX() || p.IsVEX() { 38 break 39 } 40 41 switch { 42 // Don't show prefixes implied by the instruction text. 43 case p&0xFF00 == PrefixImplicit: 44 continue 45 // Only REP and REPN are recognized repeaters. Plan 9 syntax 46 // treats them as separate opcodes. 47 case p&0xFF == PrefixREP: 48 rep = "REP; " 49 case p&0xFF == PrefixREPN: 50 rep = "REPNE; " 51 default: 52 last = p 53 } 54 } 55 56 prefix := "" 57 switch last & 0xFF { 58 case 0, 0x66, 0x67: 59 // ignore 60 default: 61 prefix += last.String() + " " 62 } 63 64 op := inst.Op.String() 65 if plan9Suffix[inst.Op] { 66 s := inst.DataSize 67 if inst.MemBytes != 0 { 68 s = inst.MemBytes * 8 69 } else if inst.Args[1] == nil { // look for register-only 64-bit instruction, like PUSHQ AX 70 if r, ok := inst.Args[0].(Reg); ok && RAX <= r && r <= R15 { 71 s = 64 72 } 73 } 74 switch s { 75 case 8: 76 op += "B" 77 case 16: 78 op += "W" 79 case 32: 80 op += "L" 81 case 64: 82 op += "Q" 83 } 84 } 85 86 if args != nil { 87 op += " " + strings.Join(args, ", ") 88 } 89 90 return rep + prefix + op 91 } 92 93 func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string { 94 switch a := arg.(type) { 95 case Reg: 96 return plan9Reg[a] 97 case Rel: 98 if pc == 0 { 99 break 100 } 101 // If the absolute address is the start of a symbol, use the name. 102 // Otherwise use the raw address, so that things like relative 103 // jumps show up as JMP 0x123 instead of JMP f+10(SB). 104 // It is usually easier to search for 0x123 than to do the mental 105 // arithmetic to find f+10. 106 addr := pc + uint64(inst.Len) + uint64(a) 107 if s, base := symname(addr); s != "" && addr == base { 108 return fmt.Sprintf("%s(SB)", s) 109 } 110 return fmt.Sprintf("%#x", addr) 111 112 case Imm: 113 if s, base := symname(uint64(a)); s != "" { 114 suffix := "" 115 if uint64(a) != base { 116 suffix = fmt.Sprintf("%+d", uint64(a)-base) 117 } 118 return fmt.Sprintf("$%s%s(SB)", s, suffix) 119 } 120 if inst.Mode == 32 { 121 return fmt.Sprintf("$%#x", uint32(a)) 122 } 123 if Imm(int32(a)) == a { 124 return fmt.Sprintf("$%#x", int64(a)) 125 } 126 return fmt.Sprintf("$%#x", uint64(a)) 127 case Mem: 128 if s, disp := memArgToSymbol(a, pc, inst.Len, symname); s != "" { 129 suffix := "" 130 if disp != 0 { 131 suffix = fmt.Sprintf("%+d", disp) 132 } 133 return fmt.Sprintf("%s%s(SB)", s, suffix) 134 } 135 s := "" 136 if a.Segment != 0 { 137 s += fmt.Sprintf("%s:", plan9Reg[a.Segment]) 138 } 139 if a.Disp != 0 { 140 s += fmt.Sprintf("%#x", a.Disp) 141 } else { 142 s += "0" 143 } 144 if a.Base != 0 { 145 s += fmt.Sprintf("(%s)", plan9Reg[a.Base]) 146 } 147 if a.Index != 0 && a.Scale != 0 { 148 s += fmt.Sprintf("(%s*%d)", plan9Reg[a.Index], a.Scale) 149 } 150 return s 151 } 152 return arg.String() 153 } 154 155 func memArgToSymbol(a Mem, pc uint64, instrLen int, symname SymLookup) (string, int64) { 156 if a.Segment != 0 || a.Disp == 0 || a.Index != 0 || a.Scale != 0 { 157 return "", 0 158 } 159 160 var disp uint64 161 switch a.Base { 162 case IP, EIP, RIP: 163 disp = uint64(a.Disp + int64(pc) + int64(instrLen)) 164 case 0: 165 disp = uint64(a.Disp) 166 default: 167 return "", 0 168 } 169 170 s, base := symname(disp) 171 return s, int64(disp) - int64(base) 172 } 173 174 var plan9Suffix = [maxOp + 1]bool{ 175 ADC: true, 176 ADD: true, 177 AND: true, 178 BSF: true, 179 BSR: true, 180 BT: true, 181 BTC: true, 182 BTR: true, 183 BTS: true, 184 CMP: true, 185 CMPXCHG: true, 186 CVTSI2SD: true, 187 CVTSI2SS: true, 188 CVTSD2SI: true, 189 CVTSS2SI: true, 190 CVTTSD2SI: true, 191 CVTTSS2SI: true, 192 DEC: true, 193 DIV: true, 194 FLDENV: true, 195 FRSTOR: true, 196 IDIV: true, 197 IMUL: true, 198 IN: true, 199 INC: true, 200 LEA: true, 201 MOV: true, 202 MOVNTI: true, 203 MUL: true, 204 NEG: true, 205 NOP: true, 206 NOT: true, 207 OR: true, 208 OUT: true, 209 POP: true, 210 POPA: true, 211 POPCNT: true, 212 PUSH: true, 213 PUSHA: true, 214 RCL: true, 215 RCR: true, 216 ROL: true, 217 ROR: true, 218 SAR: true, 219 SBB: true, 220 SHL: true, 221 SHLD: true, 222 SHR: true, 223 SHRD: true, 224 SUB: true, 225 TEST: true, 226 XADD: true, 227 XCHG: true, 228 XOR: true, 229 } 230 231 var plan9Reg = [...]string{ 232 AL: "AL", 233 CL: "CL", 234 BL: "BL", 235 DL: "DL", 236 AH: "AH", 237 CH: "CH", 238 BH: "BH", 239 DH: "DH", 240 SPB: "SP", 241 BPB: "BP", 242 SIB: "SI", 243 DIB: "DI", 244 R8B: "R8", 245 R9B: "R9", 246 R10B: "R10", 247 R11B: "R11", 248 R12B: "R12", 249 R13B: "R13", 250 R14B: "R14", 251 R15B: "R15", 252 AX: "AX", 253 CX: "CX", 254 BX: "BX", 255 DX: "DX", 256 SP: "SP", 257 BP: "BP", 258 SI: "SI", 259 DI: "DI", 260 R8W: "R8", 261 R9W: "R9", 262 R10W: "R10", 263 R11W: "R11", 264 R12W: "R12", 265 R13W: "R13", 266 R14W: "R14", 267 R15W: "R15", 268 EAX: "AX", 269 ECX: "CX", 270 EDX: "DX", 271 EBX: "BX", 272 ESP: "SP", 273 EBP: "BP", 274 ESI: "SI", 275 EDI: "DI", 276 R8L: "R8", 277 R9L: "R9", 278 R10L: "R10", 279 R11L: "R11", 280 R12L: "R12", 281 R13L: "R13", 282 R14L: "R14", 283 R15L: "R15", 284 RAX: "AX", 285 RCX: "CX", 286 RDX: "DX", 287 RBX: "BX", 288 RSP: "SP", 289 RBP: "BP", 290 RSI: "SI", 291 RDI: "DI", 292 R8: "R8", 293 R9: "R9", 294 R10: "R10", 295 R11: "R11", 296 R12: "R12", 297 R13: "R13", 298 R14: "R14", 299 R15: "R15", 300 IP: "IP", 301 EIP: "IP", 302 RIP: "IP", 303 F0: "F0", 304 F1: "F1", 305 F2: "F2", 306 F3: "F3", 307 F4: "F4", 308 F5: "F5", 309 F6: "F6", 310 F7: "F7", 311 M0: "M0", 312 M1: "M1", 313 M2: "M2", 314 M3: "M3", 315 M4: "M4", 316 M5: "M5", 317 M6: "M6", 318 M7: "M7", 319 X0: "X0", 320 X1: "X1", 321 X2: "X2", 322 X3: "X3", 323 X4: "X4", 324 X5: "X5", 325 X6: "X6", 326 X7: "X7", 327 X8: "X8", 328 X9: "X9", 329 X10: "X10", 330 X11: "X11", 331 X12: "X12", 332 X13: "X13", 333 X14: "X14", 334 X15: "X15", 335 CS: "CS", 336 SS: "SS", 337 DS: "DS", 338 ES: "ES", 339 FS: "FS", 340 GS: "GS", 341 GDTR: "GDTR", 342 IDTR: "IDTR", 343 LDTR: "LDTR", 344 MSW: "MSW", 345 TASK: "TASK", 346 CR0: "CR0", 347 CR1: "CR1", 348 CR2: "CR2", 349 CR3: "CR3", 350 CR4: "CR4", 351 CR5: "CR5", 352 CR6: "CR6", 353 CR7: "CR7", 354 CR8: "CR8", 355 CR9: "CR9", 356 CR10: "CR10", 357 CR11: "CR11", 358 CR12: "CR12", 359 CR13: "CR13", 360 CR14: "CR14", 361 CR15: "CR15", 362 DR0: "DR0", 363 DR1: "DR1", 364 DR2: "DR2", 365 DR3: "DR3", 366 DR4: "DR4", 367 DR5: "DR5", 368 DR6: "DR6", 369 DR7: "DR7", 370 DR8: "DR8", 371 DR9: "DR9", 372 DR10: "DR10", 373 DR11: "DR11", 374 DR12: "DR12", 375 DR13: "DR13", 376 DR14: "DR14", 377 DR15: "DR15", 378 TR0: "TR0", 379 TR1: "TR1", 380 TR2: "TR2", 381 TR3: "TR3", 382 TR4: "TR4", 383 TR5: "TR5", 384 TR6: "TR6", 385 TR7: "TR7", 386 }