Subversion Repositories Kolibri OS

Rev

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

  1. /****************************  cof2omf.cpp   ********************************
  2. * Author:        Agner Fog
  3. * Date created:  2007-02-03
  4. * Last modified: 2007-02-03
  5. * Project:       objconv
  6. * Module:        cof2omf.cpp
  7. * Description:
  8. * Module for converting 32 bit PE/COFF file to OMF file
  9. *
  10. * Copyright 2007-2008 GNU General Public License http://www.gnu.org/licenses
  11. *****************************************************************************/
  12. #include "stdafx.h"
  13.  
  14. CCOF2OMF::CCOF2OMF () {
  15.    // Constructor
  16.    memset(this, 0, sizeof(*this));
  17. }
  18.  
  19.  
  20. void CCOF2OMF::Convert() {
  21.    // Do the conversion
  22.    if (WordSize != 32) {
  23.       err.submit(2317, WordSize);                // Wrong word size
  24.       return;
  25.    }
  26.  
  27.    // Allocate variable size buffers
  28.    SectionBuffer.SetNum(NSections + 2);          // Allocate buffer for section translation list
  29.    SectionBuffer.SetZero();                      // Initialize
  30.    SymbolBuffer.SetNum(NumberOfSymbols + 1);     // Allocate buffer for symbol translation list
  31.    SymbolBuffer.SetZero();                       // Initialize
  32.    NameBuffer.Push(0, 1);                        // Make first entry in NameBuffer empty
  33.  
  34.    // Call the subfunctions
  35.    ToFile.SetFileType(FILETYPE_OMF);             // Set type of output file
  36.    MakeSegmentList();                            // Make temporary segment conversion list
  37.    MakeSymbolList();                             // Make temporary symbol conversion list
  38.    MakeRelocationsList();                        // Make temporary list of relocations (fixups) and sort it
  39.    MakeLNAMES();                                 // Make THEADR and LNAMES records
  40.    MakeSEGDEF();                                 // Make SEGDEF and GRPDEF records
  41.    MakeEXTDEF();                                 // Make EXTDEF records
  42.    MakePUBDEF();                                 // Make PUBDEF records
  43.    MakeLEDATA();                                 // Make LEDATA, LIDATA and FIXUPP records
  44.    MakeMODEND();                                 // Finish output file
  45.    *this << ToFile;                              // Take over new file buffer containing the converted file
  46. }
  47.  
  48.  
  49. void CCOF2OMF::MakeSegmentList() {
  50.    // Make temporary segment conversion list
  51.    const char * oldname;                         // Old name of section
  52.    uint32 namei;                                 // Name index into NameBuffer
  53.    uint32 align;                                 // Segment alignment = 2^align
  54.    int32 align2;                                 // align2 = 2^align
  55.    uint32 flags;                                 // Old flags
  56.    int i, j;                                     // Loop counters
  57.    int oldsec;                                   // Old section number
  58.  
  59.    // Loop through old sections
  60.    for (j = 0; j < NSections; j++) {
  61.       // Old section number
  62.       oldsec = j + 1;
  63.  
  64.       // Get old section header
  65.       SCOFF_SectionHeader * pSectionHeader = &SectionHeaders[j];
  66.  
  67.       // Get name
  68.       oldname = GetSectionName(pSectionHeader->Name);
  69.  
  70.       // Check for debug sections
  71.       if (strnicmp(oldname,"debug",5) == 0 || strnicmp(oldname+1,"debug",5) == 0) {
  72.          // This is a debug section
  73.          if (cmd.DebugInfo == CMDL_DEBUG_STRIP) {
  74.             // Remove debug info
  75.             SectionBuffer[oldsec].NewNumber = 0;
  76.             cmd.CountDebugRemoved();
  77.             continue;
  78.          }
  79.          else if (cmd.InputType != cmd.OutputType) {
  80.             err.submit(1029); // Warn that debug information is incompatible
  81.          }
  82.       }
  83.  
  84.       // Check for directive sections
  85.       if (strnicmp(oldname,".drectve",8) == 0 || (pSectionHeader->Flags & (PE_SCN_LNK_INFO | PE_SCN_LNK_REMOVE))) {
  86.          // This is a directive section
  87.          if (cmd.ExeptionInfo) {
  88.             // Remove directive section
  89.             SectionBuffer[oldsec].NewNumber = 0;
  90.             cmd.CountExceptionRemoved();
  91.             continue;
  92.          }
  93.       }
  94.  
  95.       // Get alignment
  96.       align = (pSectionHeader->Flags & PE_SCN_ALIGN_MASK) / PE_SCN_ALIGN_1;
  97.       if (align > 0) align--;                 // Alignment = 2^align
  98.       align2 = 1 << align;                    // 2^align
  99.  
  100.       // Check for previous sections with same name
  101.       for (i = 0; i < SectionBufferNum; i++) {
  102.          if (strcmp(oldname, NameBuffer.Buf() + SectionBuffer[i].OldName) == 0) break; // Found same name
  103.       }
  104.       if (i < SectionBufferNum) {
  105.          // Previous section with same name found.
  106.          // i = first section with this name, oldsec = current section with this name
  107.          SectionBuffer[oldsec] = SectionBuffer[i];    // Copy record
  108.          SectionBuffer[oldsec].NewNameI = 0;          // Indicate this is not the first record
  109.  
  110.          // Check if alignment is the same
  111.          if (align != SectionBuffer[i].Align) {
  112.             err.submit(1060, oldname);           // Warning different alignments
  113.             if (align > SectionBuffer[i].Align) SectionBuffer[i].Align = align; // Use highest alignment
  114.          }
  115.  
  116.          // Get section header
  117.          SectionBuffer[oldsec].psechdr = pSectionHeader;
  118.  
  119.          // Get size of this section
  120.          SectionBuffer[oldsec].Size = pSectionHeader->SizeOfRawData;
  121.  
  122.          // Get offset relative to first section with same name
  123.          SectionBuffer[oldsec].Offset = SectionBuffer[i].Offset + SectionBuffer[i].SegmentSize;
  124.  
  125.          // Align this section (We are aligning each section in the segment)
  126.          SectionBuffer[oldsec].Offset = (SectionBuffer[oldsec].Offset + align2 - 1) & (- align2);
  127.  
  128.          // Update total size of all sections with same name
  129.          SectionBuffer[i].SegmentSize = SectionBuffer[oldsec].Offset + SectionBuffer[oldsec].Size;
  130.       }
  131.       else {
  132.          // No previous section found with same name. Make SOMFSegmentList record
  133.          SectionBufferNum = oldsec + 1;                  // End of entries in SectionBuffer
  134.  
  135.          // Assign a number to this segment
  136.          SectionBuffer[oldsec].NewNumber = ++NumSegments;
  137.          SectionBuffer[oldsec].NewNameI  = NumSegments + OMF_LNAME_LAST;
  138.  
  139.          // Point to old section header
  140.          SectionBuffer[oldsec].psechdr = pSectionHeader;
  141.  
  142.          // Give it a name
  143.          namei = NameBuffer.PushString(oldname);      // Save name in buffer, because it is volatile
  144.          SectionBuffer[oldsec].OldName = namei;            // Index to name
  145.          // Segment names like .text and _TEXT are both common. No need to convert the name
  146.          // Only restriction is length < 256.
  147.          // Do we need a unique segment name if the alignment is different from segments
  148.          // with same name in another module?
  149.          if (strlen(oldname) > 255) {
  150.             // Segment name too long. This is very unlikely
  151.             namei = NameBuffer.Push(oldname, 255);    // Make truncated name
  152.             NameBuffer.Push(0, 1);                    // Terminate by zero
  153.          }
  154.          SectionBuffer[oldsec].NewName = namei;            // Index to name
  155.  
  156.          // Size
  157.          SectionBuffer[oldsec].Size = pSectionHeader->SizeOfRawData;
  158.          SectionBuffer[oldsec].SegmentSize = pSectionHeader->SizeOfRawData;
  159.          SectionBuffer[oldsec].Offset = 0;
  160.  
  161.          // Alignment
  162.          SectionBuffer[oldsec].Align = align;
  163.  
  164.          // Segment type
  165.          flags = pSectionHeader->Flags;
  166.      
  167.          // Get segment class
  168.          if (flags & (PE_SCN_CNT_CODE | PE_SCN_MEM_EXECUTE)) {
  169.             // Code segment
  170.             SectionBuffer[oldsec].Class = OMF_LNAME_CODE;
  171.          }
  172.          else if (flags & PE_SCN_CNT_UNINIT_DATA) {
  173.             // Uninitialized data
  174.             SectionBuffer[oldsec].Class = OMF_LNAME_BSS;
  175.          }
  176.          else if (!(flags & PE_SCN_MEM_WRITE)) {
  177.             // Read only
  178.             SectionBuffer[oldsec].Class = OMF_LNAME_CONST;
  179.          }
  180.          else {
  181.             // Normal data
  182.             SectionBuffer[oldsec].Class = OMF_LNAME_DATA;
  183.          }
  184.       }
  185.    }
  186.  
  187.    // Add 1 to section count because new section numbers are 1-based
  188.    SectionBufferNum = NSections + 1;
  189. }
  190.  
  191.  
  192. void CCOF2OMF::MakeSymbolList() {
  193.    // Make temporary symbol conversion list
  194.    int isym = 0;  // current symbol table entry
  195.    //int jsym = 0;  // auxiliary entry number
  196.    union {        // Pointer to symbol table
  197.       SCOFF_SymTableEntry * p;  // Normal pointer
  198.       int8 * b;                 // Used for address calculation
  199.    } Symtab;
  200.  
  201.    Symtab.p = SymbolTable;      // Set pointer to begin of SymbolTable
  202.  
  203.    // Loop through symbol table
  204.    while (isym < NumberOfSymbols) {
  205.       // Check scope
  206.       if (Symtab.p->s.StorageClass == COFF_CLASS_EXTERNAL) {
  207.          // Scope is public or external
  208.  
  209.          if (Symtab.p->s.SectionNumber > 0) {
  210.  
  211.             // Symbol is public
  212.             SymbolBuffer[isym].Scope = S_PUBLIC;               // Scope = public
  213.             SymbolBuffer[isym].NewIndex = ++NumPublicSymbols;  // Public symbol number
  214.             // Get name
  215.             SymbolBuffer[isym].Name = NameBuffer.PushString(GetSymbolName(Symtab.p->s.Name));
  216.  
  217.             // Find section in SectionBuffer
  218.             uint32 OldSection = Symtab.p->s.SectionNumber;
  219.             SymbolBuffer[isym].Segment = SectionBuffer[OldSection].NewNumber; // New segment number
  220.  
  221.             // Calculate offset = offset into old section + offset of old section to first section with same name
  222.             SymbolBuffer[isym].Offset = Symtab.p->s.Value + SectionBuffer[OldSection].Offset;
  223.          }
  224.          else if (Symtab.p->s.SectionNumber == 0) {
  225.  
  226.             // Symbol is external
  227.             SymbolBuffer[isym].Scope = S_EXTERNAL;        // Scope = external
  228.             SymbolBuffer[isym].NewIndex = ++NumExternalSymbols;  // External symbol number
  229.             SymbolBuffer[isym].Name = NameBuffer.PushString(GetSymbolName(Symtab.p->s.Name));
  230.          }
  231.          else if (Symtab.p->s.SectionNumber == COFF_SECTION_ABSOLUTE) {
  232.  
  233.             // Symbol is public, absolute
  234.             SymbolBuffer[isym].Scope = S_PUBLIC;        // Scope = public
  235.             SymbolBuffer[isym].NewIndex = ++NumPublicSymbols;  // Public symbol number
  236.             // Get name
  237.             SymbolBuffer[isym].Name = NameBuffer.PushString(GetSymbolName(Symtab.p->s.Name));
  238.  
  239.             SymbolBuffer[isym].Segment = 0;          // 0 indicates absolute
  240.  
  241.             SymbolBuffer[isym].Offset = Symtab.p->s.Value;   // Store value in Offset
  242.          }
  243.          else {
  244.             // COFF_SECTION_DEBUG, COFF_SECTION_N_TV, COFF_SECTION_P_TV
  245.             // Ignore
  246.          }
  247.       }
  248.  
  249.       // Skip auxiliary symbol table entries and increment pointer
  250.       isym += Symtab.p->s.NumAuxSymbols + 1;
  251.       Symtab.b += (Symtab.p->s.NumAuxSymbols + 1) * SIZE_SCOFF_SymTableEntry;
  252.    }
  253. }
  254.  
  255.  
  256. void CCOF2OMF::MakeRelocationsList() {
  257.    // Make temporary list of relocations (fixups) and sort it
  258.    uint32 i;                                     // Relocation number in old file
  259.    int j;                                        // Section number of relocation source in old file
  260.    int isym;                                     // Symbol table index in old file
  261.    //int32 * paddend = 0;                          // Pointer to inline addend
  262.    uint32 TargetOldSection;                      // Section number of relocation target in old file
  263.  
  264.    SOMFRelocation NewRel;                        // Entry in RelocationBuffer
  265.  
  266.    union {                                       // Pointer to symbol table
  267.       SCOFF_SymTableEntry * p;                   // Normal pointer
  268.       int8 * b;                                  // Used for address calculation
  269.    } Symtab;
  270.  
  271.    union {                                       // Pointer to relocation entry
  272.       SCOFF_Relocation * p;                      // pointer to record
  273.       int8 * b;                                  // used for address calculation and incrementing
  274.    } Reloc;
  275.  
  276.    // Loop through section headers of old file
  277.    for (j = 0; j < NSections; j++) {
  278.       SCOFF_SectionHeader * SectionHeaderp = &SectionHeaders[j];
  279.  
  280.       // Pointer to first relocation entry in section
  281.       Reloc.b = Buf() + SectionHeaderp->PRelocations;
  282.  
  283.       // Loop through relocations in section
  284.       for (i = 0; i < SectionHeaderp->NRelocations; i++) {
  285.  
  286.          // Find symbol table entry
  287.          isym = Reloc.p->SymbolTableIndex;
  288.          if ((uint32)isym >= (uint32)NumberOfSymbols) {
  289.             err.submit(2040);                    // SymbolTableIndex points outside Symbol Table
  290.             isym = 0;
  291.          }
  292.          Symtab.p = SymbolTable;                 // Set pointer to begin of SymbolTable
  293.          Symtab.b += SIZE_SCOFF_SymTableEntry * isym; // Calculate address of entry isym
  294.  
  295.          // Find inline addend
  296.          if (Reloc.p->Type < COFF32_RELOC_SEG12) {
  297.             //paddend = (int32*)(Buf()+SectionHeaderp->PRawData+Reloc.p->VirtualAddress);
  298.          }
  299.          //else paddend = 0;
  300.  
  301.          // Make entry in RelocationBuffer
  302.          // Relocation type
  303.          switch (Reloc.p->Type) {
  304.          case COFF32_RELOC_DIR32:                // Direct 32 bit
  305.             NewRel.Mode = 1;  break;             // 0 = EIP-relative, 1 = direct
  306.  
  307.          case COFF32_RELOC_REL32:                // 32 bit EIP relative
  308.             NewRel.Mode = 0;  break;             // 0 = EIP-relative, 1 = direct
  309.  
  310.          case COFF32_RELOC_ABS:                  // Ignore
  311.             continue;
  312.  
  313.          default:                                // Other. Not supported
  314.             NewRel.Mode = -1;                    // -1 = unsupported.
  315.             // Postpone error message in case it refers to a debug section that is being removed
  316.             NewRel.TargetOffset = Reloc.p->Type; // Remember relocation type
  317.             //err.submit(2030, Reloc.p->Type); continue;  // Unsupported relocation type
  318.             break;
  319.          }
  320.          // Get source
  321.          NewRel.Section = j + 1;                 // Section number in old file
  322.          NewRel.SourceOffset = Reloc.p->VirtualAddress;// Offset of source relative to section
  323.  
  324.          // Get target
  325.          if (Symtab.p->s.SectionNumber > 0) {
  326.             // Local
  327.             NewRel.Scope  = S_LOCAL;                   // 0 = local, 2 = external
  328.             TargetOldSection = Symtab.p->s.SectionNumber;    // Target section
  329.             if (TargetOldSection > uint32(NSections)) {
  330.                // SectionNumber out of range
  331.                err.submit(2035);  continue;
  332.             }
  333.             // Segment index of target in new file:
  334.             NewRel.TargetSegment = SectionBuffer[TargetOldSection].NewNumber;
  335.             // Offset relative to old section
  336.             NewRel.TargetOffset = Symtab.p->s.Value;          
  337.             // Add offset relative to first section with same name to get offset relative to new segment
  338.             NewRel.TargetOffset += SectionBuffer[TargetOldSection].Offset;
  339.          }
  340.          else {
  341.             // External
  342.             NewRel.Scope  = S_EXTERNAL;               // 0 = local, 2 = external
  343.             NewRel.TargetOffset = 0;                  // Any addend is inline    
  344.             // Find EXTDEF index in SymbolBuffer
  345.             NewRel.TargetSegment = SymbolBuffer[isym].NewIndex;
  346.          }
  347.  
  348.          // Put NewRel into RelocationBuffer
  349.          RelocationBuffer.Push(NewRel);
  350.  
  351.          // Increment pointer to relocation record
  352.          Reloc.b += SIZE_SCOFF_Relocation;       // Next relocation record
  353.       }
  354.    }
  355.    // Sort RelocationBuffer
  356.    RelocationBuffer.Sort();
  357.  
  358.    // Store number of relocations
  359.    NumRelocations = RelocationBuffer.GetNumEntries();
  360.  
  361.    // Check for overlapping relocation sources
  362.    for (uint32 i = 1; i < RelocationBuffer.GetNumEntries(); i++) {
  363.       if (RelocationBuffer[i].Section == RelocationBuffer[i-1].Section
  364.       && RelocationBuffer[i].SourceOffset >= RelocationBuffer[i-1].SourceOffset
  365.       && RelocationBuffer[i].SourceOffset <  RelocationBuffer[i-1].SourceOffset + 4
  366.       && (RelocationBuffer[i].Mode == 0 || RelocationBuffer[i].Mode == 1)) {
  367.          err.submit(2210);                       // Error: overlapping relocation sources
  368.       }
  369.    }
  370. }
  371.  
  372.  
  373. void CCOF2OMF::MakeLNAMES() {
  374.    // Make THEADR and LNAMES records
  375.    int Sec;                                      // Loop counter
  376.    uint32 NameI;                                 // Name index
  377.  
  378.    // Make first record in output file = Translator header
  379.    ToFile.StartRecord(OMF_THEADR);
  380.    // Remove path from file name and limit length
  381.    char * ShortName = CLibrary::ShortenMemberName(OutputFileName);  
  382.    ToFile.PutString(ShortName);
  383.    ToFile.EndRecord();
  384.  
  385.    // Make LNAMES record containing names of segments, groups and classes
  386.    ToFile.StartRecord(OMF_LNAMES);
  387.  
  388.    // Store default group and class names
  389.    ToFile.PutString("FLAT");                     // 1: FLAT  = group name
  390.    ToFile.PutString("CODE");                     // 2: CODE  = class name for code
  391.    ToFile.PutString("DATA");                     // 3: DATA  = class name for data segment
  392.    ToFile.PutString("BSS");                      // 4: BSS   = class name for uninitialized data
  393.    ToFile.PutString("CONST");                    // 5: CONST = class name for readonly data
  394.  
  395.    NameI = OMF_LNAME_LAST + 1;                   // Index of next name
  396.  
  397.    // Get segment names
  398.    for (Sec = 0; Sec < SectionBufferNum; Sec++) {
  399.       if (SectionBuffer[Sec].NewNameI == NameI) {
  400.          // Found next segment name to add
  401.          // Check if current record too big
  402.          if (ToFile.GetSize() >= 1024 - 256) {   // Max size = 1024
  403.             ToFile.EndRecord();                  // End current record
  404.             ToFile.StartRecord(OMF_LNAMES);      // Start new LNAMES record
  405.          }
  406.          // Store name of this segment
  407.          ToFile.PutString(NameBuffer.Buf() + SectionBuffer[Sec].NewName);
  408.          NameI++;                                // Ready for next name
  409.       }
  410.    }
  411.    // End LNAMES record
  412.    ToFile.EndRecord();
  413. }
  414.  
  415.  
  416. void CCOF2OMF::MakeSEGDEF() {
  417.    // Make SEGDEF and GRPDEF records
  418.    int Sec;                                      // Index into SectionBuffer
  419.    uint32 SegNum = 0;                            // Segment number in new file
  420.    OMF_SAttrib Attr;                             // Segment attributes bitfield
  421.    uint32 align;                                 // Alignment in new file
  422.  
  423.    // Loop through SectionBuffer
  424.    for (Sec = 0; Sec < SectionBufferNum; Sec++) {
  425.  
  426.       if (SectionBuffer[Sec].NewNumber == SegNum+1 && SectionBuffer[Sec].NewNameI) {
  427.  
  428.          // New segment found
  429.          SegNum++;                               // Segment number
  430.  
  431.          // Make a SEGDEF record for this segment
  432.          ToFile.StartRecord(OMF_SEGDEF + 1);     // Odd record number = 32 bit
  433.  
  434.          // Attributes bitfield
  435.          Attr.u.P = 1;                           // Indicate 32 bit segment
  436.          Attr.u.B = 0;                           // 1 indicates 4 Gbytes
  437.          Attr.u.C = 2;                           // Indicates public combination
  438.  
  439.          // Translate alignment
  440.          switch(SectionBuffer[Sec].Align) {
  441.          case 0:  // Align by 1
  442.             align = 1;  break;
  443.  
  444.          case 1:  // Align by 2
  445.             align = 2;  break;
  446.  
  447.          case 2:  // Align by 4
  448.             align = 5;  break;
  449.  
  450.          case 3:  // Align by 8 not supported, use 16
  451.          case 4:  // Align by 16
  452.             align = 3;  break;
  453.  
  454.          default:  // 32 or higher. Use 'page' alignment
  455.             // Note: this gives 256 on some systems, 4096 on other systems
  456.             align = 4;
  457.             if (SectionBuffer[Sec].Align > 8) {
  458.                err.submit(1205, 1 << SectionBuffer[Sec].Align); // Warning: alignment not supported
  459.             }
  460.          }
  461.          Attr.u.A = align;                      // Put alignment into bitfield
  462.  
  463.          ToFile.PutByte(Attr.b);                // Save attributes bitfield
  464.  
  465.          // Segment length
  466.          ToFile.PutNumeric(SectionBuffer[Sec].SegmentSize);
  467.  
  468.          // Segment name given by index into LNAMES record
  469.          ToFile.PutIndex(SectionBuffer[Sec].NewNameI);
  470.  
  471.          // Class name index
  472.          ToFile.PutIndex(SectionBuffer[Sec].Class);
  473.  
  474.          // Overlay index (ignored)
  475.          ToFile.PutIndex(0);
  476.  
  477.          // End SEGDEF record
  478.          ToFile.EndRecord();
  479.       }
  480.    }
  481.  
  482.    // Make GRPDEF record for the FLAT group
  483.    ToFile.StartRecord(OMF_GRPDEF);               // Strart GRPDEF record
  484.    ToFile.PutIndex(OMF_LNAME_FLAT);              // Index of name "FLAT"
  485.    // No need to put segment indices into the GRPDEF record when group is FLAT
  486.    // End GRPDEF record
  487.    ToFile.EndRecord();
  488. }
  489.  
  490.  
  491. void CCOF2OMF::MakeEXTDEF() {
  492.    // Make EXTDEF records
  493.    uint32 j;                                     // SymbolBuffer entry index
  494.    uint32 ExtSymNum = 0;                         // External symbol number
  495.  
  496.    if (NumExternalSymbols > 0) {                 // Are there any external symbols?
  497.  
  498.       // Make EXTDEF record for one or more symbols
  499.       ToFile.StartRecord(OMF_EXTDEF);            // Start record
  500.  
  501.       // Loop through SymbolBuffer
  502.       for (j = 0; j < SymbolBuffer.GetNumEntries(); j++) {
  503.          if (SymbolBuffer[j].Scope == S_EXTERNAL && SymbolBuffer[j].NewIndex == ExtSymNum+1) {
  504.             // Found external symbol
  505.             ExtSymNum++;                         // Symbol number  
  506.  
  507.             // Check if current record too big
  508.             if (ToFile.GetSize() >= 1024 - 257) {// Max size = 1024
  509.                ToFile.EndRecord();               // End current record
  510.                ToFile.StartRecord(OMF_EXTDEF);   // Start new EXTDEF record
  511.             }
  512.             // Put symbol name in record
  513.             ToFile.PutString(NameBuffer.Buf() + SymbolBuffer[j].Name);
  514.  
  515.             // Type index
  516.             ToFile.PutIndex(0);                  // Not used any more
  517.          }
  518.       }
  519.       ToFile.EndRecord();                        // End EXTDEF record
  520.    }
  521. }
  522.  
  523.  
  524. void CCOF2OMF::MakePUBDEF() {
  525.    // Make PUBDEF records
  526.    uint32 j;                                     // SymbolBuffer entry index
  527.    uint32 PubSymNum = 0;                         // Public symbol number
  528.  
  529.    // Loop through SymbolBuffer
  530.    for (j = 0; j < SymbolBuffer.GetNumEntries(); j++) {
  531.       if (SymbolBuffer[j].Scope == S_PUBLIC && SymbolBuffer[j].NewIndex == PubSymNum+1) {
  532.          // Found public symbol
  533.          PubSymNum++;                            // Symbol number  
  534.  
  535.          // Make PUBDEF record for this symbol
  536.          ToFile.StartRecord(OMF_PUBDEF + 1);     // Start new PUBDEF record, 32 bit
  537.  
  538.          // Group index
  539.          uint32 Group = SymbolBuffer[j].Segment ? OMF_LNAME_FLAT : 0; // Group = FLAT, except for absolute symbols
  540.          ToFile.PutIndex(Group);                 // Group name index
  541.  
  542.          // Segment index
  543.          ToFile.PutIndex(SymbolBuffer[j].Segment);
  544.  
  545.          // Base frame field if segment = 0
  546.          if (SymbolBuffer[j].Segment == 0) ToFile.PutWord(0);
  547.  
  548.          // Put symbol name in record
  549.          ToFile.PutString(NameBuffer.Buf() + SymbolBuffer[j].Name);
  550.  
  551.          // Offset relative to segment
  552.          ToFile.PutNumeric(SymbolBuffer[j].Offset);
  553.  
  554.          // Type index
  555.          ToFile.PutIndex(0);                     // Not used any more
  556.  
  557.          // End record
  558.          ToFile.EndRecord();                     // End PUBDEF record
  559.       }
  560.    }
  561. }
  562.  
  563.  
  564. void CCOF2OMF::MakeLEDATA() {
  565. /*
  566. This function makes both LEDATA records, containing binary data, and FIXUPP
  567. records, containing relocations.
  568.  
  569. The function is quite complicated because the LEDATA and FIXUPP records are
  570. mutually interdependent. Some explanation is in place here.
  571.  
  572. I am using the word segment for the collection of all sections in the old file
  573. having the same name. A section is a record of binary data in the old file.
  574. Each section is stored as one or more LEDATA records in the new file.
  575. A segment may thus be split into multiple sections, which again may be split
  576. into multiple LEDATA records. The sections must be aligned according to the
  577. specified alignment for the segment. The LEDATA records need not be aligned,
  578. and they may be misaligned for reasons explained below.
  579.  
  580. Each LEDATA record is followed by a FIXUPP record containing all relocations
  581. referring to a source in the LEDATA record, if any.
  582.  
  583. The size of a LEDATA record is limited to 1024 bytes because each entry in
  584. the FIXUPP record has only 10 bits for addressing it. Some linkers impose
  585. the 1024 bytes size limit to all OMF records, although this limitation is
  586. strictly necessary only for LEDATA records. If the code has many relocations
  587. then it may be necessary to make a LEDATA record smaller than 1024 bytes
  588. in order to avoid that the corresponding FIXUPP record becomes bigger than
  589. 1024 bytes. Furthermore, the size of a LEDATA record may need adjustment to
  590. avoid that a relocation source crosses a LEDATA record boundary.
  591.  
  592. I have stored all relocations in a temporary list RelocationBuffer which is
  593. sorted by relocation source address in order to make it easier to find all
  594. relocations with a source address in the current LEDATA record.
  595. */
  596.    int    Segment;                               // Segment index in new file
  597.    int    OldSection;                            // Section index in old file
  598.    uint32 SegOffset;                             // Offset of section relative to segment
  599.    uint32 SectOffset;                            // Offset of LEDATA record relative to section
  600.    uint32 CutOff;                                // Size limit for splitting section into multiple LEDATA records
  601.    uint32 RelFirst;                              // Index into RelocationBuffer of first relocation for section/record
  602.    uint32 RelLast;                               // Index into RelocationBuffer of last relocation for record + 1
  603.    uint32 Rel;                                   // Current index into RelocationBuffer
  604.    uint32 FrameDatum;                            // Frame datum field in FIXUPP record
  605.    uint32 TargetDatum;                           // Target datum field in FIXUPP record
  606.    uint32 TargetDisplacement;                    // Target displacement field in FIXUPP record
  607.    uint32 AlignmentFiller;                       // Number of unused bytes from end of one section to begin of next section due to alignment
  608.  
  609.    SOMFRelocation Reloc0;                        // Reference relocation record for compare and search
  610.    OMF_SLocat Locat;                             // Locat bitfield for FIXUPP record
  611.    OMF_SFixData FixData;                         // FixData bitfield for FIXUPP record
  612.  
  613.    // Loop through segment numbers
  614.    for (Segment = 1; Segment <= NumSegments; Segment++) {
  615.       SegOffset = 0;                             // SegOffset = 0 for first section in segment
  616.  
  617.       // Search through SectionBuffer for old sections contributing to this segment
  618.       for (OldSection = 0; OldSection < SectionBufferNum; OldSection++) {
  619.  
  620.          if (SectionBuffer[OldSection].NewNumber == (uint32)Segment && SectionBuffer[OldSection].Size) {
  621.             // This section contributes to Segment. Make LEDATA record(s)
  622.  
  623.             if (SectionBuffer[OldSection].Offset > SegOffset) {
  624.                // Fillers needed for alignment after previous section
  625.                AlignmentFiller = SectionBuffer[OldSection].Offset - SegOffset;
  626.             }
  627.             else {
  628.                AlignmentFiller = 0;
  629.             }
  630.             SectOffset = 0;                      // Offset of LEDATA record relative to section start
  631.  
  632.             if (AlignmentFiller > 0
  633.             && AlignmentFiller < 4096 && AlignmentFiller < (1u << SectionBuffer[OldSection].Align)
  634.             && SectionBuffer[OldSection].Class == OMF_LNAME_CODE) {
  635.                // This is a code segment and there is a space from previous section
  636.                // Fill the alignment space with NOP's
  637.                // Make LIDATA record with NOP's
  638.                ToFile.StartRecord(OMF_LIDATA);             // Start new LEDATA record
  639.                ToFile.PutIndex(Segment);                   // Segment index
  640.                ToFile.PutNumeric(SegOffset);               // Offset of LIDATA relative to segment
  641.                ToFile.PutNumeric(AlignmentFiller);         // Repeat count
  642.                ToFile.PutWord(0);                          // Block count
  643.                ToFile.PutByte(1);                          // Byte count
  644.                ToFile.PutByte(0x90);                       // NOP opcode
  645.                ToFile.EndRecord();                         // End LIDATA record
  646.             }
  647.  
  648.             SegOffset = SectionBuffer[OldSection].Offset; // Offset of section to segment
  649.  
  650.             // Search for relocations for this section
  651.             Reloc0.Section = OldSection;
  652.             Reloc0.SourceOffset = 0;
  653.             RelFirst = RelocationBuffer.FindFirst(Reloc0); // Points to first relocation for this section            
  654.             RelLast = RelFirst;
  655.  
  656.             // Loop for possibly more than one LEDATA records for this section
  657.             while (SectOffset < SectionBuffer[OldSection].Size) {
  658.  
  659.                CutOff = SectionBuffer[OldSection].Size - SectOffset; // Size of rest of section
  660.                if (CutOff > 1024 && SectionBuffer[OldSection].Class != OMF_LNAME_BSS) {
  661.                   CutOff = 1024; // Maximum LEDATA size
  662.                }
  663.  
  664.                // Search for last relocation entry
  665.                while (RelLast < NumRelocations) {
  666.                   if (RelocationBuffer[RelLast].Section != (uint32)OldSection) {
  667.                      break; // Reached end of relocations for this section
  668.                   }
  669.                   if (RelocationBuffer[RelLast].SourceOffset >= CutOff + SectOffset) {
  670.                      break; // Reached size limit of LEDATA record
  671.                   }
  672.                   if (RelocationBuffer[RelLast].SourceOffset + 4 > CutOff + SectOffset) {
  673.                      // Relocation crosses LEDATA boundary.
  674.                      // Reduce limit of LEDATA to before this relocation source
  675.                      CutOff = RelocationBuffer[RelLast].SourceOffset - SectOffset;
  676.                      if (CutOff == 0) {
  677.                         err.submit(2302); // Relocation source extends beyond end of section.
  678.                         CutOff = 4;       // Prevent infinite loop
  679.                      }
  680.                      break;
  681.                   }
  682.                   if (RelLast - RelFirst > 100) {
  683.                      // FIXUPP record will become too big. End LEDATA record here
  684.                      CutOff = RelocationBuffer[RelLast].SourceOffset - SectOffset;
  685.                      break;
  686.                   }
  687.                   RelLast++;
  688.                } // End of search for last relocation entry for this LEDATA
  689.  
  690.                if (SectionBuffer[OldSection].Class == OMF_LNAME_BSS) {
  691.                   // BSS: Unitialized data section needs no LEDATA record and no FIXUPP
  692.                   if (RelLast > RelFirst) {
  693.                      // Error: Relocation of uninitialized data
  694.                      err.submit(2041);
  695.                   }
  696.                }
  697.                else {
  698.                   // Section contains initialized data. Needs LEDATA and FIXUPP records
  699.  
  700.                   // Make LEDATA record for section data
  701.                   ToFile.StartRecord(OMF_LEDATA + 1);// Start new LEDATA record, 32 bit
  702.  
  703.                   // Segment index
  704.                   ToFile.PutIndex(Segment);        
  705.  
  706.                   // Offset of LEDATA relative to segment
  707.                   ToFile.PutNumeric(SegOffset + SectOffset);
  708.  
  709.                   // Binary data
  710.                   ToFile.PutBinary(Buf() + SectionBuffer[OldSection].psechdr->PRawData + SectOffset, CutOff);
  711.  
  712.                   // End LEDATA record
  713.                   ToFile.EndRecord();
  714.  
  715.                   if (RelLast > RelFirst) {      // If there are any relocations
  716.  
  717.                      // Make FIXUPP record with (RelLast-RelFirst) relocation entries
  718.                      ToFile.StartRecord(OMF_FIXUPP + 1); // Start FIXUPP record, 32 bit
  719.  
  720.                      // Loop through relocations
  721.                      for (Rel = RelFirst; Rel < RelLast; Rel++) {
  722.  
  723.                         if (RelocationBuffer[Rel].Mode < 0) {
  724.                            // Unsupported mode. Make error message
  725.                            err.submit(2030, RelocationBuffer[Rel].TargetOffset);   // TargetOffset contains COFF relocation mode
  726.                            continue;
  727.                         }
  728.  
  729.                         // Make Locat word bitfield
  730.                         Locat.s.one = 1;              // Indicates FIXUP subrecord
  731.                         Locat.s.M = RelocationBuffer[Rel].Mode; // Direct / EIP-relative
  732.                         Locat.s.Location = 9;              // Indicates 32-bit offset
  733.  
  734.                         // Offset of source relative to section (10 bits)
  735.                         uint32 RelocOffset = RelocationBuffer[Rel].SourceOffset - SectOffset; // Offset of relocation source to begin of LEDATA record
  736.                         if (RelocOffset >= 1024) err.submit(9000); // Check that it fits into 10 bits
  737.                         Locat.s.Offset = RelocOffset;
  738.  
  739.                         // Make FixData byte bitfield
  740.                         FixData.b = 0;              // Start with all bits 0
  741.  
  742.                         if (RelocationBuffer[Rel].Scope == S_LOCAL) {
  743.                            // Local target
  744.                            FixData.s.Target = 0;      // Target method T0 or T4: Target = segment
  745.                            FixData.s.Frame = 1;       // Frame method F1: specified by a group index (FLAT)
  746.                            FrameDatum = OMF_LNAME_FLAT; // Target frame = FLAT group
  747.                            TargetDatum = RelocationBuffer[Rel].TargetSegment; // Fixup target = segment
  748.                            TargetDisplacement = RelocationBuffer[Rel].TargetOffset; // Displacement or addend (?)
  749.                         }
  750.                         else {
  751.                            // External symbol target
  752.                            FixData.s.Frame = 5;       // Frame method F5: Frame specified by target, not here
  753.                            FixData.s.Target = 2;      // Target method T2 or T6: Target specified by EXTDEF index
  754.                            TargetDatum = RelocationBuffer[Rel].TargetSegment; // Index into EXTDEF
  755.                            TargetDisplacement = RelocationBuffer[Rel].TargetOffset; // This is zero. Any addend is inline
  756.                         }
  757.                         if (TargetDisplacement) {
  758.                            FixData.s.P = 0;           // Displacement field present
  759.                         }
  760.                         else {
  761.                            FixData.s.P = 1;           // Displacement field absent
  762.                         }
  763.  
  764.                         // Put these data into record
  765.                         // Locat bytes in reverse order:
  766.                         ToFile.PutByte(Locat.bytes[1]);  
  767.                         ToFile.PutByte(Locat.bytes[0]);
  768.                         // FixData byte
  769.                         ToFile.PutByte(FixData.b);      
  770.                         // Frame datum field only if FixData.F = 0 and Frame < 4
  771.                         if (FixData.s.Frame < 4) ToFile.PutIndex(FrameDatum);
  772.                         // Target datum field if FixData.T = 0, which it is here
  773.                         ToFile.PutIndex(TargetDatum);
  774.                         // Target displacement field if FixData.P = 0
  775.                         if (FixData.s.P == 0) ToFile.PutNumeric(TargetDisplacement);
  776.  
  777.                      } // End of loop through relocation for last LEDATA
  778.  
  779.                      // End FIXUPP record
  780.                      ToFile.EndRecord();
  781.                   }
  782.                }
  783.                // Update pointers to after this LEDATA
  784.                SectOffset += CutOff;
  785.                RelFirst = RelLast;
  786.  
  787.             } // End of loop for multiple LEDATA records for one section
  788.  
  789.             // Find end of section
  790.             SegOffset += SectionBuffer[OldSection].Size;   // End of section
  791.  
  792.          } // End of if section in segment
  793.       } // End of loop through multiple sections for same segment
  794.    } // End of loop through segments
  795. }
  796.  
  797.  
  798. void CCOF2OMF::MakeMODEND() {
  799.    // Make MODEND record and finish file
  800.    ToFile.StartRecord(OMF_MODEND);               // Start MODEND record
  801.    ToFile.PutByte(0);                            // Module type field. 0 if not a startup module with start address
  802.    ToFile.EndRecord();                           // End MODEND record
  803. }
  804.