Subversion Repositories Kolibri OS

Rev

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

  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 OMFAlignTranslate[8] = {0,1,2,16,256,4,0,0};
  16.  
  17. COMF2COF::COMF2COF() {
  18.     // Constructor
  19.     memset(this, 0, sizeof(*this));               // Reset everything
  20. }
  21.  
  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.  
  43. void COMF2COF::MakeFileHeader() {
  44.     // Convert subfunction: File header
  45.     // Make PE file header
  46.     NewFileHeader.Machine = PE_MACHINE_I386;
  47.     NewFileHeader.TimeDateStamp = (uint32)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.  
  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 SegLength, NameIndex, ClassIndex;
  89.     //uint32 Offset;
  90.     const char * sname;                           // Segment/section name
  91.     uint32 SegNum = 0;                            // Segment/section number
  92.     uint32 StringI;                               // New sting table index
  93.     uint32 i;                                     // Record number
  94.     int32  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*)(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)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.  
  235. void COMF2COF::MakeSymbolTable2() {
  236.     // Make symbol table and string table entries for external symbols
  237.     uint32 i;
  238.     SCOFF_SymTableEntry sym;                      // new symbol table entry
  239.     uint32 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.  
  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 i;                                     // Record index
  266.     char * string;                                // Symbol name
  267.     uint32 Segment;                               // Segment
  268.     uint32 Offset;                                // Offset
  269.     uint32 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)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.  
  323. void COMF2COF::MakeSymbolTable4() {
  324.     // Make symbol table and string table entries for communal symbols
  325.     // Warning: Currently not supported!
  326. }
  327.  
  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 i;                                     // Loop counter
  335.     uint32 Target, TargetDisplacement;            // Contents of FIXUPP record
  336.     uint8 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 * LastDataRecordPointer = 0;             // Pointer to data in the data record that relocations refer to
  342.     uint32 LastDataRecordSize = 0;                // Size of the data record that relocations refer to
  343.     SOMFLocalSymbol localsym;                     // Entry into LocalSymbols
  344.     uint32 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 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 * inlinep = LastDataRecordPointer + Locat.s.Offset;
  398.                         if (Locat.s.Location == 9 || Locat.s.Location == 13) {
  399.                             TargetDisplacement += *(int32*)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.  
  462. void COMF2COF::MakeSections() {
  463.     // Make sections and relocation tables
  464.     uint32 SegNum;                                // Index into NewSectionHeaders = segment - 1
  465.     uint32 DesiredSegment;                        // Old segment number = new section number
  466.     uint32 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 LastDataRecord = 0;                    // Index to the data record that relocations refer to
  471.     uint32 LastDataRecordSize = 0;                // Size of the data record that relocations refer to
  472.     int8 * LastDataRecordPointer = 0;             // Pointer to data in the data record that relocations refer to
  473.     uint32 Segment = 0;                           // Segment of last LEDATA, LIDATA or COMDEF record
  474.     uint32 Offset;                                // Offset of LEDATA or LIDATA record to segment
  475.     uint32 Size;                                  // Size of data in LEDATA or LIDATA record
  476.     uint32 SegmentSize;                           // Total size of segment
  477.     uint32 LastOffset;                            // Offset after last LEDATA into segment
  478.     uint32 FileOffsetData;                        // File offset of first raw data and relocations in new file
  479.     uint32 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 Target, TargetDisplacement; // Contents of FIXUPP record
  593.                 //uint32 Frame; // Contents of FIXUPP record
  594.                 uint8 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 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 * 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*)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*)(TempBuf.Buf() + LastOffset + Locat.s.Offset) != *(uint32*)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*)(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 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*)(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)(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 sym = 0; sym < NewSymbolTable.GetNumEntries(); sym++) {
  795.             if ((uint32)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.  
  807. void COMF2COF::CheckUnsupportedRecords() {
  808.     // Make warnings if file containes unsupported record types
  809.     uint32 RecNum;                                // Record number
  810.     uint32 NumComdat = 0;                         // Number of COMDAT records
  811.     uint32 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.  
  843. void COMF2COF::MakeBinaryFile() {
  844.     // Putting sections together
  845.     uint32 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>(0) = NewStringTable.GetDataSize();
  872.  
  873.     // Put string table into new file
  874.     ToFile.Push(NewStringTable.Buf(), NewStringTable.GetDataSize());
  875. }
  876.