github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/vendor_skip/golang.org/x/arch/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 s, base := symname(uint64(a)); s != "" { 120 suffix := "" 121 if uint64(a) != base { 122 suffix = fmt.Sprintf("%+d", uint64(a)-base) 123 } 124 return fmt.Sprintf("$%s%s(SB)", s, suffix) 125 } 126 if inst.Mode == 32 { 127 return fmt.Sprintf("$%#x", uint32(a)) 128 } 129 if Imm(int32(a)) == a { 130 return fmt.Sprintf("$%#x", int64(a)) 131 } 132 return fmt.Sprintf("$%#x", uint64(a)) 133 case Mem: 134 if s, disp := memArgToSymbol(a, pc, inst.Len, symname); s != "" { 135 suffix := "" 136 if disp != 0 { 137 suffix = fmt.Sprintf("%+d", disp) 138 } 139 return fmt.Sprintf("%s%s(SB)", s, suffix) 140 } 141 s := "" 142 if a.Segment != 0 { 143 s += fmt.Sprintf("%s:", plan9Reg[a.Segment]) 144 } 145 if a.Disp != 0 { 146 s += fmt.Sprintf("%#x", a.Disp) 147 } else { 148 s += "0" 149 } 150 if a.Base != 0 { 151 s += fmt.Sprintf("(%s)", plan9Reg[a.Base]) 152 } 153 if a.Index != 0 && a.Scale != 0 { 154 s += fmt.Sprintf("(%s*%d)", plan9Reg[a.Index], a.Scale) 155 } 156 return s 157 } 158 return arg.String() 159 } 160 161 func memArgToSymbol(a Mem, pc uint64, instrLen int, symname SymLookup) (string, int64) { 162 if a.Segment != 0 || a.Disp == 0 || a.Index != 0 || a.Scale != 0 { 163 return "", 0 164 } 165 166 var disp uint64 167 switch a.Base { 168 case IP, EIP, RIP: 169 disp = uint64(a.Disp + int64(pc) + int64(instrLen)) 170 case 0: 171 disp = uint64(a.Disp) 172 default: 173 return "", 0 174 } 175 176 s, base := symname(disp) 177 return s, int64(disp) - int64(base) 178 } 179 180 var plan9Suffix = [maxOp + 1]bool{ 181 ADC: true, 182 ADD: true, 183 AND: true, 184 BSF: true, 185 BSR: true, 186 BT: true, 187 BTC: true, 188 BTR: true, 189 BTS: true, 190 CMP: true, 191 CMPXCHG: true, 192 CVTSI2SD: true, 193 CVTSI2SS: true, 194 CVTSD2SI: true, 195 CVTSS2SI: true, 196 CVTTSD2SI: true, 197 CVTTSS2SI: true, 198 DEC: true, 199 DIV: true, 200 FLDENV: true, 201 FRSTOR: true, 202 IDIV: true, 203 IMUL: true, 204 IN: true, 205 INC: true, 206 LEA: true, 207 MOV: true, 208 MOVNTI: true, 209 MUL: true, 210 NEG: true, 211 NOP: true, 212 NOT: true, 213 OR: true, 214 OUT: true, 215 POP: true, 216 POPA: true, 217 POPCNT: true, 218 PUSH: true, 219 PUSHA: true, 220 RCL: true, 221 RCR: true, 222 ROL: true, 223 ROR: true, 224 SAR: true, 225 SBB: true, 226 SHL: true, 227 SHLD: true, 228 SHR: true, 229 SHRD: true, 230 SUB: true, 231 TEST: true, 232 XADD: true, 233 XCHG: true, 234 XOR: true, 235 } 236 237 var plan9Reg = [...]string{ 238 AL: "AL", 239 CL: "CL", 240 BL: "BL", 241 DL: "DL", 242 AH: "AH", 243 CH: "CH", 244 BH: "BH", 245 DH: "DH", 246 SPB: "SP", 247 BPB: "BP", 248 SIB: "SI", 249 DIB: "DI", 250 R8B: "R8", 251 R9B: "R9", 252 R10B: "R10", 253 R11B: "R11", 254 R12B: "R12", 255 R13B: "R13", 256 R14B: "R14", 257 R15B: "R15", 258 AX: "AX", 259 CX: "CX", 260 BX: "BX", 261 DX: "DX", 262 SP: "SP", 263 BP: "BP", 264 SI: "SI", 265 DI: "DI", 266 R8W: "R8", 267 R9W: "R9", 268 R10W: "R10", 269 R11W: "R11", 270 R12W: "R12", 271 R13W: "R13", 272 R14W: "R14", 273 R15W: "R15", 274 EAX: "AX", 275 ECX: "CX", 276 EDX: "DX", 277 EBX: "BX", 278 ESP: "SP", 279 EBP: "BP", 280 ESI: "SI", 281 EDI: "DI", 282 R8L: "R8", 283 R9L: "R9", 284 R10L: "R10", 285 R11L: "R11", 286 R12L: "R12", 287 R13L: "R13", 288 R14L: "R14", 289 R15L: "R15", 290 RAX: "AX", 291 RCX: "CX", 292 RDX: "DX", 293 RBX: "BX", 294 RSP: "SP", 295 RBP: "BP", 296 RSI: "SI", 297 RDI: "DI", 298 R8: "R8", 299 R9: "R9", 300 R10: "R10", 301 R11: "R11", 302 R12: "R12", 303 R13: "R13", 304 R14: "R14", 305 R15: "R15", 306 IP: "IP", 307 EIP: "IP", 308 RIP: "IP", 309 F0: "F0", 310 F1: "F1", 311 F2: "F2", 312 F3: "F3", 313 F4: "F4", 314 F5: "F5", 315 F6: "F6", 316 F7: "F7", 317 M0: "M0", 318 M1: "M1", 319 M2: "M2", 320 M3: "M3", 321 M4: "M4", 322 M5: "M5", 323 M6: "M6", 324 M7: "M7", 325 X0: "X0", 326 X1: "X1", 327 X2: "X2", 328 X3: "X3", 329 X4: "X4", 330 X5: "X5", 331 X6: "X6", 332 X7: "X7", 333 X8: "X8", 334 X9: "X9", 335 X10: "X10", 336 X11: "X11", 337 X12: "X12", 338 X13: "X13", 339 X14: "X14", 340 X15: "X15", 341 CS: "CS", 342 SS: "SS", 343 DS: "DS", 344 ES: "ES", 345 FS: "FS", 346 GS: "GS", 347 GDTR: "GDTR", 348 IDTR: "IDTR", 349 LDTR: "LDTR", 350 MSW: "MSW", 351 TASK: "TASK", 352 CR0: "CR0", 353 CR1: "CR1", 354 CR2: "CR2", 355 CR3: "CR3", 356 CR4: "CR4", 357 CR5: "CR5", 358 CR6: "CR6", 359 CR7: "CR7", 360 CR8: "CR8", 361 CR9: "CR9", 362 CR10: "CR10", 363 CR11: "CR11", 364 CR12: "CR12", 365 CR13: "CR13", 366 CR14: "CR14", 367 CR15: "CR15", 368 DR0: "DR0", 369 DR1: "DR1", 370 DR2: "DR2", 371 DR3: "DR3", 372 DR4: "DR4", 373 DR5: "DR5", 374 DR6: "DR6", 375 DR7: "DR7", 376 DR8: "DR8", 377 DR9: "DR9", 378 DR10: "DR10", 379 DR11: "DR11", 380 DR12: "DR12", 381 DR13: "DR13", 382 DR14: "DR14", 383 DR15: "DR15", 384 TR0: "TR0", 385 TR1: "TR1", 386 TR2: "TR2", 387 TR3: "TR3", 388 TR4: "TR4", 389 TR5: "TR5", 390 TR6: "TR6", 391 TR7: "TR7", 392 }