File: omf2cof.cpp

package info (click to toggle)
objconv 2.56%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,300 kB
  • sloc: cpp: 27,039; makefile: 4; sh: 2
file content (875 lines) | stat: -rw-r--r-- 42,155 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
/****************************  omf2cof.cpp   *********************************
* Author:        Agner Fog
* Date created:  2007-02-08
* Last modified: 2018-08-15
* Project:       objconv
* Module:        omf2cof.cpp
* Description:
* Module for converting OMF file to PE/COFF file
*
* Copyright 2007-2018 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
#include "stdafx.h"

// Alignment value translation table
static const uint32_t OMFAlignTranslate[8] = {0,1,2,16,256,4,0,0};

COMF2COF::COMF2COF() {
    // Constructor
    memset(this, 0, sizeof(*this));               // Reset everything
}

void COMF2COF::Convert() {
    // Do the conversion
    // Allocate variable size buffers
    //NewSectIndex.SetNum(this->NSections);// Allocate section translation table
    //NewSectIndex.SetZero();              // Initialize

    // Call the subfunctions
    ToFile.SetFileType(FILETYPE_COFF);  // Set type of to file
    MakeFileHeader();                   // Make file header
    MakeSymbolTable1();                 // Make symbol table and string table entries for file and segments
    MakeSymbolTable2();                 // Make symbol table and string table entries for external symbols
    MakeSymbolTable3();                 // Make symbol table and string table entries for public symbols
    MakeSymbolTable4();                 // Make symbol table and string table entries for communal symbols
    MakeSymbolTable5();                 // Make symbol table and string table entries for local symbols
    MakeSections();                     // Make sections and relocation tables
    CheckUnsupportedRecords();          // Make warnings if file containes unsupported record types
    MakeBinaryFile();                   // Put sections together
    *this << ToFile;                    // Take over new file buffer
}


void COMF2COF::MakeFileHeader() {
    // Convert subfunction: File header
    // Make PE file header
    NewFileHeader.Machine = PE_MACHINE_I386;
    NewFileHeader.TimeDateStamp = (uint32_t)time(0);
    NewFileHeader.SizeOfOptionalHeader = 0;
    NewFileHeader.Flags = 0;

    // Values inserted later:
    NewFileHeader.NumberOfSections = 0;
    NewFileHeader.PSymbolTable = 0;
    NewFileHeader.NumberOfSymbols = 0;
}


void COMF2COF::MakeSymbolTable1() {
    // Make symbol table string table and section table entries for file and segments
    SCOFF_SymTableEntry sym;                      // Symbol table entry
    SCOFF_SectionHeader sec;                      // Section header entry
    char * ClassName;                             // Old segment class name

    // Initialize new string table. make space for 4-bytes size
    NewStringTable.Push(0, 4);

    // Allocate SegmentTranslation buffer
    SegmentTranslation.SetNum(SegmentNameOffset.GetNumEntries());

    // Make symbol table entry for file name
    memset(&sym, 0, SIZE_SCOFF_SymTableEntry);
    strcpy(sym.s.Name, ".file");
    sym.s.SectionNumber = COFF_SECTION_DEBUG;
    sym.s.StorageClass = COFF_CLASS_FILE;
    char * ShortFileName = CLibrary::ShortenMemberName(OutputFileName);
    sym.s.NumAuxSymbols = 1;  // File name is truncated so it will fit into the 18 bytes of SIZE_SCOFF_SymTableEntry
    NewSymbolTable.Push(sym); // Store symbol table entry
    // Needs auxiliary entry:
    memset(&sym, 0, SIZE_SCOFF_SymTableEntry);
    if (strlen(ShortFileName) < SIZE_SCOFF_SymTableEntry) {
        strcpy(sym.s.Name, ShortFileName);
    }
    NewSymbolTable.Push(sym); // Store auxiliary symbol table entry

    // Define structure of attributes
    OMF_SAttrib Attributes;
    // Other segment properties
    uint32_t SegLength, NameIndex, ClassIndex;
    //uint32_t Offset;
    const char * sname;                           // Segment/section name
    uint32_t SegNum = 0;                            // Segment/section number
    uint32_t StringI;                               // New sting table index
    uint32_t i;                                     // Record number
    int32_t  j, n;                                  // Temporary

    // Loop through segments of old file
    for (i = 0; i < NumRecords; i++) {
        if (Records[i].Type2 == OMF_SEGDEF) {
            // SEGDEF record
            Records[i].Index = 3;
            // Loop through entries in record. There should be only 1
            while (Records[i].Index < Records[i].End) {
                Attributes.b = Records[i].GetByte(); // Read attributes
                if (Attributes.u.A == 0) {
                    // Frame and Offset only included if A = 0
                    Records[i].GetWord();             // Frame ignored                    
                    Records[i].GetByte();
                }
                //else Offset = 0;
                SegLength  = Records[i].GetNumeric();
                NameIndex  = Records[i].GetIndex();
                ClassIndex = Records[i].GetIndex();  // Class index
                Records[i].GetIndex();               // Overlay index ignored
                sname = GetLocalName(NameIndex);     // Segment name = new section name

                if (Attributes.u.B) {
                    // Segment is big
                    if (Attributes.u.P) {
                        // 32 bit segment. Big means 2^32 bytes!
                        err.submit(2306);
                    }
                    else {
                        // 16 bit segment. Big means 2^16 bytes
                        SegLength = 0x10000;
                    }
                }

                // make symbol table entry
                memset(&sym, 0, SIZE_SCOFF_SymTableEntry);

                // Put name into string table
                StringI = NewStringTable.PushString(sname);

                // Put name into symbol table
                //COFF_PutNameInSymbolTable(sym, sname, NewStringTable);
                ((uint32_t*)(sym.s.Name))[1] = StringI;

                sym.s.SectionNumber = ++SegNum;        // Count section number
                sym.s.StorageClass = COFF_CLASS_STATIC;
                sym.s.NumAuxSymbols = 1;               // Needs 1 aux record

                // Remember NewSymbolTable index
                SegmentTranslation[SegNum] = NewSymbolTable.GetNumEntries();
                NewSymbolTable.Push(sym);            // Store symbol table entry

                // Make auxiliary entry
                memset(&sym, 0, SIZE_SCOFF_SymTableEntry);

                // Insert section size
                sym.section.Length = SegLength;

                // Remember to insert NumberOfRelocations here later

                // Store auxiliary symbol table entry
                NewSymbolTable.Push(sym);

                // Make section header            
                memset(&sec, 0, sizeof(sec));        // Reset section header

                // Put name into section header
                sprintf(sec.Name, "/%i", StringI);

                // Put size into section header
                sec.SizeOfRawData = SegLength;

                // Alignment
                switch (Attributes.u.A) {
                case 0:  // Absolute segment
                    err.submit(2307);  break;
                case 1:  // Byte
                    sec.Flags |= PE_SCN_ALIGN_1;  break;
                case 2:  // Word
                    sec.Flags |= PE_SCN_ALIGN_2;  break;
                case 3:  // Paragraph
                    sec.Flags |= PE_SCN_ALIGN_16;  break;
                case 4:  // Page. May be 256 or 4096, depending on system
                    // If we use 4096 where the source intended 256, we may get
                    // size and symbol offsets wrong!
                    sec.Flags |= PE_SCN_ALIGN_256;  break;
                case 5:  // Dword
                    sec.Flags |= PE_SCN_ALIGN_4;  break;
                default: // Unknown alignment
                    err.submit(2308, Attributes.u.A);
                    sec.Flags |= PE_SCN_ALIGN_16;  break;
                }

                // Get further attributes from class name
                ClassName = GetLocalName(ClassIndex);

                // Convert class name to upper case
                n = (int32_t)strlen(ClassName);
                for (j = 0; j < n; j++) ClassName[j] &= ~0x20;

                // Search for known class names.
                // Standard names are CODE, DATA, BSS, CONST, STACK
                if (strstr(ClassName, "CODE") || strstr(ClassName, "TEXT")) {
                    // Code segment
                    sec.Flags |= PE_SCN_CNT_CODE | PE_SCN_MEM_EXECUTE | PE_SCN_MEM_READ;
                }
                else if (strstr(ClassName, "DATA")) {
                    // Data segment
                    sec.Flags |= PE_SCN_CNT_INIT_DATA | PE_SCN_MEM_READ | PE_SCN_MEM_WRITE;
                }
                else if (strstr(ClassName, "BSS")) {
                    // Unitialized data segment
                    sec.Flags |= PE_SCN_CNT_UNINIT_DATA | PE_SCN_MEM_READ | PE_SCN_MEM_WRITE;
                }
                else if (strstr(ClassName, "CONST")) {
                    // Constant data segment
                    sec.Flags |= PE_SCN_CNT_INIT_DATA | PE_SCN_MEM_READ;
                }
                else if (strstr(ClassName, "STACK")) {
                    // Stack segment. Ignore
                    sec.Flags |= PE_SCN_LNK_REMOVE;
                    err.submit(1206); // Warning: ignored
                }
                else {
                    // Unknown/user defined class. Assume data segment
                    sec.Flags |= PE_SCN_CNT_INIT_DATA | PE_SCN_MEM_READ | PE_SCN_MEM_WRITE;
                }

                // Insert pointers to relocations and raw data later
                // Store section header
                NewSectionHeaders.Push(sec);
            }
            if (Records[i].Index != Records[i].End) err.submit(1203);   // Check for consistency
        }
        if (Records[i].Type2 == OMF_COMDAT || Records[i].Type2 == OMF_COMDEF) {
            // Communal sections
            err.submit(1055);
        }
    }
}

void COMF2COF::MakeSymbolTable2() {
    // Make symbol table and string table entries for external symbols
    uint32_t i;
    SCOFF_SymTableEntry sym;                      // new symbol table entry
    uint32_t NumExtSym = SymbolNameOffset.GetNumEntries(); // Number of external symbols
    ExtdefTranslation.SetNum(NumExtSym+1);          // Allocate space in translation table

    // Loop through external symbol names
    for (i = 1; i < NumExtSym; i++) {
        // Reset symbol table entry
        memset(&sym, 0, SIZE_SCOFF_SymTableEntry);

        // Insert name
        COFF_PutNameInSymbolTable(sym, GetSymbolName(i), NewStringTable);

        // Insert storage class
        sym.s.StorageClass = COFF_CLASS_EXTERNAL;

        // Store symbol table entry
        NewSymbolTable.Push(sym);

        // Update table for translating old EXTDEF number (1-based) to new symbol table index (0-based)
        ExtdefTranslation[i] = NewSymbolTable.GetNumEntries() - 1;
    }
}


void COMF2COF::MakeSymbolTable3() {
    // Make symbol table and string table entries for public symbols
    SCOFF_SymTableEntry sym;                      // new symbol table entry
    uint32_t i;                                     // Record index
    char * string;                                // Symbol name
    uint32_t Segment;                               // Segment
    uint32_t Offset;                                // Offset
    uint32_t Namei;                                 // Index into symbol table
    SOMFLocalSymbol localsym;                     // Entry into LocalSymbols

    // Search for PUBDEF records
    for (i = 0; i < NumRecords; i++) {
        if (Records[i].Type2 == OMF_PUBDEF) {
            // PUBDEF record

            Records[i].Index = 3;
            Records[i].GetIndex();                  // Group. Ignore
            Segment = Records[i].GetIndex();        // Segment
            if (Segment == 0) Records[i].GetWord(); // Base frame. Ignore

            // Loop through strings in record
            while (Records[i].Index < Records[i].End) {
                string = Records[i].GetString();     // Symbol name
                Offset = Records[i].GetNumeric();    // Offset to segment
                Records[i].GetIndex();               // Type index. Ignore

                // Reset symbol table entry
                memset(&sym, 0, SIZE_SCOFF_SymTableEntry);

                // Insert name
                Namei = COFF_PutNameInSymbolTable(sym, string, NewStringTable);

                // Insert storage class
                sym.s.StorageClass = COFF_CLASS_EXTERNAL;

                // Store offset
                sym.s.Value = Offset;

                // Section number = segment number
                if (Segment == 0) sym.s.SectionNumber = COFF_SECTION_ABSOLUTE;
                else sym.s.SectionNumber = (int16_t)Segment;

                // Store symbol table entry
                NewSymbolTable.Push(sym);

                // Make entry into LocalSymbols to indicate that this symbol has a name
                if (Segment > 0) {
                    // Make index into NewStringTable if we don't allready have one
                    if (Namei == 0) Namei = NewStringTable.PushString(string);
                    localsym.Offset = Offset;
                    localsym.Segment = Segment;
                    localsym.Name = Namei;
                    localsym.NewSymtabIndex = NewSymbolTable.GetNumEntries() - 1; // 0-based index into new symbol table
                    LocalSymbols.PushUnique(localsym);
                }
            }
            if (Records[i].Index != Records[i].End) err.submit(1203);   // Check for consistency
        }
    }
}

void COMF2COF::MakeSymbolTable4() {
    // Make symbol table and string table entries for communal symbols
    // Warning: Currently not supported!
}

void COMF2COF::MakeSymbolTable5() {
    // Make symbol table and string table entries for local symbols.
    // There is no table for local symbols in OMF files. We have to search
    // through all FIXUPP records for relocation targets and assign arbitrary
    // names to them.

    uint32_t i;                                     // Loop counter
    uint32_t Target, TargetDisplacement;            // Contents of FIXUPP record
    uint8_t byte1, byte2;                           // First two bytes of FIXUPP subrecord
    // Bitfields in subrecords
    OMF_SLocat Locat;                             // Structure of first two bytes of FIXUP subrecord swapped = Locat field
    OMF_SFixData FixData;                         // Structure of FixData field in FIXUP subrecord of FIXUPP record
    OMF_STrdDat TrdDat;                           // Structure of Thread Data field in THREAD subrecord of FIXUPP record
    int8_t * LastDataRecordPointer = 0;             // Pointer to data in the data record that relocations refer to
    uint32_t LastDataRecordSize = 0;                // Size of the data record that relocations refer to
    SOMFLocalSymbol localsym;                     // Entry into LocalSymbols
    uint32_t LocalSymNum = 0;                       // Number of unnamed local symbols
    char NewName[32];                             // Buffer for making new name
    SCOFF_SymTableEntry sym;                      // New symbol table entry

    // Search for FIXUPP records and data records
    for (i = 0; i < NumRecords; i++) {

        if (Records[i].Type2 == OMF_LEDATA) {
            // LEDATA record. Remember pointer to binary data in order to read inline offset
            Records[i].Index = 3;                   // Initialize record reading
            Records[i].GetIndex();                  // Read segment and offset
            Records[i].GetNumeric();
            LastDataRecordSize = Records[i].End - Records[i].Index; // Calculate size of data
            LastDataRecordPointer = Records[i].buffer + Records[i].FileOffset + Records[i].Index;
        }

        if (Records[i].Type2 == OMF_FIXUPP) {
            // FIXUPP record
            Records[i].Index = 3;                   // Initialize record reading

            // Loop through entries in record
            while (Records[i].Index < Records[i].End) {

                // Read first byte
                byte1 = Records[i].GetByte();

                if (byte1 & 0x80) {
                    // This is a FIXUP subrecord

                    Target = 0; TargetDisplacement = 0;
                    // read second byte
                    byte2 = Records[i].GetByte();
                    // swap bytes and put into byte12 bitfield
                    Locat.bytes[1] = byte1;
                    Locat.bytes[0] = byte2;
                    // Read FixData
                    FixData.b = Records[i].GetByte();
                    // Read conditional fields
                    if (FixData.s.F == 0) {
                        if (FixData.s.Frame < 4) {
                            Records[i].GetIndex();  // Frame. Ignore
                        }
                    }
                    if (FixData.s.T == 0) {
                        // Target specified
                        Target = Records[i].GetIndex();
                        //uint32_t TargetMethod = FixData.s.Target + FixData.s.P * 4;
                    }
                    if (FixData.s.P == 0) {
                        TargetDisplacement = Records[i].GetNumeric();
                    }
                    // Get inline addend
                    if (LastDataRecordPointer && Locat.s.Offset < LastDataRecordSize) {
                        int8_t * inlinep = LastDataRecordPointer + Locat.s.Offset;
                        if (Locat.s.Location == 9 || Locat.s.Location == 13) {
                            TargetDisplacement += *(int32_t*)inlinep;
                        }
                    }
                    if (FixData.s.T == 0 && (FixData.s.Target == 0 || FixData.s.Target == 1)) {
                        // Target is local symbol

                        // Make entry in LocalSymbols
                        localsym.Offset = TargetDisplacement;    // Offset to segment
                        localsym.Segment = Target;               // Target segment
                        localsym.Name = 0;                       // Has no name yet
                        localsym.NewSymtabIndex = 0;             // Not in new symbol table yet
                        // Make entry in LocalSymbols.
                        // PushUnique will not make an entry if this target address already
                        // has an entry in LocalSymbols and possibly a public name
                        LocalSymbols.PushUnique(localsym);       
                    }
                }
                else {
                    // This is a THREAD subrecord. Read and ignore
                    TrdDat.b = byte1;                 // Put byte into bitfield
                    if (TrdDat.s.Method < 4) {
                        Records[i].GetIndex();         // has index field if method < 4 ?
                    }
                }
            } // Finished loop through subrecords
            if (Records[i].Index != Records[i].End) err.submit(1203);   // Check for consistency
        }
    } // Finished loop through records

    // Now check LocalSymbols for unnamed symbols
    for (i = 0; i < LocalSymbols.GetNumEntries(); i++) {
        if (LocalSymbols[i].Name == 0) {

            // Unnamed symbol. Give it a name
            sprintf(NewName, "?NoName%02i", ++LocalSymNum);

            // Make index in new symbol table
            // Reset symbol table entry
            memset(&sym, 0, SIZE_SCOFF_SymTableEntry);

            // Insert name
            LocalSymbols[i].Name = COFF_PutNameInSymbolTable(sym, NewName, NewStringTable);
            // if (LocalSymbols[i].Name == 0) LocalSymbols[i].Name = NewStringTable.PushString(NewName);

            // Store offset
            sym.s.Value = LocalSymbols[i].Offset;

            // Section number = segment number
            sym.s.SectionNumber = LocalSymbols[i].Segment;

            // Storage class
            sym.s.StorageClass = COFF_CLASS_STATIC;

            // Store symbol table entry
            NewSymbolTable.Push(sym);

            // Store index into new symbol table (0 - based)
            LocalSymbols[i].NewSymtabIndex = NewSymbolTable.GetNumEntries() - 1;
        }
    }
}


void COMF2COF::MakeSections() {
    // Make sections and relocation tables
    uint32_t SegNum;                                // Index into NewSectionHeaders = segment - 1
    uint32_t DesiredSegment;                        // Old segment number = new section number
    uint32_t RecNum;                                // Old record number
    CMemoryBuffer TempBuf;                        // Temporary buffer for building raw data
    CMemoryBuffer RelocationTable;                // Temporary buffer for building new relocation table
    SCOFF_Relocation rel;                         // New relocation table record
    uint32_t LastDataRecord = 0;                    // Index to the data record that relocations refer to
    uint32_t LastDataRecordSize = 0;                // Size of the data record that relocations refer to
    int8_t * LastDataRecordPointer = 0;             // Pointer to data in the data record that relocations refer to
    uint32_t Segment = 0;                           // Segment of last LEDATA, LIDATA or COMDEF record
    uint32_t Offset;                                // Offset of LEDATA or LIDATA record to segment
    uint32_t Size;                                  // Size of data in LEDATA or LIDATA record
    uint32_t SegmentSize;                           // Total size of segment
    uint32_t LastOffset;                            // Offset after last LEDATA into segment
    uint32_t FileOffsetData;                        // File offset of first raw data and relocations in new file
    uint32_t FileOffset;                            // File offset of current raw data or relocations

    // File offset of first data = size of file header and section headers
    FileOffsetData = sizeof(SCOFF_FileHeader) + NewSectionHeaders.GetNumEntries() * sizeof(SCOFF_SectionHeader);

    // Loop through segments
    for (SegNum = 0; SegNum < NewSectionHeaders.GetNumEntries(); SegNum++) {

        DesiredSegment = SegNum + 1;               // Search for records referring to this segment

        SegmentSize = NewSectionHeaders[SegNum].SizeOfRawData;
        if (SegmentSize == 0) continue;            // Empty segment

        // Allocate temporary data buffer and reset it
        TempBuf.SetSize(SegmentSize + 16);
        int FillByte = 0;                          // Byte to fill memory with
        if (NewSectionHeaders[SegNum].Flags & PE_SCN_CNT_CODE) {
            // Code segment. Fill any unused bytes with NOP opcode = 0x90
            FillByte = 0x90;
        }
        memset(TempBuf.Buf(), FillByte, SegmentSize + 16);// Reset to all 0 or NOP

        // Reset relocation table buffer
        RelocationTable.SetSize(0);

        LastOffset = 0;  LastDataRecordSize = 0;

        // Search for LEDATA, LIDATA and FIXUPP records for this segment
        for (RecNum = 0; RecNum < NumRecords; RecNum++) {
            if (Records[RecNum].Type2 == OMF_LEDATA) {

                // LEDATA record
                Records[RecNum].Index = 3;           // Initialize record reading
                Segment = Records[RecNum].GetIndex();// Read segment number

                if (Segment != DesiredSegment) continue; // Does not refer to this segment

                Offset  = Records[RecNum].GetNumeric();// Read offset
                Size    = Records[RecNum].End - Records[RecNum].Index; // Calculate size of data
                LastDataRecord = RecNum;             // Save for later FIXUPP that refers to this record
                
                // Check if data within segment
                if (Offset + Size > SegmentSize) {
                    err.submit(2309, GetSegmentName(Segment));
                    return;
                }

                if (Offset < LastOffset + LastDataRecordSize && LastOffset < Offset + Size) {
                    // Overlapping data records
                    if (Offset + 8 < LastOffset + LastDataRecordSize || !(NewSectionHeaders[SegNum].Flags & PE_SCN_CNT_CODE)) {
                        // Overlapping data by more than 7 bytes or not executable code
                        err.submit(1207);
                    }
                    else {
                        // Possibly backpatched code
                        err.submit(1208);              // Warning
                        err.ClearError(1208);          // Report only once
                    }
                }

                LastDataRecordSize = Size;
                LastDataRecordPointer = Records[RecNum].buffer + Records[RecNum].FileOffset + Records[RecNum].Index;
                LastOffset = Offset;                 // Save offset for subsequent FIXUPP records

                /*// Check if data within segment
                if (Offset + Size > SegmentSize) {
                    err.submit(2309, GetSegmentName(Segment));
                    continue;
                } */

                // Put raw data into temporary buffer
                memcpy(TempBuf.Buf() + Offset, LastDataRecordPointer, Size);

            } // Finished with LEDATA record

            if (Records[RecNum].Type2 == OMF_LIDATA) {
                // LIDATA record
                Records[RecNum].Index = 3;           // Initialize record reading
                Segment = Records[RecNum].GetIndex();

                if (Segment != DesiredSegment) continue; // Does not refer to this segment

                LastDataRecord = RecNum;             // Save for later FIXUPP that refers to this record

                Offset  = Records[RecNum].GetNumeric();// Read offset

                if (Offset > SegmentSize) {
                    err.submit(2310); return;       // Error: outside bounds
                }

                // Unpack LIDATA blocks recursively
                Size = Records[RecNum].UnpackLIDATABlock(TempBuf.Buf() + Offset, SegmentSize - Offset);

                if (Offset < LastOffset + LastDataRecordSize && LastOffset < Offset + Size) {
                    // Overlapping data records
                    err.submit(1207);                 // Warning
                }
                LastDataRecordSize = Size;           // Save data size
                LastOffset = Offset;                 // Save offset for subsequent FIXUPP records

            } // Finished with LIDATA record

            if (Records[RecNum].Type2 == OMF_COMDAT) {
                // COMDAT record. Currently not supported by objconv
                LastDataRecord = RecNum;             // Save for later FIXUPP that refers to this record
                Segment = 0;                         // Ignore any relocation referring to this
            }

            if (Records[RecNum].Type2 == OMF_FIXUPP) {
                // FIXUPP record

                if (Segment != DesiredSegment) continue; // Does not refer to this segment

                uint32_t Target, TargetDisplacement; // Contents of FIXUPP record
                //uint32_t Frame; // Contents of FIXUPP record
                uint8_t byte1, byte2;                 // First two bytes of subrecord

                // Bitfields in subrecords
                OMF_SLocat Locat;         // Structure of first two bytes of FIXUP subrecord swapped = Locat field
                OMF_SFixData FixData;     // Structure of FixData field in FIXUP subrecord of FIXUPP record
                OMF_STrdDat TrdDat;       // Structure of Thread Data field in THREAD subrecord of FIXUPP record

                Records[RecNum].Index = 3;

                if (Records[LastDataRecord].Type2 != OMF_LEDATA && Records[RecNum].Index < Records[RecNum].End) {
                    // Non-empty FIXUPP record does not refer to LEDATA record
                    if (Records[LastDataRecord].Type2 == OMF_COMDAT) {
                        // COMDAT currently not supported. Ignore!
                    }
                    else if (Records[LastDataRecord].Type2 == OMF_LIDATA) {
                        err.submit(2311);              // Error: Relocation of iterated data not supported
                    }
                    else {
                        err.submit(2312);              // Does not refer to data record
                    }
                    continue;                         // Ignore this FIXUPP record
                }

                // Loop through entries in record
                while (Records[RecNum].Index < Records[RecNum].End) {

                    // Read first byte
                    byte1 = Records[RecNum].GetByte();
                    if (byte1 & 0x80) {

                        // This is a FIXUP subrecord
                        //Frame = 0; 
                        Target = 0; TargetDisplacement = 0;

                        // read second byte
                        byte2 = Records[RecNum].GetByte();
                        // swap bytes and put into byte12 bitfield
                        Locat.bytes[1] = byte1;
                        Locat.bytes[0] = byte2;
                        // Read FixData
                        FixData.b = Records[RecNum].GetByte();

                        // Read conditional fields
                        if (FixData.s.F == 0) {
                            if (FixData.s.Frame < 4) {
                                Records[RecNum].GetIndex();
                            }
                        }

                        if (FixData.s.T == 0) {
                            // Target specified
                            Target = Records[RecNum].GetIndex();
                            //uint32_t TargetMethod = FixData.s.Target + FixData.s.P * 4;
                        }
                        else {
                            // Target specified in previous thread
                            // Does anybody still use compression of repeated fixup targets?
                            // I don't care to support this if it is never used
                            err.submit(2313);           // Error message: not supported
                            continue;
                        }

                        if (FixData.s.P == 0) {
                            TargetDisplacement = Records[RecNum].GetNumeric();
                        }

                        // Get inline addend and check relocation method
                        if (LastDataRecordPointer && Locat.s.Offset < LastDataRecordSize) {
                            // Pointer to relocation source inline in raw data:
                            int8_t * inlinep = LastDataRecordPointer + Locat.s.Offset;

                            switch (Locat.s.Location) { // Relocation method

                            case 9: case 13: // 32 bit
                                // The OMF format may indicate a relocation target by an
                                // offset stored inline in the relocation source.
                                // We prefer to store the target address explicitly in a
                                // symbol table entry. 

                                // Add the inline offset to the explicit offset
                                TargetDisplacement += *(uint32_t*)inlinep;

                                // Remove the inline addend to avoid adding it twice:
                                // We have to do this in the new buffer TempBuf because 
                                // the data have already been copied to TempBuf
                                if (*(uint32_t*)(TempBuf.Buf() + LastOffset + Locat.s.Offset) != *(uint32_t*)inlinep) {
                                    // Check that the data in Buf() and TempBuf.Buf() are the same
                                    err.submit(9000);
                                }
                                // Remove the inline addend to avoid adding it twice
                                *(uint32_t*)(TempBuf.Buf() + LastOffset + Locat.s.Offset) = 0;
                                break;

                            case 0: case 4:  // 8 bit. Not supported
                                err.submit(2316, "8 bit");  break;

                            case 1: case 2: case 5: // 16 bit. Not supported
                                err.submit(2316, "16 bit");  break;

                            case 3: // 16+16 bit. Not supported
                                err.submit(2316, "16+16 bit far");  break;

                            case 6: case 11: // 16+32 bit. Not supported
                                err.submit(2316, "16+32 bit far");  break;
                            }
                        }

                        // Make relocation record
                        // Offset of relocation source
                        rel.VirtualAddress = Locat.s.Offset + LastOffset; 

                        SOMFLocalSymbol locsym; // Symbol record for search in LocalSymbols table
                        int32_t LocalSymbolsIndex; // Index into LocalSymbols table

                        // Relocation type: direct or EIP-relative
                        // (The displacement between relocation source and EIP for 
                        // self-relative relocations is implicit in both OMF and COFF 
                        // files. No need for correction)
                        rel.Type = Locat.s.M ? COFF32_RELOC_DIR32 : COFF32_RELOC_REL32;

                        switch (FixData.s.Target) { // = Target method modulo 4
                        case 0: // T0 and T4: Target = segment

                            // Local or public symbol. Search in LocalSymbols table
                            locsym.Segment = Target;     // Target segment
                            locsym.Offset = TargetDisplacement;  // Target offset including inline displacement
                            // Find in LocalSymbols table
                            LocalSymbolsIndex = LocalSymbols.Exists(locsym);
                            if (LocalSymbolsIndex < 0) {err.submit(9000); continue;} // Not found

                            // Get index into new symbol table
                            rel.SymbolTableIndex = LocalSymbols[LocalSymbolsIndex].NewSymtabIndex;
                            break;

                        case 1: // T1 and T5: Target = segment group
                            // Don't know how to handle group-relative relocation. Make error message
                            err.submit(2315, GetLocalName(Target));
                            continue;

                        case 2: // T2 and T6: Target = external symbol

                            // Translate old EXTDEF index to new symbol table index
                            if (Target >= ExtdefTranslation.GetNumEntries()) {
                                Target = 0; err.submit(2312);
                                continue;
                            }
                            rel.SymbolTableIndex = ExtdefTranslation[Target];

                            // Put addend inline in new file
                            if (LastOffset + Locat.s.Offset < SegmentSize) {
                                *(uint32_t*)(TempBuf.Buf() + LastOffset + Locat.s.Offset) = TargetDisplacement;
                            }
                            break;

                        default: // Unknown method
                            err.submit(2314, FixData.s.Target + FixData.s.P * 4);
                        }

                        // Store in temporary relocation table
                        RelocationTable.Push(&rel, SIZE_SCOFF_Relocation);

                    }
                    else {
                        // This is a THREAD subrecord.
                        // I don't think this feature for compressing fixup data is
                        // used any more, if it ever was. I am not supporting it here.
                        // Frame threads can be safely ignored. A target thread cannot
                        // be ignored if there is any reference to it. The error is 
                        // reported above at the reference to a target thread, not here.
                        TrdDat.b = byte1;              // Put byte into bitfield
                        if (TrdDat.s.Method < 4) {     // Make sure we read this correctly, even if ignored
                            Records[RecNum].GetIndex(); // has index field if method < 4 ?
                        }
                    }
                } // Finished loop through subrecords

                if (Records[RecNum].Index != Records[RecNum].End) err.submit(1203);   // Check for consistency
            }
        } // End of loop to search for LEDATA, LIDATA and FIXUPP records for this segment

        // Transfer raw data from TempBuf to NewData buffer
        FileOffset = NewData.Push(TempBuf.Buf(), SegmentSize);

        // Put file offset of raw data into section header
        NewSectionHeaders[SegNum].PRawData = FileOffsetData + FileOffset;

        // Align relocation table by 4
        NewData.Align(4);

        // Transfer relocation table from RelocationTable to NewData buffer
        FileOffset = NewData.Push(RelocationTable.Buf(), RelocationTable.GetDataSize());

        // Put file offset of relocations into section header
        NewSectionHeaders[SegNum].PRelocations = FileOffsetData + FileOffset;

        // Put number of relocations into section header
        NewSectionHeaders[SegNum].NRelocations = (uint16_t)(RelocationTable.GetNumEntries());

        // Put number of relocations into symbol table auxiliary entry.
        // Search for the symbol table entry for this section:
        for (uint32_t sym = 0; sym < NewSymbolTable.GetNumEntries(); sym++) {
            if ((uint32_t)NewSymbolTable[sym].s.SectionNumber == DesiredSegment
                && NewSymbolTable[sym].s.StorageClass == COFF_CLASS_STATIC 
                && NewSymbolTable[sym].s.NumAuxSymbols == 1) {
                    // Found right symbol table entry. Insert NumberOfRelocations
                    NewSymbolTable[sym+1].section.NumberOfRelocations = NewSectionHeaders[SegNum].NRelocations;
                    break;  // No need to search further
            }
        }
    } // End of loop through segments
}


