plan9x.go 7.7 KB

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