1 /****************************  omf2cof.cpp   *********************************
2 * Author:        Agner Fog
3 * Date created:  2007-02-08
4 * Last modified: 2018-08-15
5 * Project:       objconv
6 * Module:        omf2cof.cpp
7 * Description:
8 * Module for converting OMF file to PE/COFF file
9 *
10 * Copyright 2007-2018 GNU General Public License http://www.gnu.org/licenses
11 *****************************************************************************/
12 #include "stdafx.h"
13 
14 // Alignment value translation table
15 static const uint32_t OMFAlignTranslate[8] = {0,1,2,16,256,4,0,0};
16 
COMF2COF()17 COMF2COF::COMF2COF() {
18     // Constructor
19     memset(this, 0, sizeof(*this));               // Reset everything
20 }
21 
Convert()22 void COMF2COF::Convert() {
23     // Do the conversion
24     // Allocate variable size buffers
25     //NewSectIndex.SetNum(this->NSections);// Allocate section translation table
26     //NewSectIndex.SetZero();              // Initialize
27 
28     // Call the subfunctions
29     ToFile.SetFileType(FILETYPE_COFF);  // Set type of to file
30     MakeFileHeader();                   // Make file header
31     MakeSymbolTable1();                 // Make symbol table and string table entries for file and segments
32     MakeSymbolTable2();                 // Make symbol table and string table entries for external symbols
33     MakeSymbolTable3();                 // Make symbol table and string table entries for public symbols
34     MakeSymbolTable4();                 // Make symbol table and string table entries for communal symbols
35     MakeSymbolTable5();                 // Make symbol table and string table entries for local symbols
36     MakeSections();                     // Make sections and relocation tables
37     CheckUnsupportedRecords();          // Make warnings if file containes unsupported record types
38     MakeBinaryFile();                   // Put sections together
39     *this << ToFile;                    // Take over new file buffer
40 }
41 
42 
MakeFileHeader()43 void COMF2COF::MakeFileHeader() {
44     // Convert subfunction: File header
45     // Make PE file header
46     NewFileHeader.Machine = PE_MACHINE_I386;
47     NewFileHeader.TimeDateStamp = (uint32_t)time(0);
48     NewFileHeader.SizeOfOptionalHeader = 0;
49     NewFileHeader.Flags = 0;
50 
51     // Values inserted later:
52     NewFileHeader.NumberOfSections = 0;
53     NewFileHeader.PSymbolTable = 0;
54     NewFileHeader.NumberOfSymbols = 0;
55 }
56 
57 
MakeSymbolTable1()58 void COMF2COF::MakeSymbolTable1() {
59     // Make symbol table string table and section table entries for file and segments
60     SCOFF_SymTableEntry sym;                      // Symbol table entry
61     SCOFF_SectionHeader sec;                      // Section header entry
62     char * ClassName;                             // Old segment class name
63 
64     // Initialize new string table. make space for 4-bytes size
65     NewStringTable.Push(0, 4);
66 
67     // Allocate SegmentTranslation buffer
68     SegmentTranslation.SetNum(SegmentNameOffset.GetNumEntries());
69 
70     // Make symbol table entry for file name
71     memset(&sym, 0, SIZE_SCOFF_SymTableEntry);
72     strcpy(sym.s.Name, ".file");
73     sym.s.SectionNumber = COFF_SECTION_DEBUG;
74     sym.s.StorageClass = COFF_CLASS_FILE;
75     char * ShortFileName = CLibrary::ShortenMemberName(OutputFileName);
76     sym.s.NumAuxSymbols = 1;  // File name is truncated so it will fit into the 18 bytes of SIZE_SCOFF_SymTableEntry
77     NewSymbolTable.Push(sym); // Store symbol table entry
78     // Needs auxiliary entry:
79     memset(&sym, 0, SIZE_SCOFF_SymTableEntry);
80     if (strlen(ShortFileName) < SIZE_SCOFF_SymTableEntry) {
81         strcpy(sym.s.Name, ShortFileName);
82     }
83     NewSymbolTable.Push(sym); // Store auxiliary symbol table entry
84 
85     // Define structure of attributes
86     OMF_SAttrib Attributes;
87     // Other segment properties
88     uint32_t SegLength, NameIndex, ClassIndex;
89     //uint32_t Offset;
90     const char * sname;                           // Segment/section name
91     uint32_t SegNum = 0;                            // Segment/section number
92     uint32_t StringI;                               // New sting table index
93     uint32_t i;                                     // Record number
94     int32_t  j, n;                                  // Temporary
95 
96     // Loop through segments of old file
97     for (i = 0; i < NumRecords; i++) {
98         if (Records[i].Type2 == OMF_SEGDEF) {
99             // SEGDEF record
100             Records[i].Index = 3;
101             // Loop through entries in record. There should be only 1
102             while (Records[i].Index < Records[i].End) {
103                 Attributes.b = Records[i].GetByte(); // Read attributes
104                 if (Attributes.u.A == 0) {
105                     // Frame and Offset only included if A = 0
106                     Records[i].GetWord();             // Frame ignored
107                     Records[i].GetByte();
108                 }
109                 //else Offset = 0;
110                 SegLength  = Records[i].GetNumeric();
111                 NameIndex  = Records[i].GetIndex();
112                 ClassIndex = Records[i].GetIndex();  // Class index
113                 Records[i].GetIndex();               // Overlay index ignored
114                 sname = GetLocalName(NameIndex);     // Segment name = new section name
115 
116                 if (Attributes.u.B) {
117                     // Segment is big
118                     if (Attributes.u.P) {
119                         // 32 bit segment. Big means 2^32 bytes!
120                         err.submit(2306);
121                     }
122                     else {
123                         // 16 bit segment. Big means 2^16 bytes
124                         SegLength = 0x10000;
125                     }
126                 }
127 
128                 // make symbol table entry
129                 memset(&sym, 0, SIZE_SCOFF_SymTableEntry);
130 
131                 // Put name into string table
132                 StringI = NewStringTable.PushString(sname);
133 
134                 // Put name into symbol table
135                 //COFF_PutNameInSymbolTable(sym, sname, NewStringTable);
136                 ((uint32_t*)(sym.s.Name))[1] = StringI;
137 
138                 sym.s.SectionNumber = ++SegNum;        // Count section number
139                 sym.s.StorageClass = COFF_CLASS_STATIC;
140                 sym.s.NumAuxSymbols = 1;               // Needs 1 aux record
141 
142                 // Remember NewSymbolTable index
143                 SegmentTranslation[SegNum] = NewSymbolTable.GetNumEntries();
144                 NewSymbolTable.Push(sym);            // Store symbol table entry
145 
146                 // Make auxiliary entry
147                 memset(&sym, 0, SIZE_SCOFF_SymTableEntry);
148 
149                 // Insert section size
150                 sym.section.Length = SegLength;
151 
152                 // Remember to insert NumberOfRelocations here later
153 
154                 // Store auxiliary symbol table entry
155                 NewSymbolTable.Push(sym);
156 
157                 // Make section header
158                 memset(&sec, 0, sizeof(sec));        // Reset section header
159 
160                 // Put name into section header
161                 sprintf(sec.Name, "/%i", StringI);
162 
163                 // Put size into section header
164                 sec.SizeOfRawData = SegLength;
165 
166                 // Alignment
167                 switch (Attributes.u.A) {
168                 case 0:  // Absolute segment
169                     err.submit(2307);  break;
170                 case 1:  // Byte
171                     sec.Flags |= PE_SCN_ALIGN_1;  break;
172                 case 2:  // Word
173                     sec.Flags |= PE_SCN_ALIGN_2;  break;
174                 case 3:  // Paragraph
175                     sec.Flags |= PE_SCN_ALIGN_16;  break;
176                 case 4:  // Page. May be 256 or 4096, depending on system
177                     // If we use 4096 where the source intended 256, we may get
178                     // size and symbol offsets wrong!
179                     sec.Flags |= PE_SCN_ALIGN_256;  break;
180                 case 5:  // Dword
181                     sec.Flags |= PE_SCN_ALIGN_4;  break;
182                 default: // Unknown alignment
183                     err.submit(2308, Attributes.u.A);
184                     sec.Flags |= PE_SCN_ALIGN_16;  break;
185                 }
186 
187                 // Get further attributes from class name
188                 ClassName = GetLocalName(ClassIndex);
189 
190                 // Convert class name to upper case
191                 n = (int32_t)strlen(ClassName);
192                 for (j = 0; j < n; j++) ClassName[j] &= ~0x20;
193 
194                 // Search for known class names.
195                 // Standard names are CODE, DATA, BSS, CONST, STACK
196                 if (strstr(ClassName, "CODE") || strstr(ClassName, "TEXT")) {
197                     // Code segment
198                     sec.Flags |= PE_SCN_CNT_CODE | PE_SCN_MEM_EXECUTE | PE_SCN_MEM_READ;
199                 }
200                 else if (strstr(ClassName, "DATA")) {
201                     // Data segment
202                     sec.Flags |= PE_SCN_CNT_INIT_DATA | PE_SCN_MEM_READ | PE_SCN_MEM_WRITE;
203                 }
204                 else if (strstr(ClassName, "BSS")) {
205                     // Unitialized data segment
206                     sec.Flags |= PE_SCN_CNT_UNINIT_DATA | PE_SCN_MEM_READ | PE_SCN_MEM_WRITE;
207                 }
208                 else if (strstr(ClassName, "CONST")) {
209                     // Constant data segment
210                     sec.Flags |= PE_SCN_CNT_INIT_DATA | PE_SCN_MEM_READ;
211                 }
212                 else if (strstr(ClassName, "STACK")) {
213                     // Stack segment. Ignore
214                     sec.Flags |= PE_SCN_LNK_REMOVE;
215                     err.submit(1206); // Warning: ignored
216                 }
217                 else {
218                     // Unknown/user defined class. Assume data segment
219                     sec.Flags |= PE_SCN_CNT_INIT_DATA | PE_SCN_MEM_READ | PE_SCN_MEM_WRITE;
220                 }
221 
222                 // Insert pointers to relocations and raw data later
223                 // Store section header
224                 NewSectionHeaders.Push(sec);
225             }
226             if (Records[i].Index != Records[i].End) err.submit(1203);   // Check for consistency
227         }
228         if (Records[i].Type2 == OMF_COMDAT || Records[i].Type2 == OMF_COMDEF) {
229             // Communal sections
230             err.submit(1055);
231         }
232     }
233 }
234 
MakeSymbolTable2()235 void COMF2COF::MakeSymbolTable2() {
236     // Make symbol table and string table entries for external symbols
237     uint32_t i;
238     SCOFF_SymTableEntry sym;                      // new symbol table entry
239     uint32_t NumExtSym = SymbolNameOffset.GetNumEntries(); // Number of external symbols
240     ExtdefTranslation.SetNum(NumExtSym+1);          // Allocate space in translation table
241 
242     // Loop through external symbol names
243     for (i = 1; i < NumExtSym; i++) {
244         // Reset symbol table entry
245         memset(&sym, 0, SIZE_SCOFF_SymTableEntry);
246 
247         // Insert name
248         COFF_PutNameInSymbolTable(sym, GetSymbolName(i), NewStringTable);
249 
250         // Insert storage class
251         sym.s.StorageClass = COFF_CLASS_EXTERNAL;
252 
253         // Store symbol table entry
254         NewSymbolTable.Push(sym);
255 
256         // Update table for translating old EXTDEF number (1-based) to new symbol table index (0-based)
257         ExtdefTranslation[i] = NewSymbolTable.GetNumEntries() - 1;
258     }
259 }
260 
261 
MakeSymbolTable3()262 void COMF2COF::MakeSymbolTable3() {
263     // Make symbol table and string table entries for public symbols
264     SCOFF_SymTableEntry sym;                      // new symbol table entry
265     uint32_t i;                                     // Record index
266     char * string;                                // Symbol name
267     uint32_t Segment;                               // Segment
268     uint32_t Offset;                                // Offset
269     uint32_t Namei;                                 // Index into symbol table
270     SOMFLocalSymbol localsym;                     // Entry into LocalSymbols
271 
272     // Search for PUBDEF records
273     for (i = 0; i < NumRecords; i++) {
274         if (Records[i].Type2 == OMF_PUBDEF) {
275             // PUBDEF record
276 
277             Records[i].Index = 3;
278             Records[i].GetIndex();                  // Group. Ignore
279             Segment = Records[i].GetIndex();        // Segment
280             if (Segment == 0) Records[i].GetWord(); // Base frame. Ignore
281 
282             // Loop through strings in record
283             while (Records[i].Index < Records[i].End) {
284                 string = Records[i].GetString();     // Symbol name
285                 Offset = Records[i].GetNumeric();    // Offset to segment
286                 Records[i].GetIndex();               // Type index. Ignore
287 
288                 // Reset symbol table entry
289                 memset(&sym, 0, SIZE_SCOFF_SymTableEntry);
290 
291                 // Insert name
292                 Namei = COFF_PutNameInSymbolTable(sym, string, NewStringTable);
293 
294                 // Insert storage class
295                 sym.s.StorageClass = COFF_CLASS_EXTERNAL;
296 
297                 // Store offset
298                 sym.s.Value = Offset;
299 
300                 // Section number = segment number
301                 if (Segment == 0) sym.s.SectionNumber = COFF_SECTION_ABSOLUTE;
302                 else sym.s.SectionNumber = (int16_t)Segment;
303 
304                 // Store symbol table entry
305                 NewSymbolTable.Push(sym);
306 
307                 // Make entry into LocalSymbols to indicate that this symbol has a name
308                 if (Segment > 0) {
309                     // Make index into NewStringTable if we don't allready have one
310                     if (Namei == 0) Namei = NewStringTable.PushString(string);
311                     localsym.Offset = Offset;
312                     localsym.Segment = Segment;
313                     localsym.Name = Namei;
314                     localsym.NewSymtabIndex = NewSymbolTable.GetNumEntries() - 1; // 0-based index into new symbol table
315                     LocalSymbols.PushUnique(localsym);
316                 }
317             }
318             if (Records[i].Index != Records[i].End) err.submit(1203);   // Check for consistency
319         }
320     }
321 }
322 
MakeSymbolTable4()323 void COMF2COF::MakeSymbolTable4() {
324     // Make symbol table and string table entries for communal symbols
325     // Warning: Currently not supported!
326 }
327 
MakeSymbolTable5()328 void COMF2COF::MakeSymbolTable5() {
329     // Make symbol table and string table entries for local symbols.
330     // There is no table for local symbols in OMF files. We have to search
331     // through all FIXUPP records for relocation targets and assign arbitrary
332     // names to them.
333 
334     uint32_t i;                                     // Loop counter
335     uint32_t Target, TargetDisplacement;            // Contents of FIXUPP record
336     uint8_t byte1, byte2;                           // First two bytes of FIXUPP subrecord
337     // Bitfields in subrecords
338     OMF_SLocat Locat;                             // Structure of first two bytes of FIXUP subrecord swapped = Locat field
339     OMF_SFixData FixData;                         // Structure of FixData field in FIXUP subrecord of FIXUPP record
340     OMF_STrdDat TrdDat;                           // Structure of Thread Data field in THREAD subrecord of FIXUPP record
341     int8_t * LastDataRecordPointer = 0;             // Pointer to data in the data record that relocations refer to
342     uint32_t LastDataRecordSize = 0;                // Size of the data record that relocations refer to
343     SOMFLocalSymbol localsym;                     // Entry into LocalSymbols
344     uint32_t LocalSymNum = 0;                       // Number of unnamed local symbols
345     char NewName[32];                             // Buffer for making new name
346     SCOFF_SymTableEntry sym;                      // New symbol table entry
347 
348     // Search for FIXUPP records and data records
349     for (i = 0; i < NumRecords; i++) {
350 
351         if (Records[i].Type2 == OMF_LEDATA) {
352             // LEDATA record. Remember pointer to binary data in order to read inline offset
353             Records[i].Index = 3;                   // Initialize record reading
354             Records[i].GetIndex();                  // Read segment and offset
355             Records[i].GetNumeric();
356             LastDataRecordSize = Records[i].End - Records[i].Index; // Calculate size of data
357             LastDataRecordPointer = Records[i].buffer + Records[i].FileOffset + Records[i].Index;
358         }
359 
360         if (Records[i].Type2 == OMF_FIXUPP) {
361             // FIXUPP record
362             Records[i].Index = 3;                   // Initialize record reading
363 
364             // Loop through entries in record
365             while (Records[i].Index < Records[i].End) {
366 
367                 // Read first byte
368                 byte1 = Records[i].GetByte();
369 
370                 if (byte1 & 0x80) {
371                     // This is a FIXUP subrecord
372 
373                     Target = 0; TargetDisplacement = 0;
374                     // read second byte
375                     byte2 = Records[i].GetByte();
376                     // swap bytes and put into byte12 bitfield
377                     Locat.bytes[1] = byte1;
378                     Locat.bytes[0] = byte2;
379                     // Read FixData
380                     FixData.b = Records[i].GetByte();
381                     // Read conditional fields
382                     if (FixData.s.F == 0) {
383                         if (FixData.s.Frame < 4) {
384                             Records[i].GetIndex();  // Frame. Ignore
385                         }
386                     }
387                     if (FixData.s.T == 0) {
388                         // Target specified
389                         Target = Records[i].GetIndex();
390                         //uint32_t TargetMethod = FixData.s.Target + FixData.s.P * 4;
391                     }
392                     if (FixData.s.P == 0) {
393                         TargetDisplacement = Records[i].GetNumeric();
394                     }
395                     // Get inline addend
396                     if (LastDataRecordPointer && Locat.s.Offset < LastDataRecordSize) {
397                         int8_t * inlinep = LastDataRecordPointer + Locat.s.Offset;
398                         if (Locat.s.Location == 9 || Locat.s.Location == 13) {
399                             TargetDisplacement += *(int32_t*)inlinep;
400                         }
401                     }
402                     if (FixData.s.T == 0 && (FixData.s.Target == 0 || FixData.s.Target == 1)) {
403                         // Target is local symbol
404 
405                         // Make entry in LocalSymbols
406                         localsym.Offset = TargetDisplacement;    // Offset to segment
407                         localsym.Segment = Target;               // Target segment
408                         localsym.Name = 0;                       // Has no name yet
409                         localsym.NewSymtabIndex = 0;             // Not in new symbol table yet
410                         // Make entry in LocalSymbols.
411                         // PushUnique will not make an entry if this target address already
412                         // has an entry in LocalSymbols and possibly a public name
413                         LocalSymbols.PushUnique(localsym);
414                     }
415                 }
416                 else {
417                     // This is a THREAD subrecord. Read and ignore
418                     TrdDat.b = byte1;                 // Put byte into bitfield
419                     if (TrdDat.s.Method < 4) {
420                         Records[i].GetIndex();         // has index field if method < 4 ?
421                     }
422                 }
423             } // Finished loop through subrecords
424             if (Records[i].Index != Records[i].End) err.submit(1203);   // Check for consistency
425         }
426     } // Finished loop through records
427 
428     // Now check LocalSymbols for unnamed symbols
429     for (i = 0; i < LocalSymbols.GetNumEntries(); i++) {
430         if (LocalSymbols[i].Name == 0) {
431 
432             // Unnamed symbol. Give it a name
433             sprintf(NewName, "?NoName%02i", ++LocalSymNum);
434 
435             // Make index in new symbol table
436             // Reset symbol table entry
437             memset(&sym, 0, SIZE_SCOFF_SymTableEntry);
438 
439             // Insert name
440             LocalSymbols[i].Name = COFF_PutNameInSymbolTable(sym, NewName, NewStringTable);
441             // if (LocalSymbols[i].Name == 0) LocalSymbols[i].Name = NewStringTable.PushString(NewName);
442 
443             // Store offset
444             sym.s.Value = LocalSymbols[i].Offset;
445 
446             // Section number = segment number
447             sym.s.SectionNumber = LocalSymbols[i].Segment;
448 
449             // Storage class
450             sym.s.StorageClass = COFF_CLASS_STATIC;
451 
452             // Store symbol table entry
453             NewSymbolTable.Push(sym);
454 
455             // Store index into new symbol table (0 - based)
456             LocalSymbols[i].NewSymtabIndex = NewSymbolTable.GetNumEntries() - 1;
457         }
458     }
459 }
460 
461 
MakeSections()462 void COMF2COF::MakeSections() {
463     // Make sections and relocation tables
464     uint32_t SegNum;                                // Index into NewSectionHeaders = segment - 1
465     uint32_t DesiredSegment;                        // Old segment number = new section number
466     uint32_t RecNum;                                // Old record number
467     CMemoryBuffer TempBuf;                        // Temporary buffer for building raw data
468     CMemoryBuffer RelocationTable;                // Temporary buffer for building new relocation table
469     SCOFF_Relocation rel;                         // New relocation table record
470     uint32_t LastDataRecord = 0;                    // Index to the data record that relocations refer to
471     uint32_t LastDataRecordSize = 0;                // Size of the data record that relocations refer to
472     int8_t * LastDataRecordPointer = 0;             // Pointer to data in the data record that relocations refer to
473     uint32_t Segment = 0;                           // Segment of last LEDATA, LIDATA or COMDEF record
474     uint32_t Offset;                                // Offset of LEDATA or LIDATA record to segment
475     uint32_t Size;                                  // Size of data in LEDATA or LIDATA record
476     uint32_t SegmentSize;                           // Total size of segment
477     uint32_t LastOffset;                            // Offset after last LEDATA into segment
478     uint32_t FileOffsetData;                        // File offset of first raw data and relocations in new file
479     uint32_t FileOffset;                            // File offset of current raw data or relocations
480 
481     // File offset of first data = size of file header and section headers
482     FileOffsetData = sizeof(SCOFF_FileHeader) + NewSectionHeaders.GetNumEntries() * sizeof(SCOFF_SectionHeader);
483 
484     // Loop through segments
485     for (SegNum = 0; SegNum < NewSectionHeaders.GetNumEntries(); SegNum++) {
486 
487         DesiredSegment = SegNum + 1;               // Search for records referring to this segment
488 
489         SegmentSize = NewSectionHeaders[SegNum].SizeOfRawData;
490         if (SegmentSize == 0) continue;            // Empty segment
491 
492         // Allocate temporary data buffer and reset it
493         TempBuf.SetSize(SegmentSize + 16);
494         int FillByte = 0;                          // Byte to fill memory with
495         if (NewSectionHeaders[SegNum].Flags & PE_SCN_CNT_CODE) {
496             // Code segment. Fill any unused bytes with NOP opcode = 0x90
497             FillByte = 0x90;
498         }
499         memset(TempBuf.Buf(), FillByte, SegmentSize + 16);// Reset to all 0 or NOP
500 
501         // Reset relocation table buffer
502         RelocationTable.SetSize(0);
503 
504         LastOffset = 0;  LastDataRecordSize = 0;
505 
506         // Search for LEDATA, LIDATA and FIXUPP records for this segment
507         for (RecNum = 0; RecNum < NumRecords; RecNum++) {
508             if (Records[RecNum].Type2 == OMF_LEDATA) {
509 
510                 // LEDATA record
511                 Records[RecNum].Index = 3;           // Initialize record reading
512                 Segment = Records[RecNum].GetIndex();// Read segment number
513 
514                 if (Segment != DesiredSegment) continue; // Does not refer to this segment
515 
516                 Offset  = Records[RecNum].GetNumeric();// Read offset
517                 Size    = Records[RecNum].End - Records[RecNum].Index; // Calculate size of data
518                 LastDataRecord = RecNum;             // Save for later FIXUPP that refers to this record
519 
520                 // Check if data within segment
521                 if (Offset + Size > SegmentSize) {
522                     err.submit(2309, GetSegmentName(Segment));
523                     return;
524                 }
525 
526                 if (Offset < LastOffset + LastDataRecordSize && LastOffset < Offset + Size) {
527                     // Overlapping data records
528                     if (Offset + 8 < LastOffset + LastDataRecordSize || !(NewSectionHeaders[SegNum].Flags & PE_SCN_CNT_CODE)) {
529                         // Overlapping data by more than 7 bytes or not executable code
530                         err.submit(1207);
531                     }
532                     else {
533                         // Possibly backpatched code
534                         err.submit(1208);              // Warning
535                         err.ClearError(1208);          // Report only once
536                     }
537                 }
538 
539                 LastDataRecordSize = Size;
540                 LastDataRecordPointer = Records[RecNum].buffer + Records[RecNum].FileOffset + Records[RecNum].Index;
541                 LastOffset = Offset;                 // Save offset for subsequent FIXUPP records
542 
543                 /*// Check if data within segment
544                 if (Offset + Size > SegmentSize) {
545                     err.submit(2309, GetSegmentName(Segment));
546                     continue;
547                 } */
548 
549                 // Put raw data into temporary buffer
550                 memcpy(TempBuf.Buf() + Offset, LastDataRecordPointer, Size);
551 
552             } // Finished with LEDATA record
553 
554             if (Records[RecNum].Type2 == OMF_LIDATA) {
555                 // LIDATA record
556                 Records[RecNum].Index = 3;           // Initialize record reading
557                 Segment = Records[RecNum].GetIndex();
558 
559                 if (Segment != DesiredSegment) continue; // Does not refer to this segment
560 
561                 LastDataRecord = RecNum;             // Save for later FIXUPP that refers to this record
562 
563                 Offset  = Records[RecNum].GetNumeric();// Read offset
564 
565                 if (Offset > SegmentSize) {
566                     err.submit(2310); return;       // Error: outside bounds
567                 }
568 
569                 // Unpack LIDATA blocks recursively
570                 Size = Records[RecNum].UnpackLIDATABlock(TempBuf.Buf() + Offset, SegmentSize - Offset);
571 
572                 if (Offset < LastOffset + LastDataRecordSize && LastOffset < Offset + Size) {
573                     // Overlapping data records
574                     err.submit(1207);                 // Warning
575                 }
576                 LastDataRecordSize = Size;           // Save data size
577                 LastOffset = Offset;                 // Save offset for subsequent FIXUPP records
578 
579             } // Finished with LIDATA record
580 
581             if (Records[RecNum].Type2 == OMF_COMDAT) {
582                 // COMDAT record. Currently not supported by objconv
583                 LastDataRecord = RecNum;             // Save for later FIXUPP that refers to this record
584                 Segment = 0;                         // Ignore any relocation referring to this
585             }
586 
587             if (Records[RecNum].Type2 == OMF_FIXUPP) {
588                 // FIXUPP record
589 
590                 if (Segment != DesiredSegment) continue; // Does not refer to this segment
591 
592                 uint32_t Target, TargetDisplacement; // Contents of FIXUPP record
593                 //uint32_t Frame; // Contents of FIXUPP record
594                 uint8_t byte1, byte2;                 // First two bytes of subrecord
595 
596                 // Bitfields in subrecords
597                 OMF_SLocat Locat;         // Structure of first two bytes of FIXUP subrecord swapped = Locat field
598                 OMF_SFixData FixData;     // Structure of FixData field in FIXUP subrecord of FIXUPP record
599                 OMF_STrdDat TrdDat;       // Structure of Thread Data field in THREAD subrecord of FIXUPP record
600 
601                 Records[RecNum].Index = 3;
602 
603                 if (Records[LastDataRecord].Type2 != OMF_LEDATA && Records[RecNum].Index < Records[RecNum].End) {
604                     // Non-empty FIXUPP record does not refer to LEDATA record
605                     if (Records[LastDataRecord].Type2 == OMF_COMDAT) {
606                         // COMDAT currently not supported. Ignore!
607                     }
608                     else if (Records[LastDataRecord].Type2 == OMF_LIDATA) {
609                         err.submit(2311);              // Error: Relocation of iterated data not supported
610                     }
611                     else {
612                         err.submit(2312);              // Does not refer to data record
613                     }
614                     continue;                         // Ignore this FIXUPP record
615                 }
616 
617                 // Loop through entries in record
618                 while (Records[RecNum].Index < Records[RecNum].End) {
619 
620                     // Read first byte
621                     byte1 = Records[RecNum].GetByte();
622                     if (byte1 & 0x80) {
623 
624                         // This is a FIXUP subrecord
625                         //Frame = 0;
626                         Target = 0; TargetDisplacement = 0;
627 
628                         // read second byte
629                         byte2 = Records[RecNum].GetByte();
630                         // swap bytes and put into byte12 bitfield
631                         Locat.bytes[1] = byte1;
632                         Locat.bytes[0] = byte2;
633                         // Read FixData
634                         FixData.b = Records[RecNum].GetByte();
635 
636                         // Read conditional fields
637                         if (FixData.s.F == 0) {
638                             if (FixData.s.Frame < 4) {
639                                 Records[RecNum].GetIndex();
640                             }
641                         }
642 
643                         if (FixData.s.T == 0) {
644                             // Target specified
645                             Target = Records[RecNum].GetIndex();
646                             //uint32_t TargetMethod = FixData.s.Target + FixData.s.P * 4;
647                         }
648                         else {
649                             // Target specified in previous thread
650                             // Does anybody still use compression of repeated fixup targets?
651                             // I don't care to support this if it is never used
652                             err.submit(2313);           // Error message: not supported
653                             continue;
654                         }
655 
656                         if (FixData.s.P == 0) {
657                             TargetDisplacement = Records[RecNum].GetNumeric();
658                         }
659 
660                         // Get inline addend and check relocation method
661                         if (LastDataRecordPointer && Locat.s.Offset < LastDataRecordSize) {
662                             // Pointer to relocation source inline in raw data:
663                             int8_t * inlinep = LastDataRecordPointer + Locat.s.Offset;
664 
665                             switch (Locat.s.Location) { // Relocation method
666 
667                             case 9: case 13: // 32 bit
668                                 // The OMF format may indicate a relocation target by an
669                                 // offset stored inline in the relocation source.
670                                 // We prefer to store the target address explicitly in a
671                                 // symbol table entry.
672 
673                                 // Add the inline offset to the explicit offset
674                                 TargetDisplacement += *(uint32_t*)inlinep;
675 
676                                 // Remove the inline addend to avoid adding it twice:
677                                 // We have to do this in the new buffer TempBuf because
678                                 // the data have already been copied to TempBuf
679                                 if (*(uint32_t*)(TempBuf.Buf() + LastOffset + Locat.s.Offset) != *(uint32_t*)inlinep) {
680                                     // Check that the data in Buf() and TempBuf.Buf() are the same
681                                     err.submit(9000);
682                                 }
683                                 // Remove the inline addend to avoid adding it twice
684                                 *(uint32_t*)(TempBuf.Buf() + LastOffset + Locat.s.Offset) = 0;
685                                 break;
686 
687                             case 0: case 4:  // 8 bit. Not supported
688                                 err.submit(2316, "8 bit");  break;
689 
690                             case 1: case 2: case 5: // 16 bit. Not supported
691                                 err.submit(2316, "16 bit");  break;
692 
693                             case 3: // 16+16 bit. Not supported
694                                 err.submit(2316, "16+16 bit far");  break;
695 
696                             case 6: case 11: // 16+32 bit. Not supported
697                                 err.submit(2316, "16+32 bit far");  break;
698                             }
699                         }
700 
701                         // Make relocation record
702                         // Offset of relocation source
703                         rel.VirtualAddress = Locat.s.Offset + LastOffset;
704 
705                         SOMFLocalSymbol locsym; // Symbol record for search in LocalSymbols table
706                         int32_t LocalSymbolsIndex; // Index into LocalSymbols table
707 
708                         // Relocation type: direct or EIP-relative
709                         // (The displacement between relocation source and EIP for
710                         // self-relative relocations is implicit in both OMF and COFF
711                         // files. No need for correction)
712                         rel.Type = Locat.s.M ? COFF32_RELOC_DIR32 : COFF32_RELOC_REL32;
713 
714                         switch (FixData.s.Target) { // = Target method modulo 4
715                         case 0: // T0 and T4: Target = segment
716 
717                             // Local or public symbol. Search in LocalSymbols table
718                             locsym.Segment = Target;     // Target segment
719                             locsym.Offset = TargetDisplacement;  // Target offset including inline displacement
720                             // Find in LocalSymbols table
721                             LocalSymbolsIndex = LocalSymbols.Exists(locsym);
722                             if (LocalSymbolsIndex < 0) {err.submit(9000); continue;} // Not found
723 
724                             // Get index into new symbol table
725                             rel.SymbolTableIndex = LocalSymbols[LocalSymbolsIndex].NewSymtabIndex;
726                             break;
727 
728                         case 1: // T1 and T5: Target = segment group
729                             // Don't know how to handle group-relative relocation. Make error message
730                             err.submit(2315, GetLocalName(Target));
731                             continue;
732 
733                         case 2: // T2 and T6: Target = external symbol
734 
735                             // Translate old EXTDEF index to new symbol table index
736                             if (Target >= ExtdefTranslation.GetNumEntries()) {
737                                 Target = 0; err.submit(2312);
738                                 continue;
739                             }
740                             rel.SymbolTableIndex = ExtdefTranslation[Target];
741 
742                             // Put addend inline in new file
743                             if (LastOffset + Locat.s.Offset < SegmentSize) {
744                                 *(uint32_t*)(TempBuf.Buf() + LastOffset + Locat.s.Offset) = TargetDisplacement;
745                             }
746                             break;
747 
748                         default: // Unknown method
749                             err.submit(2314, FixData.s.Target + FixData.s.P * 4);
750                         }
751 
752                         // Store in temporary relocation table
753                         RelocationTable.Push(&rel, SIZE_SCOFF_Relocation);
754 
755                     }
756                     else {
757                         // This is a THREAD subrecord.
758                         // I don't think this feature for compressing fixup data is
759                         // used any more, if it ever was. I am not supporting it here.
760                         // Frame threads can be safely ignored. A target thread cannot
761                         // be ignored if there is any reference to it. The error is
762                         // reported above at the reference to a target thread, not here.
763                         TrdDat.b = byte1;              // Put byte into bitfield
764                         if (TrdDat.s.Method < 4) {     // Make sure we read this correctly, even if ignored
765                             Records[RecNum].GetIndex(); // has index field if method < 4 ?
766                         }
767                     }
768                 } // Finished loop through subrecords
769 
770                 if (Records[RecNum].Index != Records[RecNum].End) err.submit(1203);   // Check for consistency
771             }
772         } // End of loop to search for LEDATA, LIDATA and FIXUPP records for this segment
773 
774         // Transfer raw data from TempBuf to NewData buffer
775         FileOffset = NewData.Push(TempBuf.Buf(), SegmentSize);
776 
777         // Put file offset of raw data into section header
778         NewSectionHeaders[SegNum].PRawData = FileOffsetData + FileOffset;
779 
780         // Align relocation table by 4
781         NewData.Align(4);
782 
783         // Transfer relocation table from RelocationTable to NewData buffer
784         FileOffset = NewData.Push(RelocationTable.Buf(), RelocationTable.GetDataSize());
785 
786         // Put file offset of relocations into section header
787         NewSectionHeaders[SegNum].PRelocations = FileOffsetData + FileOffset;
788 
789         // Put number of relocations into section header
790         NewSectionHeaders[SegNum].NRelocations = (uint16_t)(RelocationTable.GetNumEntries());
791 
792         // Put number of relocations into symbol table auxiliary entry.
793         // Search for the symbol table entry for this section:
794         for (uint32_t sym = 0; sym < NewSymbolTable.GetNumEntries(); sym++) {
795             if ((uint32_t)NewSymbolTable[sym].s.SectionNumber == DesiredSegment
796                 && NewSymbolTable[sym].s.StorageClass == COFF_CLASS_STATIC
797                 && NewSymbolTable[sym].s.NumAuxSymbols == 1) {
798                     // Found right symbol table entry. Insert NumberOfRelocations
799                     NewSymbolTable[sym+1].section.NumberOfRelocations = NewSectionHeaders[SegNum].NRelocations;
800                     break;  // No need to search further
801             }
802         }
803     } // End of loop through segments
804 }
805 
806 
CheckUnsupportedRecords()807 void COMF2COF::CheckUnsupportedRecords() {
808     // Make warnings if file containes unsupported record types
809     uint32_t RecNum;                                // Record number
810     uint32_t NumComdat = 0;                         // Number of COMDAT records
811     uint32_t NumComent = 0;                         // Number of COMENT records
812 
813     // Loop through all records
814     for (RecNum = 0; RecNum < NumRecords; RecNum++) {
815         // Check record type
816         switch (Records[RecNum].Type2) {
817         case OMF_THEADR: case OMF_MODEND: case OMF_EXTDEF: case OMF_PUBDEF:
818         case OMF_LNAMES: case OMF_SEGDEF: case OMF_GRPDEF: case OMF_FIXUPP:
819         case OMF_LEDATA: case OMF_LIDATA: case OMF_COMDEF: case OMF_VERNUM:
820             // These record types are supported or can safely be ignored
821             break;
822 
823         case OMF_LINNUM: case OMF_LINSYM:
824             // Debug records
825             cmd.CountDebugRemoved();  break;
826 
827         case OMF_COMDAT: case OMF_LCOMDEF: case OMF_CEXTDEF:
828             NumComdat++;  break;                    // Count COMDAT records
829 
830         case OMF_COMENT:
831             NumComent++;  break;                    // Count COMENT records
832 
833         default:                                   // Warning for unknown record type
834             err.submit(1212, COMF::GetRecordTypeName(Records[RecNum].Type2));
835         }
836     }
837     // Report number of unsupported sections found
838     if (NumComdat) err.submit(2305, NumComdat);
839     if (NumComent) err.submit(1211, NumComent);
840 }
841 
842 
MakeBinaryFile()843 void COMF2COF::MakeBinaryFile() {
844     // Putting sections together
845     uint32_t i;
846 
847     // Get number of symbols and sections into file header
848     NewFileHeader.NumberOfSymbols = NewSymbolTable.GetNumEntries();
849     NewFileHeader.NumberOfSections = NewSectionHeaders.GetNumEntries();
850 
851     // Put file header into new file
852     ToFile.Push(&NewFileHeader, sizeof(NewFileHeader));
853 
854     // Put section headers into new file
855     if (NewSectionHeaders.GetNumEntries()) {
856         ToFile.Push(&NewSectionHeaders[0], NewSectionHeaders.GetNumEntries() * sizeof(SCOFF_SectionHeader));
857     }
858 
859     // Put raw data and relocation tables into new file
860     ToFile.Push(NewData.Buf(), NewData.GetDataSize());
861 
862     // Get address of symbol table into file header
863     ToFile.Get<SCOFF_FileHeader>(0).PSymbolTable = ToFile.GetDataSize();
864 
865     // Put symbol table into new file
866     for (i = 0; i < NewSymbolTable.GetNumEntries(); i++) {
867         ToFile.Push(&NewSymbolTable[i], SIZE_SCOFF_SymTableEntry);
868     }
869 
870     // Insert string table size
871     NewStringTable.Get<uint32_t>(0) = NewStringTable.GetDataSize();
872 
873     // Put string table into new file
874     ToFile.Push(NewStringTable.Buf(), NewStringTable.GetDataSize());
875 }
876