void COMF2COF::CheckUnsupportedRecords() {
    // Make warnings if file containes unsupported record types
    uint32_t RecNum;                                // Record number
    uint32_t NumComdat = 0;                         // Number of COMDAT records
    uint32_t NumComent = 0;                         // Number of COMENT records

    // Loop through all records
    for (RecNum = 0; RecNum < NumRecords; RecNum++) {
        // Check record type
        switch (Records[RecNum].Type2) {
        case OMF_THEADR: case OMF_MODEND: case OMF_EXTDEF: case OMF_PUBDEF:
        case OMF_LNAMES: case OMF_SEGDEF: case OMF_GRPDEF: case OMF_FIXUPP:
        case OMF_LEDATA: case OMF_LIDATA: case OMF_COMDEF: case OMF_VERNUM:
            // These record types are supported or can safely be ignored
            break;

        case OMF_LINNUM: case OMF_LINSYM:
            // Debug records
            cmd.CountDebugRemoved();  break;

        case OMF_COMDAT: case OMF_LCOMDEF: case OMF_CEXTDEF:
            NumComdat++;  break;                    // Count COMDAT records

        case OMF_COMENT: 
            NumComent++;  break;                    // Count COMENT records

        default:                                   // Warning for unknown record type
            err.submit(1212, COMF::GetRecordTypeName(Records[RecNum].Type2));
        }
    }
    // Report number of unsupported sections found
    if (NumComdat) err.submit(2305, NumComdat);
    if (NumComent) err.submit(1211, NumComent);
}


