create_tests.js 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228
  1. #!/usr/bin/env node
  2. "use strict";
  3. // http://ref.x86asm.net/coder32.html
  4. // TODO
  5. // - lea (and all modrm/sib addressing modes)
  6. // - fix style (single quote, brace position)
  7. // - multiple random tests
  8. // - 16 bit
  9. // - describe which registers are written and read
  10. // - string instructions (initialise ds, esi, es, edi)
  11. const fs = require("fs");
  12. const zf = 1 << 6;
  13. const of = 1 << 11;
  14. const cf = 1 << 0;
  15. const af = 1 << 4;
  16. const pf = 1 << 2;
  17. const sf = 1 << 7;
  18. // os: the instruction behaves differently depending on the operand size
  19. // The following instructions are special and not properly described in this table
  20. // - C8 enter: Has an extra immediate byte after the described immediate
  21. // - EA jump / 9A callf: Have an extra immediate word after the described immediate
  22. const encodings = [
  23. { opcode: 0x06, os: 1, skip: 1, },
  24. { opcode: 0x07, os: 1, skip: 1, },
  25. { opcode: 0x0E, os: 1, skip: 1, },
  26. { opcode: 0x0F, os: 1, prefix: 1, },
  27. { opcode: 0x16, os: 1, skip: 1, },
  28. { opcode: 0x17, os: 1, skip: 1, },
  29. { opcode: 0x1E, os: 1, skip: 1, },
  30. { opcode: 0x1F, os: 1, skip: 1, },
  31. { opcode: 0x26, prefix: 1, },
  32. { opcode: 0x27, mask_flags: of, },
  33. { opcode: 0x2E, prefix: 1, },
  34. { opcode: 0x2F, mask_flags: of, },
  35. { opcode: 0x36, prefix: 1, },
  36. { opcode: 0x37, mask_flags: of | sf | pf | zf, },
  37. { opcode: 0x3E, prefix: 1, },
  38. { opcode: 0x3F, mask_flags: of | sf | pf | zf, },
  39. { opcode: 0x40, os: 1, },
  40. { opcode: 0x41, os: 1, },
  41. { opcode: 0x42, os: 1, },
  42. { opcode: 0x43, os: 1, },
  43. { opcode: 0x44, os: 1, },
  44. { opcode: 0x45, os: 1, },
  45. { opcode: 0x46, os: 1, },
  46. { opcode: 0x47, os: 1, },
  47. { opcode: 0x48, os: 1, },
  48. { opcode: 0x49, os: 1, },
  49. { opcode: 0x4A, os: 1, },
  50. { opcode: 0x4B, os: 1, },
  51. { opcode: 0x4C, os: 1, },
  52. { opcode: 0x4D, os: 1, },
  53. { opcode: 0x4E, os: 1, },
  54. { opcode: 0x4F, os: 1, },
  55. { opcode: 0x50, os: 1, },
  56. { opcode: 0x51, os: 1, },
  57. { opcode: 0x52, os: 1, },
  58. { opcode: 0x53, os: 1, },
  59. { opcode: 0x54, os: 1, },
  60. { opcode: 0x55, os: 1, },
  61. { opcode: 0x56, os: 1, },
  62. { opcode: 0x57, os: 1, },
  63. { opcode: 0x58, os: 1, },
  64. { opcode: 0x59, os: 1, },
  65. { opcode: 0x5A, os: 1, },
  66. { opcode: 0x5B, os: 1, },
  67. { opcode: 0x5C, os: 1, },
  68. { opcode: 0x5D, os: 1, },
  69. { opcode: 0x5E, os: 1, },
  70. { opcode: 0x5F, os: 1, },
  71. { opcode: 0x60, os: 1, },
  72. { opcode: 0x61, os: 1, },
  73. { opcode: 0x62, e: 1, g: 1, skip: 1, },
  74. { opcode: 0x63, e: 1, g: 1, },
  75. { opcode: 0x64, prefix: 1, },
  76. { opcode: 0x65, prefix: 1, },
  77. { opcode: 0x66, prefix: 1, },
  78. { opcode: 0x67, prefix: 1, },
  79. { opcode: 0x68, os: 1, imm1632: 1, },
  80. { opcode: 0x69, os: 1, e: 1, g: 1, imm: 1, mask_flags: af, }, // zf?
  81. { opcode: 0x6A, os: 1, imm8: 1, },
  82. { opcode: 0x6B, os: 1, e: 1, g: 1, imm8: 1, mask_flags: af, }, // zf?
  83. { opcode: 0x6C, skip: 1, },
  84. { opcode: 0x6D, os: 1, skip: 1, },
  85. { opcode: 0x6E, skip: 1, },
  86. { opcode: 0x6F, os: 1, skip: 1, },
  87. { opcode: 0x84, e: 1, g: 1, },
  88. { opcode: 0x85, os: 1, e: 1, g: 1, },
  89. { opcode: 0x86, e: 1, g: 1, },
  90. { opcode: 0x87, os: 1, e: 1, g: 1, },
  91. { opcode: 0x88, e: 1, g: 1, },
  92. { opcode: 0x89, os: 1, e: 1, g: 1, },
  93. { opcode: 0x8A, e: 1, g: 1, },
  94. { opcode: 0x8B, os: 1, e: 1, g: 1, },
  95. { opcode: 0x8C, os: 1, e: 1, g: 1, skip: 1, },
  96. { opcode: 0x8D, os: 1, e: 1, g: 1, only_mem: 1, }, // lea
  97. { opcode: 0x8E, e: 1, g: 1, skip: 1, },
  98. { opcode: 0x8F, os: 1, e: 1, fixed_g: 0, },
  99. { opcode: 0x90, },
  100. { opcode: 0x91, os: 1, },
  101. { opcode: 0x92, os: 1, },
  102. { opcode: 0x93, os: 1, },
  103. { opcode: 0x94, os: 1, },
  104. { opcode: 0x95, os: 1, },
  105. { opcode: 0x96, os: 1, },
  106. { opcode: 0x97, os: 1, },
  107. { opcode: 0x98, os: 1, },
  108. { opcode: 0x99, os: 1, },
  109. { opcode: 0x9A, os: 1, imm1632: 1, skip: 1, },
  110. { opcode: 0x9B, skip: 1, },
  111. { opcode: 0x9C, os: 1, },
  112. { opcode: 0x9D, os: 1, skip: 1, }, // popf
  113. { opcode: 0x9E, },
  114. { opcode: 0x9F, },
  115. { opcode: 0xA0, immaddr: 1, },
  116. { opcode: 0xA1, os: 1, immaddr: 1, },
  117. { opcode: 0xA2, immaddr: 1, },
  118. { opcode: 0xA3, os: 1, immaddr: 1, },
  119. { opcode: 0xA4, skip: 1, },
  120. { opcode: 0xA5, os: 1, skip: 1, },
  121. { opcode: 0xA6, skip: 1, },
  122. { opcode: 0xA7, os: 1, skip: 1, },
  123. { opcode: 0xA8, imm: 1, },
  124. { opcode: 0xA9, os: 1, imm: 1, },
  125. { opcode: 0xAA, skip: 1, },
  126. { opcode: 0xAB, os: 1, skip: 1, },
  127. { opcode: 0xAC, skip: 1, },
  128. { opcode: 0xAD, os: 1, skip: 1, },
  129. { opcode: 0xAE, skip: 1, },
  130. { opcode: 0xAF, os: 1, skip: 1, },
  131. { opcode: 0xC2, os: 1, imm16: 1, skip: 1, },
  132. { opcode: 0xC3, os: 1, skip: 1, },
  133. { opcode: 0xC4, os: 1, e: 1, g: 1, skip: 1, },
  134. { opcode: 0xC5, os: 1, e: 1, g: 1, skip: 1, },
  135. { opcode: 0xC6, e: 1, fixed_g: 0, imm: 1, },
  136. { opcode: 0xC7, os: 1, e: 1, fixed_g: 0, imm: 1, },
  137. { opcode: 0xC8, os: 1, imm16: 1, }, // enter
  138. { opcode: 0xC9, os: 1, skip: 1, }, // leave: requires valid ebp
  139. { opcode: 0xCA, os: 1, imm16: 1, skip: 1, },
  140. { opcode: 0xCB, os: 1, skip: 1, },
  141. { opcode: 0xCC, skip: 1, },
  142. { opcode: 0xCD, skip: 1, },
  143. { opcode: 0xCE, skip: 1, },
  144. { opcode: 0xCF, os: 1, skip: 1, },
  145. { opcode: 0xD4, imm8: 1, }, // aam, may trigger #de
  146. { opcode: 0xD5, imm8: 1, mask_flags: of | cf | af, },
  147. { opcode: 0xD6, },
  148. { opcode: 0xD7, skip: 1, },
  149. { opcode: 0xD8, e: 1, skip: 1, },
  150. { opcode: 0xD9, e: 1, skip: 1, },
  151. { opcode: 0xDA, e: 1, skip: 1, },
  152. { opcode: 0xDB, e: 1, skip: 1, },
  153. { opcode: 0xDC, e: 1, skip: 1, },
  154. { opcode: 0xDD, e: 1, skip: 1, },
  155. { opcode: 0xDE, e: 1, skip: 1, },
  156. { opcode: 0xDF, e: 1, skip: 1, },
  157. { opcode: 0xE0, imm8: 1, skip: 1, },
  158. { opcode: 0xE1, imm8: 1, skip: 1, },
  159. { opcode: 0xE2, imm8: 1, skip: 1, },
  160. { opcode: 0xE3, imm8: 1, skip: 1, },
  161. { opcode: 0xE4, imm8: 1, skip: 1, },
  162. { opcode: 0xE5, os: 1, imm8: 1, skip: 1, },
  163. { opcode: 0xE6, imm8: 1, skip: 1, },
  164. { opcode: 0xE7, os: 1, imm8: 1, skip: 1, },
  165. { opcode: 0xE8, os: 1, imm1632: 1, skip: 1, },
  166. { opcode: 0xE9, os: 1, imm1632: 1, skip: 1, },
  167. { opcode: 0xEA, os: 1, imm1632: 1, skip: 1, },
  168. { opcode: 0xEB, imm: 1, skip: 1, },
  169. { opcode: 0xEC, skip: 1, },
  170. { opcode: 0xED, os: 1, skip: 1, },
  171. { opcode: 0xEE, skip: 1, },
  172. { opcode: 0xEF, os: 1, skip: 1, },
  173. { opcode: 0xF0, prefix: 1, },
  174. { opcode: 0xF1, skip: 1, },
  175. { opcode: 0xF2, prefix: 1, },
  176. { opcode: 0xF3, prefix: 1, },
  177. { opcode: 0xF4, skip: 1, },
  178. { opcode: 0xF5, },
  179. { opcode: 0xF6, fixed_g: 0, imm: 1, },
  180. { opcode: 0xF6, fixed_g: 1, imm: 1, },
  181. { opcode: 0xF6, fixed_g: 2, },
  182. { opcode: 0xF6, fixed_g: 3, },
  183. { opcode: 0xF6, fixed_g: 4, mask_flags: af | zf, },
  184. { opcode: 0xF6, fixed_g: 5, mask_flags: af | zf, },
  185. { opcode: 0xF6, fixed_g: 6, skip: 1, }, // zero divide
  186. { opcode: 0xF6, fixed_g: 7, skip: 1, },
  187. { opcode: 0xF7, os: 1, fixed_g: 0, imm: 1, },
  188. { opcode: 0xF7, os: 1, fixed_g: 1, imm: 1, },
  189. { opcode: 0xF7, os: 1, fixed_g: 2, },
  190. { opcode: 0xF7, os: 1, fixed_g: 3, },
  191. { opcode: 0xF7, os: 1, fixed_g: 4, mask_flags: zf | af, },
  192. { opcode: 0xF7, os: 1, fixed_g: 5, mask_flags: zf | af, },
  193. { opcode: 0xF7, os: 1, fixed_g: 6, skip: 1, }, // zero divide
  194. { opcode: 0xF7, os: 1, fixed_g: 7, skip: 1, },
  195. { opcode: 0xF8, },
  196. { opcode: 0xF9, },
  197. { opcode: 0xFA, skip: 1, },
  198. { opcode: 0xFB, skip: 1, },
  199. { opcode: 0xFC, },
  200. { opcode: 0xFD, },
  201. { opcode: 0xFE, e: 1, fixed_g: 0, },
  202. { opcode: 0xFE, e: 1, fixed_g: 1, },
  203. { opcode: 0xFF, os: 1, e: 1, fixed_g: 0, },
  204. { opcode: 0xFF, os: 1, e: 1, fixed_g: 1, },
  205. { opcode: 0xFF, os: 1, e: 1, fixed_g: 2, skip: 1, },
  206. { opcode: 0xFF, os: 1, e: 1, fixed_g: 3, skip: 1, },
  207. { opcode: 0xFF, os: 1, e: 1, fixed_g: 4, skip: 1, },
  208. { opcode: 0xFF, os: 1, e: 1, fixed_g: 5, skip: 1, },
  209. { opcode: 0xFF, os: 1, e: 1, fixed_g: 6, },
  210. { opcode: 0x0F00, e: 1, g: 1, skip: 1 },
  211. { opcode: 0x0F01, e: 1, g: 1, skip: 1 },
  212. { opcode: 0x0F02, os: 1, e: 1, g: 1, skip: 1 },
  213. { opcode: 0x0F03, os: 1, e: 1, g: 1, skip: 1 },
  214. { opcode: 0x0F04, skip: 1 },
  215. { opcode: 0x0F05, skip: 1 },
  216. { opcode: 0x0F06, skip: 1 },
  217. { opcode: 0x0F07, skip: 1 },
  218. { opcode: 0x0F08, skip: 1 },
  219. { opcode: 0x0F09, skip: 1 },
  220. { opcode: 0x0F09, skip: 1 },
  221. { opcode: 0x0F0A, skip: 1 },
  222. { opcode: 0x0F0B, skip: 1 },
  223. { opcode: 0x0F0C, skip: 1 },
  224. { opcode: 0x0F0D, skip: 1 },
  225. { opcode: 0x0F0E, skip: 1 },
  226. { opcode: 0x0F0F, skip: 1 },
  227. { opcode: 0x0F20, e: 1, g: 1, skip: 1 },
  228. { opcode: 0x0F21, e: 1, g: 1, skip: 1 },
  229. { opcode: 0x0F22, e: 1, g: 1, skip: 1 },
  230. { opcode: 0x0F23, e: 1, g: 1, skip: 1 },
  231. { opcode: 0x0F30, skip: 1 },
  232. { opcode: 0x0F31, skip: 1 },
  233. { opcode: 0x0F32, skip: 1 },
  234. { opcode: 0x0F33, skip: 1 },
  235. { opcode: 0x0F34, skip: 1 },
  236. { opcode: 0x0F35, skip: 1 },
  237. { opcode: 0x0F40, e: 1, g: 1, os: 1, },
  238. { opcode: 0x0F41, e: 1, g: 1, os: 1, },
  239. { opcode: 0x0F42, e: 1, g: 1, os: 1, },
  240. { opcode: 0x0F43, e: 1, g: 1, os: 1, },
  241. { opcode: 0x0F44, e: 1, g: 1, os: 1, },
  242. { opcode: 0x0F45, e: 1, g: 1, os: 1, },
  243. { opcode: 0x0F46, e: 1, g: 1, os: 1, },
  244. { opcode: 0x0F47, e: 1, g: 1, os: 1, },
  245. { opcode: 0x0F48, e: 1, g: 1, os: 1, },
  246. { opcode: 0x0F49, e: 1, g: 1, os: 1, },
  247. { opcode: 0x0F4A, e: 1, g: 1, os: 1, },
  248. { opcode: 0x0F4B, e: 1, g: 1, os: 1, },
  249. { opcode: 0x0F4C, e: 1, g: 1, os: 1, },
  250. { opcode: 0x0F4D, e: 1, g: 1, os: 1, },
  251. { opcode: 0x0F4E, e: 1, g: 1, os: 1, },
  252. { opcode: 0x0F4F, e: 1, g: 1, os: 1, },
  253. { opcode: 0x0F80, os: 1, skip: 1, },
  254. { opcode: 0x0F81, os: 1, skip: 1, },
  255. { opcode: 0x0F82, os: 1, skip: 1, },
  256. { opcode: 0x0F83, os: 1, skip: 1, },
  257. { opcode: 0x0F84, os: 1, skip: 1, },
  258. { opcode: 0x0F85, os: 1, skip: 1, },
  259. { opcode: 0x0F86, os: 1, skip: 1, },
  260. { opcode: 0x0F87, os: 1, skip: 1, },
  261. { opcode: 0x0F88, os: 1, skip: 1, },
  262. { opcode: 0x0F89, os: 1, skip: 1, },
  263. { opcode: 0x0F8A, os: 1, skip: 1, },
  264. { opcode: 0x0F8B, os: 1, skip: 1, },
  265. { opcode: 0x0F8C, os: 1, skip: 1, },
  266. { opcode: 0x0F8D, os: 1, skip: 1, },
  267. { opcode: 0x0F8E, os: 1, skip: 1, },
  268. { opcode: 0x0F8F, os: 1, skip: 1, },
  269. { opcode: 0x0F90, e: 1, g: 1, },
  270. { opcode: 0x0F91, e: 1, g: 1, },
  271. { opcode: 0x0F92, e: 1, g: 1, },
  272. { opcode: 0x0F93, e: 1, g: 1, },
  273. { opcode: 0x0F94, e: 1, g: 1, },
  274. { opcode: 0x0F95, e: 1, g: 1, },
  275. { opcode: 0x0F96, e: 1, g: 1, },
  276. { opcode: 0x0F97, e: 1, g: 1, },
  277. { opcode: 0x0F98, e: 1, g: 1, },
  278. { opcode: 0x0F99, e: 1, g: 1, },
  279. { opcode: 0x0F9A, e: 1, g: 1, },
  280. { opcode: 0x0F9B, e: 1, g: 1, },
  281. { opcode: 0x0F9C, e: 1, g: 1, },
  282. { opcode: 0x0F9D, e: 1, g: 1, },
  283. { opcode: 0x0F9E, e: 1, g: 1, },
  284. { opcode: 0x0F9F, e: 1, g: 1, },
  285. { opcode: 0x0FA0, os: 1, skip: 1, },
  286. { opcode: 0x0FA1, os: 1, skip: 1, },
  287. { opcode: 0x0FA2, skip: 1, },
  288. { opcode: 0x0FA8, os: 1, skip: 1, },
  289. { opcode: 0x0FA9, os: 1, skip: 1, },
  290. { opcode: 0x0FA3, os: 1, e: 1, g: 1, only_reg: 1, }, // bt (can also index memory, but not supported by test right now)
  291. { opcode: 0x0FAB, os: 1, e: 1, g: 1, only_reg: 1, },
  292. { opcode: 0x0FB3, os: 1, e: 1, g: 1, only_reg: 1, },
  293. { opcode: 0x0FBB, os: 1, e: 1, g: 1, only_reg: 1, },
  294. { opcode: 0x0FBA, os: 1, e: 1, fixed_g: 4, imm8: 1, only_reg: 1, }, // bt
  295. { opcode: 0x0FBA, os: 1, e: 1, fixed_g: 5, imm8: 1, only_reg: 1, },
  296. { opcode: 0x0FBA, os: 1, e: 1, fixed_g: 6, imm8: 1, only_reg: 1, },
  297. { opcode: 0x0FBA, os: 1, e: 1, fixed_g: 7, imm8: 1, only_reg: 1, },
  298. { opcode: 0x0FBC, os: 1, e: 1, g: 1, mask_flags: af, }, // bsf
  299. { opcode: 0x0FBD, os: 1, e: 1, g: 1, mask_flags: af, },
  300. // note: overflow flag only undefined if shift is > 1
  301. { opcode: 0x0FA4, os: 1, e: 1, g: 1, imm8: 1, mask_flags: af | of, }, // shld
  302. { opcode: 0x0FA5, os: 1, e: 1, g: 1, mask_flags: af | of, },
  303. { opcode: 0x0FAC, os: 1, e: 1, g: 1, imm8: 1, mask_flags: af | of, },
  304. { opcode: 0x0FAD, os: 1, e: 1, g: 1, mask_flags: af | of, },
  305. { opcode: 0x0FAE, e: 1, fixed_g: 0, only_mem: 1, skip: 1, }, // fxsave, ...
  306. { opcode: 0x0FAE, e: 1, fixed_g: 1, only_mem: 1, skip: 1, },
  307. { opcode: 0x0FAE, e: 1, fixed_g: 2, only_mem: 1, skip: 1, },
  308. { opcode: 0x0FAE, e: 1, fixed_g: 3, only_mem: 1, skip: 1, },
  309. { opcode: 0x0FAE, e: 1, fixed_g: 5, only_reg: 1, }, // mfence, ...
  310. { opcode: 0x0FAE, e: 1, fixed_g: 6, only_reg: 1, },
  311. { opcode: 0x0FAE, e: 1, fixed_g: 7, only_reg: 1, },
  312. { opcode: 0x0FAF, os: 1, e: 1, g: 1, mask_flags: af | zf }, // imul
  313. { opcode: 0x0FB0, e: 1, g: 1 }, // cmxchg
  314. { opcode: 0x0FB1, os: 1, e: 1, g: 1 },
  315. { opcode: 0x0FC7, e: 1, fixed_g: 1, only_mem: 1, }, // cmpxchg8b (memory)
  316. { opcode: 0x0FB2, os: 1, e: 1, g: 1, skip: 1, }, // lss, lfs, lgs
  317. { opcode: 0x0FB4, os: 1, e: 1, g: 1, skip: 1, },
  318. { opcode: 0x0FB5, os: 1, e: 1, g: 1, skip: 1, },
  319. { opcode: 0x0FB6, os: 1, e: 1, g: 1, }, // movzx
  320. { opcode: 0x0FB7, os: 1, e: 1, g: 1, },
  321. { opcode: 0xF30FB8, os: 1, e: 1, g: 1 }, // popcnt
  322. { opcode: 0x0FBE, os: 1, e: 1, g: 1, }, // movzx
  323. { opcode: 0x0FBF, os: 1, e: 1, g: 1, },
  324. { opcode: 0x0FC0, e: 1, g: 1, }, // xadd
  325. { opcode: 0x0FC1, os: 1, e: 1, g: 1, },
  326. { opcode: 0x0FC8, }, // bswap
  327. { opcode: 0x0FC9, },
  328. { opcode: 0x0FCA, },
  329. { opcode: 0x0FCB, },
  330. { opcode: 0x0FCC, },
  331. { opcode: 0x0FCD, },
  332. { opcode: 0x0FCE, },
  333. { opcode: 0x0FCF, },
  334. // mmx, sse
  335. // - Commented out are not implemented
  336. // - Missing are sse3+, and floating point
  337. { opcode: 0x660F12, only_mem: 1, e: 1, g: 1 },
  338. { opcode: 0x660F13, only_mem: 1, e: 1, g: 1 },
  339. { opcode: 0x660F14, e: 1, g: 1 },
  340. { opcode: 0x0F28, e: 1, g: 1 },
  341. { opcode: 0x660F28, e: 1, g: 1 },
  342. { opcode: 0x0F29, only_mem: 1, e: 1, g: 1 }, // XXX: Remove only_mem once supported by v86
  343. { opcode: 0x660F29, only_mem: 1, e: 1, g: 1 }, // XXX: Remove only_mem once supported by v86
  344. { opcode: 0x0F2B, only_mem: 1, e: 1, g: 1 },
  345. { opcode: 0x660F2B, only_mem: 1, e: 1, g: 1 },
  346. { opcode: 0xF20F2C, e: 1, g: 1 },
  347. { opcode: 0x0F54, e: 1, g: 1 },
  348. { opcode: 0x660F54, e: 1, g: 1 },
  349. { opcode: 0x0F57, e: 1, g: 1 },
  350. { opcode: 0x660F57, e: 1, g: 1 },
  351. { opcode: 0x660F60, e: 1, g: 1 },
  352. { opcode: 0x0F60, e: 1, g: 1 },
  353. { opcode: 0x660F61, e: 1, g: 1 },
  354. { opcode: 0x0F61, e: 1, g: 1 },
  355. //{ opcode: 0x660F62, e: 1, g: 1 },
  356. { opcode: 0x0F62, e: 1, g: 1 },
  357. //{ opcode: 0x660F63, e: 1, g: 1 },
  358. { opcode: 0x0F63, e: 1, g: 1 },
  359. //{ opcode: 0x660F64, e: 1, g: 1 },
  360. { opcode: 0x0F64, e: 1, g: 1 },
  361. //{ opcode: 0x660F65, e: 1, g: 1 },
  362. { opcode: 0x0F65, e: 1, g: 1 },
  363. //{ opcode: 0x660F66, e: 1, g: 1 },
  364. { opcode: 0x0F66, e: 1, g: 1 },
  365. { opcode: 0x660F67, e: 1, g: 1 },
  366. { opcode: 0x0F67, e: 1, g: 1 },
  367. { opcode: 0x660F68, e: 1, g: 1 },
  368. { opcode: 0x0F68, e: 1, g: 1 },
  369. //{ opcode: 0x660F69, e: 1, g: 1 },
  370. { opcode: 0x0F69, e: 1, g: 1 },
  371. //{ opcode: 0x660F6A, e: 1, g: 1 },
  372. { opcode: 0x0F6A, e: 1, g: 1 },
  373. //{ opcode: 0x660F6B, e: 1, g: 1 },
  374. { opcode: 0x0F6B, e: 1, g: 1 },
  375. //{ opcode: 0x660F6C, e: 1, g: 1 },
  376. //{ opcode: 0x660F6D, e: 1, g: 1 },
  377. //{ opcode: 0xF30F6E, e: 1, g: 1 },
  378. { opcode: 0x660F6E, e: 1, g: 1 },
  379. { opcode: 0x0F6E, e: 1, g: 1 },
  380. { opcode: 0xF30F6F, e: 1, g: 1 },
  381. { opcode: 0x660F6F, e: 1, g: 1 },
  382. { opcode: 0x0F6F, e: 1, g: 1 },
  383. { opcode: 0x660F70, e: 1, g: 1, imm8: 1, },
  384. { opcode: 0xF20F70, e: 1, g: 1, imm8: 1, },
  385. { opcode: 0xF30F70, e: 1, g: 1, imm8: 1, },
  386. { opcode: 0x0F70, e: 1, g: 1, imm8: 1, },
  387. { opcode: 0x0F71, e: 1, fixed_g: 2, imm8: 1, only_reg: 1, },
  388. //{ opcode: 0x660F71, e: 1, fixed_g: 2, imm8: 1, only_reg: 1, },
  389. { opcode: 0x0F71, e: 1, fixed_g: 4, imm8: 1, only_reg: 1, },
  390. //{ opcode: 0x660F71, e: 1, fixed_g: 4, imm8: 1, only_reg: 1, },
  391. { opcode: 0x0F71, e: 1, fixed_g: 6, imm8: 1, only_reg: 1, },
  392. //{ opcode: 0x660F71, e: 1, fixed_g: 6, imm8: 1, only_reg: 1, },
  393. { opcode: 0x0F72, e: 1, fixed_g: 2, imm8: 1, only_reg: 1, },
  394. //{ opcode: 0x660F72, e: 1, fixed_g: 2, imm8: 1, only_reg: 1, },
  395. { opcode: 0x0F72, e: 1, fixed_g: 4, imm8: 1, only_reg: 1, },
  396. //{ opcode: 0x660F72, e: 1, fixed_g: 4, imm8: 1, only_reg: 1, },
  397. { opcode: 0x0F72, e: 1, fixed_g: 6, imm8: 1, only_reg: 1, },
  398. //{ opcode: 0x660F72, e: 1, fixed_g: 6, imm8: 1, only_reg: 1, },
  399. { opcode: 0x0F73, e: 1, fixed_g: 2, imm8: 1, only_reg: 1, },
  400. { opcode: 0x660F73, e: 1, fixed_g: 2, imm8: 1, only_reg: 1, },
  401. //{ opcode: 0x660F73, e: 1, fixed_g: 3, imm8: 1, only_reg: 1, },
  402. { opcode: 0x0F73, e: 1, fixed_g: 6, imm8: 1, only_reg: 1, },
  403. //{ opcode: 0x660F73, e: 1, fixed_g: 6, imm8: 1, only_reg: 1, },
  404. //{ opcode: 0x660F73, e: 1, fixed_g: 7, imm8: 1, only_reg: 1, },
  405. { opcode: 0x0F74, e: 1, g: 1, },
  406. { opcode: 0x660F74, e: 1, g: 1, },
  407. { opcode: 0x0F75, e: 1, g: 1, },
  408. { opcode: 0x660F75, e: 1, g: 1, },
  409. { opcode: 0x0F76, e: 1, g: 1, },
  410. { opcode: 0x660F76, e: 1, g: 1, },
  411. { opcode: 0x0F77 },
  412. { opcode: 0x0F7E, e: 1, g: 1 },
  413. { opcode: 0x660F7E, e: 1, g: 1 },
  414. { opcode: 0xF30F7E, e: 1, g: 1 },
  415. { opcode: 0x0F7F, e: 1, g: 1 },
  416. { opcode: 0x660F7F, only_mem: 1, e: 1, g: 1 }, // XXX: Remove only_mem once supported by v86
  417. { opcode: 0xF30F7F, only_mem: 1, e: 1, g: 1 }, // XXX: Remove only_mem once supported by v86
  418. { opcode: 0x0FC3, e: 1, g: 1, only_mem: 1, },
  419. { opcode: 0x660FC5, e: 1, g: 1, only_reg: 1, imm8: 1, },
  420. { opcode: 0x0FD1, e: 1, g: 1 },
  421. //{ opcode: 0x660FD1, e: 1, g: 1 },
  422. { opcode: 0x0FD2, e: 1, g: 1 },
  423. //{ opcode: 0x660FD2, e: 1, g: 1 },
  424. { opcode: 0x0FD3, e: 1, g: 1 },
  425. { opcode: 0x660FD3, e: 1, g: 1 },
  426. { opcode: 0x0FD3, e: 1, g: 1 },
  427. //{ opcode: 0x660FD3, e: 1, g: 1 },
  428. //{ opcode: 0x0FD4, e: 1, g: 1 },
  429. //{ opcode: 0x660FD4, e: 1, g: 1 },
  430. { opcode: 0x0FD5, e: 1, g: 1 },
  431. { opcode: 0x660FD5, e: 1, g: 1 },
  432. { opcode: 0x660FD6, only_mem: 1, e: 1, g: 1 }, // XXX: Remove only_mem once supported by v86
  433. //{ opcode: 0xF20FD6, e: 1, g: 1 },
  434. //{ opcode: 0xF30FD6, e: 1, g: 1 },
  435. //{ opcode: 0x0FD7, e: 1, g: 1, only_reg: 1, },
  436. { opcode: 0x660FD7, e: 1, g: 1, only_reg: 1, },
  437. { opcode: 0x0FD8, e: 1, g: 1 },
  438. //{ opcode: 0x660FD8, e: 1, g: 1 },
  439. { opcode: 0x0FD9, e: 1, g: 1 },
  440. //{ opcode: 0x660FD9, e: 1, g: 1 },
  441. //{ opcode: 0x0FDA, e: 1, g: 1 },
  442. { opcode: 0x660FDA, e: 1, g: 1 },
  443. { opcode: 0x0FDB, e: 1, g: 1 },
  444. //{ opcode: 0x660FDB, e: 1, g: 1 },
  445. { opcode: 0x0FDC, e: 1, g: 1 },
  446. { opcode: 0x660FDC, e: 1, g: 1 },
  447. { opcode: 0x0FDD, e: 1, g: 1 },
  448. { opcode: 0x660FDD, e: 1, g: 1 },
  449. //{ opcode: 0x0FDE, e: 1, g: 1 },
  450. { opcode: 0x660FDE, e: 1, g: 1 },
  451. { opcode: 0x0FDF, e: 1, g: 1 },
  452. //{ opcode: 0x660FDF, e: 1, g: 1 },
  453. //{ opcode: 0x0FE0, e: 1, g: 1 },
  454. //{ opcode: 0x660FE0, e: 1, g: 1 },
  455. { opcode: 0x0FE1, e: 1, g: 1 },
  456. //{ opcode: 0x660FE1, e: 1, g: 1 },
  457. { opcode: 0x0FE2, e: 1, g: 1 },
  458. //{ opcode: 0x660FE2, e: 1, g: 1 },
  459. //{ opcode: 0x0FE3, e: 1, g: 1 },
  460. //{ opcode: 0x660FE3, e: 1, g: 1 },
  461. //{ opcode: 0x0FE4, e: 1, g: 1 },
  462. { opcode: 0x660FE4, e: 1, g: 1 },
  463. { opcode: 0x0FE5, e: 1, g: 1 },
  464. //{ opcode: 0x660FE5, e: 1, g: 1 },
  465. //{ opcode: 0x660FE6, e: 1, g: 1 },
  466. //{ opcode: 0xF20FE6, e: 1, g: 1 },
  467. //{ opcode: 0xF30FE6, e: 1, g: 1 },
  468. //{ opcode: 0x0FE7, e: 1, g: 1, only_mem: 1, },
  469. { opcode: 0x660FE7, e: 1, g: 1, only_mem: 1, },
  470. { opcode: 0x0FE8, e: 1, g: 1 },
  471. //{ opcode: 0x660FE8, e: 1, g: 1 },
  472. { opcode: 0x0FE9, e: 1, g: 1 },
  473. //{ opcode: 0x660FE9, e: 1, g: 1 },
  474. //{ opcode: 0x0FEA, e: 1, g: 1 },
  475. //{ opcode: 0x660FEA, e: 1, g: 1 },
  476. { opcode: 0x0FEB, e: 1, g: 1 },
  477. { opcode: 0x660FEB, e: 1, g: 1 },
  478. { opcode: 0x0FEC, e: 1, g: 1 },
  479. //{ opcode: 0x660FEC, e: 1, g: 1 },
  480. { opcode: 0x0FED, e: 1, g: 1 },
  481. //{ opcode: 0x660FED, e: 1, g: 1 },
  482. //{ opcode: 0x0FEE, e: 1, g: 1 },
  483. //{ opcode: 0x660FEE, e: 1, g: 1 },
  484. { opcode: 0x0FEF, e: 1, g: 1 },
  485. { opcode: 0x660FEF, e: 1, g: 1 },
  486. { opcode: 0x0FF1, e: 1, g: 1 },
  487. //{ opcode: 0x660FF1, e: 1, g: 1 },
  488. { opcode: 0x0FF2, e: 1, g: 1 },
  489. //{ opcode: 0x660FF2, e: 1, g: 1 },
  490. { opcode: 0x0FF3, e: 1, g: 1 },
  491. //{ opcode: 0x660FF3, e: 1, g: 1 },
  492. //{ opcode: 0x0FF4, e: 1, g: 1 },
  493. //{ opcode: 0x660FF4, e: 1, g: 1 },
  494. { opcode: 0x0FF5, e: 1, g: 1 },
  495. //{ opcode: 0x660FF5, e: 1, g: 1 },
  496. //{ opcode: 0x0FF6, e: 1, g: 1 },
  497. //{ opcode: 0x660FF6, e: 1, g: 1 },
  498. //{ opcode: 0x0FF7, e: 1, g: 1 },
  499. //{ opcode: 0x660FF7, e: 1, g: 1 },
  500. { opcode: 0x0FF8, e: 1, g: 1 },
  501. //{ opcode: 0x660FF8, e: 1, g: 1 },
  502. { opcode: 0x0FF9, e: 1, g: 1 },
  503. //{ opcode: 0x660FF9, e: 1, g: 1 },
  504. { opcode: 0x0FFA, e: 1, g: 1 },
  505. { opcode: 0x660FFA, e: 1, g: 1 },
  506. //{ opcode: 0x0FFB, e: 1, g: 1 },
  507. //{ opcode: 0x660FFB, e: 1, g: 1 },
  508. { opcode: 0x0FFC, e: 1, g: 1 },
  509. //{ opcode: 0x660FFC, e: 1, g: 1 },
  510. { opcode: 0x0FFD, e: 1, g: 1 },
  511. //{ opcode: 0x660FFD, e: 1, g: 1 },
  512. { opcode: 0x0FFE, e: 1, g: 1 },
  513. //{ opcode: 0x660FFE, e: 1, g: 1 },
  514. ];
  515. for(var i = 0; i < 8; i++)
  516. {
  517. encodings.push.apply(encodings, [
  518. { opcode: 0x00 | i << 3, e: 1, g: 1, },
  519. { opcode: 0x01 | i << 3, os: 1, e: 1, g: 1, },
  520. { opcode: 0x02 | i << 3, e: 1, g: 1, },
  521. { opcode: 0x03 | i << 3, os: 1, e: 1, g: 1, },
  522. { opcode: 0x04 | i << 3, eax: 1, imm: 1, },
  523. { opcode: 0x05 | i << 3, os: 1, eax: 1, imm: 1, },
  524. { opcode: 0x70 | i, imm8: 1, skip: 1, },
  525. { opcode: 0x78 | i, imm8: 1, skip: 1, },
  526. { opcode: 0x80, e: 1, fixed_g: i, imm: 1, },
  527. { opcode: 0x81, os: 1, e: 1, fixed_g: i, imm: 1, },
  528. { opcode: 0x82, e: 1, fixed_g: i, imm: 1, },
  529. { opcode: 0x83, os: 1, e: 1, fixed_g: i, imm8: 1, },
  530. { opcode: 0xB0 | i, imm8: 1, },
  531. { opcode: 0xB8 | i, os: 1, imm1632: 1, },
  532. // note: overflow flag only undefined if shift is > 1
  533. // note: the adjust flag is undefined for shifts > 0 and unaffected by rotates
  534. { opcode: 0xC0, e: 1, fixed_g: i, imm8: 1, mask_flags: of | af, },
  535. { opcode: 0xC1, os: 1, e: 1, fixed_g: i, imm8: 1, mask_flags: of | af, },
  536. { opcode: 0xD0, e: 1, fixed_g: i, mask_flags: af, },
  537. { opcode: 0xD1, os: 1, e: 1, fixed_g: i, mask_flags: af, },
  538. { opcode: 0xD2, e: 1, fixed_g: i, mask_flags: of | af, },
  539. { opcode: 0xD3, os: 1, e: 1, fixed_g: i, mask_flags: of | af, },
  540. ]);
  541. }
  542. encodings.sort((e1, e2) => {
  543. let o1 = (e1.opcode & 0xFF00) === 0x0F00 ? e1.opcode & 0xFFFF : e1.opcode & 0xFF;
  544. let o2 = (e2.opcode & 0xFF00) === 0x0F00 ? e2.opcode & 0xFFFF : e2.opcode & 0xFF;
  545. return o1 - o2 || e1.fixed_g - e2.fixed_g;
  546. });
  547. function repeat(s, n)
  548. {
  549. let out = "";
  550. for(let i = 0; i < n; i++) out += s;
  551. return out;
  552. }
  553. function indent(lines, how_much)
  554. {
  555. return lines.map(line => repeat(" ", how_much) + line);
  556. }
  557. function hex_byte(n)
  558. {
  559. let s = n.toString(16).toUpperCase();
  560. if(s.length === 1) s = "0" + s;
  561. return s;
  562. }
  563. function print_syntax_tree(statements)
  564. {
  565. let code = [];
  566. for(let statement of statements)
  567. {
  568. if(typeof statement === "string")
  569. {
  570. code.push(statement);
  571. }
  572. else if(statement.type === "switch")
  573. {
  574. console.assert(statement.condition);
  575. code.push(`switch(${statement.condition})`);
  576. code.push(`{`);
  577. code.push.apply(code, indent(print_syntax_tree(statement.body), 4));
  578. code.push(`}`);
  579. }
  580. else if(statement.type === "case")
  581. {
  582. for(let case_ of statement.cases)
  583. {
  584. code.push(`case ${case_}:`);
  585. }
  586. code.push(`{`);
  587. code.push.apply(code, indent(print_syntax_tree(statement.body), 4));
  588. code.push(`}`);
  589. code.push(`break;`);
  590. }
  591. else if(statement.type === "default-case")
  592. {
  593. console.assert(statement.body);
  594. code.push(`default:`);
  595. code.push.apply(code, indent(statement.body, 4));
  596. }
  597. else
  598. {
  599. console.assert(false, "Unexpected type: " + statement.type);
  600. }
  601. }
  602. return code;
  603. }
  604. function gen_read_imm_call(op, size_variant)
  605. {
  606. let size = (op.os || op.opcode % 2 === 1) ? size_variant : 8;
  607. if(op.imm || op.imm8 || op.imm16 || op.imm1632 || op.immaddr)
  608. {
  609. if(op.imm8 || (op.imm && size === 8))
  610. {
  611. return "read_imm8()";
  612. }
  613. else
  614. {
  615. if(op.immaddr)
  616. {
  617. // immaddr: depends on address size
  618. return "read_moffs()";
  619. }
  620. else
  621. {
  622. console.assert(op.imm1632 || op.imm16 || (op.imm && (size === 16 || size === 32)));
  623. if(size === 16 || op.imm16)
  624. {
  625. return "read_imm16()";
  626. }
  627. else
  628. {
  629. return "read_imm32s()";
  630. }
  631. }
  632. }
  633. }
  634. else
  635. {
  636. return undefined;
  637. }
  638. }
  639. function gen_instruction_body(encoding, size)
  640. {
  641. let suffix = encoding[0].os ? `${size}` : "";
  642. let opcode = encoding[0].opcode & 0xFF;
  643. let opcode_hex = hex_byte(opcode);
  644. if(encoding[0].fixed_g === undefined && encoding[0].e)
  645. {
  646. let prefix_call = [];
  647. if(opcode === 0x8D)
  648. {
  649. // special case: requires call before modrm_resolve
  650. prefix_call = [`if(modrm_byte < 0xC0) { instr${suffix}_${opcode_hex}_mem_pre(); };`];
  651. }
  652. return [].concat(
  653. `int32_t modrm_byte = read_imm8();`,
  654. prefix_call,
  655. `modrm_byte < 0xC0 ?`,
  656. ` instr${suffix}_${opcode_hex}_mem(modrm_resolve(modrm_byte), modrm_byte >> 3 & 7) :`,
  657. ` instr${suffix}_${opcode_hex}_reg(modrm_byte & 7, modrm_byte >> 3 & 7);`
  658. );
  659. }
  660. else if(encoding[0].fixed_g !== undefined)
  661. {
  662. let cases = encoding.slice().sort((e1, e2) => e1.fixed_g - e2.fixed_g);
  663. for(let case_ of cases)
  664. {
  665. console.assert(typeof case_.fixed_g === "number");
  666. }
  667. return [
  668. "int32_t modrm_byte = read_imm8();",
  669. {
  670. type: "switch",
  671. condition: "modrm_byte >> 3 & 7",
  672. body: cases.map(case_ => {
  673. let prefix_call = [];
  674. if(opcode === 0x8F)
  675. {
  676. // special case: requires call before modrm_resolve
  677. prefix_call = [`if(modrm_byte < 0xC0) { instr${suffix}_${opcode_hex}_${case_.fixed_g}_mem_pre(); };`];
  678. }
  679. return {
  680. type: "case",
  681. cases: [case_.fixed_g],
  682. body: prefix_call.concat([
  683. `modrm_byte < 0xC0 ?`,
  684. ` instr${suffix}_${opcode_hex}_${case_.fixed_g}_mem(modrm_resolve(modrm_byte)) :`,
  685. ` instr${suffix}_${opcode_hex}_${case_.fixed_g}_reg(modrm_byte & 7);`,
  686. ]),
  687. };
  688. }).concat([
  689. {
  690. type: "default-case",
  691. body: ["assert(false);"],
  692. }
  693. ]),
  694. }
  695. ];
  696. }
  697. else
  698. {
  699. if(opcode === 0x9A || opcode === 0xEA) // special case: 2 immediate operands
  700. {
  701. var imm_read = gen_read_imm_call(encoding[0], size);
  702. console.assert(imm_read);
  703. return [`instr${suffix}_${opcode_hex}(${imm_read}, read_imm16());`];
  704. }
  705. else if(opcode === 0xC8) // special case: 2 immediate operands
  706. {
  707. var imm_read = gen_read_imm_call(encoding[0], size);
  708. console.assert(imm_read);
  709. return [`instr${suffix}_${opcode_hex}(${imm_read}, read_imm8());`];
  710. }
  711. else
  712. {
  713. return [`instr${suffix}_${opcode_hex}();`];
  714. }
  715. }
  716. }
  717. function gen_table()
  718. {
  719. let by_opcode = Object.create(null);
  720. let by_opcode0f = Object.create(null);
  721. for(let o of encodings)
  722. {
  723. let opcode = o.opcode;
  724. if(opcode >= 0x100)
  725. {
  726. if((opcode & 0xFF00) === 0x0F00)
  727. {
  728. opcode &= 0xFF;
  729. by_opcode0f[opcode] = by_opcode0f[opcode] || [];
  730. by_opcode0f[opcode].push(o);
  731. }
  732. }
  733. else
  734. {
  735. by_opcode[opcode] = by_opcode[opcode] || [];
  736. by_opcode[opcode].push(o);
  737. }
  738. }
  739. let t = [];
  740. for(let opcode = 0; opcode < 0x100; opcode++)
  741. {
  742. let encoding = by_opcode[opcode];
  743. console.assert(encoding && encoding.length);
  744. let opcode_hex = hex_byte(opcode);
  745. if(encoding[0].os)
  746. {
  747. t.push({
  748. type: "case",
  749. cases: [`0x${opcode_hex}`],
  750. body: gen_instruction_body(encoding, 16),
  751. });
  752. t.push({
  753. type: "case",
  754. cases: [`0x${opcode_hex}|0x100`],
  755. body: gen_instruction_body(encoding, 32),
  756. });
  757. }
  758. else
  759. {
  760. t.push({
  761. type: "case",
  762. cases: [`0x${opcode_hex}`, `0x${opcode_hex}|0x100`],
  763. body: gen_instruction_body(encoding, undefined),
  764. });
  765. }
  766. }
  767. t.push({
  768. type: "default-case",
  769. body: ["assert(false);"],
  770. });
  771. fs.writeFileSync("/tmp/table", print_syntax_tree(t).join("\n"));
  772. let t0f_16 = ``;
  773. let t0f_32 = ``;
  774. for(let opcode = 0; opcode < 0x100; opcode++)
  775. {
  776. let encoding = by_opcode0f[opcode];
  777. if(!encoding)
  778. {
  779. encoding = [
  780. {},
  781. ];
  782. }
  783. console.assert(encoding && encoding.length);
  784. let opcode_hex = opcode.toString(16).toUpperCase();
  785. if(opcode_hex.length === 1) opcode_hex = "0" + opcode_hex;
  786. if(encoding[0].os)
  787. {
  788. t0f_16 += `case 0x${opcode_hex}:\n`;
  789. t0f_16 += ` instr16_0F${opcode_hex}();\n`;
  790. t0f_16 += ` break;\n`;
  791. t0f_32 += `case 0x${opcode_hex}:\n`;
  792. t0f_32 += ` instr32_0F${opcode_hex}();\n`;
  793. t0f_32 += ` break;\n`;
  794. }
  795. else
  796. {
  797. t0f_16 += `case 0x${opcode_hex}:\n`;
  798. t0f_16 += ` instr_0F${opcode_hex}();\n`;
  799. t0f_16 += ` break;\n`;
  800. t0f_32 += `case 0x${opcode_hex}:\n`;
  801. t0f_32 += ` instr_0F${opcode_hex}();\n`;
  802. t0f_32 += ` break;\n`;
  803. }
  804. }
  805. t0f_16 += `default: assert(false);\n`;
  806. t0f_32 += `default: assert(false);\n`;
  807. fs.writeFileSync("/tmp/table0f_16", t0f_16);
  808. fs.writeFileSync("/tmp/table0f_32", t0f_32);
  809. }
  810. gen_table();
  811. try
  812. {
  813. fs.mkdirSync(__dirname + "/build/");
  814. }
  815. catch(e)
  816. {
  817. if(e.code !== 'EEXIST')
  818. {
  819. throw e;
  820. }
  821. }
  822. for(const op of encodings)
  823. {
  824. const configurations = [
  825. { mem: 0, size: 16, },
  826. { mem: 0, size: 32, },
  827. { mem: 1, size: 16, },
  828. { mem: 1, size: 32, },
  829. ];
  830. let i = 0;
  831. for(const config of configurations)
  832. {
  833. for(const code of create_nasm(op, config))
  834. {
  835. const filename = "gen_" + format_opcode(op.opcode) + "_" + (op.fixed_g || 0) + "_" + i + ".asm";
  836. const dirname = __dirname + "/build/" + filename;
  837. let old_code = undefined;
  838. try
  839. {
  840. old_code = fs.readFileSync(dirname, { encoding: "ascii" });
  841. }
  842. catch(e)
  843. {
  844. }
  845. if(old_code !== code)
  846. {
  847. console.log("Creating %s", filename);
  848. fs.writeFileSync(dirname, code);
  849. }
  850. else
  851. {
  852. console.log("Unchanged: %s", filename);
  853. }
  854. i++;
  855. }
  856. }
  857. }
  858. function format_opcode(n)
  859. {
  860. let x = n.toString(16);
  861. return (x.length === 1 || x.length === 3) ? "0" + x : x;
  862. }
  863. function random_int32()
  864. {
  865. return Math.random() * 0x100000000 | 0;
  866. }
  867. function create_nasm(op, config)
  868. {
  869. if(op.prefix || op.skip)
  870. {
  871. return [];
  872. }
  873. if(config.mem ? op.only_reg : op.only_mem)
  874. {
  875. // illegal opcode
  876. return [];
  877. }
  878. if(!op.e)
  879. {
  880. if(config.mem)
  881. {
  882. // doesn't use memory, don't test both
  883. return [];
  884. }
  885. }
  886. if(!op.os)
  887. {
  888. if(config.size === 16)
  889. {
  890. // equivalent to 32-bit version, don't test both
  891. return [];
  892. }
  893. }
  894. var size = (op.os || op.opcode % 2 === 1) ? config.size : 8;
  895. var is_modrm = op.e || op.g || op.fixed_g !== undefined;
  896. var codes = [];
  897. for(let reg of ["eax", "ecx", "edx", "ebx", "ebp", "esi", "edi"])
  898. {
  899. let rand = random_int32();
  900. codes.push("mov " + reg + ", " + rand);
  901. }
  902. if(true) // generate random mmx registers
  903. {
  904. codes.push("sub esp, 8");
  905. for(let i = 0; i < 8; i++)
  906. {
  907. codes.push("mov dword [esp], " + random_int32());
  908. codes.push("mov dword [esp + 4], " + random_int32());
  909. codes.push("movq mm" + i + ", [esp]");
  910. }
  911. codes.push("add esp, 8");
  912. }
  913. if(true) // generate random xmm registers
  914. {
  915. codes.push("sub esp, 16");
  916. for(let i = 0; i < 8; i++)
  917. {
  918. codes.push("mov dword [esp], " + random_int32());
  919. codes.push("mov dword [esp + 4], " + random_int32());
  920. codes.push("mov dword [esp + 8], " + random_int32());
  921. codes.push("mov dword [esp + 12], " + random_int32());
  922. codes.push("movdqu xmm" + i + ", [esp]");
  923. }
  924. codes.push("add esp, 16");
  925. }
  926. if(true) // generate random stack memory
  927. {
  928. for(let i = 0; i < 8; i++)
  929. {
  930. codes.push("sub esp, 4");
  931. codes.push("mov dword [esp], " + random_int32());
  932. }
  933. }
  934. codes.push("push dword " + (random_int32() & ~(1 << 8 | 1 << 9)));
  935. codes.push("popf");
  936. if(true)
  937. {
  938. // generate random flags using arithmatic instruction
  939. // not well-distributed, but can trigger bugs in lazy flag calculation
  940. if(true)
  941. {
  942. // rarely sets zero flag, other flags mostly well-distributed
  943. codes.push("add al, ah");
  944. }
  945. else
  946. {
  947. // always sets zero flag
  948. codes.push("sub al, al");
  949. }
  950. }
  951. if(size === 16)
  952. {
  953. codes.push("db 66h ; 16 bit");
  954. }
  955. let opcode = op.opcode;
  956. console.assert(opcode < 0x1000000);
  957. if(opcode >= 0x10000)
  958. {
  959. let c = opcode >> 16;
  960. console.assert(c === 0x66 || c === 0xF3 || c === 0xF2);
  961. codes.push("db " + c);
  962. opcode &= ~0xFF0000;
  963. }
  964. if(opcode >= 0x100)
  965. {
  966. let c = opcode >> 8;
  967. console.assert(c === 0x0F, "Expected 0f prefix, got " + c.toString(16));
  968. codes.push("db " + c);
  969. opcode &= ~0xFF00;
  970. }
  971. codes.push("db " + opcode);
  972. if(is_modrm)
  973. {
  974. let g = 7; // edi / di / bh
  975. if(op.fixed_g !== undefined)
  976. {
  977. g = op.fixed_g;
  978. }
  979. let e;
  980. let sib;
  981. if(config.mem)
  982. {
  983. e = 0x04; // [esp]
  984. sib = 0x24;
  985. }
  986. else // op.only_mem
  987. {
  988. e = 0xc2; // edx
  989. sib = "<invalid>";
  990. }
  991. codes.push("db " + (e | g << 3));
  992. if(e < 0xC0)
  993. {
  994. codes.push("db " + sib);
  995. }
  996. }
  997. if(op.opcode === 0xC8) // special case: enter
  998. {
  999. codes.push("dw 8h");
  1000. codes.push("db 0h");
  1001. }
  1002. else
  1003. if(op.imm || op.imm8 || op.imm16 || op.imm1632 || op.immaddr)
  1004. {
  1005. if(op.imm8 || (op.imm && size === 8))
  1006. {
  1007. codes.push("db 12h");
  1008. }
  1009. else
  1010. {
  1011. if(op.immaddr)
  1012. {
  1013. // immaddr: depends on address size
  1014. // generate valid pointer into bss section
  1015. codes.push("dd (120000h-16)");
  1016. }
  1017. else
  1018. {
  1019. console.assert(op.imm1632 || op.imm16 || (op.imm && (size === 16 || size === 32)));
  1020. if(size === 16 || op.imm16)
  1021. {
  1022. codes.push("dw 34cdh");
  1023. }
  1024. else
  1025. {
  1026. codes.push("dd 1234abcdh");
  1027. }
  1028. }
  1029. }
  1030. }
  1031. if(op.mask_flags)
  1032. {
  1033. codes.push(
  1034. "pushf",
  1035. "and dword [esp], ~" + op.mask_flags,
  1036. "popf"
  1037. );
  1038. }
  1039. return all_combinations(codes).map(c => {
  1040. return (
  1041. "global _start\n" +
  1042. '%include "header.inc"\n\n' +
  1043. c.join("\n") + "\n" +
  1044. '%include "footer.inc"\n'
  1045. );
  1046. });
  1047. }
  1048. function all_combinations(xs)
  1049. {
  1050. var result = [xs];
  1051. for(let i = 0; i < xs.length; i++)
  1052. {
  1053. let x = xs[i];
  1054. if(x instanceof Array)
  1055. {
  1056. let new_result = [];
  1057. for(let r of result)
  1058. {
  1059. for(let x_ of x)
  1060. {
  1061. r = r.slice();
  1062. r[i] = x_;
  1063. new_result.push(r);
  1064. }
  1065. }
  1066. result = new_result;
  1067. }
  1068. }
  1069. return result;
  1070. }