Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
9683 turbocat 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(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(s.AddressField);
226
        break;
227
    case 2:  // 2 bytes displacement
228
        Addend = Get(s.AddressField);
229
        break;
230
    case 4:  // 4 bytes displacement
231
        Addend = Get(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(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(s.ImmediateField) >> 4;  break;
618
    case 2:  // Use immediate bits 0-3 (Unused. For possible future use)
619
        Num = Get(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(FieldPointer) & 0x0F;
1005
        break;
1006
 
1007
    case 1:  // 8 bits
1008
        Value = Get(FieldPointer);
1009
        break;
1010
 
1011
    case 2:  // 16 bits
1012
        Value = Get(FieldPointer);  break;
1013
 
1014
    case 6:  // 48 bits
1015
        Value  = Get(FieldPointer);
1016
        Value += (uint64)Get(FieldPointer + 4) << 32;
1017
        break;
1018
 
1019
    case 4:  // 32 bits
1020
        Value = Get(FieldPointer);  break;
1021
 
1022
    case 8:  // 64 bits
1023
        Value = Get(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(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(Pos);  break;
1625
            case 2:  Value = Get(Pos);  break;
1626
            case 4:  Value = Get(Pos);  break;
1627
            case 6:  Value = Get(Pos) + ((uint64)Get(Pos+4) << 32); break;
1628
            case 8:  Value = Get(Pos);  break;
1629
            case 10: Value = Get(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(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(pos1), 1); // Write as hexadecimal
2025
            }
2026
            else {
2027
                OutFile.PutDecimal(Get(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(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(pos1));
2045
            }
2046
            else {
2047
                // Other. Write as decimal
2048
                OutFile.PutDecimal(Get(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(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(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(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(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(i), 1);
3699
        }
3700
        OutFile.Tabulate(AsmTab3);                 // Tabulate
3701
        OutFile.Put(CommentSeparator);
3702
        if ((s.OpcodeDef->AllowedPrefixes & 8) && Get(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(i));
4112
            break;
4113
        case 2:  // Write two bytes
4114
            OutFile.PutHex(Get(i));
4115
            break;
4116
        case 3:  // Write three bytes (operands for "enter" instruction)
4117
            OutFile.PutHex(Get(i));
4118
            OutFile.Put(", ");
4119
            OutFile.PutHex(Get(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(i));
4125
                OutFile.Put(" ");
4126
                OutFile.PutHex(Get(i+2));
4127
            }
4128
            else {
4129
                // Any other 32 bit operand
4130
                OutFile.PutHex(Get(i));
4131
            }
4132
            break;
4133
        case 6:  // Write six bytes (far jump address)
4134
            OutFile.PutHex(Get(i));
4135
            OutFile.Put(" ");
4136
            OutFile.PutHex(Get(i+4));
4137
            break;
4138
        case 8:  // Write eight bytes
4139
            OutFile.PutHex(Get(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
}