disassem.cpp 22 KB

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