void COMF2COF::MakeBinaryFile() {
    // Putting sections together
    uint32_t i;

    // Get number of symbols and sections into file header
    NewFileHeader.NumberOfSymbols = NewSymbolTable.GetNumEntries();
    NewFileHeader.NumberOfSections = NewSectionHeaders.GetNumEntries();

    // Put file header into new file
    ToFile.Push(&NewFileHeader, sizeof(NewFileHeader));

    // Put section headers into new file
    if (NewSectionHeaders.GetNumEntries()) {
        ToFile.Push(&NewSectionHeaders[0], NewSectionHeaders.GetNumEntries() * sizeof(SCOFF_SectionHeader));
    }

    // Put raw data and relocation tables into new file
    ToFile.Push(NewData.Buf(), NewData.GetDataSize());

    // Get address of symbol table into file header
    ToFile.Get<SCOFF_FileHeader>(0).PSymbolTable = ToFile.GetDataSize();

    // Put symbol table into new file
    for (i = 0; i < NewSymbolTable.GetNumEntries(); i++) {
        ToFile.Push(&NewSymbolTable[i], SIZE_SCOFF_SymTableEntry);
    }

    // Insert string table size
    NewStringTable.Get<uint32_t>(0) = NewStringTable.GetDataSize();

    // Put string table into new file
    ToFile.Push(NewStringTable.Buf(), NewStringTable.GetDataSize());
}