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