disassem.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
  1. /****************************************************************************
  2. * dcc project disassembler
  3. * (C) Cristina Cifuentes, Mike van Emmerik, Jeff Ledermann
  4. ****************************************************************************/
  5. #include "disassem.h"
  6. #include "dcc.h"
  7. #include "msvc_fixes.h"
  8. #include "symtab.h"
  9. #include "project.h"
  10. #include <stdint.h>
  11. #include <vector>
  12. #include <map>
  13. #include <sstream>
  14. #include <iomanip>
  15. #include <stdio.h>
  16. #include <string.h>
  17. // Note: for the time being, there is no interactive disassembler
  18. // for unix
  19. using namespace std;
  20. #define POS_LAB 15 /* Position of label */
  21. #define POS_OPC 20 /* Position of opcode */
  22. #define POS_OPR 25 /* Position of operand */
  23. #define WID_PTR 10 /* Width of the "xword ptr" lingo */
  24. #define POS_OPR2 POS_OPR+WID_PTR /* Position of operand after "xword ptr" */
  25. #define POS_CMT 54 /* Position of comment */
  26. static const char *szFlops0C[] =
  27. {
  28. "FCHS", "FABS", "???", "???", "FTST", "FXAM", "???", "???"
  29. };
  30. static const char *szFlops0D[] =
  31. {
  32. "FLD1", "FLDL2T","FLDL2E","FLDP1", "FLDLG2","FLDLN2","FLDZ", "???"
  33. };
  34. static const char *szFlops0E[] =
  35. {
  36. "F2XM1", "FYL2X", "FPTAN", "FPATAN","FXTRACT","FPREM1","FDECSTP","FINCSTP"
  37. };
  38. static const char *szFlops0F[] =
  39. {
  40. "FPREM", "FYLXP1","FSQRT", "FSINCOS","FRNDINT","FSCALE","FSIN","FCOS"
  41. };
  42. static const char *szFlops15[] =
  43. {
  44. "???", "FUCOMPP", "???", "???", "???", "???", "???", "???"
  45. };
  46. static const char *szFlops1C[] =
  47. {
  48. "???", "???", "FCLEX", "FINIT", "FTST", "FXAM", "???", "???"
  49. };
  50. static const char *szFlops33[] =
  51. {
  52. "???", "FCOMPP", "???", "???", "???", "???", "???", "???"
  53. };
  54. static const char *szFlops3C[] =
  55. {
  56. "FSTSWAX","???", "???", "???", "???", "???", "???", "???"
  57. };
  58. static const char *szPtr[2] = { "word ptr ", "byte ptr " };
  59. static void formatRM(ostringstream &p, const LLOperand &pm);
  60. static ostringstream &strDst(ostringstream &os, uint32_t flg, const LLOperand &pm);
  61. static char *strHex(uint32_t d);
  62. //static int checkScanned(uint32_t pcCur);
  63. //static void setProc(Function * proc);
  64. //static void dispData(uint16_t dataSeg);
  65. bool callArg(uint16_t off, char *temp); /* Check for procedure name */
  66. //static FILE *dis_g_fp;
  67. static CIcodeRec pc;
  68. static int cb, j, numIcode, allocIcode;
  69. static map<int,int> pl;
  70. static uint32_t nextInst;
  71. static bool fImpure;
  72. //static int g_lab;
  73. static Function * pProc; /* Points to current proc struct */
  74. struct POSSTACK_ENTRY
  75. {
  76. int ic; /* An icode offset */
  77. Function * pProc; /* A pointer to a PROCEDURE structure */
  78. } ;
  79. static vector<POSSTACK_ENTRY> posStack; /* position stack */
  80. //static uint8_t iPS; /* Index into the stack */
  81. // These are "curses equivalent" functions. (Used to use curses for all this,
  82. // but it was too much of a distribution hassle
  83. #define printfd(x) printf(x)
  84. #define dis_newline() printf("\n")
  85. #define dis_show() // Nothing to do unless using Curses
  86. void LLInst::findJumpTargets(CIcodeRec &_pc)
  87. {
  88. if (testFlags(I) and not testFlags(JMP_ICODE) and isJmpInst())
  89. {
  90. /* Replace the immediate operand with an icode index */
  91. iICODE labTgt=_pc.labelSrch(src().getImm2());
  92. if (labTgt!=_pc.end())
  93. {
  94. m_src.SetImmediateOp(labTgt->loc_ip);
  95. /* This icode is the target of a jump */
  96. labTgt->ll()->setFlags(TARGET);
  97. setFlags(JMP_ICODE); /* So its not done twice */
  98. }
  99. else
  100. {
  101. /* This jump cannot be linked to a label */
  102. setFlags(NO_LABEL);
  103. }
  104. }
  105. }
  106. /*****************************************************************************
  107. * disassem - Prints a disassembled listing of a procedure.
  108. * pass == 1 generates output on file .a1
  109. * pass == 2 generates output on file .a2
  110. * pass == 3 generates output on file .b
  111. ****************************************************************************/
  112. void Disassembler::disassem(Function * ppProc)
  113. {
  114. pProc = ppProc; /* Save the passes pProc */
  115. createSymTables();
  116. allocIcode = numIcode = pProc->Icode.size();
  117. cb = allocIcode * sizeof(ICODE);
  118. if (numIcode == 0)
  119. {
  120. return; /* No Icode */
  121. }
  122. /* Open the output file (.a1 or .a2 only) */
  123. if (pass != 3)
  124. {
  125. auto p = (pass == 1)? asm1_name: asm2_name;
  126. m_fp.open(p.toStdString(),ios_base::app);
  127. if (!m_fp.is_open())
  128. {
  129. fatalError(CANNOT_OPEN, p.toStdString().c_str());
  130. }
  131. }
  132. /* Create temporary code array */
  133. // Mike: needs objectising!
  134. pc=pProc->Icode;
  135. if (pass == 1)
  136. {
  137. /* Bind jump offsets to labels */
  138. //for (i = 0; i < numIcode; i++)
  139. for( ICODE &icode : pc)
  140. {
  141. LLInst *ll=icode.ll();
  142. ll->findJumpTargets(pc);
  143. }
  144. }
  145. /* Create label array to keep track of location => label name */
  146. pl.clear();
  147. /* Write procedure header */
  148. if (pass != 3)
  149. {
  150. std::string near_far=(pProc->flg & PROC_FAR)? "FAR": "NEAR";
  151. m_fp << "\t\t"<<pProc->name<<" PROC "<< near_far<<"\n";
  152. }
  153. /* Loop over array printing each record */
  154. nextInst = 0;
  155. for( ICODE &icode : pc)
  156. {
  157. this->dis1Line(*icode.ll(),icode.loc_ip,pass);
  158. }
  159. /* Write procedure epilogue */
  160. if (pass != 3)
  161. {
  162. m_fp << "\n\t\t"<<pProc->name<<" ENDP\n\n";
  163. m_fp.close();
  164. }
  165. pc.clear();
  166. destroySymTables();
  167. }
  168. /****************************************************************************
  169. * dis1Line() - disassemble one line to stream fp *
  170. * i is index into Icode for this proc *
  171. * It is assumed that icode i is already scanned *
  172. ****************************************************************************/
  173. void Disassembler::dis1Line(LLInst &inst,int loc_ip, int pass)
  174. {
  175. PROG &prog(Project::get()->prog);
  176. ostringstream oper_stream;
  177. ostringstream hex_bytes;
  178. ostringstream result_stream;
  179. ostringstream opcode_with_mods;
  180. ostringstream operands_s;
  181. oper_stream << uppercase;
  182. hex_bytes << uppercase;
  183. /* Disassembly stage 1 --
  184. * Do not try to display NO_CODE entries or synthetic instructions,
  185. * other than JMPs, that have been introduced for def/use analysis. */
  186. if ((option.asm1) and
  187. ( inst.testFlags(NO_CODE) or
  188. (inst.testFlags(SYNTHETIC) and (inst.getOpcode() != iJMP))))
  189. {
  190. return;
  191. }
  192. else if (inst.testFlags(NO_CODE))
  193. {
  194. return;
  195. }
  196. if (inst.testFlags(TARGET | CASE))
  197. {
  198. if (pass == 3)
  199. cCode.appendCode("\n"); /* Print to c code buffer */
  200. else
  201. m_fp<< "\n"; /* No, print to the stream */
  202. }
  203. /* Find next instruction label and print hex bytes */
  204. if (inst.testFlags(SYNTHETIC))
  205. nextInst = inst.label;
  206. else
  207. {
  208. cb = (uint32_t) inst.numBytes;
  209. nextInst = inst.label + cb;
  210. /* Output hexa code in program image */
  211. if (pass != 3)
  212. {
  213. for (j = 0; j < cb; j++)
  214. {
  215. hex_bytes << hex << setw(2) << setfill('0') << uint16_t(prog.image()[inst.label + j]);
  216. }
  217. hex_bytes << ' ';
  218. }
  219. }
  220. oper_stream << setw(POS_LAB) << left<< hex_bytes.str();
  221. /* Check if there is a symbol here */
  222. selectTable(Label);
  223. oper_stream << setw(5)<<left; // align for the labels
  224. {
  225. ostringstream lab_contents;
  226. if (readVal(lab_contents, inst.label, nullptr))
  227. {
  228. lab_contents << ':'; /* Also removes the null */
  229. }
  230. else if (inst.testFlags(TARGET)) /* Symbols override Lnn labels */
  231. {
  232. /* Print label */
  233. if (pl.count(loc_ip)==0)
  234. {
  235. pl[loc_ip] = ++g_lab;
  236. }
  237. lab_contents<< "L"<<pl[loc_ip]<<':';
  238. }
  239. oper_stream<< lab_contents.str();
  240. }
  241. if ((inst.getOpcode()==iSIGNEX )and inst.testFlags(B))
  242. {
  243. inst.setOpcode(iCBW);
  244. }
  245. opcode_with_mods<<Machine_X86::opcodeName(inst.getOpcode());
  246. switch ( inst.getOpcode() )
  247. {
  248. case iADD: case iADC: case iSUB: case iSBB: case iAND: case iOR:
  249. case iXOR: case iTEST: case iCMP: case iMOV: case iLEA: case iXCHG:
  250. strDst(operands_s,inst.getFlag(), inst.m_dst);
  251. inst.strSrc(operands_s);
  252. break;
  253. case iESC:
  254. inst.flops(operands_s);
  255. break;
  256. case iSAR: case iSHL: case iSHR: case iRCL: case iRCR: case iROL:
  257. case iROR:
  258. strDst(operands_s,inst.getFlag() | I, inst.m_dst);
  259. if(inst.testFlags(I))
  260. inst.strSrc(operands_s);
  261. else
  262. operands_s<<", cl";
  263. break;
  264. case iINC: case iDEC: case iNEG: case iNOT: case iPOP:
  265. strDst(operands_s,inst.getFlag() | I, inst.m_dst);
  266. break;
  267. case iPUSH:
  268. if (inst.testFlags(I))
  269. {
  270. operands_s<<strHex(inst.src().getImm2());
  271. }
  272. else
  273. {
  274. strDst(operands_s,inst.getFlag() | I, inst.m_dst);
  275. }
  276. break;
  277. case iDIV: case iIDIV: case iMUL: case iIMUL: case iMOD:
  278. if (inst.testFlags(I))
  279. {
  280. strDst(operands_s,inst.getFlag(), inst.m_dst) <<", ";
  281. formatRM(operands_s, inst.src());
  282. inst.strSrc(operands_s);
  283. }
  284. else
  285. strDst(operands_s,inst.getFlag() | I, inst.src());
  286. break;
  287. case iLDS: case iLES: case iBOUND:
  288. strDst(operands_s,inst.getFlag(), inst.m_dst)<<", dword ptr";
  289. inst.strSrc(operands_s,true);
  290. break;
  291. case iJB: case iJBE: case iJAE: case iJA:
  292. case iJL: case iJLE: case iJGE: case iJG:
  293. case iJE: case iJNE: case iJS: case iJNS:
  294. case iJO: case iJNO: case iJP: case iJNP:
  295. case iJCXZ:case iLOOP: case iLOOPE:case iLOOPNE:
  296. case iJMP: case iJMPF:
  297. /* Check if there is a symbol here */
  298. {
  299. ICODE *lab=pc.GetIcode(inst.src().getImm2());
  300. selectTable(Label);
  301. if ((inst.src().getImm2() < (uint32_t)numIcode) and /* Ensure in range */
  302. readVal(operands_s, lab->ll()->label, nullptr))
  303. {
  304. break; /* Symbolic label. Done */
  305. }
  306. }
  307. if (inst.testFlags(NO_LABEL))
  308. {
  309. //strcpy(p + WID_PTR, strHex(pIcode->ll()->immed.op));
  310. operands_s<<strHex(inst.src().getImm2());
  311. }
  312. else if (inst.testFlags(I) )
  313. {
  314. j = inst.src().getImm2();
  315. if (pl.count(j)==0) /* Forward jump */
  316. {
  317. pl[j] = ++g_lab;
  318. }
  319. if (inst.getOpcode() == iJMPF)
  320. {
  321. operands_s<<" far ptr ";
  322. }
  323. operands_s<<"L"<<pl[j];
  324. }
  325. else if (inst.getOpcode() == iJMPF)
  326. {
  327. operands_s<<"dword ptr";
  328. inst.strSrc(operands_s,true);
  329. }
  330. else
  331. {
  332. strDst(operands_s,I, inst.src());
  333. }
  334. break;
  335. case iCALL: case iCALLF:
  336. if (inst.testFlags(I))
  337. {
  338. if((inst.getOpcode() == iCALL))
  339. operands_s<< "near";
  340. else
  341. operands_s<< " far";
  342. operands_s<<" ptr "<<(inst.src().proc.proc)->name;
  343. }
  344. else if (inst.getOpcode() == iCALLF)
  345. {
  346. operands_s<<"dword ptr ";
  347. inst.strSrc(operands_s,true);
  348. }
  349. else
  350. strDst(operands_s,I, inst.src());
  351. break;
  352. case iENTER:
  353. operands_s<<strHex(inst.m_dst.off) << ", " << strHex(inst.src().getImm2());
  354. break;
  355. case iRET: case iRETF: case iINT:
  356. if (inst.testFlags(I))
  357. {
  358. operands_s<<strHex(inst.src().getImm2());
  359. }
  360. break;
  361. case iCMPS: case iREPNE_CMPS: case iREPE_CMPS:
  362. case iSCAS: case iREPNE_SCAS: case iREPE_SCAS:
  363. case iSTOS: case iREP_STOS:
  364. case iLODS: case iREP_LODS:
  365. case iMOVS: case iREP_MOVS:
  366. case iINS: case iREP_INS:
  367. case iOUTS: case iREP_OUTS:
  368. if (inst.src().segOver)
  369. {
  370. bool is_dx_src=(inst.getOpcode() == iOUTS or inst.getOpcode() == iREP_OUTS);
  371. if(is_dx_src)
  372. operands_s<<"dx, "<<szPtr[inst.getFlag() & B];
  373. else
  374. operands_s<<szPtr[inst.getFlag() & B];
  375. if (inst.getOpcode() == iLODS or
  376. inst.getOpcode() == iREP_LODS or
  377. inst.getOpcode() == iOUTS or
  378. inst.getOpcode() == iREP_OUTS)
  379. {
  380. operands_s<<Machine_X86::regName(inst.src().segOver); // szWreg[src.segOver-rAX]
  381. }
  382. else
  383. {
  384. operands_s<<"es:[di], "<<Machine_X86::regName(inst.src().segOver);
  385. }
  386. operands_s<<":[si]";
  387. }
  388. else
  389. {
  390. (inst.getFlag() & B)? opcode_with_mods<< "B": opcode_with_mods<< "W";
  391. }
  392. break;
  393. case iXLAT:
  394. if (inst.src().segOver)
  395. {
  396. operands_s<<" "<<szPtr[1];
  397. operands_s<<Machine_X86::regName(inst.src().segOver)<<":[bx]";
  398. }
  399. break;
  400. case iIN:
  401. (inst.getFlag() & B)? operands_s<<"al, " : operands_s<< "ax, ";
  402. (inst.testFlags(I))? operands_s << strHex(inst.src().getImm2()) : operands_s<< "dx";
  403. break;
  404. case iOUT:
  405. {
  406. std::string d1=((inst.testFlags(I))? strHex(inst.src().getImm2()): "dx");
  407. std::string d2=((inst.getFlag() & B) ? ", al": ", ax");
  408. operands_s<<d1 << d2;
  409. }
  410. break;
  411. default:
  412. break;
  413. }
  414. oper_stream << setw(15) << left <<opcode_with_mods.str();
  415. oper_stream << operands_s.str();
  416. /* Comments */
  417. if (inst.testFlags(SYNTHETIC))
  418. {
  419. fImpure = false;
  420. }
  421. else
  422. {
  423. for (j = inst.label, fImpure = 0; j > 0 and j < (int)nextInst; j++)
  424. {
  425. fImpure |= BITMAP(j, BM_DATA);
  426. }
  427. }
  428. result_stream << setw(54) << left << oper_stream.str();
  429. /* Check for user supplied comment */
  430. selectTable(Comment);
  431. ostringstream cbuf;
  432. if (readVal(cbuf, inst.label, nullptr))
  433. {
  434. result_stream <<"; "<<cbuf.str();
  435. }
  436. else if (fImpure or (inst.testFlags(SWITCH | CASE | SEG_IMMED | IMPURE | SYNTHETIC | TERMINATES)))
  437. {
  438. if (inst.testFlags(CASE))
  439. {
  440. result_stream << ";Case l"<< inst.caseEntry;
  441. }
  442. if (inst.testFlags(SWITCH))
  443. {
  444. result_stream << ";Switch ";
  445. }
  446. if (fImpure)
  447. {
  448. result_stream << ";Accessed as data ";
  449. }
  450. if (inst.testFlags(IMPURE))
  451. {
  452. result_stream << ";Impure operand ";
  453. }
  454. if (inst.testFlags(SEG_IMMED))
  455. {
  456. result_stream << ";Segment constant";
  457. }
  458. if (inst.testFlags(TERMINATES))
  459. {
  460. result_stream << ";Exit to DOS";
  461. }
  462. }
  463. /* Comment on iINT icodes */
  464. if (inst.getOpcode() == iINT)
  465. inst.writeIntComment(result_stream);
  466. /* Display output line */
  467. if(pass==3)
  468. {
  469. /* output to .b code buffer */
  470. if (inst.testFlags(SYNTHETIC))
  471. result_stream<<";Synthetic inst";
  472. if (pass == 3) /* output to .b code buffer */
  473. cCode.appendCode("%s\n", result_stream.str().c_str());
  474. }
  475. else
  476. {
  477. char buf[12];
  478. /* output to .a1 or .a2 file */
  479. if (not inst.testFlags(SYNTHETIC) )
  480. {
  481. sprintf(buf,"%03d %06X",loc_ip, inst.label);
  482. }
  483. else /* SYNTHETIC instruction */
  484. {
  485. sprintf(buf,"%03d ",loc_ip);
  486. result_stream<<";Synthetic inst";
  487. }
  488. m_fp<<buf<< " " << result_stream.str() << "\n";
  489. }
  490. }
  491. /****************************************************************************
  492. * formatRM
  493. ***************************************************************************/
  494. static void formatRM(std::ostringstream &p, const LLOperand &pm)
  495. {
  496. //char seg[4];
  497. if (pm.segOver)
  498. {
  499. p <<Machine_X86::regName(pm.segOver)<<':';
  500. }
  501. if (pm.regi == rUNDEF)
  502. {
  503. p<<"["<<strHex((uint32_t)pm.off)<<"]";
  504. }
  505. else if (pm.isReg())
  506. {
  507. p<<Machine_X86::regName(pm.regi);
  508. }
  509. else if (pm.off)
  510. {
  511. if (pm.off < 0)
  512. {
  513. p <<"["<<Machine_X86::regName(pm.regi)<<"-"<<strHex((uint32_t)(- pm.off))<<"]";
  514. }
  515. else
  516. {
  517. p <<"["<<Machine_X86::regName(pm.regi)<<"+"<<strHex((uint32_t)(pm.off))<<"]";
  518. }
  519. }
  520. else
  521. p <<"["<<Machine_X86::regName(pm.regi)<<"]";
  522. }
  523. /*****************************************************************************
  524. * strDst
  525. ****************************************************************************/
  526. static ostringstream & strDst(ostringstream &os,uint32_t flg, const LLOperand &pm)
  527. {
  528. /* Immediates to memory require size descriptor */
  529. //os << setw(WID_PTR);
  530. if ((flg & I) and not pm.isReg())
  531. os << szPtr[flg & B];
  532. formatRM(os, pm);
  533. return os;
  534. }
  535. /****************************************************************************
  536. * strSrc *
  537. ****************************************************************************/
  538. ostringstream &LLInst::strSrc(ostringstream &os,bool skip_comma)
  539. {
  540. if(false==skip_comma)
  541. os<<", ";
  542. if (testFlags(I))
  543. os<<strHex(src().getImm2());
  544. else if (testFlags(IM_SRC)) /* level 2 */
  545. os<<"dx:ax";
  546. else
  547. formatRM(os, src());
  548. return os;
  549. }
  550. /****************************************************************************
  551. * strHex *
  552. ****************************************************************************/
  553. static char *strHex(uint32_t d)
  554. {
  555. static char buf[10];
  556. d &= 0xFFFF;
  557. sprintf(buf, "0%X%s", d, (d > 9)? "h": "");
  558. return (buf + (buf[1] <= '9'));
  559. }
  560. /****************************************************************************
  561. * interactDis - interactive disassembler *
  562. ****************************************************************************/
  563. void interactDis(Function * initProc, int initIC)
  564. {
  565. const char *procname = "UNKNOWN";
  566. if(initProc)
  567. procname = initProc->name.c_str();
  568. printf("Wanted to start interactive disasassembler for %s:%d\n",procname,initIC);
  569. return;
  570. }
  571. /* Handle the floating point opcodes (icode iESC) */
  572. void LLInst::flops(std::ostringstream &out)
  573. {
  574. //char bf[30];
  575. uint8_t op = (uint8_t)src().getImm2();
  576. /* Note that op is set to the escape number, e.g.
  577. esc 0x38 is FILD */
  578. if ( not m_dst.isReg() )
  579. {
  580. /* The mod/rm mod bits are not set to 11 (i.e. register). This is the normal floating point opcode */
  581. out<<Machine_X86::floatOpName(op)<<' ';
  582. out <<setw(10);
  583. if ((op == 0x29) or (op == 0x1F))
  584. {
  585. out << "tbyte ptr ";
  586. }
  587. else switch (op & 0x30)
  588. {
  589. case 0x00:
  590. case 0x10:
  591. out << "dword ptr ";
  592. break;
  593. case 0x20:
  594. out << "qword ptr ";
  595. break;
  596. case 0x30:
  597. switch (op)
  598. {
  599. case 0x3C: /* FBLD */
  600. case 0x3E: /* FBSTP */
  601. out << "tbyte ptr ";
  602. break;
  603. case 0x3D: /* FILD 64 bit */
  604. case 0x3F: /* FISTP 64 bit */
  605. out << "qword ptr ";
  606. break;
  607. default:
  608. out << "uint16_t ptr ";
  609. break;
  610. }
  611. }
  612. formatRM(out, m_dst);
  613. }
  614. else
  615. {
  616. /* The mod/rm mod bits are set to 11 (i.e. register).
  617. Could be specials (0x0C-0x0F, etc), or the st(i) versions of
  618. normal opcodes. Because the opcodes are slightly different for
  619. this case (e.g. op=04 means FSUB if reg != 3, but FSUBR for
  620. reg == 3), a separate table is used (szFlops2). */
  621. int destRegIdx=m_dst.regi - rAX;
  622. switch (op)
  623. {
  624. case 0x0C:
  625. out << szFlops0C[destRegIdx];
  626. break;
  627. case 0x0D:
  628. out << szFlops0D[destRegIdx];
  629. break;
  630. case 0x0E:
  631. out << szFlops0E[destRegIdx];
  632. break;
  633. case 0x0F:
  634. out << szFlops0F[destRegIdx];
  635. break;
  636. case 0x15:
  637. out << szFlops15[destRegIdx];
  638. break;
  639. case 0x1C:
  640. out << szFlops1C[destRegIdx];
  641. break;
  642. case 0x33:
  643. out << szFlops33[destRegIdx];
  644. break;
  645. case 0x3C:
  646. out << szFlops3C[destRegIdx];
  647. break;
  648. default:
  649. out << Machine_X86::floatOpName(0x40+op);
  650. if ((op >= 0x20) and (op <= 0x27))
  651. {
  652. /* This is the ST(i), ST form. */
  653. out << "ST("<<destRegIdx - rAX<<"),ST";
  654. }
  655. else
  656. {
  657. /* ST, ST(i) */
  658. out << "ST,ST("<<destRegIdx;
  659. }
  660. break;
  661. }
  662. }
  663. }