Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /****************************  disasm2.cpp   ********************************
  2. * Author:        Agner Fog
  3. * Date created:  2007-02-25
  4. * Last modified: 2016-11-27
  5. * Project:       objconv
  6. * Module:        disasm2.cpp
  7. * Description:
  8. * Module for disassembler containing file output functions
  9. *
  10. * Changes that relate to assembly language syntax should be done in this file only.
  11. *
  12. * Copyright 2007-2016 GNU General Public License http://www.gnu.org/licenses
  13. *****************************************************************************/
  14. #include "stdafx.h"
  15.  
  16. /**********************  Warning and error texts   ***************************
  17. These texts are inserted in disassembled code in case of warnings or errors.
  18.  
  19. The occurrence of an error makes the disassembler mark the code block between
  20. the nearest known code labels as dubious. This means that the byte sequence
  21. might be data in the code segment or the disassembler might be out of phase
  22. with instruction boundaries. Dubious code will be shown both as code and as
  23. data.
  24.  
  25. A warning will be shown as 'Note:' before the instruction it applies to.
  26. This might indicate suboptimal coding or a possible cause for concern.
  27.  
  28. The criteria for distinguishing between warnings and errors is not the
  29. severity of consequences, but whether the condition is likely to be caused
  30. by common programming errors or by data in the code segment.
  31.  
  32. Some of the warning messages are quite benign, e.g. an unnecessary prefix.
  33. Other warning messages can have severe consequences, e.g. a function missing
  34. a return statement.
  35.  
  36. Still other warnings are no case for concern, but a condition requiring
  37. attention. For example the message: "Multi-byte NOP. Replace with ALIGN",
  38. might actually indicate a well optimized code. But it requires attention
  39. because the assembler cannot re-create the multi-byte NOP if the code
  40. is assembled again. The programmer needs to decide what level of alignment
  41. is optimal and replace the NOP with an align statement.
  42.  
  43. *****************************************************************************/
  44.  
  45. // Define error texts.
  46. SIntTxt AsmErrorTexts[] = {
  47.     {1,         "Instruction longer than 15 bytes"},
  48.     {2,         "Lock prefix not allowed for this opcode"},
  49.     {4,         "Illegal opcode"},
  50.     {8,         "Illegal operands for this opcode"},
  51.     {0x10,      "Instruction extends beyond end of code block"},
  52.     {0x20,      "Prefix after REX prefix not allowed"},
  53.     {0x40,      "This instruction is not allowed in 64 bit mode"},
  54.     {0x80,      "Instruction out of phase with next label"},
  55.     {0x100,     "Attempt to use R13 as base register without displacement"},
  56.     {0x200,     "Register 8 - 15 only allowed in 64 bit mode (Ignored)."},
  57.     {0x400,     "REX prefix not allowed on instruction with DREX byte"},
  58.     {0x800,     "VEX has X bit but no SIB byte (Probably ignored)"},
  59.     {0x1000,    "Relocation source does not match address or operand field"},
  60.     {0x2000,    "Overlapping relocations"},
  61.     {0x4000,    "This is unlikely to be code"}, // Consecutive bytes of 0 found
  62.     {0x8000,    "VEX.L bit not allowed here"},
  63.     {0x10000,   "VEX.mmmm bits out of range"},
  64.     {0x80000,   "Internal error in opcode table in opcodes.cpp"}
  65. };
  66.  
  67. // Warning texts 1: Warnings about conditions that could be intentional and suboptimal code
  68. SIntTxt AsmWarningTexts1[] = {
  69.     {1,          "Immediate operand could be made smaller by sign extension"},
  70.     {2,          "Immediate operand could be made smaller by zero extension"},
  71.     {4,          "Zero displacement could be omitted"},
  72.     {8,          "Displacement could be made smaller by sign extension"},
  73.     {0x10,       "SIB byte unnecessary here"},
  74.     {0x20,       "A shorter instruction exists for register operand"},
  75.     {0x40,       "Length-changing prefix causes delay on Intel processors"},
  76.     {0x80,       "Address size prefix should be avoided"},
  77.     {0x100,      "Same prefix occurs more than once"},
  78.     {0x200,      "Prefix valid but unnecessary"},
  79.     {0x400,      "Prefix bit or byte has no meaning in this context"},
  80.     {0x800,      "Contradicting prefixes"},
  81.     {0x1000,     "Required prefix missing"},
  82.     {0x2000,     "Address has scale factor but no index register"},
  83.     {0x4000,     "Address is not rip-relative"},
  84.     {0x8000,     "Absolute memory address without relocation"},
  85.     {0x10000,    "Unusual relocation type for this operand"},
  86.     {0x20000,    "Instruction pointer truncated by operand size prefix"},
  87.     {0x40000,    "Stack pointer truncated by address size prefix"},
  88.     {0x80000,    "Jump or call to data segment not allowed"},
  89.     {0x100000,   "Undocumented opcode"},
  90.     {0x200000,   "Unknown opcode reserved for future extensions"},
  91.     {0x400000,   "Memory operand is misaligned. Performance penalty"},
  92.     {0x800000,   "Alignment fault. Memory operand must be aligned"},
  93.     {0x1000000,  "Multi-byte NOP. Replace with ALIGN"},
  94.     {0x2000000,  "Bogus length-changing prefix causes delay on Intel processors here"},
  95.     {0x4000000,  "Non-default size for stack operation"},
  96.     {0x8000000,  "Function does not end with ret or jmp"},
  97.     {0x10000000, "No jump seems to point here"},
  98.     {0x20000000, "Full 64-bit address"},
  99.     {0x40000000, "VEX prefix bits not allowed here"}
  100. };
  101.  
  102. // Warning texts 2: Warnings about possible misinterpretation; serious warnings
  103. SIntTxt AsmWarningTexts2[] = {
  104.     {1,          "Label out of phase with instruction. Possibly spurious"},
  105.     {2,          "Planned future instruction, according to preliminary specification"},
  106.     {4,          "This instruction has been planned but never implemented because plans were changed. Will not work"},
  107.     {0x10,       "EVEX prefix not allowed for this instruction"},
  108.     {0x20,       "MVEX prefix not allowed for this instruction"},
  109.     {0x40,       "EVEX prefix option bits not allowed here"},
  110.     {0x80,       "MVEX prefix option bits not allowed here"},
  111.     {0x100,      "Mask register must be nonzero"},
  112.     {0x200,      "Broadcasting to scalar not allowd"},
  113. };
  114.  
  115.  
  116. // Indication of relocation types in comments:
  117. SIntTxt RelocationTypeNames[] = {
  118.     {0x001,  "(d)" },                   // Direct address in flat address space
  119.     {0x002,  "(rel)" },                 // Self-relative
  120.     {0x004,  "(imgrel)" },              // Image-relative
  121.     {0x008,  "(segrel)" },              // Segment-relative
  122.     {0x010,  "(refpoint)" },            // Relative to arbitrary point (position-independent code in Mach-O)
  123.     {0x021,  "(d)" },                   // Direct (adjust by image base)
  124.     {0x041,  "(d)" },                   // Direct (make procecure linkage table entry)
  125.     {0x081,  "(indirect)" },            // Gnu indirect function dispatcher (make procecure linkage table entry?)
  126.     {0x100,  "(seg)" },                 // Segment address or descriptor
  127.     {0x200,  "(sseg)" },                // Segment of symbol
  128.     {0x400,  "(far)" },                 // Far segment:offset address
  129.     {0x1001, "(GOT)" },                 // GOT entry
  130.     {0x1002, "(GOT r)" },               // self-relative to GOT entry
  131.     {0x2002, "(PLT r)" }                // self-relative to PLT entry
  132. };
  133.  
  134. // Instruction set names
  135. const char * InstructionSetNames[] = {
  136.     "8086", "80186", "80286", "80386",               // 0 - 3
  137.     "80486", "Pentium", "Pentium Pro", "MMX",        // 4 - 7
  138.     "Pentium II", "", "", "",                        // 8 - B
  139.     "", "", "", "",                                  // C - F
  140.     "", "SSE", "SSE2", "SSE3",                       // 10 - 13
  141.     "Supplementary SSE3", "SSE4.1", "SSE4.2", "AES", // 14 - 17
  142.     "CLMUL", "AVX", "FMA3", "?",                     // 18 - 1B
  143.     "AVX2", "BMI etc.", "?", "?",                    // 1C - 1F
  144.     "AVX-512", "AVX512PF/ER/CD", "MPX,SHA,TBD", "AVX512IFMA/VBMI", // 20 - 23
  145.     "AVX512_4FMAPS", "?", "?", "?",                                // 24 - 27
  146.     "?", "?", "?", "?",                              // 28 - 2B
  147.     "?", "?", "?", "?",                              // 2C - 2F
  148.     "?", "?", "?", "?",                              // 30 - 33
  149.     "?", "?", "?", "?",                              // 34 - 37
  150.     "?", "?", "?", "?",                              // 38 - 3B
  151.     "?", "?", "?", "?",                              // 3C - 3F
  152.     "?", "?", "?", "?",                              // 40 - 43
  153.     "?", "?", "?", "?",                              // 44 - 47
  154.     "?", "?", "?", "?",                              // 48 - 4B
  155.     "?", "?", "?", "?",                              // 4C - 4F
  156.     "?", "?", "?", "?",                              // 50 - 53
  157.     "?", "?", "?", "?",                              // 54 - 57
  158.     "?", "?", "?", "?",                              // 58 - 5B
  159.     "?", "?", "?", "?",                              // 5C - 5F
  160.     "?", "?", "?", "?",                              // 60 - 63
  161.     "?", "?", "?", "?",                              // 64 - 67
  162.     "?", "?", "?", "?",                              // 68 - 6B
  163.     "?", "?", "?", "?",                              // 6C - 6F
  164.     "?", "?", "?", "?",                              // 70 - 73
  165.     "?", "?", "?", "?",                              // 74 - 77
  166.     "?", "?", "?", "?",                              // 78 - 7B
  167.     "?", "?", "?", "?",                              // 7C - 7F
  168.     "Knights Corner", "?", "?", "?",                 // 80 - 83
  169.     "?", "?", "?", "?"                               // 84 - 87
  170. };
  171.  
  172. const int InstructionSetNamesLen = TableSize(InstructionSetNames);
  173.  
  174.  
  175. /**************************  class CDisassembler  *****************************
  176. Most member functions of CDisassembler are defined in disasm1.cpp
  177.  
  178. Only the functions that produce output are defined here:
  179. ******************************************************************************/
  180.  
  181. void CDisassembler::WriteShortRegOperand(uint32 Type) {
  182.     // Write register operand from lower 3 bits of opcode byte to OutFile
  183.     uint32 rnum = Get<uint8>(s.OpcodeStart2) & 7;
  184.     // Check REX.B prefix
  185.     if (s.Prefixes[7] & 1) rnum |= 8;             // Add 8 if REX.B prefix
  186.     // Write register name
  187.     WriteRegisterName(rnum, Type);
  188. }
  189.  
  190. void CDisassembler::WriteRegOperand(uint32 Type) {
  191.     // Write register operand from reg bits
  192.     uint32 Num = s.Reg;                           // Register number
  193.  
  194.     // Write register name
  195.     WriteRegisterName(Num, Type);
  196. }
  197.  
  198. void CDisassembler::WriteRMOperand(uint32 Type) {
  199.     // Write memory or register operand from mod/rm bits of mod/reg/rm byte
  200.     // and possibly SIB byte or direct memory operand to OutFile.
  201.     // Also used for writing direct memory operand
  202.  
  203.     if ((Type & 0xFF) == 0) {
  204.         // No explicit operand
  205.         return;
  206.     }
  207.  
  208.     uint32 Components = 0;                        // Count number of addends inside []
  209.     int64  Addend = 0;                            // Inline displacement or addend
  210.     int AddressingMode = 0;                       // 0: 16- or 32 bit addressing mode
  211.     // 1: 64-bit pointer
  212.     // 2: 32-bit absolute in 64-bit mode
  213.     // 4: 64-bit rip-relative
  214.     // 8: 64-bit absolute
  215.     // Check if register or memory
  216.     if (s.Mod == 3) {
  217.         // Register operand
  218.         WriteRegisterName(s.RM, Type);
  219.         return;
  220.     }
  221.  
  222.     // Find addend, if any
  223.     switch (s.AddressFieldSize) {
  224.     case 1:  // 1 byte displacement
  225.         Addend = Get<int8>(s.AddressField);
  226.         break;
  227.     case 2:  // 2 bytes displacement
  228.         Addend = Get<int16>(s.AddressField);
  229.         break;
  230.     case 4:  // 4 bytes displacement
  231.         Addend = Get<int32>(s.AddressField);
  232.         if ((s.MFlags & 0x100) && !s.AddressRelocation) {
  233.             // rip-relative
  234.             Addend += ImageBase + uint64(SectionAddress + IEnd);
  235.         }
  236.         break;
  237.     case 8:  // 8 bytes address
  238.         Addend = Get<int64>(s.AddressField);
  239.         break;
  240.     }
  241.     // Get AddressingMode
  242.     if (s.AddressSize > 32) {
  243.         if (s.MFlags & 0x100) {
  244.             AddressingMode = 4;                     // 64-bit rip-relative
  245.         }
  246.         else if (s.AddressFieldSize == 8) {
  247.             AddressingMode = 8;                     // 64-bit absolute
  248.         }
  249.         else if (s.AddressRelocation || (s.BaseReg==0 && s.IndexReg==0)) {
  250.             AddressingMode = 2;                     // 32-bit absolute in 64-bit mode
  251.         }
  252.         else {
  253.             AddressingMode = 1;                     // 64-bit pointer
  254.         }
  255.     }
  256.  
  257.     // Make exception for LEA with no type
  258.     if (Opcodei == 0x8D) {
  259.         Type = 0;
  260.     }
  261.     // Write type override
  262.     if ((s.OpcodeDef->InstructionFormat & 0x1F) == 0x1E) {    
  263.         WriteOperandType(Type & 0xFF);    // has vsib address: write element type rather than vector type
  264.     }
  265.     else if (!(s.OpcodeDef->Options & 0x800)) {
  266.         WriteOperandType(Type);           // write operand type
  267.     }
  268.  
  269.     if (Syntax != SUBTYPE_MASM) {
  270.         // Write "[" around memory operands, before segment
  271.         OutFile.Put("[");
  272.     }
  273.  
  274.     // Write segment prefix, if any
  275.     if (s.Prefixes[0]) {
  276.         OutFile.Put(RegisterNamesSeg[GetSegmentRegisterFromPrefix()]);
  277.         OutFile.Put(":");
  278.     }
  279.     else if (!s.BaseReg && !s.IndexReg && (!s.AddressRelocation || (s.Warnings1 & 0x10000)) && Syntax != SUBTYPE_YASM) {
  280.         // No pointer register and no memory reference or wrong type of memory reference.
  281.         // Write segment register to indicate that we have a memory operand
  282.         OutFile.Put("DS:");
  283.     }
  284.  
  285.     if (Syntax == SUBTYPE_MASM) {
  286.         // Write "[" around memory operands, after segment
  287.         OutFile.Put("[");
  288.     }
  289.  
  290.     if (Syntax == SUBTYPE_YASM && (AddressingMode & 0x0E)) {
  291.         // Specify absolute or relative addressing mode
  292.         switch (AddressingMode) {
  293.         case 2: OutFile.Put("abs ");  break;
  294.         case 4: OutFile.Put("rel ");  break;
  295.         case 8: OutFile.Put("abs qword ");  break;
  296.         }
  297.     }
  298.  
  299.     // Write relocation target, if any
  300.     if (s.AddressRelocation) {
  301.         // Write cross reference
  302.         WriteRelocationTarget(s.AddressRelocation, 4 | (s.MFlags & 0x100), Addend);
  303.         // Addend has been written, don't write it again
  304.         Addend = 0;
  305.         // Remember that something has been written
  306.         Components++;
  307.     }
  308.  
  309.     // Check address size for pointer registers
  310.     //const char * * PointerRegisterNames;
  311.     uint32 RegisterType = 0;
  312.     switch (s.AddressSize) {
  313.     case 16:
  314.         RegisterType = 2;  break;
  315.     case 32:
  316.         RegisterType = 3;  break;
  317.     case 64:
  318.         RegisterType = 4;  break;
  319.     }
  320.  
  321.     // Write base register, if any
  322.     if (s.BaseReg) {
  323.         if (Components++) OutFile.Put("+");      // Put "+" if anything before
  324.         WriteRegisterName(s.BaseReg - 1, RegisterType);
  325.     }
  326.  
  327.     // Write index register, if any
  328.     if (s.IndexReg) {
  329.         if (Components++) OutFile.Put("+");        // Put "+" if anything before
  330.         if ((s.OpcodeDef->InstructionFormat & 0x1F) != 0x1E) {
  331.             // normal index register
  332.             WriteRegisterName(s.IndexReg - 1, RegisterType);
  333.         }
  334.         else {
  335.             // VSIB byte specifies vector index register
  336.             WriteRegisterName(s.IndexReg - 1, Type & 0xF00);
  337.         }
  338.         // Write scale factor, if any
  339.         if (s.Scale) {
  340.             OutFile.Put("*");
  341.             OutFile.PutDecimal(1 << s.Scale);
  342.         }
  343.     }
  344.  
  345.     // Write +/- before addend
  346.     if (Components && Addend) {
  347.         // Displacement comes after base/index registers
  348.         if (Addend >= 0 || s.AddressFieldSize == 8) {
  349.             // Positive. Write +
  350.             OutFile.Put("+");
  351.         }
  352.         else {
  353.             // Negative. Write -
  354.             OutFile.Put("-");
  355.             Addend = -Addend;
  356.         }
  357.     }
  358.  
  359.     if (Addend || Components == 0) {
  360.         // Find minimum number of digits needed
  361.         uint32 AddendSize = s.AddressFieldSize;
  362.         if ((uint64)Addend < 0x100 && AddendSize > 1) AddendSize = 1;
  363.         else if ((uint64)Addend < 0x10000 && AddendSize > 2) AddendSize = 2;
  364.  
  365.         // Write address or addend as hexadecimal
  366.         OutFile.PutHex((uint64)Addend, 2);
  367.  
  368.         // Check if offset multiplier needed
  369.         if (s.OffsetMultiplier && s.AddressFieldSize == 1 && Addend) {
  370.             OutFile.Put("*");
  371.             OutFile.PutHex(s.OffsetMultiplier, 2);
  372.         }
  373.     }
  374.  
  375.     if (Syntax == SUBTYPE_GASM && (AddressingMode == 4)) {
  376.         // Need to specify rip-relative address
  377.         OutFile.Put("+rip");
  378.     }
  379.  
  380.     // End with "]"
  381.     OutFile.Put("]");
  382. }
  383.  
  384.  
  385. void CDisassembler::WriteOperandType(uint32 type) {
  386.     switch (Syntax) {
  387.     case SUBTYPE_MASM:
  388.         WriteOperandTypeMASM(type);  break;
  389.     case SUBTYPE_YASM:
  390.         WriteOperandTypeYASM(type);  break;
  391.     case SUBTYPE_GASM:
  392.         WriteOperandTypeGASM(type);  break;
  393.     }
  394. }
  395.  
  396. void CDisassembler::WriteOperandTypeMASM(uint32 type) {
  397.     // Write type override before operand, e.g. "dword ", MASM syntax
  398.     if (type & 0xF00) {
  399.         type &= 0xF00;                             // Ignore element type for vectors
  400.     }
  401.     else {
  402.         type &= 0xFF;                              // Use operand type only
  403.     }
  404.  
  405.     switch (type) {
  406.     case 1:  // 8 bits
  407.         OutFile.Put("byte ");  break;
  408.     case 2:  // 16 bits
  409.         OutFile.Put("word ");  break;
  410.     case 3:  // 32 bits
  411.         OutFile.Put("dword ");  break;
  412.     case 4:  // 64 bits
  413.         OutFile.Put("qword ");  break;
  414.     case 5:  // 80 bits
  415.         if ((s.OpcodeDef->Destination & 0xFF) == 0xD) {
  416.             // 64+16 bit far pointer. Not supported by MASM
  417.             OutFile.Put("fword ");
  418.             s.OpComment = "64+16 bit. Need REX.W prefix";
  419.         }
  420.         else {
  421.             OutFile.Put("tbyte ");}
  422.         break;
  423.     case 6: case 0x40: case 0x48: case 0:
  424.         // Other size. Write nothing
  425.         break;
  426.     case 7: case 0x0D: // 48 bits or far
  427.         OutFile.Put("fword ");  
  428.         if ((s.OpcodeDef->Destination & 0xFF) == 0xD && WordSize == 64) {
  429.             // All assemblers I have tried forget the REX.W prefix here. Make a notice
  430.             s.OpComment = "32+16 bit. Possibly forgot REX.W prefix";
  431.         }      
  432.         break;
  433.     case 0x4A: // 16 bits float
  434.         OutFile.Put("word ");  break;
  435.     case 0x43: // 32 bits float (x87)
  436.     case 0x4B: // 32 bits float (SSE2)
  437.         OutFile.Put("dword ");  break;
  438.     case 0x44: // 64 bits float
  439.     case 0x4C: // 64 bits float (SSE2)
  440.         OutFile.Put("qword ");  break;
  441.     case 0x45: // 80 bits float
  442.         OutFile.Put("tbyte ");  break;
  443.     case 0x84: case 0x85: // far call
  444.         OutFile.Put("far ");  break;
  445.     case 0x95: // 16 bits mask register
  446.         OutFile.Put("word ");  break;
  447.     case 0x300:  // MMX
  448.         OutFile.Put("qword ");  break;
  449.     case 0x400:  // XMM
  450.         OutFile.Put("xmmword ");  break;
  451.     case 0x500:  // YMM
  452.         OutFile.Put("ymmword ");  break;
  453.     case 0x600:  // ZMM
  454.         OutFile.Put("zmmword ");  break;
  455.     case 0x700:  // future 1024 bit
  456.         OutFile.Put("?mmword ");  break;
  457.     }
  458.     OutFile.Put("ptr ");
  459. }
  460.  
  461. void CDisassembler::WriteOperandTypeYASM(uint32 type) {
  462.     // Write type override before operand, e.g. "dword", NASM/YASM syntax
  463.     if (type & 0xF00) {
  464.         type &= 0xF00;                             // Ignore element type for vectors
  465.     }
  466.     else {
  467.         type &= 0xFF;                              // Use operand type only
  468.     }
  469.     uint32 Dest = s.OpcodeDef->Destination & 0xFF;// Destination operand
  470.     if (Dest >= 0xB && Dest < 0x10) {
  471.         // This is a pointer
  472.         if (Dest < 0x0D) {
  473.             OutFile.Put("near ");                   // Near indirect jump/call
  474.         }
  475.         else {
  476.             // Far pointer
  477.             if ((WordSize == 16 && type == 3) || (WordSize == 32 && type == 7)) {
  478.                 OutFile.Put("far ");
  479.             }
  480.             else {
  481.                 // Size currently not supported by YASM
  482.                 switch (type) {
  483.                 case 3: OutFile.Put("far ");
  484.                     s.OpComment = "16+16 bit. Needs 66H prefix";
  485.                     break;
  486.                 case 7: OutFile.Put("far ");  
  487.                     s.OpComment = "32+16 bit. Possibly forgot REX.W prefix";
  488.                     break;
  489.                 case 5: OutFile.Put("far ");  
  490.                     s.OpComment = "64+16 bit. Needs REX.W prefix";
  491.                     break;
  492.                 }
  493.             }
  494.         }
  495.         return;
  496.     }
  497.     switch (type) {
  498.     case 1:  // 8 bits
  499.         OutFile.Put("byte ");  break;
  500.     case 2:  // 16 bits
  501.         OutFile.Put("word ");  break;
  502.     case 3:  // 32 bits
  503.         OutFile.Put("dword ");  break;
  504.     case 4:  // 64 bits
  505.         OutFile.Put("qword ");  break;
  506.     case 5:  // 80 bits
  507.         OutFile.Put("tbyte ");  break;
  508.     case 7:  // 48 bits
  509.         OutFile.Put("fword ");  break;
  510.     case 0x4A: // 16 bits float
  511.         OutFile.Put("word ");  break;
  512.     case 0x43: // 32 bits float (x87)
  513.     case 0x4B: // 32 bits float (SSE2)
  514.         OutFile.Put("dword ");  break;
  515.     case 0x44: // 64 bits float
  516.     case 0x4C: // 64 bits float (SSE2)
  517.         OutFile.Put("qword ");  break;
  518.     case 0x45: // 80 bits float
  519.         OutFile.Put("tbyte ");  break;
  520.     case 0x84: case 0x85: // far call
  521.         OutFile.Put("far ");  break;
  522.     case 0x95: // 16 bits mask register
  523.         OutFile.Put("word ");  break;
  524.     case 0x300:  // MMX
  525.         OutFile.Put("qword ");  break;
  526.     case 0x400:  // XMM
  527.         OutFile.Put("oword ");  break;
  528.     case 0x500:  // YMM
  529.         OutFile.Put("yword ");  break;
  530.     case 0x600:  // ZMM
  531.         OutFile.Put("zword ");  break;
  532.     case 0x700:  // Future 128 bytes
  533.         OutFile.Put("?word ");  break;
  534.     default:; // Anything else: write nothing
  535.     }
  536. }
  537.  
  538. void CDisassembler::WriteOperandTypeGASM(uint32 type) {
  539.     // Write type override before operand, e.g. "dword ", GAS syntax
  540.     if (type & 0xF00) {
  541.         type &= 0xF00;                             // Ignore element type for vectors
  542.     }
  543.     else {
  544.         type &= 0xFF;                              // Use operand type only
  545.     }
  546.  
  547.     switch (type) {
  548.     case 1:  // 8 bits
  549.         OutFile.Put("byte ");  break;
  550.     case 2:  // 16 bits
  551.         OutFile.Put("word ");  break;
  552.     case 3:  // 32 bits
  553.         OutFile.Put("dword ");  break;
  554.     case 4:  // 64 bits
  555.         OutFile.Put("qword ");  break;
  556.     case 5:  // 80 bits
  557.         if ((s.OpcodeDef->Destination & 0xFF) == 0xD) {
  558.             // 64+16 bit far pointer. Not supported by Gas
  559.             OutFile.Put("fword ");
  560.             s.OpComment = "64+16 bit. Needs REX.W prefix";
  561.         }
  562.         else {
  563.             OutFile.Put("tbyte ");}
  564.         break;
  565.     case 6: case 0x40: case 0x48: case 0:
  566.         // Other size. Write nothing
  567.         break;
  568.     case 7:    // 48 bits
  569.         OutFile.Put("fword ");  
  570.         if ((s.OpcodeDef->Destination & 0xFF) == 0xD && WordSize == 64) {
  571.             // All assemblers I have tried forget the REX.W prefix here. Make a notice
  572.             s.OpComment = "32+16 bit. Possibly forgot REX.W prefix";
  573.         }      
  574.         break;
  575.     case 0x4A: // 16 bits float
  576.         OutFile.Put("word ");  break;
  577.     case 0x43: // 32 bits float (x87)
  578.     case 0x4B: // 32 bits float (SSE2)
  579.         OutFile.Put("dword ");  break;
  580.     case 0x44: // 64 bits float
  581.     case 0x4C: // 64 bits float (SSE2)
  582.         OutFile.Put("qword ");  break;
  583.     case 0x45: // 80 bits float
  584.         OutFile.Put("tbyte ");  break;
  585.     case 0x84: case 0x85: // far call
  586.         OutFile.Put("far ");  break;
  587.     case 0x95: // 16 bits mask register
  588.         OutFile.Put("word ");  break;
  589.     case 0x300:  // MMX
  590.         OutFile.Put("qword ");  break;
  591.     case 0x400:  // XMM
  592.         OutFile.Put("xmmword ");  break;
  593.     case 0x500:  // YMM
  594.         OutFile.Put("ymmword ");  break;
  595.     case 0x600:  // ZMM
  596.         OutFile.Put("zmmword ");  break;
  597.     case 0x700:  // future 1024 bit
  598.         OutFile.Put("?mmword ");  break;
  599.     }
  600. }
  601.  
  602.  
  603. void CDisassembler::WriteDREXOperand(uint32 Type) {
  604.     // Write register operand from dest bits of DREX byte (AMD only)
  605.     uint32 Num = s.Vreg >> 4;                    // Register number
  606.     // Write register name
  607.     WriteRegisterName(Num, Type);
  608. }
  609.  
  610. void CDisassembler::WriteVEXOperand(uint32 Type, int i) {
  611.     // Write register operand from VEX.vvvv bits or immediate bits
  612.     uint32 Num;                                   // Register number
  613.     switch (i) {
  614.     case 0:  // Use VEX.vvvv bits
  615.         Num = s.Vreg & 0x1F;  break;
  616.     case 1:  // Use immediate bits 4-7
  617.         Num = Get<uint8>(s.ImmediateField) >> 4;  break;
  618.     case 2:  // Use immediate bits 0-3 (Unused. For possible future use)
  619.         Num = Get<uint8>(s.ImmediateField) & 0x0F;  break;
  620.     default:
  621.         Num = 0;
  622.     }
  623.     // Write register name
  624.     WriteRegisterName(Num, Type);
  625. }
  626.  
  627.  
  628. void CDisassembler::WriteOperandAttributeEVEX(int i, int isMem) {
  629.     // Write operand attributes and instruction attributes from EVEX z, LL, b and aaa bits
  630.     // i = operand number (0 = destination, 1 = first source, 2 = second source,
  631.     // 98 = after last SIMD operand, 99 = after last operand)
  632.     // isMem: true if memory operand, false if register operand
  633.     uint32 swiz = s.OpcodeDef->EVEX;   // indicates meaning of EVEX attribute bits
  634.  
  635.     if ((swiz & 0x30) && (i == 0 || (s.OpcodeDef->Destination == 0 && i == 1))) {  // first operand
  636.         // write mask
  637.         if (s.Kreg || (swiz & 0xC0)) {
  638.             OutFile.Put(" {k");
  639.             OutFile.PutDecimal(s.Kreg);
  640.             OutFile.Put("}");
  641.             if ((swiz & 0x20) && (s.Esss & 8)) {
  642.                 // zeroing
  643.                 OutFile.Put("{z}");
  644.             }
  645.         }
  646.     }
  647.     if (swiz & 0x07) {
  648.         // broadcast, rounding or sae allowed
  649.         if (isMem && i < 8) {
  650.             // memory operand
  651.             if ((swiz & 0x01) && (s.Esss & 1)) {            
  652.                 // write memory broadcast
  653.                 // calculate broadcast factor
  654.                 uint32 op = s.Operands[i];  // operand
  655.                 uint32 elementsize = GetDataElementSize(op); // element size
  656.                 uint32 opv = s.Operands[0];  // any vector operand
  657.                 if (!(opv & 0xF00)) opv = s.Operands[1]; // first operand is not a vector, use next
  658.                 uint32 vectorsize  = GetDataItemSize(opv); // vector size
  659.                 if (vectorsize > elementsize) { // avoid broadcasting to scalar
  660.                     if (elementsize) { // avoid division by zero
  661.                         OutFile.Put(" {1to");
  662.                         OutFile.PutDecimal(vectorsize/elementsize);
  663.                         OutFile.Put("}");
  664.                     }
  665.                     else {
  666.                         OutFile.Put("{unknown broadcast}");
  667.                     }
  668.                 }
  669.             }
  670.         }
  671.         if (i == 98 && s.Mod == 3) {   // after last SIMD operand. no memory operand
  672.             // NASM has rounding mode and sae decoration after last SIMD operand with a comma.
  673.             // No spec. for other assemblers available yet (2014).
  674.             // use i == 99 if it should be placed after last operand.
  675.             // Perhaps the comma should be removed for other assemblers?
  676.             if ((swiz & 0x4) && (s.Esss & 1)) {
  677.                 // write rounding mode
  678.                 uint32 rounding = (s.Esss >> 1) & 3;
  679.                 OutFile.Put(", {");
  680.                 OutFile.Put(EVEXRoundingNames[rounding]);
  681.                 OutFile.Put("}");
  682.             }
  683.             else if ((swiz & 0x2) && (s.Esss & 1)) {
  684.                 // no rounding mode. write sae
  685.                 OutFile.Put(", {");
  686.                 OutFile.Put(EVEXRoundingNames[4]);
  687.                 OutFile.Put("}");
  688.             }
  689.         }
  690.     }
  691. }
  692.  
  693.  
  694. void CDisassembler::WriteOperandAttributeMVEX(int i, int isMem) {
  695.     // Write operand attributes and instruction attributes from MVEX sss, e and kkk bits.
  696.     // i = operand number (0 = destination, 1 = first source, 2 = second source, 99 = after last operand)
  697.     // isMem: true if memory operand, false if register operand
  698.     uint32 swiz = s.OpcodeDef->MVEX;   // indicates meaning of MVEX attribute bits
  699.     const int R_sae_syntax = 0;   // syntax alternatives for rounding mode + sae
  700.                                   // 0: {rn-sae}, 1: {rn}{sae}
  701.     const char * text = 0;        // temporary text pointer
  702.  
  703.     if ((swiz & 0x1000) && (i == 0 || (s.OpcodeDef->Destination == 0 && i == 1))) {  // first operand
  704.         // write mask
  705.         if (s.Kreg || (swiz & 0x2000)) {
  706.             OutFile.Put(" {k");
  707.             OutFile.PutDecimal(s.Kreg);
  708.             OutFile.Put("}");
  709.         }
  710.     }
  711.     if (swiz & 0x1F) {
  712.         // swizzle allowed    
  713.         if (isMem && i < 90) {
  714.             // write memory broadcast/up/down conversion
  715.             text = s.SwizRecord->name;
  716.             if (text && *text) {
  717.                 OutFile.Put(" {");  OutFile.Put(text);  OutFile.Put("}");
  718.             }
  719.         }
  720.         //if (i == 2 || ((s.OpcodeDef->Source2 & 0xF0F00) == 0 && i == 1)) {
  721.         if (i == 98) {   // after last SIMD operand
  722.             // last register or memory operand
  723.             if (s.Mod == 3 && !((swiz & 0x700) && (s.Esss & 8))) { // skip alternative meaning of sss field for register operand when E=1
  724.                 // write register swizzle
  725.                 text = s.SwizRecord->name;
  726.                 if (text && *text) {
  727.                     OutFile.Put(" {");  OutFile.Put(text);  OutFile.Put("}");
  728.                 }
  729.             }
  730.         }
  731.         if (i == 99) {   // after last operand
  732.             if (s.Mod == 3 && (swiz & 0x300) && (s.Esss & 8)) {            
  733.                 // alternative meaning of sss field for register operand when E=1
  734.                 switch (swiz & 0x300) {
  735.                 case 0x100:  // rounding mode and not sae
  736.                     text = SwizRoundTables[0][0][s.Esss & 3].name;
  737.                     break;
  738.                 case 0x200:  // suppress all exceptions
  739.                     if ((s.Esss & 4) && !(swiz & 0x800)) text = "sae";
  740.                     break;
  741.                 case 0x300:  // rounding mode and sae
  742.                     text = SwizRoundTables[0][R_sae_syntax][s.Esss & 7].name;
  743.                     break;
  744.                 }
  745.             }
  746.             if (text && *text) {
  747.                 OutFile.Put(", {");  OutFile.Put(text);  OutFile.Put("}");
  748.             }
  749.         }
  750.     }
  751.     if (isMem && (s.Esss & 8) && !(swiz & 0x800)) {
  752.         // cache eviction hint after memory operand
  753.         OutFile.Put(" {eh}");
  754.     }
  755. }
  756.  
  757. void CDisassembler::WriteRegisterName(uint32 Value, uint32 Type) {
  758.     // Write name of register to OutFile
  759.     if (Type & 0xF00) {
  760.         // vector register
  761.         Type &= 0xF00;
  762.     }
  763.     else {
  764.         // Other register
  765.         Type &= 0xFF;                              // Remove irrelevant bits
  766.     }
  767.  
  768.     // Check fixed registers (do not depend on Value)
  769.     switch (Type) {
  770.     case 0xA1:  // al
  771.         Type = 1;  Value = 0;
  772.         break;
  773.  
  774.     case 0xA2:  // ax
  775.         Type = 2;  Value = 0;
  776.         break;
  777.  
  778.     case 0xA3:  // eax
  779.         Type = 3;  Value = 0;
  780.         break;
  781.  
  782.     case 0xA4:  // rax
  783.         Type = 4;  Value = 0;
  784.         break;
  785.  
  786.     case 0xAE:  // xmm0
  787.         Type = 0x400;  Value = 0;
  788.         break;
  789.  
  790.     case 0xAF:  // st(0)
  791.         Type = 0x40;  Value = 0;
  792.         break;
  793.  
  794.     case 0xB2:  // dx
  795.         Type = 2;  Value = 2;
  796.         break;
  797.  
  798.     case 0xB3:  // cl
  799.         Type = 1;  Value = 1;
  800.         break;
  801.     }
  802.  
  803.     // Get register number limit
  804.     uint32 RegNumLimit = 7;    // largest register number
  805.     if (WordSize >= 64) {
  806.         RegNumLimit = 15;
  807.         if ((s.Prefixes[6] & 0x40) && (Type & 0xF40)) {
  808.             // EVEX or MVEX prefix and vector
  809.             RegNumLimit = 31;
  810.         }
  811.     }
  812.  
  813.     switch (Type) {
  814.     case 0x91:     // segment register
  815.         RegNumLimit = 5;
  816.         break;
  817.     case 0x300:  // mmx
  818.     case 0x40:   // st register        
  819.     case 0x95:   // k mask register
  820.         RegNumLimit = 7;
  821.         break;
  822.     case 0x98:   // bounds register
  823.         RegNumLimit = 3;
  824.         break;
  825.     }
  826.     if (Value > RegNumLimit) {
  827.         // register number out of range
  828.         OutFile.Put("unknown register ");
  829.         switch (Type) {
  830.         case 1:
  831.             OutFile.Put("(8 bit) ");  break;
  832.         case 2:
  833.             OutFile.Put("(16 bit) ");  break;
  834.         case 3:
  835.             OutFile.Put("(32 bit) ");  break;
  836.         case 4:
  837.             OutFile.Put("(64 bit) ");  break;
  838.         case 0x40:   // st register
  839.             OutFile.Put("st");  break;
  840.         case 0x91:  // Segment register
  841.             OutFile.Put("seg");  break;
  842.         case 0x92:  // Control register
  843.             OutFile.Put("cr");  break;
  844.         case 0x95:  // k mask register
  845.             OutFile.Put("k");  break;
  846.         case 0x300:  // mmx register
  847.             OutFile.Put("mm");  break;
  848.         case 0x400:  // xmm register
  849.             OutFile.Put("xmm");  break;
  850.         case 0x500:  // ymm register
  851.             OutFile.Put("ymm");  break;
  852.         case 0x600:  // zmm register
  853.             OutFile.Put("zmm");  break;
  854.         case 0x700:  // future 1024 bit register
  855.             OutFile.Put("?mm");  break;
  856.         }
  857.         OutFile.PutDecimal(Value);
  858.     }
  859.     else {
  860.         // Write register name depending on type
  861.         switch (Type) {
  862.         case 1:  // 8 bit register. Depends on any REX prefix
  863.             OutFile.Put(s.Prefixes[7] ? RegisterNames8x[Value] : RegisterNames8[Value & 7]);
  864.             break;
  865.  
  866.         case 2:  // 16 bit register
  867.             OutFile.Put(RegisterNames16[Value]);
  868.             break;
  869.  
  870.         case 3:  // 32 bit register
  871.             OutFile.Put(RegisterNames32[Value]);
  872.             break;
  873.  
  874.         case 4:  // 64 bit register
  875.             OutFile.Put(RegisterNames64[Value]);
  876.             break;
  877.  
  878.         case 0x300:  // mmx register
  879.             OutFile.Put("mm");
  880.             OutFile.PutDecimal(Value);
  881.             break;
  882.  
  883.         case 0x400:  // xmm register (packed integer or float)
  884.         case 0x48: case 0x4B: case 0x4C: // xmm register (scalar float)
  885.             OutFile.Put("xmm");
  886.             OutFile.PutDecimal(Value);
  887.             break;
  888.  
  889.         case 0x500:  // ymm register (packed)
  890.             OutFile.Put("ymm");
  891.             OutFile.PutDecimal(Value);
  892.             break;
  893.  
  894.         case 0x600:  // zmm register (packed)
  895.             OutFile.Put("zmm");
  896.             OutFile.PutDecimal(Value);
  897.             break;
  898.  
  899.         case 0x700:  // future 1024 bit register
  900.             OutFile.Put("?mm");
  901.             OutFile.PutDecimal(Value);
  902.             break;
  903.  
  904.         case 0x40:  // st register
  905.             if (Syntax == SUBTYPE_YASM) {
  906.                 // NASM, YASM and GAS-AT&T use st0
  907.                 OutFile.Put("st");
  908.                 OutFile.PutDecimal(Value);
  909.             }
  910.             else {
  911.                 // MASM and GAS-Intel use st(0),
  912.                 OutFile.Put("st(");
  913.                 OutFile.PutDecimal(Value);
  914.                 OutFile.Put(")");
  915.             }
  916.             break;
  917.  
  918.         case 0x91:  // Segment register
  919.             OutFile.Put(RegisterNamesSeg[Value & 7]);
  920.             break;
  921.  
  922.         case 0x92:  // Control register
  923.             OutFile.Put(RegisterNamesCR[Value]);
  924.             break;
  925.  
  926.         case 0x93:  // Debug register
  927.             OutFile.Put("dr");
  928.             OutFile.PutDecimal(Value);
  929.             break;
  930.  
  931.         case 0x94:  // Test register (obsolete)
  932.             OutFile.Put("tr");
  933.             OutFile.PutDecimal(Value);
  934.             break;
  935.  
  936.         case 0x95:  // k mask register
  937.             OutFile.Put("k");
  938.             OutFile.PutDecimal(Value);
  939.             break;
  940.  
  941.         case 0x98:  // bounds register
  942.             OutFile.Put("bnd");
  943.             OutFile.PutDecimal(Value);
  944.             break;
  945.  
  946.         case 0xB1:  // 1
  947.             OutFile.Put("1");
  948.             break;
  949.  
  950.         default:    // Unexpected
  951.             OutFile.Put("UNKNOWN REGISTER TYPE ");
  952.             OutFile.PutDecimal(Value);
  953.             break;
  954.         }
  955.     }
  956. }
  957.  
  958.  
  959. void CDisassembler::WriteImmediateOperand(uint32 Type) {
  960.     // Write immediate operand or direct jump/call address
  961.     int    WriteFormat;                 // 0: unsigned, 1: signed, 2: hexadecimal
  962.     int    Components = 0;              // Number of components in immediate operand      
  963.     uint32 OSize;                       // Operand size
  964.     uint32 FieldPointer;                // Pointer to field containing value
  965.     uint32 FieldSize;                   // Size of field containing value
  966.     int64  Value = 0;                   // Value of immediate operand
  967.  
  968.     // Check if far
  969.     if ((Type & 0xFE) == 0x84) {
  970.         // Write far
  971.         WriteOperandType(Type);
  972.     }
  973.  
  974.     // Check if type override needed
  975.     if ((s.OpcodeDef->AllowedPrefixes & 2) && s.Prefixes[4] == 0x66
  976.         && (Opcodei == 0x68 || Opcodei == 0x6A)) {
  977.             // Push immediate with non-default operand size needs type override
  978.             WriteOperandType(s.OperandSize == 16 ? 2 : 3);
  979.     }
  980.  
  981.     FieldPointer = s.ImmediateField;
  982.     FieldSize    = s.ImmediateFieldSize;
  983.  
  984.     if (Syntax == SUBTYPE_YASM && (Type & 0x0F) == 4 && FieldSize == 8) {
  985.         // Write type override to make sure we get 8 bytes address in case there is a relocation here
  986.         WriteOperandType(4);
  987.     }
  988.  
  989.     if (Type & 0x200000) {
  990.         if (FieldSize > 1) {
  991.             // Uses second part of field. Single byte only
  992.             FieldPointer += FieldSize-1;
  993.             FieldSize = 1;
  994.         }
  995.         else {
  996.             // Uses half a byte
  997.             FieldSize = 0;
  998.         }
  999.     }
  1000.  
  1001.     // Get inline value
  1002.     switch (FieldSize) {
  1003.     case 0:  // 4 bits
  1004.         Value = Get<uint8>(FieldPointer) & 0x0F;
  1005.         break;
  1006.  
  1007.     case 1:  // 8 bits
  1008.         Value = Get<int8>(FieldPointer);  
  1009.         break;
  1010.  
  1011.     case 2:  // 16 bits
  1012.         Value = Get<int16>(FieldPointer);  break;
  1013.  
  1014.     case 6:  // 48 bits
  1015.         Value  = Get<int32>(FieldPointer);  
  1016.         Value += (uint64)Get<uint16>(FieldPointer + 4) << 32;  
  1017.         break;
  1018.  
  1019.     case 4:  // 32 bits
  1020.         Value = Get<int32>(FieldPointer);  break;
  1021.  
  1022.     case 8:  // 64 bits
  1023.         Value = Get<int64>(FieldPointer);  break;
  1024.  
  1025.     case 3:  // 16+8 bits ("Enter" instruction)
  1026.         if ((Type & 0xFF) == 0x12) {
  1027.             // First 16 bits
  1028.             FieldSize = 2; Value = Get<int16>(FieldPointer);  break;
  1029.         }
  1030.         // else continue in default case to get error message
  1031.  
  1032.     default:  // Other sizes should not occur
  1033.         err.submit(3000);  Value = -1;
  1034.     }
  1035.  
  1036.     // Check if relocation
  1037.     if (s.ImmediateRelocation) {
  1038.         // Write relocation target name
  1039.         uint32 Context = 2;
  1040.         if ((Type & 0xFC) == 0x80) Context = 8;     // Near jump/call destination
  1041.         if ((Type & 0xFC) == 0x84) Context = 0x10;  // Far jump/call destination
  1042.  
  1043.         // Write cross reference
  1044.         WriteRelocationTarget(s.ImmediateRelocation, Context, Value);
  1045.  
  1046.         // Remember that Value has been written
  1047.         Value = 0;
  1048.         Components++;
  1049.     }
  1050.     // Check if AAM or AAD
  1051.     if (Value == 10 && (Opcodei & 0xFE) == 0xD4) {
  1052.         // Don't write operand for AAM or AAD if = 10
  1053.         return;
  1054.     }
  1055.  
  1056.     // Write as unsigned, signed or hexadecimal:
  1057.     if ((Type & 0xF0) == 0x30 || (Type & 0xF0) == 0x80) {
  1058.         // Hexadecimal
  1059.         WriteFormat = 2;
  1060.     }
  1061.     else if (s.ImmediateFieldSize == 8) {
  1062.         // 64 bit constant
  1063.         if (Value == (int32)Value) {
  1064.             // Signed
  1065.             WriteFormat = 1;
  1066.         }
  1067.         else {
  1068.             // Hexadecimal
  1069.             WriteFormat = 2;
  1070.         }
  1071.     }
  1072.     else if ((Type & 0xF0) == 0x20) {
  1073.         // Signed
  1074.         WriteFormat = 1;
  1075.     }
  1076.     else {
  1077.         // Unsigned
  1078.         WriteFormat = 0;
  1079.     }
  1080.  
  1081.     if ((Type & 0xFC) == 0x80 && !s.ImmediateRelocation) {
  1082.         // Self-relative jump or call without relocation. Adjust immediate value
  1083.         Value += IEnd;                             // Get absolute address of target
  1084.  
  1085.         // Look for symbol at target address
  1086.         uint32 ISymbol = Symbols.FindByAddress(Section, (uint32)Value);
  1087.         if (ISymbol && (Symbols[ISymbol].Name || CodeMode == 1)) {
  1088.             // Symbol found. Write its name
  1089.             OutFile.Put(Symbols.GetName(ISymbol));
  1090.             // No offset to write
  1091.             return;
  1092.         }
  1093.         // Target address has no name
  1094.         Type |= 0x4000;                            // Write target as hexadecimal
  1095.     }
  1096.  
  1097.     // Operand size
  1098.     if ((s.Operands[0] & 0xFFF) <= 0xA || (s.Operands[0] & 0xF0) == 0xA0) {
  1099.         // Destination is general purpose register
  1100.         OSize = s.OperandSize;
  1101.     }
  1102.     else {
  1103.         // Constant probably unrelated to destination size
  1104.         OSize = 8;
  1105.     }
  1106.     // Check if destination is 8 bit operand
  1107.     //if ((s.Operands[0] & 0xFF) == 1 || (s.Operands[0] & 0xFF) == 0xA1) OSize = 8;
  1108.  
  1109.     // Check if sign extended
  1110.     if (OSize > s.ImmediateFieldSize * 8) {
  1111.         if (WriteFormat == 2 && Value >= 0) {
  1112.             // Hexadecimal sign extended, not negative:
  1113.             // Does not need full length
  1114.             OSize = s.ImmediateFieldSize * 8;
  1115.         }
  1116.         else if (WriteFormat == 0) {
  1117.             // Unsigned and sign extended, change to signed
  1118.             WriteFormat = 1;
  1119.         }
  1120.     }
  1121.  
  1122.     if (Components) {
  1123.         // There was a relocated name
  1124.         if (Value) {
  1125.             // Addend to relocation is not zero
  1126.             if (Value > 0 || WriteFormat != 1) {
  1127.                 OutFile.Put("+");                  // Put "+" between name and addend
  1128.             }
  1129.             else {
  1130.                 OutFile.Put("-");                  // Put "-" between name and addend
  1131.                 Value = - Value;                  // Change sign to avoid another "-"
  1132.             }
  1133.         }
  1134.         else {
  1135.             // No addend to relocated name
  1136.             return;
  1137.         }
  1138.     }
  1139.     // Write value
  1140.     if (WriteFormat == 2) {
  1141.         // Write with hexadecimal number appropriate size
  1142.         switch (OSize) {
  1143.         case 8:  // 8 bits
  1144.             OutFile.PutHex((uint8)Value, 1);  break;
  1145.         case 16:  // 16 bits
  1146.             if ((Type & 0xFC) == 0x84) {
  1147.                 // Segment of far call
  1148.                 OutFile.PutHex((uint16)(Value >> 16), 1);
  1149.                 OutFile.Put(':');
  1150.             }
  1151.             OutFile.PutHex((uint16)Value, 2);  break;
  1152.         case 32:  // 32 bits
  1153.         default:  // Should not occur
  1154.             if ((Type & 0xFC) == 0x84) {
  1155.                 // Segment of far call
  1156.                 OutFile.PutHex((uint16)(Value >> 32), 1);
  1157.                 OutFile.Put(':');
  1158.             }
  1159.             OutFile.PutHex((uint32)Value, 2);  break;
  1160.         case 64:  // 64 bits
  1161.             OutFile.PutHex((uint64)Value, 2);  break;
  1162.         }
  1163.     }
  1164.     else {
  1165.         // Write as signed or unsigned decimal
  1166.         if (WriteFormat == 0) { // unsigned
  1167.             switch (OSize) {
  1168.             case 8:  // 8 bits
  1169.                 Value &= 0x00FF;  break;
  1170.             case 16:  // 16 bits
  1171.                 Value &= 0xFFFF;  break;
  1172.             }
  1173.         }
  1174.         OutFile.PutDecimal((int32)Value, WriteFormat);  // Write value. Signed or usigned decimal
  1175.     }
  1176. }
  1177.  
  1178.  
  1179. void CDisassembler::WriteOtherOperand(uint32 Type) {
  1180.     // Write other type of operand
  1181.     const char * * OpRegisterNames;               // Pointer to list of register names
  1182.     uint32 RegI = 0;                              // Index into list of register names
  1183.  
  1184.     switch (Type & 0x8FF) {
  1185.     case 0xA1:  // AL
  1186.         OpRegisterNames = RegisterNames8;
  1187.         break;
  1188.     case 0xA2:  // AX
  1189.         OpRegisterNames = RegisterNames16;
  1190.         break;
  1191.     case 0xA3:  // EAX
  1192.         OpRegisterNames = RegisterNames32;
  1193.         break;
  1194.     case 0xA4:  // RAX
  1195.         OpRegisterNames = RegisterNames64;
  1196.         break;
  1197.     case 0xAE:  // xmm0
  1198.         OutFile.Put("xmm0");
  1199.         return;
  1200.     case 0xAF:  // ST(0)
  1201.         OutFile.Put("st(0)");
  1202.         return;
  1203.     case 0xB1:  // 1
  1204.         OutFile.Put("1");
  1205.         return;
  1206.     case 0xB2:  // DX
  1207.         OpRegisterNames = RegisterNames16;
  1208.         RegI = 2;
  1209.         break;
  1210.     case 0xB3: // CL
  1211.         OpRegisterNames = RegisterNames8;
  1212.         RegI = 1;
  1213.         break;
  1214.     default:
  1215.         OutFile.Put("unknown operand");
  1216.         err.submit(3000);
  1217.         return;
  1218.     }
  1219.     // Write register name
  1220.     OutFile.Put(OpRegisterNames[RegI]);
  1221. }
  1222.  
  1223.  
  1224. void CDisassembler::WriteErrorsAndWarnings() {
  1225.     // Write errors, warnings and comments, if any
  1226.     uint32 n;                                     // Error bit
  1227.     if (s.Errors) {
  1228.         // There are errors
  1229.         // Loop through all bits in s.Errors
  1230.         for (n = 1; n; n <<= 1) {
  1231.             if (s.Errors & n) {
  1232.                 if (OutFile.GetColumn()) OutFile.NewLine();
  1233.                 OutFile.Put(CommentSeparator);       // Write "\n; "
  1234.                 OutFile.Put("Error: ");              // Write "Error: "
  1235.                 OutFile.Put(Lookup(AsmErrorTexts,n));// Write error text
  1236.                 OutFile.NewLine();
  1237.             }
  1238.         }
  1239.     }
  1240.  
  1241.     if (s.Warnings1) {
  1242.         // There are warnings 1
  1243.         // Loop through all bits in s.Warnings1
  1244.         for (n = 1; n; n <<= 1) {
  1245.             if (s.Warnings1 & n) {
  1246.                 if (OutFile.GetColumn()) OutFile.NewLine();
  1247.                 OutFile.Put(CommentSeparator);       // Write "; "
  1248.                 OutFile.Put("Note: ");               // Write "Note: "
  1249.                 OutFile.Put(Lookup(AsmWarningTexts1, n));// Write warning text
  1250.                 OutFile.NewLine();
  1251.             }
  1252.         }
  1253.     }
  1254.     if (s.Warnings2) {
  1255.         // There are warnings 2
  1256.         // Loop through all bits in s.Warnings2
  1257.         for (n = 1; n; n <<= 1) {
  1258.             if (s.Warnings2 & n) {
  1259.                 if (OutFile.GetColumn()) OutFile.NewLine();
  1260.                 OutFile.Put(CommentSeparator);            // Write "; "
  1261.                 OutFile.Put("Warning: ");                 // Write "Warning: "
  1262.                 OutFile.Put(Lookup(AsmWarningTexts2, n)); // Write warning text
  1263.                 OutFile.NewLine();
  1264.             }
  1265.         }
  1266.         if (s.Warnings2 & 1) {
  1267.             // Write spurious label
  1268.             uint32 sym1 = Symbols.FindByAddress(Section, LabelEnd);
  1269.             if (sym1) {
  1270.                 const char * name = Symbols.GetName(sym1);
  1271.                 OutFile.Put(CommentSeparator);
  1272.                 OutFile.Put(name);
  1273.                 OutFile.Put("; Misplaced symbol at address ");
  1274.                 OutFile.PutHex(Symbols[sym1].Offset);
  1275.                 OutFile.NewLine();
  1276.             }
  1277.         }
  1278.     }
  1279.  
  1280.     if (s.OpcodeDef && (s.OpcodeDef->AllowedPrefixes & 8) && !s.Warnings1) {
  1281.         if (s.Prefixes[0]) {
  1282.             // Branch hint prefix. Write comment
  1283.             OutFile.Put(CommentSeparator);             // Write "; "
  1284.             switch (s.Prefixes[0]) {
  1285.             case 0x2E:
  1286.                 OutFile.Put("Branch hint prefix for Pentium 4: Predict no jump");  
  1287.                 break;
  1288.             case 0x3E:
  1289.                 OutFile.Put("Branch hint prefix for Pentium 4: Predict jump");  
  1290.                 break;
  1291.             case 0x64:
  1292.                 OutFile.Put("Branch hint prefix for Pentium 4: Predict alternate");  
  1293.                 break;
  1294.             default:
  1295.                 OutFile.Put("Note: Unrecognized branch hint prefix");  
  1296.             }
  1297.             OutFile.NewLine();
  1298.         }
  1299.     }
  1300. }
  1301.  
  1302. void CDisassembler::WriteSymbolName(uint32 symi) {
  1303.     // Write symbol name. symi = new symbol index
  1304.     OutFile.Put(Symbols.GetName(symi));
  1305. }
  1306.  
  1307. void CDisassembler::WriteSectionName(int32 SegIndex) {
  1308.     // Write name of section, segment or group from section index
  1309.     const char * Name = 0;
  1310.     // Check for special index values
  1311.     switch (SegIndex) {
  1312.     case ASM_SEGMENT_UNKNOWN:   // Unknown segment. Typical for external symbols
  1313.         Name = "Unknown";  break;
  1314.     case ASM_SEGMENT_ABSOLUTE:  // No segment. Used for absolute symbols
  1315.         Name = "Absolute";  break;
  1316.     case ASM_SEGMENT_FLAT:      // Flat segment group
  1317.         Name = "flat";  break;
  1318.     case ASM_SEGMENT_NOTHING:   // No segment
  1319.         Name = "Nothing";  break;
  1320.     case ASM_SEGMENT_ERROR:     // Segment register assumed to error
  1321.         Name = "Error";  break;
  1322.     case ASM_SEGMENT_IMGREL:    // Segment unknown. Offset relative to image base or file base
  1323.         Name = "ImageBased";  break;
  1324.     default:                    // > 0 means normal segment index
  1325.         if ((uint32)SegIndex >= Sections.GetNumEntries()) {
  1326.             // Out of range
  1327.             Name = "IndexOutOfRange";
  1328.        }
  1329.        else {
  1330.            // Get index into NameBuffer
  1331.            uint32 NameIndex = Sections[SegIndex].Name;
  1332.            // Check if valid
  1333.            if (NameIndex == 0 || NameIndex >= NameBuffer.GetDataSize()) {
  1334.                Name = "ErrorNameMissing";
  1335.            }
  1336.            else {
  1337.                // Normal valid name of segment, section or group
  1338.                Name = NameBuffer.Buf() + NameIndex;
  1339.            }
  1340.        }
  1341.        break;
  1342.     }
  1343.     if (Syntax == SUBTYPE_YASM && Name[0] == '_') {
  1344.         // Change leading underscore to dot
  1345.         OutFile.Put('.');
  1346.         OutFile.Put(Name+1); // Write rest of name
  1347.     }
  1348.     else {
  1349.         // Write name
  1350.         OutFile.Put(Name);
  1351.     }
  1352. }
  1353.  
  1354. void CDisassembler::WriteDataItems() {
  1355.     // Write data items to output file
  1356.  
  1357.     int LineState;  // 0: Start of new line, write label
  1358.     // 1: Label written if any, write data directive
  1359.     // 2: Data directive written, write data
  1360.     // 3: First data item written, write comma and more data
  1361.     // 4: Last data item written, write comment
  1362.     // 5: Comment written if any, start new line
  1363.     uint32 Pos = IBegin;                          // Current position
  1364.     uint32 LinePos = IBegin;                      // Position for beginning of output line
  1365.     uint32 BytesPerLine;                          // Number of bytes to write per line
  1366.     uint32 LineEnd;                               // Data position for end of line
  1367.     uint32 DataEnd;                               // End of data
  1368.     uint32 ElementSize, OldElementSize;           // Size of each data element
  1369.     uint32 RelOffset;                             // Offset of relocation
  1370.     uint32 irel, Oldirel;                         // Relocation index
  1371.     int64  Value;                                 // Inline value or addend
  1372.     const char * Symname;                         // Symbol name
  1373.     int    SeparateLine;                          // Label is on separate line
  1374.  
  1375.     SARelocation Rel;                             // Dummy relocation record
  1376.  
  1377.     // Check if size is valid
  1378.     if (DataSize == 0) DataSize = 1;
  1379.     if (DataSize > 32) DataSize = 32;  
  1380.  
  1381.     // Expected end position
  1382.     if (CodeMode & 3) {
  1383.         // Writing data for dubious code. Make same length as code instruction
  1384.         DataEnd = IEnd;
  1385.     }
  1386.     else {
  1387.         // Regular data. End at next label
  1388.         DataEnd = LabelEnd;
  1389.         if (DataEnd > FunctionEnd) DataEnd = FunctionEnd;
  1390.         if (DataEnd <= Pos) DataEnd = Pos + DataSize;
  1391.         if (DataEnd > Sections[Section].InitSize && Pos < Sections[Section].InitSize) {
  1392.             DataEnd = Sections[Section].InitSize;
  1393.         }
  1394.     }
  1395.  
  1396.     // Size of each data element
  1397.     ElementSize = DataSize;
  1398.  
  1399.     // Check if packed type
  1400.     if (DataType & 0xF00) {
  1401.         // This is a packed vector type. Get element size
  1402.         ElementSize = GetDataElementSize(DataType);
  1403.     }
  1404.  
  1405.     // Avoid sizes that are not powers of 2
  1406.     if (ElementSize == 6 || ElementSize == 10) ElementSize = 2;
  1407.  
  1408.     // Set maximum element size to 8
  1409.     if (ElementSize > 8)  ElementSize = 8;
  1410.  
  1411.     // Set minimum element size to 1
  1412.     if (ElementSize < 1)  ElementSize = 1;
  1413.  
  1414.     if (Pos + ElementSize > DataEnd) {
  1415.         // Make sure we end at DataEnd
  1416.         ElementSize = 1;  BytesPerLine = 8;
  1417.         LineEnd = DataEnd;
  1418.     }
  1419.  
  1420.     // Set number of bytes per line
  1421.     BytesPerLine = (DataSize == 10) ? 10 : 8;
  1422.  
  1423.     if (!(CodeMode & 3)) {
  1424.         // Begin new line for each data item (except in code segment)
  1425.         OutFile.NewLine();
  1426.     }
  1427.     LineState = 0; irel = 0;
  1428.  
  1429.     // Check if alignment required
  1430.     if (DataSize >= 16 && (DataType & 0xC00) && (DataType & 0xFF) != 0x51
  1431.         && (FlagPrevious & 0x100) < (DataSize << 4) && !(IBegin & (DataSize-1))) {
  1432.             // Write align directive
  1433.             WriteAlign(DataSize);
  1434.             // Remember that data is aligned
  1435.             FlagPrevious |= (DataSize << 4);
  1436.     }
  1437.  
  1438.     // Get symbol name for label
  1439.     uint32 sym;                                   // Current symbol index
  1440.     uint32 sym1, sym2 = 0;                        // First and last symbol at current address
  1441.  
  1442.     sym1 = Symbols.FindByAddress(Section, Pos, &sym2);
  1443.  
  1444.     // Loop for one or more symbols at this address
  1445.     for (sym = sym1; sym <= sym2; sym++) {
  1446.  
  1447.         if (sym && Symbols[sym].Scope && !(Symbols[sym].Scope & 0x100) && !(Symbols[sym].Type & 0x80000000)) {
  1448.  
  1449.             // Prepare for writing symbol label
  1450.             Symname = Symbols.GetName(sym);         // Symbol name
  1451.             // Check if label needs a separate line
  1452.             SeparateLine = (ElementSize != DataSize
  1453.                 || Symbols[sym].Size != DataSize
  1454.                 || strlen(Symname) > AsmTab1
  1455.                 || sym < sym2
  1456.                 // || (Sections[Section].Type & 0xFF) == 3
  1457.                 || ((Symbols[sym].Type+1) & 0xFE) == 0x0C);
  1458.  
  1459.             // Write symbol label
  1460.             switch (Syntax) {
  1461.             case SUBTYPE_MASM:
  1462.                 WriteDataLabelMASM(Symname, sym, SeparateLine);  break;
  1463.             case SUBTYPE_YASM:
  1464.                 WriteDataLabelYASM(Symname, sym, SeparateLine);  break;
  1465.             case SUBTYPE_GASM:
  1466.                 WriteDataLabelGASM(Symname, sym, SeparateLine);  break;
  1467.             }
  1468.             LineState = 1;                          // Label written
  1469.             if (SeparateLine) {
  1470.                 LineState = 0;
  1471.             }
  1472.         }
  1473.     }
  1474.  
  1475.     if ((Sections[Section].Type & 0xFF) == 3 || Pos >= Sections[Section].InitSize) {
  1476.         // This is an unitialized data (BSS) section
  1477.         // Data repeat count
  1478.         uint32 DataCount = (DataEnd - Pos) / ElementSize;
  1479.         if (DataCount) {
  1480.             OutFile.Tabulate(AsmTab1);
  1481.             // Write data directives
  1482.             switch (Syntax) {
  1483.             case SUBTYPE_MASM:
  1484.                 WriteUninitDataItemsMASM(ElementSize, DataCount);  break;
  1485.             case SUBTYPE_YASM:
  1486.                 WriteUninitDataItemsYASM(ElementSize, DataCount);  break;
  1487.             case SUBTYPE_GASM:
  1488.                 WriteUninitDataItemsGASM(ElementSize, DataCount);  break;
  1489.             }
  1490.             // Write comment
  1491.             WriteDataComment(ElementSize, Pos, Pos, 0);
  1492.             OutFile.NewLine();
  1493.             LineState = 0;
  1494.         }
  1495.         // Update data position
  1496.         Pos += DataCount * ElementSize;
  1497.  
  1498.         if (Pos < DataEnd) {
  1499.             // Some odd data remain. Write as bytes
  1500.             DataCount = DataEnd - Pos;
  1501.             ElementSize = 1;
  1502.             OutFile.Tabulate(AsmTab1);
  1503.             switch (Syntax) {
  1504.             case SUBTYPE_MASM:
  1505.                 WriteUninitDataItemsMASM(ElementSize, DataCount);  break;
  1506.             case SUBTYPE_YASM:
  1507.                 WriteUninitDataItemsYASM(ElementSize, DataCount);  break;
  1508.             case SUBTYPE_GASM:
  1509.                 WriteUninitDataItemsGASM(ElementSize, DataCount);  break;
  1510.             }
  1511.             // Write comment
  1512.             WriteDataComment(ElementSize, Pos, Pos, 0);
  1513.             OutFile.NewLine();
  1514.             Pos = DataEnd;
  1515.             LineState = 0;
  1516.         }
  1517.     }
  1518.     else {
  1519.         // Not a BSS section
  1520.         // Label has been written, write data
  1521.  
  1522.         // Loop for one or more elements
  1523.         LinePos = Pos;
  1524.         while (Pos < DataEnd) {
  1525.  
  1526.             // Find end of line position
  1527.             LineEnd = LinePos + BytesPerLine;
  1528.  
  1529.             // Remember element size and relocation
  1530.             OldElementSize = ElementSize;
  1531.             Oldirel = irel;
  1532.  
  1533.             // Check if relocation
  1534.             Rel.Section = Section;
  1535.             Rel.Offset  = Pos;
  1536.             uint32 irel = Relocations.FindFirst(Rel);
  1537.             if (irel >= Relocations.GetNumEntries() || Relocations[irel].Section != (int32)Section) {
  1538.                 // No relevant relocation
  1539.                 irel = 0;
  1540.             }
  1541.             if (irel) {
  1542.                 // A relocation is found
  1543.                 // Check relocation source
  1544.                 RelOffset = Relocations[irel].Offset;
  1545.                 if (RelOffset == Pos) {
  1546.                     // Relocation source is here
  1547.                     // Make sure the size fits and begin new line
  1548.                     ElementSize = Relocations[irel].Size;  BytesPerLine = 8;
  1549.                     if (ElementSize < 1) ElementSize = WordSize / 8;
  1550.                     if (ElementSize < 1) ElementSize = 4;
  1551.                     LineEnd = Pos + ElementSize;
  1552.                     if (LineState > 2) LineState = 4; // Make sure we begin at new line
  1553.                 }
  1554.                 else if (RelOffset < Pos + ElementSize) {
  1555.                     // Relocation source begins before end of element with current ElementSize
  1556.                     // Change ElementSize to make sure a new element begins at relocation source
  1557.                     ElementSize = 1;  BytesPerLine = 8;
  1558.                     LineEnd = RelOffset;
  1559.                     if (LineState > 2) LineState = 4; // Make sure we begin at new line
  1560.                     irel = 0;
  1561.                 }
  1562.                 else {
  1563.                     // Relocation is after this element
  1564.                     irel = 0;
  1565.                 }
  1566.                 // Check for overlapping relocations
  1567.                 if (irel && irel+1 < Relocations.GetNumEntries()
  1568.                     && Relocations[irel+1].Section == (int32)Section
  1569.                     && Relocations[irel+1].Offset < RelOffset + ElementSize) {
  1570.                         // Overlapping relocations
  1571.                         s.Errors |= 0x2000;
  1572.                         WriteErrorsAndWarnings();
  1573.                         LineEnd = Relocations[irel+1].Offset;
  1574.                         if (LineState > 2) LineState = 4; // Make sure we begin at new line
  1575.                 }
  1576.                 // Drop alignment
  1577.                 FlagPrevious &= ~0xF00;
  1578.             }
  1579.             if (irel == 0) {
  1580.                 // No relocation here
  1581.                 // Check if DataEnd would be exceeded
  1582.                 if (Pos + ElementSize > DataEnd) {
  1583.                     // Make sure we end at DataEnd unless there is a relocation source here
  1584.                     ElementSize = 1;  BytesPerLine = 8;
  1585.                     LineEnd = DataEnd;
  1586.                     if (LineState > 2) LineState = 4; // Make sure we begin at new line
  1587.                     FlagPrevious &= ~0xF00;           // Drop alignment
  1588.                 }
  1589.             }
  1590.             // Check if new line needed
  1591.             if (LineState == 4) {
  1592.                 // Finish this line
  1593.                 if (!(CodeMode & 3)) {
  1594.                     WriteDataComment(OldElementSize, LinePos, Pos, Oldirel);
  1595.                 }
  1596.                 // Start new line
  1597.                 OutFile.NewLine();
  1598.                 LineState = 0;
  1599.                 LinePos = Pos;
  1600.                 continue;
  1601.             }
  1602.  
  1603.             // Tabulate
  1604.             OutFile.Tabulate(AsmTab1);
  1605.  
  1606.             if (LineState < 2) {
  1607.                 // Write data definition directive for appropriate size
  1608.                 switch (Syntax) {
  1609.                 case SUBTYPE_MASM:
  1610.                     WriteDataDirectiveMASM(ElementSize);  break;
  1611.                 case SUBTYPE_YASM:
  1612.                     WriteDataDirectiveYASM(ElementSize);  break;
  1613.                 case SUBTYPE_GASM:
  1614.                     WriteDataDirectiveGASM(ElementSize);  break;
  1615.                 }
  1616.                 LineState = 2;
  1617.             }
  1618.             else if (LineState == 3) {
  1619.                 // Not the first element, write comma
  1620.                 OutFile.Put(", ");
  1621.             }
  1622.             // Get inline value
  1623.             switch (ElementSize) {
  1624.             case 1:  Value = Get<int8>(Pos);  break;
  1625.             case 2:  Value = Get<int16>(Pos);  break;
  1626.             case 4:  Value = Get<int32>(Pos);  break;
  1627.             case 6:  Value = Get<uint32>(Pos) + ((uint64)Get<uint16>(Pos+4) << 32); break;
  1628.             case 8:  Value = Get<int64>(Pos);  break;
  1629.             case 10: Value = Get<int64>(Pos); break;
  1630.             default: Value = 0; // should not occur
  1631.             }
  1632.             if (irel) {
  1633.                 // There is a relocation here. Write the name etc.
  1634.                 WriteRelocationTarget(irel, 1, Value);
  1635.             }
  1636.             else {
  1637.                 // Write value
  1638.                 switch (ElementSize) {
  1639.                 case 1:
  1640.                     OutFile.PutHex((uint8)Value, 1);  
  1641.                     break;
  1642.                 case 2:
  1643.                     OutFile.PutHex((uint16)Value, 1);  
  1644.                     break;
  1645.                 case 4:
  1646.                     OutFile.PutHex((uint32)Value, 1);  
  1647.                     break;
  1648.                 case 6:
  1649.                     OutFile.PutHex((uint16)(Value >> 32), 1);  
  1650.                     OutFile.Put(":");
  1651.                     OutFile.PutHex((uint32)Value, 1);  
  1652.                     break;
  1653.                 case 8:
  1654.                     OutFile.PutHex((uint64)Value, 1);  
  1655.                     break;
  1656.                 case 10:
  1657.                     OutFile.Put("??");
  1658.                     break;
  1659.                 }
  1660.             }
  1661.             LineState = 3;
  1662.             // Increment position
  1663.             Pos += ElementSize;
  1664.  
  1665.             // Check if end of line
  1666.             if (Pos >= LineEnd || Pos >= DataEnd) LineState = 4;
  1667.  
  1668.             if (LineState == 4) {
  1669.                 // End of line
  1670.                 if (!(CodeMode & 3)) {
  1671.                     // Write comment
  1672.                     WriteDataComment(ElementSize, LinePos, Pos, irel);
  1673.                 }
  1674.                 OutFile.NewLine();
  1675.                 LinePos = Pos;
  1676.                 LineState = 0;
  1677.             }
  1678.         }
  1679.     }
  1680.  
  1681.     // Indicate end
  1682.     if (IEnd < Pos) IEnd = Pos;
  1683.     if (IEnd > LabelEnd) IEnd = LabelEnd;
  1684.     if (IEnd > FunctionEnd && FunctionEnd) IEnd = FunctionEnd;
  1685.  
  1686.     // Reset FlagPrevious if not aligned
  1687.     if (DataSize < 16 || (DataType & 0xFF) == 0x28) FlagPrevious = 0;
  1688. }
  1689.  
  1690.  
  1691. void CDisassembler::WriteDataLabelMASM(const char * name, uint32 sym, int line) {
  1692.     // Write label before data item, MASM syntax
  1693.     // name = name of data item(s)
  1694.     // sym  = symbol index
  1695.     // line = 1 if label is on separate line, 0 if data follows on same line
  1696.     // Write name
  1697.     OutFile.Put(name);
  1698.     // At least one space
  1699.     OutFile.Put(" ");
  1700.     // Tabulate
  1701.     OutFile.Tabulate(AsmTab1);
  1702.  
  1703.     if (line) {
  1704.         // Write label and type on seperate line
  1705.         // Get size
  1706.         uint32 Symsize = Symbols[sym].Size;
  1707.         if (Symsize == 0) Symsize = DataSize;
  1708.         OutFile.Put("label ");
  1709.         // Write type
  1710.         switch(Symsize) {
  1711.         case 1: default:
  1712.             OutFile.Put("byte");  break;
  1713.         case 2:
  1714.             OutFile.Put("word");  break;
  1715.         case 4:
  1716.             OutFile.Put("dword");  break;
  1717.         case 6:
  1718.             OutFile.Put("fword");  break;
  1719.         case 8:
  1720.             OutFile.Put("qword");  break;
  1721.         case 10:
  1722.             OutFile.Put("tbyte");  break;
  1723.         case 16:
  1724.             OutFile.Put("xmmword");  break;
  1725.         case 32:
  1726.             OutFile.Put("ymmword");  break;
  1727.         }
  1728.         // Check if jump table or call table
  1729.         if (((Symbols[sym].Type+1) & 0xFE) == 0x0C) {
  1730.             OutFile.Tabulate(AsmTab3);
  1731.             OutFile.Put(CommentSeparator);
  1732.             if (Symbols[sym].DLLName) {
  1733.                 // DLL import
  1734.                 OutFile.Put("import from ");
  1735.                 OutFile.Put(Symbols.GetDLLName(sym));
  1736.             }
  1737.             else if (Symbols[sym].Type & 1) {
  1738.                 OutFile.Put("switch/case jump table");
  1739.             }
  1740.             else {
  1741.                 OutFile.Put("virtual table or function pointer");
  1742.             }
  1743.         }
  1744.         // New line
  1745.         OutFile.NewLine();
  1746.     }
  1747. }
  1748.  
  1749. void CDisassembler::WriteDataLabelYASM(const char * name, uint32 sym, int line) {
  1750.     // Write label before data item, YASM syntax
  1751.     // name = name of data item(s)
  1752.     // sym  = symbol index
  1753.     // line = 1 if label is on separate line, 0 if data follows on same line
  1754.     // Write name and colon
  1755.     OutFile.Put(name);
  1756.     OutFile.Put(": ");
  1757.     // Tabulate
  1758.     OutFile.Tabulate(AsmTab1);
  1759.  
  1760.     if (line) {
  1761.         // Write label on seperate line
  1762.         // Write comment
  1763.         OutFile.Tabulate(AsmTab3);
  1764.         OutFile.Put(CommentSeparator);
  1765.         // Check if jump table or call table
  1766.         if (((Symbols[sym].Type+1) & 0xFE) == 0x0C) {
  1767.             if (Symbols[sym].DLLName) {
  1768.                 // DLL import
  1769.                 OutFile.Put("import from ");
  1770.                 OutFile.Put(Symbols.GetDLLName(sym));
  1771.             }
  1772.             else if (Symbols[sym].Type & 1) {
  1773.                 OutFile.Put("switch/case jump table");
  1774.             }
  1775.             else {
  1776.                 OutFile.Put("virtual table or function pointer");
  1777.             }
  1778.         }
  1779.         else {
  1780.             // Write size
  1781.             uint32 Symsize = Symbols[sym].Size;
  1782.             if (Symsize == 0) Symsize = DataSize;
  1783.             switch(Symsize) {
  1784.             case 1: default:
  1785.                 OutFile.Put("byte");  break;
  1786.             case 2:
  1787.                 OutFile.Put("word");  break;
  1788.             case 4:
  1789.                 OutFile.Put("dword");  break;
  1790.             case 6:
  1791.                 OutFile.Put("fword");  break;
  1792.             case 8:
  1793.                 OutFile.Put("qword");  break;
  1794.             case 10:
  1795.                 OutFile.Put("tbyte");  break;
  1796.             case 16:
  1797.                 OutFile.Put("oword");  break;
  1798.             case 32:
  1799.                 OutFile.Put("yword");  break;
  1800.             case 64:
  1801.                 OutFile.Put("zword");  break;
  1802.             }
  1803.         }
  1804.         // New line
  1805.         OutFile.NewLine();
  1806.     }
  1807. }
  1808.  
  1809. void CDisassembler::WriteDataLabelGASM(const char * name, uint32 sym, int line) {
  1810.     // Write label before data item, GAS syntax
  1811.     // name = name of data item(s)
  1812.     // sym  = symbol index
  1813.     // line = 1 if label is on separate line, 0 if data follows on same line
  1814.     // Write name and colon
  1815.     OutFile.Put(name);
  1816.     OutFile.Put(": ");
  1817.     // Tabulate
  1818.     OutFile.Tabulate(AsmTab1);
  1819.  
  1820.     if (line) {
  1821.         // Write label on seperate line
  1822.         // Write comment
  1823.         OutFile.Tabulate(AsmTab3);
  1824.         OutFile.Put(CommentSeparator);
  1825.         // Check if jump table or call table
  1826.         if (((Symbols[sym].Type+1) & 0xFE) == 0x0C) {
  1827.             if (Symbols[sym].DLLName) {
  1828.                 // DLL import
  1829.                 OutFile.Put("import from ");
  1830.                 OutFile.Put(Symbols.GetDLLName(sym));
  1831.             }
  1832.             else if (Symbols[sym].Type & 1) {
  1833.                 OutFile.Put("switch/case jump table");
  1834.             }
  1835.             else {
  1836.                 OutFile.Put("virtual table or function pointer");
  1837.             }
  1838.         }
  1839.         else {
  1840.             // Write size
  1841.             uint32 Symsize = Symbols[sym].Size;
  1842.             if (Symsize == 0) Symsize = DataSize;
  1843.             switch(Symsize) {
  1844.             case 1: default:
  1845.                 OutFile.Put("byte");  break;
  1846.             case 2:
  1847.                 OutFile.Put("word");  break;
  1848.             case 4:
  1849.                 OutFile.Put("int");  break;
  1850.             case 6:
  1851.                 OutFile.Put("farword");  break;
  1852.             case 8:
  1853.                 OutFile.Put("qword");  break;
  1854.             case 10:
  1855.                 OutFile.Put("tfloat");  break;
  1856.             case 16:
  1857.                 OutFile.Put("xmmword");  break;
  1858.             case 32:
  1859.                 OutFile.Put("ymmword");  break;
  1860.             }
  1861.         }
  1862.         // New line
  1863.         OutFile.NewLine();
  1864.     }
  1865. }
  1866.  
  1867. void CDisassembler::WriteUninitDataItemsMASM(uint32 size, uint32 count) {
  1868.     // Write uninitialized (BSS) data, MASM syntax
  1869.     // size = size of each data element
  1870.     // count = number of data elements on each line
  1871.  
  1872.     // Write data definition directive for appropriate size
  1873.     switch (size) {
  1874.     case 1:
  1875.         OutFile.Put("db ");  break;
  1876.     case 2:
  1877.         OutFile.Put("dw ");  break;
  1878.     case 4:
  1879.         OutFile.Put("dd ");  break;
  1880.     case 6:
  1881.         OutFile.Put("df ");  break;
  1882.     case 8:
  1883.         OutFile.Put("dq ");  break;
  1884.     case 10:
  1885.         OutFile.Put("dt ");  break;
  1886.     }
  1887.     OutFile.Tabulate(AsmTab2);
  1888.     if (count > 1) {
  1889.         // Write duplication operator
  1890.         OutFile.PutDecimal(count);
  1891.         OutFile.Put(" dup (?)");
  1892.     }
  1893.     else {
  1894.         // DataCount == 1
  1895.         OutFile.Put("?");
  1896.     }
  1897. }
  1898.  
  1899. void CDisassembler::WriteUninitDataItemsYASM(uint32 size, uint32 count) {
  1900.     // Write uninitialized (BSS) data, YASM syntax
  1901.     // Write data definition directive for appropriate size
  1902.     switch (size) {
  1903.     case 1:
  1904.         OutFile.Put("resb ");  break;
  1905.     case 2:
  1906.         OutFile.Put("resw ");  break;
  1907.     case 4:
  1908.         OutFile.Put("resd ");  break;
  1909.     case 6:
  1910.         OutFile.Put("resw ");  count *= 3;  break;
  1911.     case 8:
  1912.         OutFile.Put("resq ");  break;
  1913.     case 10:
  1914.         OutFile.Put("rest ");  break;
  1915.     }
  1916.     OutFile.Tabulate(AsmTab2);
  1917.     OutFile.PutDecimal(count);
  1918. }
  1919.  
  1920. void CDisassembler::WriteUninitDataItemsGASM(uint32 size, uint32 count) {
  1921.     // Write uninitialized (BSS) data, GAS  syntax
  1922.     OutFile.Put(".zero");
  1923.     OutFile.Tabulate(AsmTab2);
  1924.     if (count != 1) {
  1925.         OutFile.PutDecimal(count);  OutFile.Put(" * ");
  1926.     }
  1927.     OutFile.PutDecimal(size);
  1928. }
  1929.  
  1930. void CDisassembler::WriteDataDirectiveMASM(uint32 size) {
  1931.     // Write DB, etc., MASM syntax
  1932.     // Write data definition directive for appropriate size
  1933.     switch (size) {
  1934.     case 1:  OutFile.Put("db ");  break;
  1935.     case 2:  OutFile.Put("dw ");  break;
  1936.     case 4:  OutFile.Put("dd ");  break;
  1937.     case 6:  OutFile.Put("df ");  break;
  1938.     case 8:  OutFile.Put("dq ");  break;
  1939.     case 10: OutFile.Put("dt ");  break;
  1940.     case 16: OutFile.Put("xmmword ");  break;
  1941.     case 32: OutFile.Put("ymmword ");  break;
  1942.     default: OutFile.Put("Error ");  break;
  1943.     }
  1944. }
  1945.  
  1946. void CDisassembler::WriteDataDirectiveYASM(uint32 size) {
  1947.     // Write DB, etc., YASM syntax
  1948.     // Write data definition directive for appropriate size
  1949.     switch (size) {
  1950.     case 1:  OutFile.Put("db ");  break;
  1951.     case 2:  OutFile.Put("dw ");  break;
  1952.     case 4:  OutFile.Put("dd ");  break;
  1953.     case 6:  OutFile.Put("df ");  break;
  1954.     case 8:  OutFile.Put("dq ");  break;
  1955.     case 10: OutFile.Put("dt ");  break;
  1956.     case 16: OutFile.Put("ddq ");  break;
  1957.     default: OutFile.Put("Error ");  break;
  1958.     }
  1959. }
  1960.  
  1961. void CDisassembler::WriteDataDirectiveGASM(uint32 size) {
  1962.     // Write DB, etc., GAS syntax
  1963.     // Write data definition directive for appropriate size
  1964.     switch (size) {
  1965.     case 1:  OutFile.Put(".byte  ");  break;
  1966.     case 2:  OutFile.Put(".short ");  break;
  1967.     case 4:  OutFile.Put(".int   ");  break;
  1968.     case 8:  OutFile.Put(".quad  ");  break;
  1969.     case 10: OutFile.Put(".tfloat ");  break;
  1970.     default: OutFile.Put("Error ");  break;
  1971.     }
  1972. }
  1973.  
  1974.  
  1975. void CDisassembler::WriteDataComment(uint32 ElementSize, uint32 LinePos, uint32 Pos, uint32 irel) {
  1976.     // Write comment after data item
  1977.     uint32 pos1;                            // Position of data for comment
  1978.     uint32 RelType = 0;                     // Relocation type
  1979.     char TextBuffer[64];                    // Buffer for writing floating point number
  1980.  
  1981.     OutFile.Tabulate(AsmTab3);              // Tabulate to comment field
  1982.     OutFile.Put(CommentSeparator);          // Start comment
  1983.  
  1984.     // Write address
  1985.     if (SectionEnd + SectionAddress + (uint32)ImageBase > 0xFFFF) {
  1986.         // Write 32 bit address
  1987.         OutFile.PutHex(LinePos + SectionAddress + (uint32)ImageBase);
  1988.     }
  1989.     else {
  1990.         // Write 16 bit address
  1991.         OutFile.PutHex((uint16)(LinePos + SectionAddress));
  1992.     }
  1993.  
  1994.     if ((Sections[Section].Type & 0xFF) == 3 || Pos > Sections[Section].InitSize) {
  1995.         // Unitialized data. Write no data
  1996.         return;
  1997.     }
  1998.  
  1999.     if (irel && irel < Relocations.GetNumEntries() && Relocations[irel].Offset == LinePos) {
  2000.         // Value is relocated, get relocation type
  2001.         RelType = Relocations[irel].Type;
  2002.     }
  2003.  
  2004.     // Space after address
  2005.     OutFile.Put(" _ ");
  2006.  
  2007.     // Comment type depends on ElementSize and DataType
  2008.     switch (ElementSize) {
  2009.     case 1:
  2010.         // Bytes. Write ASCII characters
  2011.         for (pos1 = LinePos; pos1 < Pos; pos1++) {
  2012.             // Get character
  2013.             int8 c = Get<int8>(pos1);
  2014.             // Avoid non-printable characters
  2015.             if (c < ' ' || c == 0x7F) c = '.';
  2016.             // Print ASCII character
  2017.             OutFile.Put(c);
  2018.         }
  2019.         break;
  2020.     case 2:
  2021.         // Words. Write as decimal
  2022.         for (pos1 = LinePos; pos1 < Pos; pos1 += 2) {
  2023.             if (RelType) {
  2024.                 OutFile.PutHex(Get<uint16>(pos1), 1); // Write as hexadecimal
  2025.             }
  2026.             else {
  2027.                 OutFile.PutDecimal(Get<int16>(pos1), 1);// Write as signed decimal
  2028.             }
  2029.             OutFile.Put(' ');
  2030.         }
  2031.         break;
  2032.     case 4:
  2033.         // Dwords      
  2034.         for (pos1 = LinePos; pos1 < Pos; pos1 += 4) {
  2035.             if ((DataType & 0x47) == 0x43) {
  2036.                 // Write as float
  2037.                 sprintf(TextBuffer, "%.8G", Get<float>(pos1));
  2038.                 OutFile.Put(TextBuffer);
  2039.                 // Make sure the number has a . or E to indicate a floating point number
  2040.                 if (!strchr(TextBuffer,'.') && !strchr(TextBuffer,'E')) OutFile.Put(".0");
  2041.             }
  2042.             else if (((DataType + 1) & 0xFF) == 0x0C || RelType) {
  2043.                 // jump/call address or offset. Write as hexadecimal
  2044.                 OutFile.PutHex(Get<uint32>(pos1));
  2045.             }
  2046.             else {
  2047.                 // Other. Write as decimal
  2048.                 OutFile.PutDecimal(Get<int32>(pos1), 1);
  2049.             }
  2050.             OutFile.Put(' ');
  2051.         }
  2052.         break;                
  2053.     case 8:
  2054.         // Qwords
  2055.         for (pos1 = LinePos; pos1 < Pos; pos1 += 8) {
  2056.             if ((DataType & 0x47) == 0x44) {
  2057.                 // Write as double
  2058.                 sprintf(TextBuffer, "%.16G", Get<double>(pos1));
  2059.                 OutFile.Put(TextBuffer);
  2060.                 // Make sure the number has a . or E to indicate a floating point number
  2061.                 if (!strchr(TextBuffer,'.') && !strchr(TextBuffer,'E')) OutFile.Put(".0");
  2062.             }
  2063.             else {
  2064.                 // Write as hexadecimal
  2065.                 OutFile.PutHex(Get<uint64>(pos1));
  2066.             }
  2067.             OutFile.Put(' ');
  2068.         }
  2069.         break;
  2070.     case 10:
  2071.         // tbyte. Many compilers do not support long doubles in sprintf. Write as bytes
  2072.         for (pos1 = LinePos; pos1 < Pos; pos1++) {
  2073.             OutFile.PutHex(Get<uint8>(pos1), 1);
  2074.         }
  2075.         break;
  2076.     }
  2077.     if (RelType) {
  2078.         // Indicate relocation type
  2079.         OutFile.Put(Lookup(RelocationTypeNames, RelType));
  2080.     }
  2081. }
  2082.  
  2083.  
  2084. void CDisassembler::WriteRelocationTarget(uint32 irel, uint32 Context, int64 Addend) {
  2085.     // Write cross reference, including addend, but not including segment override and []
  2086.     // irel = index into Relocations
  2087.     // Context:
  2088.     // 1      = Data definition
  2089.     // 2      = Immediate data field in instruction
  2090.     // 4      = Data address in instruction
  2091.     // 8      = Near jump/call destination
  2092.     // 0x10   = Far  jump/call destination
  2093.     // 0x100  = Self-relative address expected
  2094.     // Addend:  inline addend
  2095.     // Implicit parameters:
  2096.     // IBegin:  value of '$' operator
  2097.     // IEnd:    reference point for self-relative addressing
  2098.     // BaseReg, IndexReg
  2099.  
  2100.     uint32 RefFrame;                    // Target segment
  2101.     int32  Addend2 = 0;                 // Difference between '$' and reference point
  2102.  
  2103.     // Get relocation type
  2104.     uint32 RelType = Relocations[irel].Type;
  2105.  
  2106.     if (RelType & 0x60) {
  2107.         // Inline addend is already relocated.
  2108.         // Ignore addend and treat as direct relocation
  2109.         RelType = 1;
  2110.         Addend = 0;
  2111.     }
  2112.  
  2113.     // Get relocation size
  2114.     uint32 RelSize = Relocations[irel].Size;
  2115.  
  2116.     // Get relocation addend
  2117.     Addend += Relocations[irel].Addend;
  2118.  
  2119.     // Get relocation target
  2120.     uint32 Target = Relocations[irel].TargetOldIndex;
  2121.  
  2122.     // Is offset operand needed?
  2123.     if (Syntax != SUBTYPE_YASM && (
  2124.         ((RelType & 0xB) && (Context & 2))
  2125.         || ((RelType & 8) && (Context & 0x108)))) {
  2126.             // offset operator needed to convert memory operand to immediate address
  2127.             OutFile.Put("offset ");
  2128.     }
  2129.  
  2130.     // Is seg operand needed?
  2131.     if (RelType & 0x200) {
  2132.         // seg operator needed to convert memory operand to its segment
  2133.         OutFile.Put("seg ");
  2134.     }
  2135.  
  2136.     // Is explicit segment or frame needed?
  2137.     if ((RelType & 0x408) && (Context & 0x11B)) {
  2138.         // Write name of segment/group frame
  2139.         RefFrame = Relocations[irel].RefOldIndex;
  2140.         if (!RefFrame) {
  2141.             // No frame. Use segment of symbol
  2142.             RefFrame = Symbols[Symbols.Old2NewIndex(Target)].Section;
  2143.         }
  2144.         if (RefFrame && RefFrame < Sections.GetNumEntries()) {
  2145.             // Write segment or group name
  2146.             const char * SecName = NameBuffer.Buf()+Sections[RefFrame].Name;
  2147.             OutFile.Put(SecName);
  2148.             OutFile.Put(":");
  2149.         }
  2150.     }
  2151.  
  2152.     // Is imagerel operator needed?
  2153.     if (RelType & 4) {
  2154.         // imagerel operator needed to get image-relative address
  2155.         OutFile.Put("imagerel(");
  2156.     }
  2157.  
  2158.     // Adjust addend
  2159.     // Adjust offset if self-relative relocation expected and found
  2160.     if ((RelType & 2) && (Context & 0x108)) {
  2161.         // Self-relative relocation expected and found
  2162.         // Adjust by size of address field and immediate field
  2163.         Addend += IEnd - Relocations[irel].Offset;
  2164.     }
  2165.     // Subtract self-reference if unexpected self-relative relocation
  2166.     if ((RelType & 2) && !(Context & 0x108)) {
  2167.         // Self-relative relocation found but not expected
  2168.         // Fix difference between '$' and reference point
  2169.         Addend2 = Relocations[irel].Offset - IBegin;
  2170.         Addend -= Addend2;
  2171.     }
  2172.     // Add self-reference if self-relative relocation expected but not found
  2173.     if (!(RelType & 2) && (Context & 0x108)) {
  2174.         // Self-relative relocation expected but not found
  2175.         // Fix difference between '$' and reference point
  2176.         Addend += IEnd - IBegin;
  2177.     }
  2178.  
  2179.     if (RelType & 0x100) {
  2180.         // Target is a segment
  2181.         RefFrame = Symbols[Symbols.Old2NewIndex(Target)].Section;
  2182.         if (RefFrame && RefFrame < Sections.GetNumEntries()) {
  2183.             const char * SecName = NameBuffer.Buf()+Sections[RefFrame].Name;
  2184.             OutFile.Put(SecName);
  2185.         }
  2186.         else {
  2187.             OutFile.Put("undefined segment");
  2188.         }
  2189.     }
  2190.     else {
  2191.         // Target is a symbol
  2192.  
  2193.         // Find target symbol
  2194.         uint32 TargetSym = Symbols.Old2NewIndex(Target);
  2195.  
  2196.         // Check if Target is appropriate
  2197.         if (((Symbols[TargetSym].Type & 0x80000000) || (int32)Addend)
  2198.             && !(CodeMode == 1 && s.BaseReg)) {
  2199.                 // Symbol is a start-of-section entry in symbol table, or has an addend
  2200.                 // Look for a more appropriate symbol, except if code with base register
  2201.                 uint32 sym, sym1, sym2 = 0;
  2202.                 sym1 = Symbols.FindByAddress(Symbols[TargetSym].Section, Symbols[TargetSym].Offset + (int32)Addend, &sym2);
  2203.                 for (sym = sym1; sym && sym <= sym2; sym++) {
  2204.                     if (Symbols[sym].Scope && !(Symbols[sym].Type & 0x80000000)) {
  2205.                         // Found a better symbol name for target address
  2206.                         TargetSym = sym;
  2207.                         Addend = Addend2;
  2208.                     }
  2209.                 }
  2210.         }
  2211.         // Write name of target symbol
  2212.         OutFile.Put(Symbols.GetName(TargetSym));
  2213.  
  2214.         if (Syntax == SUBTYPE_GASM && (
  2215.             RelType == 0x41 || RelType == 0x81 || RelType == 0x2002)) {
  2216.                 // make PLT entry
  2217.                 OutFile.Put("@PLT");
  2218.         }
  2219.     }
  2220.  
  2221.     // End parenthesis if we started one
  2222.     if (RelType & 4) {
  2223.         OutFile.Put(")");
  2224.     }
  2225.  
  2226.     // Subtract reference point, if any
  2227.     if (RelType & 0x10) {
  2228.         OutFile.Put("-");
  2229.         // Write name of segment/group frame
  2230.         uint32 RefPoint = Relocations[irel].RefOldIndex;
  2231.         if (RefPoint) {
  2232.             // Reference point name valid
  2233.             OutFile.Put(Symbols.GetNameO(RefPoint));
  2234.         }
  2235.         else {
  2236.             OutFile.Put("Reference_Point_Missing");
  2237.         }
  2238.     }
  2239.  
  2240.     // Subtract self-reference if unexpected self-relative relocation
  2241.     if ((RelType & 2) && !(Context & 0x108)) {
  2242.         // Self-relative relocation found but not expected
  2243.         OutFile.Put("-"); OutFile.Put(HereOperator);
  2244.     }
  2245.  
  2246.     // Add self-reference if self-relative relocation expected but not found
  2247.     if (!(RelType & 2) && (Context & 0x108)) {
  2248.         // Self-relative relocation expected but not found
  2249.         OutFile.Put("+"); OutFile.Put(HereOperator);
  2250.     }
  2251.  
  2252.     // Write addend, if not zero
  2253.     if (Addend) {
  2254.         if (Addend < 0) {
  2255.             // Negative, write "-"
  2256.             OutFile.Put("-");
  2257.             Addend = -Addend;
  2258.         }
  2259.         else {
  2260.             // Positive, write "+"
  2261.             OutFile.Put("+");
  2262.         }
  2263.  
  2264.         // Write value as hexadecimal
  2265.         switch (RelSize) {
  2266.         case 1:
  2267.             OutFile.PutHex((uint8)Addend, 1);
  2268.             break;
  2269.         case 2:
  2270.             OutFile.PutHex((uint16)Addend, 2);
  2271.             break;
  2272.         case 4:
  2273.             OutFile.PutHex((uint32)Addend, 2);
  2274.             break;
  2275.         case 6:
  2276.             OutFile.PutHex((uint16)(Addend >> 32), 1);
  2277.             OutFile.Put(":");
  2278.             OutFile.PutHex((uint32)Addend, 1);
  2279.             break;
  2280.         case 8:
  2281.             OutFile.PutHex((uint64)Addend, 2);
  2282.             break;
  2283.         default:
  2284.             OutFile.Put("??"); // Should not occur
  2285.             break;
  2286.         }
  2287.     }
  2288. }
  2289.  
  2290.  
  2291. int CDisassembler::WriteFillers() {
  2292.     // Check if code is a series of NOPs or other fillers.
  2293.     // If so then write it as filler and return 1.
  2294.     // If not, then return 0.
  2295.  
  2296.     // Check if code is filler
  2297.     if (!(OpcodeOptions & 0x40)) {
  2298.         // This instruction can not be used as filler
  2299.         return 0;
  2300.     }
  2301.     uint32 FillerType;                            // Type of filler
  2302.     const char * FillerName = s.OpcodeDef->Name;  // Name of filler
  2303.     uint32 IFillerBegin = IBegin;                 // Start of filling space
  2304.     uint32 IFillerEnd;                            // End of filling space
  2305.  
  2306.     // check for CC = int 3 breakpoint, 3C00 = 90 NOP, 11F = multibyte NOP
  2307.     if (Opcodei == 0xCC || (Opcodei & 0xFFFE) == 0x3C00 || Opcodei == 0x11F) {
  2308.         // Instruction is a NOP or int 3 breakpoint
  2309.         FillerType = Opcodei;
  2310.     }
  2311.     else if (s.Warnings1 & 0x1000000) {
  2312.         // Instruction is a LEA, MOV, etc. with same source and destination
  2313.         // used as a multi-byte NOP
  2314.         FillerType = 0xFFFFFFFF;
  2315.     }
  2316.     else {
  2317.         // This instruction does something. Not a filler
  2318.         return 0;
  2319.     }
  2320.     // Save beginning position
  2321.     IFillerEnd = IEnd = IBegin;
  2322.  
  2323.     // Loop through instructions to find all consecutive fillers
  2324.     while (NextInstruction2()) {
  2325.  
  2326.         // Parse instruction
  2327.         ParseInstruction();
  2328.  
  2329.         // Check if code is filler
  2330.         if (!(OpcodeOptions & 0x40)) {
  2331.             // This instruction can not be a filler
  2332.             // Save position of this instruction
  2333.             IFillerEnd = IBegin;
  2334.             break;
  2335.         }
  2336.         if (Opcodei != 0xCC && (Opcodei & 0xFFFE) != 0x3C00 && Opcodei != 0x11F
  2337.             && !(s.Warnings1 & 0x1000000)) {
  2338.                 // Not a filler
  2339.                 // Save position of this instruction
  2340.                 IFillerEnd = IBegin;
  2341.                 break;
  2342.         }
  2343.         // If loop exits here then fillers end at end of this instruction
  2344.         IFillerEnd = IEnd;
  2345.     }
  2346.     // Safety check
  2347.     if (IFillerEnd <= IFillerBegin) return 0;
  2348.  
  2349.     // Size of fillers
  2350.     uint32 FillerSize = IFillerEnd - IFillerBegin;
  2351.  
  2352.     // Write size of filling space
  2353.     OutFile.Put(CommentSeparator);
  2354.     OutFile.Put("Filling space: ");
  2355.     OutFile.PutHex(FillerSize, 2);
  2356.     OutFile.NewLine();
  2357.     // Write filler type
  2358.     OutFile.Put(CommentSeparator);
  2359.     OutFile.Put("Filler type: ");
  2360.     switch (FillerType) {
  2361.     case 0xCC:
  2362.         FillerName = "INT 3 Debug breakpoint"; break;
  2363.     case 0x3C00:
  2364.         FillerName = "NOP"; break;
  2365.     case 0x3C01:
  2366.         FillerName = "NOP with prefixes"; break;
  2367.     case 0x011F:
  2368.         FillerName = "Multi-byte NOP";break;
  2369.     }
  2370.     OutFile.Put(FillerName);
  2371.     if (FillerType == 0xFFFFFFFF) {
  2372.         OutFile.Put(" with same source and destination");
  2373.     }
  2374.  
  2375.     // Write as bytes
  2376.     uint32 Pos;
  2377.     for (Pos = IFillerBegin; Pos < IFillerEnd; Pos++) {
  2378.         if (((Pos - IFillerBegin) & 7) == 0) {
  2379.             // Start new line
  2380.             OutFile.NewLine();
  2381.             OutFile.Put(CommentSeparator);
  2382.             OutFile.Tabulate(AsmTab1);
  2383.             OutFile.Put(Syntax == SUBTYPE_GASM ? ".byte " : "db ");
  2384.         }
  2385.         else {
  2386.             // Continue on same line
  2387.             OutFile.Put(", ");
  2388.         }
  2389.         // Write byte value
  2390.         OutFile.PutHex(Get<uint8>(Pos), 1);
  2391.     }
  2392.     // Blank line
  2393.     OutFile.NewLine(); OutFile.NewLine();
  2394.  
  2395.     // Find alignment
  2396.     uint32 Alignment = 4;                         // Limit to 2^4 = 16
  2397.  
  2398.     // Check if first non-filler is aligned by this value
  2399.     while (Alignment && (IFillerEnd & ((1 << Alignment) - 1))) {
  2400.         // Not aligned by 2^Alignment
  2401.         Alignment--;
  2402.     }
  2403.     if (Alignment) {
  2404.  
  2405.         // Check if smaller alignment would do
  2406.         if (Alignment > 3 && FillerSize < 1u << (Alignment-1)) {
  2407.             // End is aligned by 16, but there are less than 8 filler bytes.
  2408.             // Change to align 8
  2409.             Alignment--;
  2410.         }
  2411.         // Write align directive
  2412.         WriteAlign(1 << Alignment);
  2413.         // Prevent writing ALIGN again
  2414.         FlagPrevious &= ~1;
  2415.     }
  2416.  
  2417.     // Restore IBegin and IEnd to beginning of first non-filler instruction
  2418.     IBegin = IEnd = IFillerEnd;
  2419.  
  2420.     if (LabelInaccessible == IFillerBegin && IFillerEnd < LabelEnd) {
  2421.         // Mark first instruction after filler as inaccessible
  2422.         LabelInaccessible = IFillerEnd;
  2423.     }
  2424.  
  2425.     // Return success. Fillers have been written. Don't write as normal instructions
  2426.     return 1;
  2427. }
  2428.  
  2429. void CDisassembler::WriteAlign(uint32 a) {
  2430.     // Write alignment directive
  2431.     OutFile.Put(Syntax == SUBTYPE_GASM ? ".ALIGN" : "ALIGN");
  2432.     OutFile.Tabulate(AsmTab1);
  2433.     OutFile.PutDecimal(a);
  2434.     OutFile.NewLine();
  2435. }
  2436.  
  2437. void CDisassembler::WriteFileBegin() {
  2438.     // Write begin of file
  2439.  
  2440.     OutFile.SetFileType(FILETYPE_ASM);
  2441.  
  2442.     // Initial comment
  2443.     OutFile.Put(CommentSeparator);
  2444.     OutFile.Put("Disassembly of file: ");
  2445.     OutFile.Put(cmd.InputFile);
  2446.     OutFile.NewLine();
  2447.     // Date and time.
  2448.     // Note: will fail after year 2038 on computers that use 32-bit time_t
  2449.     time_t time1 = time(0);
  2450.     char * timestring = ctime(&time1);
  2451.     if (timestring) {
  2452.         // Remove terminating '\n' in timestring
  2453.         for (char *c = timestring; *c; c++) {
  2454.             if (*c < ' ') *c = 0;
  2455.         }
  2456.         // Write date and time as comment
  2457.         OutFile.Put(CommentSeparator);
  2458.         OutFile.Put(timestring);
  2459.         OutFile.NewLine();
  2460.     }
  2461.  
  2462.     // Write mode
  2463.     OutFile.Put(CommentSeparator);
  2464.     OutFile.Put("Mode: ");
  2465.     OutFile.PutDecimal(WordSize);
  2466.     OutFile.Put(" bits");
  2467.     OutFile.NewLine();
  2468.  
  2469.     // Write syntax dialect
  2470.     OutFile.Put(CommentSeparator);
  2471.     OutFile.Put("Syntax: ");
  2472.     switch (Syntax) {
  2473.     case SUBTYPE_MASM:
  2474.         OutFile.Put(WordSize < 64 ? "MASM/ML" : "MASM/ML64");  break;
  2475.     case SUBTYPE_YASM:
  2476.         OutFile.Put("YASM/NASM");  break;
  2477.     case SUBTYPE_GASM:
  2478.         OutFile.Put("GAS(Intel)");  break;
  2479.     }
  2480.     OutFile.NewLine();
  2481.  
  2482.     // Write instruction set as comment
  2483.     // Instruction set is at least .386 if 32 bit mode
  2484.     if (InstructionSetMax < 3 && (MasmOptions & 0x200)) InstructionSetMax = 3;
  2485.  
  2486.     // Get name of basic instruction set
  2487.     const char * set0 = "";
  2488.     if (InstructionSetMax < InstructionSetNamesLen) {
  2489.         set0 = InstructionSetNames[InstructionSetMax];
  2490.     }
  2491.  
  2492.     // Write as comment
  2493.     OutFile.Put(CommentSeparator);
  2494.     OutFile.Put("Instruction set: ");
  2495.     OutFile.Put(set0);
  2496.  
  2497.     if (InstructionSetAMDMAX) {
  2498.         // Get name of any AMD-specific instruction set
  2499.         const char * setA = "";
  2500.         switch (InstructionSetAMDMAX) {
  2501.         case 1:  setA = "AMD 3DNow";   break;
  2502.         case 2:  setA = "AMD 3DNowE";  break;
  2503.         case 4:  setA = "AMD SSE4a";   break;
  2504.         case 5:  setA = "AMD XOP";     break;
  2505.         case 6:  setA = "AMD FMA4";    break;
  2506.         case 7:  setA = "AMD TBM";   break;
  2507.         }
  2508.         if (*setA) {
  2509.             OutFile.Put(", ");
  2510.             OutFile.Put(setA);
  2511.         }
  2512.     }
  2513.     // VIA instruction set:
  2514.     if (InstructionSetOR & 0x2000) OutFile.Put(", VIA");
  2515.  
  2516.     // Additional instruction sets:
  2517.     if (WordSize > 32) OutFile.Put(", x64");
  2518.     if (InstructionSetOR & 0x100) OutFile.Put(", 80x87");
  2519.     if (InstructionSetOR & 0x800) OutFile.Put(", privileged instructions");
  2520.     OutFile.NewLine();
  2521.  
  2522.     if (NamesChanged) {
  2523.         // Tell that symbol names have been changed
  2524.         OutFile.NewLine();
  2525.         OutFile.Put(CommentSeparator);
  2526.         OutFile.Put("Error: symbol names contain illegal characters,");
  2527.         OutFile.NewLine(); OutFile.Put(CommentSeparator);
  2528.         OutFile.PutDecimal(NamesChanged);
  2529. #if ReplaceIllegalChars
  2530.         OutFile.Put(" Symbol names changed");
  2531. #else
  2532.         OutFile.Put(" Symbol names not changed");
  2533. #endif
  2534.         OutFile.NewLine();
  2535.     }
  2536.  
  2537.     // Write syntax-specific initializations
  2538.     switch (Syntax) {
  2539.     case SUBTYPE_MASM:
  2540.         WriteFileBeginMASM();  
  2541.         WritePublicsAndExternalsMASM();
  2542.         break;
  2543.     case SUBTYPE_YASM:
  2544.         WriteFileBeginYASM();  
  2545.         WritePublicsAndExternalsYASMGASM();
  2546.         break;
  2547.     case SUBTYPE_GASM:
  2548.         WriteFileBeginGASM();
  2549.         WritePublicsAndExternalsYASMGASM();
  2550.         break;
  2551.     }
  2552. }
  2553.  
  2554.  
  2555. void CDisassembler::WriteFileBeginMASM() {
  2556.     // Write MASM-specific file init
  2557.     if (WordSize < 64) {
  2558.         // Write instruction set directive, except for 64 bit assembler
  2559.         const char * set1 = "";
  2560.         switch (InstructionSetMax) {
  2561.         case 0:  set1 = ".8086";  break;
  2562.         case 1:  set1 = ".186";  break;
  2563.         case 2:  set1 = ".286";  break;
  2564.         case 3:  set1 = ".386";  break;
  2565.         case 4:  set1 = ".486";  break;
  2566.         case 5:  set1 = ".586";  break;
  2567.         case 6: default:
  2568.             set1 = ".686";  break;
  2569.         }
  2570.         // Write basic instruction set
  2571.         OutFile.NewLine();
  2572.         OutFile.Put(set1);
  2573.         if (InstructionSetOR & 0x800) {
  2574.             // Privileged. Add "p"
  2575.             OutFile.Put("p");
  2576.         }
  2577.         OutFile.NewLine();
  2578.         // Write extended instruction set
  2579.         if (InstructionSetOR & 0x100) {
  2580.             // Floating point
  2581.             if (InstructionSetMax < 3) {
  2582.                 OutFile.Put(".8087");  OutFile.NewLine();
  2583.             }
  2584.             else if (InstructionSetMax < 5) {
  2585.                 OutFile.Put(".387");  OutFile.NewLine();
  2586.             }
  2587.         }
  2588.         if (InstructionSetMax >= 0x11) {
  2589.             // .xmm directive. Not differentiated between SSE, SSE2, etc.
  2590.             OutFile.Put(".xmm");  OutFile.NewLine();
  2591.         }
  2592.         else if (InstructionSetMax >= 7) {
  2593.             // .mmx directive
  2594.             OutFile.Put(".mmx");  OutFile.NewLine();
  2595.         }
  2596.     }
  2597.     if (MasmOptions & 1) {
  2598.         // Need dotname option
  2599.         OutFile.Put("option dotname");  OutFile.NewLine();
  2600.     }
  2601.     if (WordSize == 32) {
  2602.         // Write .model flat if 32 bit mode
  2603.         OutFile.Put(".model flat");  OutFile.NewLine();
  2604.     }
  2605.     // Initialize Assumes for segment registers
  2606.     if (!(MasmOptions & 0x100)) {
  2607.         // No 16-bit segments. Assume CS=DS=ES=SS=flat
  2608.         Assumes[0]=Assumes[1]=Assumes[2]=Assumes[3] = ASM_SEGMENT_FLAT;
  2609.     }
  2610.     else {
  2611.         // 16-bit segmented model. Segment register values unknown
  2612.         Assumes[0]=Assumes[1]=Assumes[2]=Assumes[3] = ASM_SEGMENT_UNKNOWN;
  2613.     }
  2614.     // FS and GS assumed to ERROR
  2615.     Assumes[4] = Assumes[5] = ASM_SEGMENT_ERROR;
  2616.  
  2617.     // Write assume if FS or GS used
  2618.     // This is superfluous because an assume directive will be written at first use of FS/GS
  2619.     if (MasmOptions & 2) {
  2620.         OutFile.Put("assume fs:nothing");  OutFile.NewLine();
  2621.     }
  2622.     if (MasmOptions & 4) {
  2623.         OutFile.Put("assume gs:nothing");  OutFile.NewLine();
  2624.     }
  2625.     OutFile.NewLine();                            // Blank line
  2626. }
  2627.  
  2628. void CDisassembler::WriteFileBeginYASM() {
  2629.     // Write YASM-specific file init
  2630.     OutFile.NewLine();
  2631.     if (WordSize == 64) {
  2632.         OutFile.Put("default rel"); OutFile.NewLine();
  2633.     }
  2634.     //if (InstructionSetMax >= 0x11) {OutFile.Put("%define xmmword  oword");  OutFile.NewLine();}
  2635.     //if (InstructionSetMax >= 0x19) {OutFile.Put("%define ymmword");  OutFile.NewLine();}
  2636.     OutFile.NewLine();
  2637. }
  2638.  
  2639. void CDisassembler::WriteFileBeginGASM() {
  2640.     // Write  GAS-specific file init
  2641.     OutFile.NewLine();
  2642.     OutFile.Put(CommentSeparator);
  2643.     OutFile.Put("Note: Uses Intel syntax with destination operand first. Remember to");
  2644.     OutFile.NewLine();
  2645.     OutFile.Put(CommentSeparator);
  2646.     OutFile.Put("put syntax directives in the beginning and end of inline assembly:");
  2647.     OutFile.NewLine();
  2648.     OutFile.Put(".intel_syntax noprefix ");
  2649.     OutFile.NewLine(); OutFile.NewLine();
  2650. }
  2651.  
  2652. void CDisassembler::WritePublicsAndExternalsMASM() {
  2653.     // Write public and external symbol definitions
  2654.     uint32 i;                                     // Loop counter
  2655.     uint32 LinesWritten = 0;                      // Count lines written
  2656.     const char * XName;                           // Name of external symbols
  2657.  
  2658.     // Loop through public symbols
  2659.     for (i = 0; i < Symbols.GetNumEntries(); i++) {
  2660.         if (Symbols[i].Scope & 0x1C) {
  2661.             // Symbol is public
  2662.             OutFile.Put("public ");
  2663.             // Write name
  2664.             OutFile.Put(Symbols.GetName(i));
  2665.             // Check if weak or communal
  2666.             if (Symbols[i].Scope & 0x18) {
  2667.                 // Scope is weak or communal
  2668.                 OutFile.Tabulate(AsmTab3);
  2669.                 OutFile.Put(CommentSeparator);
  2670.                 if (Symbols[i].Scope & 8) OutFile.Put("Note: Weak. Not supported by MASM ");
  2671.                 if (Symbols[i].Scope & 0x10) OutFile.Put("Note: Communal. Not supported by MASM");
  2672.             }
  2673.             OutFile.NewLine();  LinesWritten++;
  2674.         }
  2675.     }
  2676.     // Blank line if anything written
  2677.     if (LinesWritten) {
  2678.         OutFile.NewLine();
  2679.         LinesWritten = 0;
  2680.     }
  2681.     // Loop through external symbols
  2682.     for (i = 0; i < Symbols.GetNumEntries(); i++) {
  2683.  
  2684.         if (Symbols[i].Scope & 0x20) {
  2685.             // Symbol is external
  2686.             OutFile.Put("extern ");
  2687.             // Get name
  2688.             XName = Symbols.GetName(i);
  2689.             // Check for dynamic import
  2690.             if (Symbols[i].DLLName && strncmp(XName, Symbols.ImportTablePrefix, (uint32)strlen(Symbols.ImportTablePrefix)) == 0) {
  2691.                 // Remove "_imp" prefix from name
  2692.                 XName += (uint32)strlen(Symbols.ImportTablePrefix);
  2693.             }
  2694.  
  2695.             // Write name
  2696.             OutFile.Put(XName);
  2697.             OutFile.Put(": ");
  2698.  
  2699.             // Write type
  2700.             if ((Symbols[i].Type & 0xFE) == 0x84) {
  2701.                 // Far
  2702.                 OutFile.Put("far");
  2703.             }
  2704.             else if ((Symbols[i].Type & 0xF0) == 0x80 || Symbols[i].DLLName) {
  2705.                 // Near
  2706.                 OutFile.Put("near");
  2707.             }
  2708.             else {
  2709.                 // Data. Write size
  2710.                 switch (GetDataItemSize(Symbols[i].Type)) {
  2711.                 case 1: default: OutFile.Put("byte");  break;
  2712.                 case 2: OutFile.Put("word");  break;
  2713.                 case 4: OutFile.Put("dword");  break;
  2714.                 case 6: OutFile.Put("fword");  break;
  2715.                 case 8: OutFile.Put("qword");  break;
  2716.                 case 10: OutFile.Put("tbyte");  break;
  2717.                 case 16: OutFile.Put("xmmword");  break;
  2718.                 case 32: OutFile.Put("ymmword");  break;
  2719.                 }
  2720.             }
  2721.             // Add comment if DLL import
  2722.             if (Symbols[i].DLLName) {
  2723.                 OutFile.Tabulate(AsmTab3);
  2724.                 OutFile.Put(CommentSeparator);
  2725.                 OutFile.Put(Symbols.GetDLLName(i));
  2726.             }
  2727.             // Finished line
  2728.             OutFile.NewLine();  LinesWritten++;
  2729.         }
  2730.     }
  2731.     // Blank line if anything written
  2732.     if (LinesWritten) {
  2733.         OutFile.NewLine();
  2734.         LinesWritten = 0;
  2735.     }
  2736.     // Write the value of any constants
  2737.     // Loop through symbols
  2738.     for (i = 0; i < Symbols.GetNumEntries(); i++) {
  2739.         // Local symbols included because there might be a rip-relative address to a named constant = 0
  2740.         if (Symbols[i].Section == ASM_SEGMENT_ABSOLUTE /*&& (Symbols[i].Scope & 0x1C)*/) {
  2741.             // Symbol is constant
  2742.             // Write name
  2743.             OutFile.Put(Symbols.GetName(i));
  2744.             OutFile.Put(" equ ");
  2745.             // Write value as hexadecimal
  2746.             OutFile.PutHex(Symbols[i].Offset, 1);
  2747.             // Write decimal value as comment
  2748.             OutFile.Tabulate(AsmTab3);
  2749.             OutFile.Put(CommentSeparator);
  2750.             OutFile.PutDecimal(Symbols[i].Offset, 1);
  2751.             OutFile.NewLine();  LinesWritten++;
  2752.         }
  2753.     }
  2754.     // Blank line if anything written
  2755.     if (LinesWritten) {
  2756.         OutFile.NewLine();
  2757.         LinesWritten = 0;
  2758.     }
  2759.     // Write any group definitions
  2760.     int32 GroupId, SegmentId;
  2761.     // Loop through sections to search for group definitions
  2762.     for (GroupId = 1; GroupId < (int32)Sections.GetNumEntries(); GroupId++) {
  2763.  
  2764.         // Get section type
  2765.         uint32 SectionType = Sections[GroupId].Type;
  2766.         if (SectionType & 0x800) {
  2767.             // This is a segment group definition
  2768.             // Count number of members
  2769.             uint32 NumMembers = 0;
  2770.             // Write group name
  2771.             WriteSectionName(GroupId);
  2772.             // Write "group"
  2773.             OutFile.Put(" ");  OutFile.Tabulate(AsmTab1);  OutFile.Put("GROUP ");
  2774.             // Search for group members
  2775.             for (SegmentId = 1; SegmentId < (int32)Sections.GetNumEntries(); SegmentId++) {
  2776.                 if (Sections[SegmentId].Group == GroupId && !(Sections[SegmentId].Type & 0x800)) {
  2777.                     // is this first member?
  2778.                     if (NumMembers++) {
  2779.                         // Not first member. Write comma
  2780.                         OutFile.Put(", ");
  2781.                     }
  2782.                     // Write group member
  2783.                     WriteSectionName(SegmentId);
  2784.                 }
  2785.             }
  2786.             // End line
  2787.             OutFile.NewLine();  LinesWritten++;
  2788.         }
  2789.     }
  2790.     // Blank line if anything written
  2791.     if (LinesWritten) {
  2792.         OutFile.NewLine();
  2793.         LinesWritten = 0;
  2794.     }
  2795. }
  2796.  
  2797.  
  2798. void CDisassembler::WritePublicsAndExternalsYASMGASM() {
  2799.     // Write public and external symbol definitions, YASM and GAS syntax
  2800.     uint32 i;                                     // Loop counter
  2801.     uint32 LinesWritten = 0;                      // Count lines written
  2802.     const char * XName;                           // Name of external symbols
  2803.  
  2804.     // Loop through public symbols
  2805.     for (i = 0; i < Symbols.GetNumEntries(); i++) {
  2806.         if (Symbols[i].Scope & 0x1C) {
  2807.             // Symbol is public
  2808.             if (Syntax == SUBTYPE_GASM) OutFile.Put(".");
  2809.             OutFile.Put("global ");
  2810.             // Write name
  2811.             OutFile.Put(Symbols.GetName(i));
  2812.  
  2813.             // Write type
  2814.             if ((Symbols[i].Type & 0xF0) == 0x80) {        
  2815.                 // Symbol is a function
  2816.                 if (Syntax == SUBTYPE_YASM) {
  2817.                     OutFile.Put(": function");
  2818.                 }
  2819.                 else if (Syntax == SUBTYPE_GASM) {
  2820.                     OutFile.NewLine();
  2821.                     OutFile.Put(".type ");
  2822.                     OutFile.Put(Symbols.GetName(i));
  2823.                     OutFile.Put(", @function");
  2824.                 }
  2825.             }
  2826.  
  2827.             // Check if weak or communal
  2828.             if (Symbols[i].Scope & 0x18) {
  2829.                 // Scope is weak or communal
  2830.                 OutFile.Tabulate(AsmTab3);
  2831.                 OutFile.Put(CommentSeparator);
  2832.                 if (Symbols[i].Scope & 8) OutFile.Put("Note: Weak.");
  2833.                 if (Symbols[i].Scope & 0x10) OutFile.Put("Note: Communal.");
  2834.             }
  2835.             OutFile.NewLine();  LinesWritten++;
  2836.         }
  2837.     }
  2838.     // Blank line if anything written
  2839.     if (LinesWritten) {
  2840.         OutFile.NewLine();
  2841.         LinesWritten = 0;
  2842.     }
  2843.     // Loop through external symbols
  2844.     for (i = 0; i < Symbols.GetNumEntries(); i++) {
  2845.  
  2846.         if (Symbols[i].Scope & 0x20) {
  2847.             // Symbol is external
  2848.             if (Syntax == SUBTYPE_GASM) OutFile.Put(".");
  2849.             OutFile.Put("extern ");
  2850.             // Get name
  2851.             XName = Symbols.GetName(i);
  2852.             // Check for dynamic import
  2853.             if (Symbols[i].DLLName && strncmp(XName, Symbols.ImportTablePrefix, (uint32)strlen(Symbols.ImportTablePrefix)) == 0) {
  2854.                 // Remove "_imp" prefix from name
  2855.                 XName += (uint32)strlen(Symbols.ImportTablePrefix);
  2856.             }
  2857.             // Write name
  2858.             OutFile.Put(XName);
  2859.             OutFile.Put(" ");
  2860.             OutFile.Tabulate(AsmTab3);
  2861.             OutFile.Put(CommentSeparator);
  2862.  
  2863.             // Write type
  2864.             if ((Symbols[i].Type & 0xFE) == 0x84) {
  2865.                 // Far
  2866.                 OutFile.Put("far");
  2867.             }
  2868.             else if ((Symbols[i].Type & 0xF0) == 0x80 || Symbols[i].DLLName) {
  2869.                 // Near
  2870.                 OutFile.Put("near");
  2871.             }
  2872.             else {
  2873.                 // Data. Write size
  2874.                 switch (GetDataItemSize(Symbols[i].Type)) {
  2875.                 case 1: default: OutFile.Put("byte");  break;
  2876.                 case 2: OutFile.Put("word");  break;
  2877.                 case 4: OutFile.Put("dword");  break;
  2878.                 case 6: OutFile.Put("fword");  break;
  2879.                 case 8: OutFile.Put("qword");  break;
  2880.                 case 10: OutFile.Put("tbyte");  break;
  2881.                 case 16: OutFile.Put("xmmword");  break;
  2882.                 case 32: OutFile.Put("ymmword");  break;
  2883.                 }
  2884.             }
  2885.             // Add comment if DLL import
  2886.             if (Symbols[i].DLLName) {
  2887.                 OutFile.Tabulate(AsmTab3);
  2888.                 OutFile.Put(CommentSeparator);
  2889.                 OutFile.Put(Symbols.GetDLLName(i));
  2890.             }
  2891.             // Finished line
  2892.             OutFile.NewLine();  LinesWritten++;
  2893.         }
  2894.     }
  2895.     // Blank line if anything written
  2896.     if (LinesWritten) {
  2897.         OutFile.NewLine();  LinesWritten = 0;
  2898.     }
  2899.     // Write the value of any constants
  2900.     // Loop through symbols
  2901.     for (i = 0; i < Symbols.GetNumEntries(); i++) {
  2902.         if (Symbols[i].Section == ASM_SEGMENT_ABSOLUTE /*&& (Symbols[i].Scope & 0x1C)*/) {
  2903.             // Symbol is constant
  2904.             if (Syntax == SUBTYPE_YASM) {
  2905.                 // Write name equ value
  2906.                 OutFile.Put(Symbols.GetName(i));
  2907.                 OutFile.Put(" equ ");
  2908.             }
  2909.             else {
  2910.                 // Gas: write .equ name, value
  2911.                 OutFile.Put(".equ ");
  2912.                 OutFile.Tabulate(AsmTab1);
  2913.                 OutFile.Put(Symbols.GetName(i));
  2914.                 OutFile.Put(", ");
  2915.             }
  2916.             // Write value as hexadecimal
  2917.             OutFile.PutHex(Symbols[i].Offset, 1);
  2918.             // Write decimal value as comment
  2919.             OutFile.Tabulate(AsmTab3);
  2920.             OutFile.Put(CommentSeparator);
  2921.             OutFile.PutDecimal(Symbols[i].Offset, 1);
  2922.             OutFile.NewLine();  LinesWritten++;
  2923.         }
  2924.     }
  2925.     // Blank line if anything written
  2926.     if (LinesWritten) {
  2927.         OutFile.NewLine();
  2928.         LinesWritten = 0;
  2929.     }
  2930.     // Write any group definitions
  2931.     int32 GroupId, SegmentId;
  2932.     // Loop through sections to search for group definitions
  2933.     for (GroupId = 1; GroupId < (int32)Sections.GetNumEntries(); GroupId++) {
  2934.         // Get section type
  2935.         uint32 SectionType = Sections[GroupId].Type;
  2936.         if (SectionType & 0x800) {
  2937.             // This is a segment group definition
  2938.             // Count number of members
  2939.             uint32 NumMembers = 0;
  2940.             // Write group name
  2941.             WriteSectionName(GroupId);
  2942.             // Write "group"
  2943.             OutFile.Put(" ");  OutFile.Tabulate(AsmTab1);  OutFile.Put("GROUP ");
  2944.             // Search for group members
  2945.             for (SegmentId = 1; SegmentId < (int32)Sections.GetNumEntries(); SegmentId++) {
  2946.                 if (Sections[SegmentId].Group == GroupId && !(Sections[SegmentId].Type & 0x800)) {
  2947.                     // is this first member?
  2948.                     if (NumMembers++) {
  2949.                         // Not first member. Write comma
  2950.                         OutFile.Put(", ");
  2951.                     }
  2952.                     // Write group member
  2953.                     WriteSectionName(SegmentId);
  2954.                 }
  2955.             }
  2956.             // End line
  2957.             OutFile.NewLine();  LinesWritten++;
  2958.         }
  2959.     }
  2960.     // Blank line if anything written
  2961.     if (LinesWritten) {
  2962.         OutFile.NewLine();
  2963.         LinesWritten = 0;
  2964.     }
  2965. }
  2966.  
  2967.  
  2968. void CDisassembler::WriteFileEnd() {
  2969.     // Write end of file
  2970.     OutFile.NewLine();
  2971.     switch(Syntax) {
  2972.     case SUBTYPE_MASM:
  2973.         OutFile.Put("END");  break;
  2974.     case SUBTYPE_GASM:
  2975.         OutFile.Put(CommentSeparator);
  2976.         OutFile.Put("Return to AT&T syntax with destination operand last:");
  2977.         OutFile.NewLine();
  2978.         OutFile.Put(".att_syntax prefix ");
  2979.         OutFile.NewLine();
  2980.         break;
  2981.     case SUBTYPE_YASM:
  2982.         break;
  2983.     }
  2984. }
  2985.  
  2986.  
  2987. void CDisassembler::WriteSegmentBegin() {
  2988.     // Write begin of segment
  2989.     // Choose dialect
  2990.     switch (Syntax) {
  2991.     case SUBTYPE_MASM:
  2992.         WriteSegmentBeginMASM();  break;
  2993.     case SUBTYPE_YASM:
  2994.         WriteSegmentBeginYASM();  break;
  2995.     case SUBTYPE_GASM:
  2996.         WriteSegmentBeginGASM();  break;
  2997.     }
  2998. }
  2999.  
  3000.  
  3001. void CDisassembler::WriteSegmentBeginMASM() {
  3002.     // Write begin of segment
  3003.     OutFile.NewLine();                            // Blank line
  3004.  
  3005.     // Check if Section is valid
  3006.     if (Section == 0 || Section >= Sections.GetNumEntries()) {
  3007.         // Illegal segment entry
  3008.         OutFile.Put("UNKNOWN SEGMENT");  OutFile.NewLine();
  3009.         return;
  3010.     }
  3011.  
  3012.     // Write segment name
  3013.     WriteSectionName(Section);
  3014.     // Tabulate
  3015.     OutFile.Put(" "); OutFile.Tabulate(AsmTab1);
  3016.     // Write "segment"
  3017.     OutFile.Put("SEGMENT ");
  3018.  
  3019.     // Write alignment
  3020.     switch (Sections[Section].Align) {
  3021.     case 0:  // 1
  3022.         OutFile.Put("BYTE ");  break;
  3023.     case 1:  // 2
  3024.         OutFile.Put("WORD ");  break;
  3025.     case 2:  // 4
  3026.         OutFile.Put("DWORD ");  break;
  3027.     case 4:  // 16
  3028.         OutFile.Put("PARA ");  break;
  3029.         //case 8:  // 256 or 4096. Definition is ambiguous!
  3030.         //   OutFile.Put("PAGE ");  break;
  3031.     default:
  3032.         // Non-standard alignment
  3033.         OutFile.Put("ALIGN(");
  3034.         OutFile.PutDecimal(1 << Sections[Section].Align);
  3035.         OutFile.Put(") ");
  3036.         break;
  3037.     }
  3038.     if (WordSize != 64) {
  3039.         // "PUBLIC" not supported by ml64 assembler
  3040.         OutFile.Put("PUBLIC ");
  3041.         // Write segment word size if necessary
  3042.         if (MasmOptions & 0x100) {
  3043.             // There is at least one 16-bit segment. Write segment word size
  3044.             OutFile.Put("USE");
  3045.             OutFile.PutDecimal(Sections[Section].WordSize);
  3046.             OutFile.Put(" ");
  3047.         }
  3048.     }
  3049.     // Write segment class
  3050.     switch (Sections[Section].Type & 0xFF) {
  3051.     case 1:
  3052.         OutFile.Put("'CODE'");   break;
  3053.     case 2:
  3054.         OutFile.Put("'DATA'");   break;
  3055.     case 3:
  3056.         OutFile.Put("'BSS'");    break;
  3057.     case 4:
  3058.         OutFile.Put("'CONST'");  break;
  3059.     default:;
  3060.         // Unknown class. Write nothing
  3061.     }
  3062.  
  3063.     // Tabulate to comment
  3064.     OutFile.Put(" ");  OutFile.Tabulate(AsmTab3);
  3065.     OutFile.Put(CommentSeparator);
  3066.     // Write section number
  3067.     OutFile.Put("section number ");  
  3068.     OutFile.PutDecimal(Section);
  3069.  
  3070.     // New line
  3071.     OutFile.NewLine();
  3072.  
  3073.     if (Sections[Section].Type & 0x1000) {
  3074.         // Communal
  3075.         OutFile.Put(CommentSeparator);
  3076.         OutFile.Put(" Communal section not supported by MASM");
  3077.         OutFile.NewLine();
  3078.     }
  3079.  
  3080.     if (WordSize == 16 && Sections[Section].Type == 1) {
  3081.         // 16 bit code segment. Write ASSUME CS: SEGMENTNAME
  3082.         OutFile.Put("ASSUME ");
  3083.         OutFile.Tabulate(AsmTab1);
  3084.         OutFile.Put("CS:");
  3085.         if (Sections[Section].Group) {
  3086.             // Group name takes precedence over segment name
  3087.             WriteSectionName(Sections[Section].Group);
  3088.         }
  3089.         else {
  3090.             WriteSectionName(Section);
  3091.         }
  3092.         OutFile.NewLine();
  3093.         Assumes[1] = Section;
  3094.     }
  3095. }
  3096.  
  3097. void CDisassembler::WriteSegmentBeginYASM() {
  3098.     // Write begin of segment
  3099.     OutFile.NewLine();                            // Blank line
  3100.  
  3101.     // Check if Section is valid
  3102.     if (Section == 0 || Section >= Sections.GetNumEntries()) {
  3103.         // Illegal segment entry
  3104.         OutFile.Put("UNKNOWN SEGMENT");  OutFile.NewLine();
  3105.         return;
  3106.     }
  3107.  
  3108.     // Write SECTION directive
  3109.     OutFile.Put("SECTION ");  
  3110.     // Write segment name
  3111.     WriteSectionName(Section);
  3112.     // Tabulate
  3113.     OutFile.Put(" ");  OutFile.Tabulate(AsmTab2);
  3114.     OutFile.Put("align=");
  3115.     OutFile.PutDecimal(1 << Sections[Section].Align);
  3116.     if (Sections[Section].WordSize != WordSize) {
  3117.         OutFile.Put(" use");
  3118.         OutFile.PutDecimal(Sections[Section].WordSize);
  3119.     }
  3120.     if ((Sections[Section].Type & 0xFF) == 1) {
  3121.         OutFile.Put(" execute");
  3122.     }
  3123.     else {
  3124.         OutFile.Put(" noexecute");
  3125.     }
  3126.  
  3127.     // Tabulate to comment
  3128.     OutFile.Put(" ");  OutFile.Tabulate(AsmTab3);
  3129.     OutFile.Put(CommentSeparator);
  3130.     // Write section number
  3131.     OutFile.Put("section number ");  
  3132.     OutFile.PutDecimal(Section);
  3133.     // Write type
  3134.     OutFile.Put(", ");
  3135.     switch (Sections[Section].Type & 0xFF) {
  3136.     case 1: OutFile.Put("code");  break;
  3137.     case 2: OutFile.Put("data");  break;
  3138.     case 3: OutFile.Put("bss");  break;
  3139.     case 4: OutFile.Put("const");  break;
  3140.     default: OutFile.Put("unknown type: ");  
  3141.         OutFile.PutHex(Sections[Section].Type & 0xFF);        
  3142.         break;
  3143.     }
  3144.  
  3145.     // New line
  3146.     OutFile.NewLine();
  3147.  
  3148.     if (Sections[Section].Type & 0x1000) {
  3149.         // Communal
  3150.         OutFile.Put(CommentSeparator);
  3151.         OutFile.Put(" Communal section not supported by YASM");
  3152.         OutFile.NewLine();
  3153.     }
  3154. }
  3155.  
  3156. void CDisassembler::WriteSegmentBeginGASM() {
  3157.     // Write begin of segment
  3158.     uint32 Type;                                  // Section type
  3159.  
  3160.     OutFile.NewLine();                            // Blank line
  3161.  
  3162.     // Check if Section is valid
  3163.     if (Section == 0 || Section >= Sections.GetNumEntries()) {
  3164.         // Illegal segment entry
  3165.         OutFile.Put("UNKNOWN SEGMENT");  OutFile.NewLine();
  3166.         return;
  3167.     }
  3168.  
  3169.     // Write SECTION directive
  3170.     OutFile.Put(".SECTION ");
  3171.     OutFile.Tabulate(AsmTab1);
  3172.     // Write segment name
  3173.     WriteSectionName(Section);
  3174.     // Tabulate
  3175.     OutFile.Put(" ");  OutFile.Tabulate(AsmTab2);
  3176.     // Flags not supported by all versions of Gas. Put as comment:
  3177.     OutFile.Put(CommentSeparator);
  3178.     // Write flags
  3179.     OutFile.Put('"');
  3180.     Type = Sections[Section].Type & 0xFF;
  3181.     if (Type) OutFile.Put('a');                   // Allocatable
  3182.     if (Type != 1 && Type != 4) OutFile.Put('w'); // Writeable
  3183.     if (Type == 1) OutFile.Put('x');              // Executable
  3184.     OutFile.Put('"');
  3185.     if (Type) OutFile.Put(", @progbits");         // Allocatable
  3186.  
  3187.     // Tabulate to comment
  3188.     OutFile.Put(" ");  OutFile.Tabulate(AsmTab3);
  3189.     OutFile.Put(CommentSeparator);
  3190.     // Write section number
  3191.     OutFile.Put("section number ");  
  3192.     OutFile.PutDecimal(Section);
  3193.     // Write type
  3194.     OutFile.Put(", ");
  3195.     switch (Sections[Section].Type & 0xFF) {
  3196.     case 1: OutFile.Put("code");  break;
  3197.     case 2: OutFile.Put("data");  break;
  3198.     case 3: OutFile.Put("bss");  break;
  3199.     case 4: OutFile.Put("const");  break;
  3200.     default: OutFile.Put("unknown");  break;
  3201.     }
  3202.     OutFile.NewLine();                            // Blank line
  3203.     if (Sections[Section].Type & 0x1000) {
  3204.         // Communal
  3205.         OutFile.Put(CommentSeparator);
  3206.         OutFile.Put(" Communal section ");
  3207.         OutFile.NewLine();
  3208.     }
  3209.  
  3210.     // Write alignment
  3211.     OutFile.Tabulate(AsmTab1);
  3212.     OutFile.Put(".ALIGN");
  3213.     OutFile.Tabulate(AsmTab2);
  3214.     OutFile.PutDecimal(1 << Sections[Section].Align);
  3215.  
  3216.     // New line
  3217.     OutFile.NewLine();
  3218. }
  3219.  
  3220.  
  3221. void CDisassembler::WriteSegmentEnd() {
  3222.     // Write end of segment
  3223.     OutFile.NewLine();
  3224.  
  3225.     if (Syntax != SUBTYPE_MASM) {
  3226.         // Not MASM syntax, write only blank line
  3227.         return;
  3228.     }
  3229.  
  3230.     // Check if Section is valid
  3231.     if (Section == 0 || Section >= Sections.GetNumEntries()) {
  3232.         // Illegal segment entry
  3233.         OutFile.Put("UNKNOWN ENDS");  OutFile.NewLine();
  3234.         return;
  3235.     }
  3236.  
  3237.     // Write segment name
  3238.     const char * segname = NameBuffer.Buf() + Sections[Section].Name;
  3239.     OutFile.Put(segname);
  3240.  
  3241.     // Tabulate
  3242.     OutFile.Put(" "); OutFile.Tabulate(AsmTab1);
  3243.     // Write "segment"
  3244.     OutFile.Put("ENDS");
  3245.     // New line
  3246.     OutFile.NewLine();
  3247. }
  3248.  
  3249.  
  3250.  
  3251. void CDisassembler::WriteFunctionBegin() {
  3252.     // Write begin of function IFunction
  3253.  
  3254.     // Check if IFunction is valid
  3255.     if (IFunction == 0 || IFunction >= FunctionList.GetNumEntries()) {
  3256.         // Should not occur
  3257.         OutFile.Put(CommentSeparator);
  3258.         OutFile.Put("Internal error: undefined function begin");
  3259.         return;
  3260.     }
  3261.  
  3262.     // Get symbol old index
  3263.     uint32 symi = FunctionList[IFunction].OldSymbolIndex;
  3264.  
  3265.     // Get symbol record
  3266.     uint32 SymI = Symbols.Old2NewIndex(symi);
  3267.  
  3268.     OutFile.NewLine();                        // Blank line
  3269.  
  3270.     // Remember that symbol has been written
  3271.     Symbols[SymI].Scope |= 0x100;
  3272.  
  3273.     // Check alignment if preceded by NOP
  3274.     if ((FlagPrevious & 1) && (IBegin & 0x0F) == 0 && Sections[Section].Align >= 4) {
  3275.         WriteAlign(16);
  3276.     }
  3277.  
  3278.     if (Symbols[SymI].Name == 0) {
  3279.         // Has no name. Probably only NOP fillers
  3280.         return;
  3281.     }
  3282.  
  3283.     // Write function name etc.
  3284.     switch (Syntax) {
  3285.     case SUBTYPE_MASM:
  3286.         WriteFunctionBeginMASM(SymI, Symbols[SymI].Scope);  break;
  3287.     case SUBTYPE_YASM:
  3288.         WriteFunctionBeginYASM(SymI, Symbols[SymI].Scope);  break;
  3289.     case SUBTYPE_GASM:
  3290.         WriteFunctionBeginGASM(SymI, Symbols[SymI].Scope);  break;
  3291.     }
  3292. }
  3293.  
  3294. void CDisassembler::WriteFunctionBeginMASM(uint32 symi, uint32 scope) {
  3295.     // Write begin of function, MASM syntax
  3296.     // Write name
  3297.     WriteSymbolName(symi);
  3298.     // Space
  3299.     OutFile.Put(" "); OutFile.Tabulate(AsmTab1);
  3300.  
  3301.     if (scope & 0x1C) {
  3302.         // Scope is public
  3303.         // Write "PROC"
  3304.         OutFile.Put("PROC");
  3305.         // Write "NEAR" unless 64 bit mode
  3306.         if (WordSize < 64) OutFile.Put(" NEAR");
  3307.         // Check if weak
  3308.         if (scope & 8) {
  3309.             OutFile.NewLine();
  3310.             OutFile.Put(CommentSeparator);
  3311.             OutFile.Put(" WEAK ");
  3312.             WriteSymbolName(symi);
  3313.         }
  3314.         // Check if communal
  3315.         if (scope & 0x10) {
  3316.             OutFile.NewLine();
  3317.             OutFile.Put(CommentSeparator);
  3318.             OutFile.Put(" COMDEF ");
  3319.             WriteSymbolName(symi);
  3320.         }
  3321.     }
  3322.     else {
  3323.         // Scope is local
  3324.         OutFile.Put("LABEL NEAR");
  3325.     }
  3326.     // Check if Gnu indirect
  3327.     if (Symbols[symi].Type & 0x40000000) {
  3328.         OutFile.Put(CommentSeparator);
  3329.         OutFile.Put("Gnu indirect function"); // Cannot be represented in Masm syntax
  3330.     }
  3331.     // End line
  3332.     OutFile.NewLine();
  3333. }
  3334.  
  3335. void CDisassembler::WriteFunctionBeginYASM(uint32 symi, uint32 scope) {
  3336.     // Write begin of function, YASM syntax
  3337.     // Write name
  3338.     WriteSymbolName(symi);
  3339.     // Colon
  3340.     OutFile.Put(":"); OutFile.Tabulate(AsmTab1);
  3341.  
  3342.     if (scope & 0x1C) {
  3343.         // Scope is public
  3344.         // Write comment
  3345.         OutFile.Put(CommentSeparator);
  3346.         OutFile.Put("Function begin");
  3347.         // Check if weak
  3348.         if (scope & 8) {
  3349.             OutFile.Put(", weak");
  3350.         }
  3351.         // Check if communal
  3352.         if (scope & 0x10) {
  3353.             OutFile.Put(", communal");
  3354.         }
  3355.     }
  3356.     else {
  3357.         // Scope is local. Write comment
  3358.         OutFile.Put(CommentSeparator);
  3359.         OutFile.Put("Local function");
  3360.     }
  3361.     // Check if Gnu indirect
  3362.     if (Symbols[symi].Type & 0x40000000) {
  3363.         OutFile.Put(CommentSeparator);
  3364.         OutFile.Put("Gnu indirect function"); // Cannot be represented in NASM/YASM syntax
  3365.     }
  3366.     // End line
  3367.     OutFile.NewLine();
  3368. }
  3369.  
  3370. void CDisassembler::WriteFunctionBeginGASM(uint32 symi, uint32 scope) {
  3371.     // Write begin of function, GAS syntax
  3372.     WriteSymbolName(symi);                        // Write name
  3373.     OutFile.Put(":");
  3374.     OutFile.Tabulate(AsmTab3);  OutFile.Put(CommentSeparator);
  3375.     if (scope & 3) OutFile.Put("Local ");
  3376.     if (scope & 8) OutFile.Put("weak ");
  3377.     if (scope & 0x10) OutFile.Put("communal ");
  3378.     OutFile.Put("Function");
  3379.     OutFile.NewLine();
  3380.     OutFile.Tabulate(AsmTab1);
  3381.     OutFile.Put(".type ");
  3382.     OutFile.Tabulate(AsmTab2);
  3383.     WriteSymbolName(symi); // Write name
  3384.     if (Symbols[symi].Type & 0x40000000) {
  3385.         OutFile.Put(", @gnu_indirect_function");
  3386.     }
  3387.     else {
  3388.         OutFile.Put(", @function");
  3389.     }
  3390.     OutFile.NewLine();
  3391. }
  3392.  
  3393.  
  3394. void CDisassembler::WriteFunctionEnd() {
  3395.     // Write end of function
  3396.  
  3397.     // Check if IFunction is valid
  3398.     if (IFunction == 0 || IFunction >= FunctionList.GetNumEntries()) {
  3399.         // Should not occur
  3400.         OutFile.Put(CommentSeparator);
  3401.         OutFile.Put("Internal error: undefined function end");
  3402.         return;
  3403.     }
  3404.  
  3405.     // Get symbol index
  3406.     uint32 SymOldI = FunctionList[IFunction].OldSymbolIndex;
  3407.     uint32 SymNewI = Symbols.Old2NewIndex(SymOldI);
  3408.  
  3409.     // check scope
  3410.     if (Symbols[SymNewI].Scope & 0x1C) {
  3411.         // Has public scope. Write end of function
  3412.         switch (Syntax) {
  3413.         case SUBTYPE_MASM:
  3414.             WriteFunctionEndMASM(SymNewI);  break;
  3415.         case SUBTYPE_YASM:
  3416.             WriteFunctionEndYASM(SymNewI);  break;
  3417.         case SUBTYPE_GASM:
  3418.             WriteFunctionEndGASM(SymNewI);  break;
  3419.         }
  3420.     }
  3421. }
  3422.  
  3423. void CDisassembler::WriteFunctionEndMASM(uint32 symi) {
  3424.     // Write end of function, MASM syntax
  3425.     // Write name
  3426.     WriteSymbolName(symi);
  3427.  
  3428.     // Space
  3429.     OutFile.Put(" "); OutFile.Tabulate(AsmTab1);
  3430.     // Write "ENDP"
  3431.     OutFile.Put("ENDP");
  3432.     OutFile.NewLine();
  3433. }
  3434.  
  3435. void CDisassembler::WriteFunctionEndYASM(uint32 symi) {
  3436.     // Write end of function, YASM syntax
  3437.     // Write comment
  3438.     OutFile.Put(CommentSeparator);
  3439.     // Write name
  3440.     WriteSymbolName(symi);
  3441.     OutFile.Put(" End of function");
  3442.     OutFile.NewLine();
  3443. }
  3444.  
  3445. void CDisassembler::WriteFunctionEndGASM(uint32 symi){
  3446.     // Write end of function, GAS syntax
  3447.     // Write .size directive
  3448.     OutFile.Tabulate(AsmTab1);
  3449.     OutFile.Put(".size ");
  3450.     OutFile.Tabulate(AsmTab2);
  3451.     WriteSymbolName(symi);                        // Name of function
  3452.     OutFile.Put(", . - ");
  3453.     WriteSymbolName(symi);                        // Name of function
  3454.     OutFile.Tabulate(AsmTab3);
  3455.     OutFile.Put(CommentSeparator);
  3456.     OutFile.Put("End of function is probably here");
  3457.     OutFile.NewLine();
  3458. }
  3459.  
  3460.  
  3461. void CDisassembler::WriteCodeLabel(uint32 symi) {
  3462.     // Write private or public code label. symi is new symbol index
  3463.  
  3464.     // Get scope
  3465.     uint32 Scope = Symbols[symi].Scope;
  3466.  
  3467.     // Check scope
  3468.     if (Scope & 0x100) return;                    // Has been written as function begin
  3469.  
  3470.     if (Scope == 0) {
  3471.         // Inaccessible. No name. Make blank line
  3472.         OutFile.NewLine();
  3473.         // Remember position for warning check
  3474.         LabelInaccessible = IBegin;
  3475.         return;
  3476.     }
  3477.  
  3478.     // Begin on new line if preceded by another symbol
  3479.     if (OutFile.GetColumn()) OutFile.NewLine();
  3480.  
  3481.     // Check alignment if preceded by NOP
  3482.     if ((Scope & 0xFF) > 1 && (FlagPrevious & 1) && (IBegin & 0x0F) == 0 && Sections[Section].Align >= 4) {
  3483.         WriteAlign(16);
  3484.     }
  3485.  
  3486.     switch (Syntax) {
  3487.     case SUBTYPE_MASM:
  3488.         WriteCodeLabelMASM(symi, Symbols[symi].Scope);  break;
  3489.     case SUBTYPE_YASM:
  3490.         WriteCodeLabelYASM(symi, Symbols[symi].Scope);  break;
  3491.     case SUBTYPE_GASM:
  3492.         WriteCodeLabelGASM(symi, Symbols[symi].Scope);  break;
  3493.     }
  3494.  
  3495.     // Remember this has been written
  3496.     Symbols[symi].Scope |= 0x100;
  3497. }
  3498.  
  3499.  
  3500. void CDisassembler::WriteCodeLabelMASM(uint32 symi, uint32 scope) {
  3501.     // Write private or public code label, MASM syntax
  3502.     if ((scope & 0xFF) > 1) {
  3503.         // Scope > function local. Write as label near
  3504.         // Check if extra linefeed needed
  3505.         // if (!(IFunction && FunctionList[IFunction].Start == IBegin))
  3506.         // New line
  3507.         OutFile.NewLine();
  3508.  
  3509.         // Write name
  3510.         WriteSymbolName(symi);
  3511.         // Space
  3512.         OutFile.Put(" "); OutFile.Tabulate(AsmTab1);
  3513.         // Write "LABEL"
  3514.         OutFile.Put("LABEL");
  3515.         // Write "NEAR" even 64 bit mode
  3516.         OutFile.Put(" NEAR");
  3517.         // New line
  3518.         OutFile.NewLine();
  3519.  
  3520.         // Check if weak
  3521.         if (scope & 8) {
  3522.             OutFile.Put(CommentSeparator);
  3523.             OutFile.Put(" WEAK ");
  3524.             WriteSymbolName(symi);
  3525.             OutFile.NewLine();
  3526.         }
  3527.         // Check if communal
  3528.         if (scope & 0x10) {
  3529.             OutFile.Put(CommentSeparator);
  3530.             OutFile.Put(" COMDEF ");
  3531.             WriteSymbolName(symi);
  3532.             OutFile.NewLine();
  3533.         }
  3534.     }
  3535.     else {
  3536.         // Symbol is local to current function. Write name with colon
  3537.         if (FlagPrevious & 2) {
  3538.             // Insert blank line if previous instruction was unconditional jump or return
  3539.             OutFile.NewLine();
  3540.         }
  3541.         // Write name
  3542.         WriteSymbolName(symi);
  3543.         // Write ":"
  3544.         OutFile.Put(":");
  3545.         if (OutFile.GetColumn() > AsmTab1) {
  3546.             // Past tabstop. Go to next line
  3547.             OutFile.NewLine();                   // New line
  3548.         }
  3549.     }
  3550. }
  3551.  
  3552. void CDisassembler::WriteCodeLabelYASM(uint32 symi, uint32 scope) {
  3553.     // Write private or public code label, YASM syntax
  3554.     if ((scope & 0xFF) > 2) {
  3555.         // Scope is public
  3556.         OutFile.NewLine();
  3557.         // Write name
  3558.         WriteSymbolName(symi);
  3559.         OutFile.Put(":");
  3560.  
  3561.         // Check if weak
  3562.         if (scope & 8) {
  3563.             OutFile.Put(CommentSeparator);
  3564.             OutFile.Put(" weak ");
  3565.             WriteSymbolName(symi);
  3566.         }
  3567.         // Check if communal
  3568.         if (scope & 0x10) {
  3569.             OutFile.Put(CommentSeparator);
  3570.             OutFile.Put(" communal ");
  3571.             WriteSymbolName(symi);
  3572.         }
  3573.         OutFile.NewLine();
  3574.     }
  3575.     else {
  3576.         // Symbol is local to current function. Write name with colon
  3577.         if (FlagPrevious & 2) {
  3578.             // Insert blank line if previous instruction was unconditional jump or return
  3579.             OutFile.NewLine();
  3580.         }
  3581.         // Write name
  3582.         WriteSymbolName(symi);
  3583.         // Write ":"
  3584.         OutFile.Put(":");
  3585.         if (OutFile.GetColumn() > AsmTab1) {
  3586.             // Past tabstop. Go to next line
  3587.             OutFile.NewLine();                   // New line
  3588.         }
  3589.     }
  3590. }
  3591.  
  3592. void CDisassembler::WriteCodeLabelGASM(uint32 symi, uint32 scope) {
  3593.     // Write private or public code label, GAS syntax same as YASM syntax
  3594.     WriteCodeLabelYASM(symi, scope);
  3595. }
  3596.  
  3597. void CDisassembler::WriteAssume() {
  3598.     // Write assume directive for segment register if MASM syntax
  3599.     if (Syntax != SUBTYPE_MASM) return;
  3600.     if (!s.AddressField) return;
  3601.  
  3602.     int32 SegReg, PrefixSeg;                      // Segment register used
  3603.     uint32 symo;                                  // Target symbol old index
  3604.     uint32 symi;                                  // Target symbol new index
  3605.     int32 TargetSegment;                          // Target segment/section
  3606.     int32 TargetGroup;                            // Group containing target segment
  3607.  
  3608.     // Find which segment register is used for addressing memory operand
  3609.     SegReg = 3;  // DS is default
  3610.     if (s.BaseReg == 4+1 || s.BaseReg == 5+1) {
  3611.         // Base register is (E)BP or ESP
  3612.         SegReg = 2;     // SS register used unless there is a prefix
  3613.     }
  3614.     if (s.Prefixes[0]) {
  3615.         // There is a segment prefix
  3616.         PrefixSeg = GetSegmentRegisterFromPrefix();
  3617.         if (PrefixSeg >= 0 && PrefixSeg <= 5) {
  3618.             // Segment prefix is valid. Segment determined by segment prefix
  3619.             SegReg = PrefixSeg;
  3620.         }
  3621.     }
  3622.     // Default target segment is none
  3623.     TargetSegment = TargetGroup = 0;
  3624.  
  3625.     // Find symbol referenced by next instruction
  3626.     if (s.AddressRelocation && s.AddressRelocation < Relocations.GetNumEntries()) {
  3627.         symo = Relocations[s.AddressRelocation].TargetOldIndex; // Target symbol old index
  3628.         if (symo) {
  3629.             symi = Symbols.Old2NewIndex(symo);                   // Target symbol new index
  3630.             if (symi) {
  3631.                 TargetSegment = Symbols[symi].Section;            // Target segment
  3632.                 if (TargetSegment < 0 || TargetSegment >= (int32)Sections.GetNumEntries()) {
  3633.                     TargetSegment = 0;
  3634.                 }
  3635.                 else {
  3636.                     TargetGroup = Sections[TargetSegment].Group;   // Group containing target segment
  3637.                     if (TargetGroup <= ASM_SEGMENT_ERROR || TargetGroup >= (int32)Sections.GetNumEntries()) {
  3638.                         TargetGroup = 0;
  3639.                     }
  3640.                 }
  3641.             }
  3642.         }
  3643.     }
  3644.     if (TargetSegment) {
  3645.         // Target has a segment. Check if it is different from currently assumed segment
  3646.         if (TargetSegment != Assumes[SegReg] && TargetGroup != Assumes[SegReg]) {
  3647.             // Assume directive needed
  3648.             // If segment belongs to a group then the group takes precedence
  3649.             if (TargetGroup) TargetSegment = TargetGroup;
  3650.             // Write assume directive
  3651.             OutFile.Put("ASSUME ");
  3652.             OutFile.Tabulate(AsmTab1);
  3653.             OutFile.Put(RegisterNamesSeg[SegReg]);  // Name of segment register used
  3654.             OutFile.Put(":");
  3655.             WriteSectionName(TargetSegment);        // Name of segment or group referenced
  3656.             OutFile.NewLine();
  3657.             Assumes[SegReg] = TargetSegment;
  3658.         }
  3659.     }
  3660.     else {
  3661.         // Target segment not specified. Assumed value may be anyting but 'error'
  3662.         if (Assumes[SegReg] <= ASM_SEGMENT_ERROR) {
  3663.             // Segment register is assumed to 'error'. Change assume to 'nothing'
  3664.             OutFile.Put("ASSUME ");
  3665.             OutFile.Tabulate(AsmTab1);
  3666.             OutFile.Put(RegisterNamesSeg[SegReg]);  // Name of segment register used
  3667.             OutFile.Put(":NOTHING");
  3668.             OutFile.NewLine();
  3669.             Assumes[SegReg] = ASM_SEGMENT_NOTHING;
  3670.         }
  3671.     }
  3672. }
  3673.  
  3674.  
  3675. void CDisassembler::WriteInstruction() {
  3676.     // Write instruction and operands
  3677.     uint32 NumOperands = 0;                       // Number of operands written
  3678.     uint32 i;                                     // Loop index
  3679.     const char * OpName;                          // Opcode name
  3680.  
  3681.     if (s.AddressFieldSize && Syntax == SUBTYPE_MASM) {
  3682.         // There is a memory operand. Check if ASSUME directive needed
  3683.         WriteAssume();
  3684.     }
  3685.  
  3686.     if (CodeMode & 6) {
  3687.         // Code is dubious. Show as comment only
  3688.         OutFile.Put(CommentSeparator);             // Start comment
  3689.     }
  3690.     else if ((s.OpcodeDef->Options & 0x20) && s.OpcodeStart1 > IBegin) {
  3691.         // Write prefixes explicitly.
  3692.         // This is used for rare cases where the assembler cannot generate the prefix
  3693.         OutFile.Tabulate(AsmTab1);                 // Tabulate
  3694.         OutFile.Put(Syntax == SUBTYPE_GASM ? ".byte " : "DB ");
  3695.         OutFile.Tabulate(AsmTab2);                 // Tabulate
  3696.         for (i = IBegin; i < s.OpcodeStart1; i++) {
  3697.             if (i > IBegin) OutFile.Put(", ");
  3698.             OutFile.PutHex(Get<uint8>(i), 1);
  3699.         }
  3700.         OutFile.Tabulate(AsmTab3);                 // Tabulate
  3701.         OutFile.Put(CommentSeparator);
  3702.         if ((s.OpcodeDef->AllowedPrefixes & 8) && Get<uint8>(IBegin) == 0xF2) {
  3703.             OutFile.Put("BND prefix coded explicitly");    // Comment
  3704.         }
  3705.         else {        
  3706.             OutFile.Put("Prefix coded explicitly");    // Comment
  3707.         }
  3708.         OutFile.NewLine();
  3709.     }
  3710.  
  3711.     if ((s.Operands[0] & 0xF0) == 0xC0 || (s.Operands[1] & 0xF0) == 0xC0) {
  3712.         // String instruction or xlat instruction
  3713.         WriteStringInstruction();
  3714.         return;
  3715.     }
  3716.  
  3717.     OutFile.Tabulate(AsmTab1);                     // Tabulate
  3718.  
  3719.     if ((s.OpcodeDef->AllowedPrefixes & 0xC40) == 0xC40) {
  3720.         switch (s.Prefixes[5]) {
  3721.         case 0xF2:
  3722.             OutFile.Put("xacquire ");  break;      // xacquire prefix
  3723.         case 0xF3:
  3724.             OutFile.Put("xrelease ");  break;      // xrelease prefix
  3725.         }
  3726.     }
  3727.     if (s.Prefixes[2]) {
  3728.         OutFile.Put("lock ");                      // Lock prefix
  3729.     }
  3730.  
  3731.     // Get opcode name
  3732.     if (s.OpcodeDef->Name) {
  3733.         // Opcode name
  3734.         OpName = s.OpcodeDef->Name;
  3735.         // Search for opcode comment
  3736.         s.OpComment = strchr(OpName, ';');
  3737.         if (s.OpComment) s.OpComment++;            // Point to after ';'
  3738.     }
  3739.     else {
  3740.         OpName = "UNDEFINED";                      // Undefined code with no name
  3741.         s.OpComment = 0;
  3742.     }
  3743.  
  3744.     // Check prefix option
  3745.     if ((s.OpcodeDef->Options & 2) && (s.Prefixes[7] & 0x30)) {
  3746.         // Put prefix 'v' for VEX-prefixed instruction
  3747.         OutFile.Put('v');
  3748.     }
  3749.  
  3750.     // Write opcode name
  3751.     if (s.OpComment) {
  3752.         // OpName string contains opcode name and comment, separated by ';'
  3753.         while (*OpName != ';' && *OpName != 0) {   // Write opcode name until comment
  3754.             OutFile.Put(*(OpName++));
  3755.         }
  3756.     }
  3757.     else {
  3758.         OutFile.Put(OpName);                       // Write normal opcode name
  3759.     }
  3760.  
  3761.     // Check suffix option
  3762.     if (s.OpcodeDef->Options & 1) {
  3763.         // Append suffix for operand size or type to name
  3764.         if ((s.OpcodeDef->AllowedPrefixes & 0x7000) == 0x1000) {
  3765.             // F.P. operand size defined by W prefix bit
  3766.             i = s.Prefixes[7] & 8;  // W prefix bit
  3767.             OutFile.Put(i ? 'd' : 's');
  3768.         }
  3769.         else if ((s.OpcodeDef->AllowedPrefixes & 0x7000) == 0x3000) {
  3770.             // Integer or f.p. operand size defined by W prefix bit
  3771.             bool f = false;
  3772.             // Find out if operands are integer or f.p.
  3773.             for (i = 0; i < s.MaxNumOperands; i++) {
  3774.                 if ((s.Operands[i] & 0xF0) == 0x40) {
  3775.                     f = true; break;
  3776.                 }
  3777.             }
  3778.             i = s.Prefixes[7] & 8;  // W prefix bit
  3779.             if (f) {
  3780.                 OutFile.Put(i ? 'd' : 's');  // float precision suffix
  3781.             }
  3782.             else {            
  3783.                 OutFile.Put(i ? 'q' : 'd');  // integer size suffix
  3784.             }
  3785.         }
  3786.         else if ((s.OpcodeDef->AllowedPrefixes & 0x7000) == 0x4000) {
  3787.             // Integer operand size defined by W prefix bit
  3788.             i = s.Prefixes[7] & 8;  // W prefix bit
  3789.             OutFile.Put(i ? 'w' : 'b');
  3790.         }
  3791.         else if ((s.OpcodeDef->AllowedPrefixes & 0x7000) == 0x5000) {
  3792.             // mask register operand size defined by W prefix bit and 66 prefix
  3793.             i  = (s.Prefixes[7] & 8) >> 2;      // W prefix bit
  3794.             i |= s.Prefixes[5] != 0x66;         // 66 prefix bit
  3795.             OutFile.Put("bwdq"[i]);
  3796.         }
  3797.         else if (s.OpcodeDef->AllowedPrefixes & 0xE00) {
  3798.             // F.P. operand type and size defined by prefixes
  3799.             switch (s.Prefixes[5]) {
  3800.             case 0:     // No prefix = ps
  3801.                 OutFile.Put("ps");  break;
  3802.             case 0x66:  // 66 prefix = pd
  3803.                 OutFile.Put("pd");  break;
  3804.             case 0xF3:  // F3 prefix = ss
  3805.                 OutFile.Put("ss");  break;
  3806.             case 0xF2:  // F2 prefix = sd
  3807.                 OutFile.Put("sd");  break;
  3808.             default:
  3809.                 err.submit(9000); // Should not occur
  3810.             }
  3811.         }
  3812.         else if (s.OpcodeDef->AllowedPrefixes & 0x100){
  3813.             // Integer operand size defined by prefixes
  3814.             // Suffix for operand size
  3815.             i = s.OperandSize / 8;
  3816.             if (i <= 8) {
  3817.                 static const char SizeSuffixes[] = " bw d f q"; // Table of suffixes
  3818.                 OutFile.Put(SizeSuffixes[i]);
  3819.             }
  3820.         }
  3821.     }
  3822.     // Alternative suffix option
  3823.     if (s.OpcodeDef->Options & 0x1000) {
  3824.         // Append alternative suffix for vector element size to name
  3825.         if ((s.OpcodeDef->AllowedPrefixes & 0x7000) == 0x3000) {
  3826.             // Integer operand size defined by W prefix bit
  3827.             i = ((s.Prefixes[7] & 8) + 8) * 4;  // W prefix bit -> 8 / 16
  3828.             OutFile.PutDecimal(i);
  3829.         }
  3830.         if ((s.OpcodeDef->AllowedPrefixes & 0x7000) == 0x4000) { // 32 / 64
  3831.             i = (s.Prefixes[7] & 8) + 8;  // W prefix bit -> 8 / 16
  3832.             OutFile.PutDecimal(i);
  3833.         }
  3834.     }
  3835.     // More suffix option
  3836.     if ((s.OpcodeDef->Options & 0x400) && s.ImmediateFieldSize == 8) {
  3837.         // 64 bit immediate mov
  3838.         if (Syntax == SUBTYPE_GASM) OutFile.Put("abs");
  3839.     }  
  3840.  
  3841.     // Space between opcode name and operands
  3842.     OutFile.Put(" "); OutFile.Tabulate(AsmTab2);  // Tabulate. At least one space
  3843.  
  3844.     // Loop for all operands to write
  3845.     for (i = 0; i < s.MaxNumOperands; i++) {
  3846.         if (s.Operands[i] & 0xFFFF) {
  3847.  
  3848.             // Write operand i
  3849.             if (NumOperands++) {
  3850.                 // At least one operand before this one. Separate by ", "
  3851.                 OutFile.Put(", ");
  3852.             }
  3853.  
  3854.             // Write constant and jump operands
  3855.             switch (s.Operands[i] & 0xF0) {
  3856.             case 0x10: case 0x20: case 0x30: case 0x80:
  3857.                 WriteImmediateOperand(s.Operands[i]);
  3858.                 continue;
  3859.             }
  3860.  
  3861.             // Write register and memory operands
  3862.             uint32 optype = (s.Operands[i] >> 16) & 0x0F;
  3863.             switch (optype) {
  3864.             case 0:        // Other type of operand
  3865.                 WriteOtherOperand(s.Operands[i]);  break;
  3866.  
  3867.             case 0x1:  // Direct memory operand
  3868.                 WriteRMOperand(s.Operands[i]);  break;
  3869.  
  3870.             case 0x2:  // Register operand indicated by last bits of opcode
  3871.                 WriteShortRegOperand(s.Operands[i]);  break;
  3872.  
  3873.             case 0x3:  // Register or memory operand indicated by mod/rm bits
  3874.                 WriteRMOperand(s.Operands[i]);  break;
  3875.  
  3876.             case 0x4:  // Register operand indicated by reg bits
  3877.                 WriteRegOperand(s.Operands[i]);  break;
  3878.  
  3879.             case 0x5:  // Register operand indicated by dest bits of DREX byte
  3880.                 WriteDREXOperand(s.Operands[i]);  break;
  3881.  
  3882.             case 0x6:  // Register operand indicated by VEX.vvvv bits
  3883.                 WriteVEXOperand(s.Operands[i], 0);  break;
  3884.  
  3885.             case 0x7:  // Register operand indicated by bits 4-7 of immediate operand
  3886.                 WriteVEXOperand(s.Operands[i], 1);  break;
  3887.  
  3888.             case 0x8:  // Register operand indicated by bits 0-3 of immediate operand
  3889.                 WriteVEXOperand(s.Operands[i], 2);  break; // Unused. For future use
  3890.             }
  3891.             int isMem = optype == 3 && s.Mod != 3;
  3892.             if (s.Prefixes[3] == 0x62) { // EVEX and MVEX prefix can have extra operand attributes
  3893.                 if (s.Prefixes[6] & 0x20) {                
  3894.                     WriteOperandAttributeEVEX(i, isMem);
  3895.                 }
  3896.                 else {
  3897.                     WriteOperandAttributeMVEX(i, isMem);
  3898.                 }
  3899.             }
  3900.             if (s.Prefixes[3] == 0x62 && (i == s.MaxNumOperands - 1 || (s.Operands[i+1] & 0xFFF) < 0x40)) {
  3901.                 // This is the last SIMD operand
  3902.                 if (!(s.Operands[4] & 0x80000000)) {
  3903.                     s.Operands[4] |= 0x80000000;  // Make sure we don't write this twice
  3904.                     if (s.Prefixes[6] & 0x20) {                
  3905.                         WriteOperandAttributeEVEX(98, isMem);
  3906.                     }
  3907.                     else {
  3908.                         WriteOperandAttributeMVEX(98, isMem);
  3909.                     }
  3910.                 }
  3911.             }
  3912.         }
  3913.     }
  3914.     if (s.Prefixes[3] == 0x62) { // EVEX and MVEX prefix can have extra attributes after operands
  3915.         if (s.Prefixes[6] & 0x20) {                
  3916.             WriteOperandAttributeEVEX(99, 0);
  3917.         }
  3918.         else {
  3919.             WriteOperandAttributeMVEX(99, 0);
  3920.         }
  3921.     }
  3922.     if (s.OpComment) {
  3923.         // Write opcode comment
  3924.         OutFile.Put(' ');
  3925.         OutFile.Put(CommentSeparator);
  3926.         OutFile.Put(s.OpComment);
  3927.     }
  3928. }
  3929.  
  3930.  
  3931. void CDisassembler::WriteStringInstruction() {
  3932.     // Write string instruction or xlat instruction
  3933.     uint32 NumOperands = 0;                       // Number of operands written
  3934.     uint32 i;                                     // Loop index
  3935.     uint32 Segment;                               // Possible segment prefix
  3936.  
  3937.     if (!(s.OpcodeDef->AllowedPrefixes & 0x1100)) {
  3938.         // Operand size is 8 if operand size prefixes not allowed
  3939.         s.OperandSize = 8;
  3940.     }
  3941.  
  3942.     OutFile.Tabulate(AsmTab1);                    // Tabulate
  3943.  
  3944.     if (Syntax != SUBTYPE_MASM && s.Prefixes[0] && (s.OpcodeDef->AllowedPrefixes & 4)) {
  3945.         // Get segment prefix
  3946.         Segment = GetSegmentRegisterFromPrefix();  // Interpret segment prefix
  3947.         // Write segment override
  3948.         OutFile.Put(RegisterNamesSeg[Segment]);
  3949.         OutFile.Put(" ");
  3950.     }    
  3951.  
  3952.     // Check repeat prefix
  3953.     if (s.OpcodeDef->AllowedPrefixes & 0x20) {
  3954.         if (s.Prefixes[3]) {
  3955.             // Repeat prefix
  3956.             OutFile.Put("rep ");
  3957.         }
  3958.     }
  3959.     else if (s.OpcodeDef->AllowedPrefixes & 0x40) {
  3960.         if (s.Prefixes[3] == 0xF2) {
  3961.             // repne prefix
  3962.             OutFile.Put("repne ");
  3963.         }
  3964.         else if (s.Prefixes[3] == 0xF3) {
  3965.             // repe prefix
  3966.             OutFile.Put("repe ");
  3967.         }
  3968.     }
  3969.  
  3970.     // Write opcode name
  3971.     OutFile.Put(s.OpcodeDef->Name);               // Opcode name
  3972.  
  3973.     if (Syntax == SUBTYPE_MASM
  3974.         && (((s.OpcodeDef->AllowedPrefixes & 4) && s.Prefixes[0])
  3975.         || ((s.OpcodeDef->AllowedPrefixes & 1) && s.Prefixes[1]))) {
  3976.             // Has segment or address size prefix. Must write operands explicitly
  3977.             OutFile.Put(" ");                          // Space before operands
  3978.  
  3979.             // Check address size for pointer registers
  3980.             const char * * PointerRegisterNames;
  3981.             switch (s.AddressSize) {
  3982.             case 16:
  3983.                 PointerRegisterNames = RegisterNames16;  break;
  3984.             case 32:
  3985.                 PointerRegisterNames = RegisterNames32;  break;
  3986.             case 64:
  3987.                 PointerRegisterNames = RegisterNames64;  break;
  3988.             default:
  3989.                 PointerRegisterNames = 0;  // should not occur
  3990.             }
  3991.  
  3992.             // Loop for possibly two operands
  3993.             for (i = 0; i < 2; i++) {
  3994.                 if (s.Operands[i]) {
  3995.                     // Operand i defined
  3996.                     if (NumOperands++) {
  3997.                         // An operand before this one. Separate by ", "
  3998.                         OutFile.Put(", ");
  3999.                     }
  4000.                     if (NumOperands == 1) {
  4001.                         // Write operand size for first operand
  4002.                         switch (s.OperandSize) {
  4003.                         case 8:
  4004.                             OutFile.Put("byte  ");  break;
  4005.                         case 16:
  4006.                             OutFile.Put("word  ");  break;
  4007.                         case 32:
  4008.                             OutFile.Put("dword  ");  break;
  4009.                         case 64:
  4010.                             OutFile.Put("qword  ");  break;
  4011.                         }
  4012.                     }
  4013.                     // Get segment
  4014.                     Segment = 1;                        // Default segment is DS
  4015.                     if (s.Prefixes[0]) {
  4016.                         Segment = GetSegmentRegisterFromPrefix(); // Interpret segment prefix
  4017.                     }
  4018.                     if ((s.Operands[i] & 0xCF) == 0xC2) {
  4019.                         Segment = 0;                      // Segment is ES regardless of prefix for [edi] operand
  4020.                     }
  4021.                     // Write segment override
  4022.                     OutFile.Put(RegisterNamesSeg[Segment]);
  4023.                     OutFile.Put(":");
  4024.                     // Opening "["
  4025.                     OutFile.Put("[");
  4026.  
  4027.                     // Write pointer register
  4028.                     switch (s.Operands[i] & 0xCF) {
  4029.                     case 0xC0:  // [bx], [ebx] or [rbx]
  4030.                         OutFile.Put(PointerRegisterNames[3]);  
  4031.                         break;
  4032.                     case 0xC1:  // [si], [esi] or [rsi]
  4033.                         OutFile.Put(PointerRegisterNames[6]);  
  4034.                         break;
  4035.                     case 0xC2:  // [di], [edi] or [rdi]
  4036.                         OutFile.Put(PointerRegisterNames[7]);  
  4037.                         break;
  4038.                     }
  4039.                     // Closing "]"
  4040.                     OutFile.Put("]");
  4041.                 }
  4042.             }
  4043.     }
  4044.     else {
  4045.         // We don't have to write the operands
  4046.         // Append suffix for operand size, except for xlat
  4047.         if ((s.Operands[1] & 0xCF) != 0xC0) {
  4048.  
  4049.             // Suffix for operand size
  4050.             uint32 i = s.OperandSize / 8;
  4051.             if (i <= 8) {
  4052.                 static const char SizeSuffixes[] = " bw d   q"; // Table of suffixes
  4053.                 OutFile.Put(SizeSuffixes[i]);
  4054.             }
  4055.         }
  4056.     }
  4057. }
  4058.  
  4059.  
  4060. void CDisassembler::WriteCodeComment() {
  4061.     // Write hex listing of instruction as comment after instruction
  4062.     uint32 i;                                     // Index to current byte
  4063.     uint32 FieldSize;                             // Number of bytes in field
  4064.     const char * Spacer;                          // Space between fields
  4065.  
  4066.     OutFile.Tabulate(AsmTab3);                    // Tabulate to comment field
  4067.     OutFile.Put(CommentSeparator);                // Start comment
  4068.  
  4069.     // Write address
  4070.     if (SectionEnd + SectionAddress + (uint32)ImageBase > 0xFFFF) {
  4071.         // Write 32 bit address
  4072.         OutFile.PutHex(IBegin + SectionAddress + (uint32)ImageBase);
  4073.     }
  4074.     else {
  4075.         // Write 16 bit address
  4076.         OutFile.PutHex((uint16)(IBegin + SectionAddress));
  4077.     }
  4078.  
  4079.     // Space after address
  4080.     OutFile.Put(" _");
  4081.  
  4082.     // Start of instruction
  4083.     i = IBegin;
  4084.  
  4085.     // Write bytes
  4086.     while (i < IEnd) {
  4087.         FieldSize = 1;                             // Size of field to write
  4088.         Spacer = " ";                              // Space between fields
  4089.  
  4090.         // Spacer and FieldSize depends on fields
  4091.         if (i == s.OpcodeStart1 && i > IBegin) {
  4092.             Spacer = ": ";                          // Space between prefixes and opcode
  4093.         }
  4094.         if (i == s.OpcodeStart2 + 1) {
  4095.             Spacer = ". ";                          // Space between opcode and mod/reg/rm bytes
  4096.         }
  4097.         if (i == s.AddressField && s.AddressFieldSize) {
  4098.             Spacer = ", ";                          // Space before address field
  4099.             FieldSize = s.AddressFieldSize;
  4100.         }
  4101.         if (i == s.ImmediateField && s.ImmediateFieldSize) {
  4102.             Spacer = ", ";                          // Space before immediate operand field
  4103.             FieldSize = s.ImmediateFieldSize;
  4104.         }
  4105.         // Write space
  4106.         OutFile.Put(Spacer);
  4107.  
  4108.         // Write byte or bytes
  4109.         switch (FieldSize) {
  4110.         case 1:  // Write single byte
  4111.             OutFile.PutHex(Get<uint8>(i));
  4112.             break;
  4113.         case 2:  // Write two bytes
  4114.             OutFile.PutHex(Get<uint16>(i));
  4115.             break;
  4116.         case 3:  // Write three bytes (operands for "enter" instruction)
  4117.             OutFile.PutHex(Get<uint16>(i));
  4118.             OutFile.Put(", ");
  4119.             OutFile.PutHex(Get<uint8>(i+2));
  4120.             break;
  4121.         case 4:  // Write four bytes
  4122.             if ((s.Operands[0] & 0xFE) == 0x84) {
  4123.                 // Far jump/call address
  4124.                 OutFile.PutHex(Get<uint16>(i));
  4125.                 OutFile.Put(" ");
  4126.                 OutFile.PutHex(Get<uint16>(i+2));
  4127.             }
  4128.             else {
  4129.                 // Any other 32 bit operand
  4130.                 OutFile.PutHex(Get<uint32>(i));
  4131.             }
  4132.             break;
  4133.         case 6:  // Write six bytes (far jump address)
  4134.             OutFile.PutHex(Get<uint32>(i));
  4135.             OutFile.Put(" ");
  4136.             OutFile.PutHex(Get<uint16>(i+4));
  4137.             break;
  4138.         case 8:  // Write eight bytes
  4139.             OutFile.PutHex(Get<uint64>(i));
  4140.             break;
  4141.         }
  4142.         // Search for relocation
  4143.         SARelocation rel1;                            // Make relocation records for searching
  4144.         rel1.Section = Section;
  4145.         rel1.Offset  = i;                             // rel1 marks current field in instruction
  4146.  
  4147.         // Is there a relocation source exactly here?
  4148.         int32 irel = Relocations.Exists(rel1);        // Finds relocation with source = i
  4149.  
  4150.         if (irel > 0) {
  4151.             // This field has a relocation. Indicate relocation type
  4152.             // 0 = unknown, 1 = direct, 2 = self-relative, 3 = image-relative,
  4153.             // 4 = segment relative, 5 = relative to arbitrary ref. point, 8 = segment address/descriptor
  4154.             uint32 RelType = Relocations[irel].Type;
  4155.             if (RelType) {
  4156.                 OutFile.Put(Lookup(RelocationTypeNames, RelType));
  4157.             }
  4158.             if (Relocations[irel].Size > FieldSize) {
  4159.                 // Relocation has wrong size
  4160.                 OutFile.Put(" Misplaced relocation.");
  4161.             }
  4162.         }
  4163.  
  4164.         // Point to next byte
  4165.         i += FieldSize;
  4166.     }
  4167.     // New line
  4168.     OutFile.NewLine();
  4169. }
  4170.  
  4171.  
  4172. void CDisassembler::CountInstructions() {
  4173.     // Count total number of instructions defined in opcodes.cpp
  4174.     // Two instructions are regarded as the same and counted as one if they
  4175.     // have the same name and differ only in the bits that define register
  4176.     // name, operand size, etc.
  4177.  
  4178.     uint32 map;                                   // Map number
  4179.     uint32 index;                                 // Index into map
  4180.     uint32 n;                                     // Number of instructions with same code
  4181.     uint32 iset;                                  // Instruction set
  4182.     uint32 instructions = 0;                      // Total number of instructions
  4183.     uint32 mmxinstr = 0;                          // Number of MMX instructions
  4184.     uint32 sseinstr = 0;                          // Number of SSE instructions
  4185.     uint32 sse2instr = 0;                         // Number of SSE2 instructions
  4186.     uint32 sse3instr = 0;                         // Number of SSE3 instructions
  4187.     uint32 ssse3instr = 0;                        // Number of SSSE3 instructions
  4188.     uint32 sse41instr = 0;                        // Number of SSE4.1 instructions
  4189.     uint32 sse42instr = 0;                        // Number of SSE4.2 instructions
  4190.     uint32 AVXinstr  = 0;                         // Number of AVX instructions
  4191.     uint32 FMAinstr  = 0;                         // Number of FMA3 and later instructions
  4192.     uint32 AVX2instr  = 0;                        // Number of AVX2 instructions
  4193.     uint32 BMIinstr  = 0;                         // Number of BMI instructions and other small instruction sets
  4194.     uint32 AVX512instr = 0;                       // Number of AVX-512 instructions
  4195.     uint32 MICinstr = 0;                          // Number of MIC instructions
  4196.     uint32 AMDinstr = 0;                          // Number of AMD instructions
  4197.     uint32 VIAinstr = 0;                          // Number of AMD instructions
  4198.     uint32 privilinstr = 0;                       // Number of privileged instructions
  4199.     uint32 undocinstr = 0;                        // Number of undocumented instructions
  4200.     uint32 droppedinstr = 0;                      // Number of opcodes planned but never implemented
  4201.     uint32 VEXdouble = 0;                         // Number of instructions that have both VEX and non-VEX version
  4202.     SOpcodeDef const * opcode;                    // Pointer to map entry
  4203.  
  4204.     // Loop through all maps
  4205.     for (map = 0; map < NumOpcodeTables1; map++) {
  4206.         // Loop through each map
  4207.         for (index = 0; index < OpcodeTableLength[map]; index++) {
  4208.             opcode = OpcodeTables[map] + index;
  4209.             if (opcode->InstructionFormat && opcode->Name
  4210.             && !opcode->TableLink && !(opcode->InstructionFormat & 0x8000)) {
  4211.                 // instruction is defined
  4212.                 if ((opcode->InstructionFormat & 0xFFF) == 3
  4213.                 && index > 0 && (opcode-1)->Name
  4214.                 && strcmp(opcode->Name, (opcode-1)->Name) == 0) {
  4215.                     // Same as previous instruction, just with another register
  4216.                     continue;                         // Don't count this
  4217.                 }
  4218.                 n = 1;                               // Default = one instruction per map entry
  4219.                 // Check if we have multiple instructions with different prefixes
  4220.                 if (opcode->Options & 1) {
  4221.                     if (opcode->AllowedPrefixes & 0x3000) {
  4222.                         n++;                           // Extra instruction with W prefix bit
  4223.                     }
  4224.                     else if (opcode->AllowedPrefixes & 0xE00) {              
  4225.                         if (opcode->AllowedPrefixes & 0x200) n++; // Extra instruction with 66 prefix
  4226.                         if (opcode->AllowedPrefixes & 0x400) n++; // Extra instruction with F3 prefix
  4227.                         if (opcode->AllowedPrefixes & 0x800) n++; // Extra instruction with F2 prefix
  4228.                     }
  4229.                     else if (opcode->AllowedPrefixes & 0x100) {
  4230.                         n++;                                      // Extra instruction with 66 prefix
  4231.                         if (opcode->AllowedPrefixes & 0x1000) n++;// Extra instruction with L prefix bit
  4232.                     }
  4233.                 }
  4234.                 if (opcode->Options & 2) VEXdouble += n; // Instructions that have both VEX and non-VEX version
  4235.                 instructions += n;                   // Count total instructions
  4236.  
  4237.                 iset = opcode->InstructionSet;       // Instruction set
  4238.                 if (iset & 0x20000) {
  4239.                     droppedinstr += n; iset = 0;      // Opcodes planned but never implemented
  4240.                 }
  4241.                 if (iset & 0x800) privilinstr += n;  // Privileged instruction
  4242.                 if (opcode->InstructionFormat & 0x4000) undocinstr += n; // Undocumented instruction
  4243.  
  4244.                 switch (iset & 0x37FF) {
  4245.                 case 7:  // MMX
  4246.                     mmxinstr += n;  break;
  4247.                 case 0x11:  // SSE
  4248.                     sseinstr += n;  break;
  4249.                 case 0x12:  // SSE2
  4250.                     sse2instr += n;  break;
  4251.                 case 0x13: // SSE3
  4252.                     sse3instr += n;  break;
  4253.                 case 0x14: // SSSE3
  4254.                     ssse3instr += n;  break;
  4255.                 case 0x15: // SSE4.1
  4256.                     sse41instr += n;  break;
  4257.                 case 0x16: // SSE4.2
  4258.                     sse42instr += n;  break;
  4259.                 case 0x17: case 0x18: case 0x19: // VEX etc.
  4260.                     AVXinstr += n;  break;
  4261.                 case 0x1A: case 0x1B:            // FMA and later instructions
  4262.                     FMAinstr += n;  break;
  4263.                 case 0x1C:                       // AVX2 instructions
  4264.                     AVX2instr += n; break;
  4265.                 case 0x1D: case 0x1E:            // BMI and other small instruction sets
  4266.                     BMIinstr += n; break;
  4267.                 case 0x20:                       // AVX-512 instructions
  4268.                     AVX512instr += n; break;
  4269.                 case 0x80:                       // MIC instructions
  4270.                     MICinstr += n; break;
  4271.                 case 0x1001: case 0x1002: case 0x1004: case 0x1005: case 0x1006:  // AMD
  4272.                     AMDinstr += n;  break;
  4273.                 case 0x2001: // VIA
  4274.                     VIAinstr += n;  break;              
  4275.                 }
  4276.             }
  4277.         }
  4278.     }
  4279.  
  4280.     // output result
  4281.     printf("\n\nNumber of instruction opcodes supported by disassembler:\n%5i Total, including:",
  4282.         instructions);
  4283.     printf("\n%5i Privileged instructions", privilinstr);
  4284.     printf("\n%5i MMX    instructions", mmxinstr);
  4285.     printf("\n%5i SSE    instructions", sseinstr);
  4286.     printf("\n%5i SSE2   instructions", sse2instr);
  4287.     printf("\n%5i SSE3   instructions", sse3instr);
  4288.     printf("\n%5i SSSE3  instructions", ssse3instr);
  4289.     printf("\n%5i SSE4.1 instructions", sse41instr);
  4290.     printf("\n%5i SSE4.2 instructions", sse42instr);
  4291.     printf("\n%5i AVX    instructions etc.", AVXinstr);
  4292.     printf("\n%5i AVX2   instructions", AVX2instr);
  4293.     printf("\n%5i FMA3   instructions", FMAinstr);
  4294.     printf("\n%5i BMI/micsellaneous instr.", BMIinstr);
  4295.     printf("\n%5i AVX-512 instructions", AVX512instr);
  4296.     printf("\n%5i MIC/Xeon Phi instructions", MICinstr);
  4297.     printf("\n%5i AMD    instructions", AMDinstr);
  4298.     printf("\n%5i VIA    instructions", VIAinstr);  
  4299.     printf("\n%5i instructions planned but never implemented in any CPU", droppedinstr);
  4300.     printf("\n%5i undocumented or illegal instructions", undocinstr);
  4301.     printf("\n%5i instructions have both VEX and non-VEX versions", VEXdouble);
  4302.     printf("\n");
  4303.  
  4304. #if 0   // temporary test code
  4305.  
  4306.     // find entries with 0x2000 prefix code
  4307.     printf("\n\nInstructions with operand swap flag:\n");
  4308.     // Loop through all maps
  4309.     for (map = 0; map < NumOpcodeTables1; map++) {
  4310.         // Loop through each map
  4311.         for (index = 0; index < OpcodeTableLength[map]; index++) {
  4312.             opcode = OpcodeTables[map] + index;
  4313.             if ((opcode->AllowedPrefixes & 0x2000) == 0x2000) {
  4314.                 printf("\n%04X %02X  %s", map, index, opcode->Name);
  4315.             }
  4316.         }
  4317.     }
  4318.  
  4319.     /*
  4320.     printf("\n\nTables linked by type 0x0E:\n");
  4321.     // Loop through all maps
  4322.     for (map = 0; map < NumOpcodeTables1; map++) {
  4323.         // Loop through each map
  4324.         for (index = 0; index < OpcodeTableLength[map]; index++) {
  4325.             opcode = OpcodeTables[map] + index;
  4326.             if (opcode->TableLink == 0x0E) {
  4327.                 printf("  0x%02X", opcode->InstructionSet);
  4328.             }
  4329.         }
  4330.     }*/
  4331.  
  4332.     printf("\n");
  4333.  
  4334. #endif
  4335. }
  4336.