golang.org/x/arch@v0.17.0/x86/x86asm/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 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 inst.Op == CMP { 87 // Use reads-left-to-right ordering for comparisons. 88 // See issue 60920. 89 args[0], args[1] = args[1], args[0] 90 } 91 92 if args != nil { 93 op += " " + strings.Join(args, ", ") 94 } 95 96 return rep + prefix + op 97 } 98 99 func plan9Arg(inst *Inst, pc uint64, symname func(uint64) (string, uint64), arg Arg) string { 100 switch a := arg.(type) { 101 case Reg: 102 return plan9Reg[a] 103 case Rel: 104 if pc == 0 { 105 break 106 } 107 // If the absolute address is the start of a symbol, use the name. 108 // Otherwise use the raw address, so that things like relative 109 // jumps show up as JMP 0x123 instead of JMP f+10(SB). 110 // It is usually easier to search for 0x123 than to do the mental 111 // arithmetic to find f+10. 112 addr := pc + uint64(inst.Len) + uint64(a) 113 if s, base := symname(addr); s != "" && addr == base { 114 return fmt.Sprintf("%s(SB)", s) 115 } 116 return fmt.Sprintf("%#x", addr) 117 118 case Imm: 119 if (inst.Op == MOV || inst.Op == PUSH) && inst.DataSize == 32 { 120 // Only try to convert an immediate to a symbol in certain 121 // special circumstances. See issue 72942. 122 // 123 // On 64-bit, symbol addresses always hit the Mem case below. 124 // Particularly, we use LEAQ to materialize the address of 125 // a global or function. 126 // 127 // On 32-bit, we sometimes use MOVL. Still try to symbolize 128 // those immediates. 129 if s, base := symname(uint64(a)); s != "" { 130 suffix := "" 131 if uint64(a) != base { 132 suffix = fmt.Sprintf("%+d", uint64(a)-base) 133 } 134 return fmt.Sprintf("$%s%s(SB)", s, suffix) 135 } 136 } 137 if inst.Mode == 32 { 138 return fmt.Sprintf("$%#x", uint32(a)) 139 } 140 if Imm(int32(a)) == a { 141 return fmt.Sprintf("$%#x", int64(a)) 142 } 143 return fmt.Sprintf("$%#x", uint64(a)) 144 case Mem: 145 if s, disp := memArgToSymbol(a, pc, inst.Len, symname); s != "" { 146 suffix := "" 147 if disp != 0 { 148 suffix = fmt.Sprintf("%+d", disp) 149 } 150 return fmt.Sprintf("%s%s(SB)", s, suffix) 151 } 152 s := "" 153 if a.Segment != 0 { 154 s += fmt.Sprintf("%s:", plan9Reg[a.Segment]) 155 } 156 if a.Disp != 0 { 157 s += fmt.Sprintf("%#x", a.Disp) 158 } else { 159 s += "0" 160 } 161 if a.Base != 0 { 162 s += fmt.Sprintf("(%s)", plan9Reg[a.Base]) 163 } 164 if a.Index != 0 && a.Scale != 0 { 165 s += fmt.Sprintf("(%s*%d)", plan9Reg[a.Index], a.Scale) 166 } 167 return s 168 } 169 return arg.String() 170 } 171 172 func memArgToSymbol(a Mem, pc uint64, instrLen int, symname SymLookup) (string, int64) { 173 if a.Segment != 0 || a.Disp == 0 || a.Index != 0 || a.Scale != 0 { 174 return "", 0 175 } 176 177 var disp uint64 178 switch a.Base { 179 case IP, EIP, RIP: 180 disp = uint64(a.Disp + int64(pc) + int64(instrLen)) 181 case 0: 182 disp = uint64(a.Disp) 183 default: 184 return "", 0 185 } 186 187 s, base := symname(disp) 188 return s, int64(disp) - int64(base) 189 } 190 191 var plan9Suffix = [maxOp + 1]bool{ 192 ADC: true, 193 ADD: true, 194 AND: true, 195 BSF: true, 196 BSR: true, 197 BT: true, 198 BTC: true, 199 BTR: true, 200 BTS: true, 201 CMP: true, 202 CMPXCHG: true, 203 CVTSI2SD: true, 204 CVTSI2SS: true, 205 CVTSD2SI: true, 206 CVTSS2SI: true, 207 CVTTSD2SI: true, 208 CVTTSS2SI: true, 209 DEC: true, 210 DIV: true, 211 FLDENV: true, 212 FRSTOR: true, 213 IDIV: true, 214 IMUL: true, 215 IN: true, 216 INC: true, 217 LEA: true, 218 MOV: true, 219 MOVNTI: true, 220 MUL: true, 221 NEG: true, 222 NOP: true, 223 NOT: true, 224 OR: true, 225 OUT: true, 226 POP: true, 227 POPA: true, 228 POPCNT: true, 229 PUSH: true, 230 PUSHA: true, 231 RCL: true, 232 RCR: true, 233 ROL: true, 234 ROR: true, 235 SAR: true, 236 SBB: true, 237 SHL: true, 238 SHLD: true, 239 SHR: true, 240 SHRD: true, 241 SUB: true, 242 TEST: true, 243 XADD: true, 244 XCHG: true, 245 XOR: true, 246 } 247 248 var plan9Reg = [...]string{ 249 AL: "AL", 250 CL: "CL", 251 BL: "BL", 252 DL: "DL", 253 AH: "AH", 254 CH: "CH", 255 BH: "BH", 256 DH: "DH", 257 SPB: "SP", 258 BPB: "BP", 259 SIB: "SI", 260 DIB: "DI", 261 R8B: "R8", 262 R9B: "R9", 263 R10B: "R10", 264 R11B: "R11", 265 R12B: "R12", 266 R13B: "R13", 267 R14B: "R14", 268 R15B: "R15", 269 AX: "AX", 270 CX: "CX", 271 BX: "BX", 272 DX: "DX", 273 SP: "SP", 274 BP: "BP", 275 SI: "SI", 276 DI: "DI", 277 R8W: "R8", 278 R9W: "R9", 279 R10W: "R10", 280 R11W: "R11", 281 R12W: "R12", 282 R13W: "R13", 283 R14W: "R14", 284 R15W: "R15", 285 EAX: "AX", 286 ECX: "CX", 287 EDX: "DX", 288 EBX: "BX", 289 ESP: "SP", 290 EBP: "BP", 291 ESI: "SI", 292 EDI: "DI", 293 R8L: "R8", 294 R9L: "R9", 295 R10L: "R10", 296 R11L: "R11", 297 R12L: "R12", 298 R13L: "R13", 299 R14L: "R14", 300 R15L: "R15", 301 RAX: "AX", 302 RCX: "CX", 303 RDX: "DX", 304 RBX: "BX", 305 RSP: "SP", 306 RBP: "BP", 307 RSI: "SI", 308 RDI: "DI", 309 R8: "R8", 310 R9: "R9", 311 R10: "R10", 312 R11: "R11", 313 R12: "R12", 314 R13: "R13", 315 R14: "R14", 316 R15: "R15", 317 IP: "IP", 318 EIP: "IP", 319 RIP: "IP", 320 F0: "F0", 321 F1: "F1", 322 F2: "F2", 323 F3: "F3", 324 F4: "F4", 325 F5: "F5", 326 F6: "F6", 327 F7: "F7", 328 M0: "M0", 329 M1: "M1", 330 M2: "M2", 331 M3: "M3", 332 M4: "M4", 333 M5: "M5", 334 M6: "M6", 335 M7: "M7", 336 X0: "X0", 337 X1: "X1", 338 X2: "X2", 339 X3: "X3", 340 X4: "X4", 341 X5: "X5", 342 X6: "X6", 343 X7: "X7", 344 X8: "X8", 345 X9: "X9", 346 X10: "X10", 347 X11: "X11", 348 X12: "X12", 349 X13: "X13", 350 X14: "X14", 351 X15: "X15", 352 CS: "CS", 353 SS: "SS", 354 DS: "DS", 355 ES: "ES", 356 FS: "FS", 357 GS: "GS", 358 GDTR: "GDTR", 359 IDTR: "IDTR", 360 LDTR: "LDTR", 361 MSW: "MSW", 362 TASK: "TASK", 363 CR0: "CR0", 364 CR1: "CR1", 365 CR2: "CR2", 366 CR3: "CR3", 367 CR4: "CR4", 368 CR5: "CR5", 369 CR6: "CR6", 370 CR7: "CR7", 371 CR8: "CR8", 372 CR9: "CR9", 373 CR10: "CR10", 374 CR11: "CR11", 375 CR12: "CR12", 376 CR13: "CR13", 377 CR14: "CR14", 378 CR15: "CR15", 379 DR0: "DR0", 380 DR1: "DR1", 381 DR2: "DR2", 382 DR3: "DR3", 383 DR4: "DR4", 384 DR5: "DR5", 385 DR6: "DR6", 386 DR7: "DR7", 387 DR8: "DR8", 388 DR9: "DR9", 389 DR10: "DR10", 390 DR11: "DR11", 391 DR12: "DR12", 392 DR13: "DR13", 393 DR14: "DR14", 394 DR15: "DR15", 395 TR0: "TR0", 396 TR1: "TR1", 397 TR2: "TR2", 398 TR3: "TR3", 399 TR4: "TR4", 400 TR5: "TR5", 401 TR6: "TR6", 402 TR7: "TR7", 403 }