disassem.cpp 23 KB

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