Subversion Repositories Kolibri OS

Rev

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

  1. /****************************  omf2asm.cpp   *********************************
  2. * Author:        Agner Fog, modified by Don Clugston
  3. * Date created:  2007-05-27
  4. * Last modified: 2014-05-32
  5. * Project:       objconv
  6. * Module:        omf2asm.cpp
  7. * Description:
  8. * Module for disassembling OMF object files
  9. *
  10. * (c) 2007-2014 GNU General Public License www.gnu.org/copyleft/gpl.html
  11. *****************************************************************************/
  12. #include "stdafx.h"
  13.  
  14.  
  15. // Constructor
  16. COMF2ASM::COMF2ASM() {
  17. }
  18.  
  19.  
  20. // Convert
  21. void COMF2ASM::Convert() {
  22.    // Do the conversion
  23.    
  24.    // Tell disassembler
  25.    Disasm.Init(0, 0);
  26.  
  27.    // Make temporary Segments table
  28.    CountSegments();
  29.  
  30.    // Make external symbols in Disasm
  31.    MakeExternalSymbolsTable();
  32.  
  33.    // Make public symbols in Disasm
  34.    MakePublicSymbolsTable();
  35.  
  36.    // Make symbol table entries for communal symbols.
  37.    MakeCommunalSymbolsTable();
  38.  
  39.    // Make Segment list and relocations list
  40.    MakeSegmentList();
  41.  
  42.    // Make group definitions
  43.    MakeGroupDefinitions();
  44.  
  45.    // Disassemble
  46.    Disasm.Go();  
  47.  
  48.    // Take over output file from Disasm
  49.    *this << Disasm.OutFile;
  50. }
  51.  
  52. void COMF2ASM::CountSegments() {
  53.    // Make temporary Segments table
  54.    uint32 i;                                     // Record number
  55.    uint32 NameIndex;                             // Name index
  56.    uint32 ClassIndex;                            // Class name index
  57.    SOMFSegment SegRecord;                        // Segment record
  58.  
  59.    // Define structure of attributes
  60.    OMF_SAttrib Attributes;
  61.  
  62.    // Initialize temporary list of segments. Entry 0 is blank
  63.    Segments.PushZero();
  64.    
  65.    // Search for SEGDEF records
  66.    for (i = 0; i < NumRecords; i++) {
  67.       if (Records[i].Type2 == OMF_SEGDEF) {
  68.          // SEGDEF record
  69.          Records[i].Index = 3;
  70.          // Loop through entries in record. There should be only 1
  71.          while (Records[i].Index < Records[i].End) {
  72.             // Read segment attributes
  73.             Attributes.b = Records[i].GetByte();
  74.             if (Attributes.u.A == 0) {
  75.                // Frame and Offset only included if A = 0
  76.                Records[i].GetWord();             // Frame ignored
  77.                SegRecord.Offset = Records[i].GetByte();
  78.             }
  79.             else SegRecord.Offset = 0;
  80.  
  81.             SegRecord.Size = Records[i].GetNumeric();
  82.             NameIndex  = Records[i].GetIndex();
  83.             ClassIndex = Records[i].GetIndex();  // Class index
  84.             Records[i].GetIndex();               // Overlay index ignored
  85.             SegRecord.NameO = GetLocalNameO(NameIndex);     // Segment name
  86.  
  87.             if (Attributes.u.B) {
  88.                // Segment is big
  89.                if (Attributes.u.P) {
  90.                   // 32 bit segment. Big means 2^32 bytes!
  91.                   err.submit(2306);
  92.                }
  93.                else {
  94.                   // 16 bit segment. Big means 2^16 bytes
  95.                   SegRecord.Size = 0x10000;
  96.                }
  97.             }
  98.  
  99.             // Get word size
  100.             SegRecord.WordSize = Attributes.u.P ? 32 : 16;
  101.  
  102.             // Get alignment
  103.             switch (Attributes.u.A) {
  104.             case 0:  // Absolute segment
  105.             case 1:  // Byte alignment
  106.                SegRecord.Align = 0;
  107.                break;
  108.  
  109.             case 2:  // Word alignment
  110.                SegRecord.Align = 1;
  111.                break;
  112.  
  113.             case 3:  // Paragraph alignment
  114.                SegRecord.Align = 4;
  115.                break;
  116.  
  117.             case 4:  // Page alignment
  118.                SegRecord.Align = 16;
  119.                break;
  120.  
  121.             case 5:  // DWord alignment
  122.                SegRecord.Align = 2;
  123.                break;
  124.  
  125.             default: // Unknown
  126.                SegRecord.Align = 3; // Arbitrary value
  127.                break;
  128.             }
  129.  
  130.             // Get further attributes from class name
  131.             char * ClassName = GetLocalName(ClassIndex);
  132.  
  133.             // Convert class name to upper case
  134.             uint32 n = (uint32)strlen(ClassName);
  135.             for (uint32 j = 0; j < n; j++) ClassName[j] &= ~0x20;
  136.  
  137.             // Search for known class names.
  138.             // Standard names are CODE, DATA, BSS, CONST, STACK
  139.             if (strstr(ClassName, "CODE") || strstr(ClassName, "TEXT")) {
  140.                // Code segment
  141.                SegRecord.Type = 1;
  142.             }
  143.             else if (strstr(ClassName, "DATA")) {
  144.                // Data segment
  145.                SegRecord.Type = 2;
  146.             }
  147.             else if (strstr(ClassName, "BSS")) {
  148.                // Unitialized data segment
  149.                SegRecord.Type = 3;
  150.             }
  151.             else if (strstr(ClassName, "CONST")) {
  152.                // Constant data segment
  153.                SegRecord.Type = 4;
  154.             }
  155.             else if (strstr(ClassName, "STACK")) {
  156.                // Stack segment.
  157.                SegRecord.Type = 0;
  158.             }
  159.             else {
  160.                // Unknown/user defined class. Assume data segment
  161.                SegRecord.Type = 2;
  162.             }
  163.  
  164.             // Store temporary segment record
  165.             Segments.Push(SegRecord);
  166.          }
  167.          if (Records[i].Index != Records[i].End) err.submit(1203);   // Check for consistency
  168.       }
  169.    }
  170.  
  171.    FirstComDatSection = Segments.GetNumEntries();
  172.    // Communal sections (as used by Digital Mars):
  173.    // This part by Don Clugston
  174.    for (i = 0; i < NumRecords; i++) {
  175.       if (Records[i].Type2 == OMF_COMDAT) {
  176.          Records[i].Index = 3;
  177.  
  178.          uint8 flags = Records[i].GetByte();
  179.          if ((flags & 2) != 0) {
  180.             // don't support iterated data yet
  181.             err.submit(2318);           // Error message: not supported
  182.             continue;
  183.          }
  184.          uint8 attribs = Records[i].GetByte();
  185.          uint8 align = Records[i].GetByte();
  186.          uint32 ofs  = Records[i].GetNumeric();
  187.          Records[i].GetIndex(); // type (ignore)
  188.          //uint16 publicBase = 0;
  189.          uint16 publicSegment = 0;
  190.          // From the OMF Spec 1.1: "If alloc type is EXPLICIT, public base is present and is
  191.          // identical to public base fields BaseGroup, Base Segment & BaseFrame in the PUBDEF."
  192.          // BUT: In the diagram in the spec it is described as 1-2 bytes (ie, an Index field).
  193.          // but in PUBDEF, those fields are Index, Index, or Index, zero, Index. (2-5 bytes)
  194.          // The diagram appears to be erroneous.
  195.          if ((attribs & 0xF) == 0){
  196.             //publicBase = Records[i].GetIndex();
  197.             publicSegment = Records[i].GetIndex();
  198.             if (publicSegment == 0) {
  199.                 //Records[i].GetIndex(); // skip frame in this case
  200.                 // I don't have the Digital Mars obj spec, but this seems to help ??
  201.                 publicSegment = Records[i].GetIndex(); // ??
  202.             }
  203.          }
  204.          uint16 publicName = Records[i].GetIndex();
  205.          uint32 RecSize = Records[i].End - Records[i].Index; // Calculate size of data
  206.          if (attribs & 0xF) {
  207.             SegRecord.Type = 0x1000  | (attribs & 0xFF);
  208.             SegRecord.WordSize = (attribs & 0x2) ? 32 : 16;
  209.          }
  210.          else {                  
  211.             // use value from segdef
  212.             SegRecord.Type = 0x1000 | Segments[publicSegment].Type;
  213.             SegRecord.WordSize = Segments[publicSegment].WordSize;
  214.          }
  215.  
  216.          //SegRecord.Type |= 1;//!!
  217.  
  218.          if (align != 0) {
  219.             // alignment: (none), byte, word, paragraph, page, dword, arbitrary, arbitrary.
  220.             static const int alignvalues[] = {0, 0, 1, 4, 16, 2, 3, 3};
  221.             SegRecord.Align = alignvalues[align & 0x7];
  222.          }
  223.          else { // use value from segdef
  224.             SegRecord.Align = Segments[publicSegment].Align;
  225.          }
  226.          SegRecord.Size = RecSize;
  227.  
  228.          // Get function name
  229.          const char * name = GetLocalName(publicName);
  230.  
  231.          // Make a section name by putting _text$ before function name
  232.          uint32 ComdatSectionNameIndex = NameBuffer.Push("_text$", 6);
  233.          NameBuffer.PushString(name); // append function name
  234.          SegRecord.NameO = ComdatSectionNameIndex;
  235.          SegRecord.NameIndex = publicName;
  236.  
  237.          if (flags & 1) {
  238.             // continuation.
  239.             // Add to the length to the previous entry.
  240.             Segments[Segments.GetNumEntries()-1].Size += RecSize;
  241.          }
  242.          else {
  243.             SegRecord.Offset = ofs;
  244.             Segments.Push(SegRecord);
  245.          }
  246.       }
  247.    }
  248.  
  249.    // Communal sections (as used by Borland):
  250.    for (i = 0; i < NumRecords; i++) {
  251.       if (Records[i].Type2 == OMF_COMDEF) {
  252.          uint32 DType, DSize = 0, DNum;
  253.          uint16 Segment = 0;
  254.          const char * FuncName = 0;
  255.  
  256.          // Loop through possibly multiple entries in record
  257.          while (Records[i].Index < Records[i].End) {
  258.             // Get function name
  259.             FuncName = Records[i].GetString();
  260.             Records[i].GetByte(); // Type index, should be 0, ignored
  261.             DType = Records[i].GetByte(); // Data type
  262.             switch (DType) {
  263.             case 0x61:
  264.                DNum  = Records[i].GetLength();
  265.                DSize = Records[i].GetLength() * DNum;
  266.                break;
  267.             case 0x62:
  268.                DSize = Records[i].GetLength();
  269.                break;
  270.             default:
  271.                DSize = Records[i].GetLength();
  272.                if (DType < 0x60) { // Borland segment index
  273.                   Segment = DType;
  274.                   break;
  275.                }
  276.                err.submit(2016); // unknown type
  277.                break;
  278.             }
  279.          }
  280.          if (Segment >= Segments.GetNumEntries()) {err.submit(2016); return;}
  281.  
  282.          // Copy segment record
  283.          SegRecord = Segments[Segment];
  284.  
  285.          // Make a section name as SEGMENTNAME$FUNCTIONNAME
  286.          const char * SegmentName = NameBuffer.Buf() + SegRecord.NameO;
  287.          uint32 ComdatSectionNameIndex = NameBuffer.Push(SegmentName, strlen(SegmentName));
  288.          NameBuffer.Push("$", 1);
  289.          NameBuffer.PushString(FuncName); // append function name
  290.          SegRecord.NameO = ComdatSectionNameIndex;
  291.          SegRecord.Size = DSize;
  292.          SegRecord.Type |= 0x1000;
  293.          //SegRecord.BufOffset = ??
  294.  
  295.          // Store segment
  296.          Segments.Push(SegRecord);
  297.  
  298.          if (Records[i].Index != Records[i].End) err.submit(1203);   // Check for consistency
  299.       }
  300.    }
  301.    // Number of segments, not including blank zero entry
  302.    NumSegments = Segments.GetNumEntries() - 1;
  303. }
  304.  
  305.  
  306. void COMF2ASM::MakeExternalSymbolsTable() {
  307.    // Make symbol table and string table entries for external symbols
  308.    uint32 iextsym;                               // External symbol index
  309.    uint32 isymo;                                 // Symbol index in disassembler
  310.    uint32 NumExtSym = SymbolNameOffset.GetNumEntries(); // Number of external symbols
  311.    ExtdefTranslation.SetNum(NumExtSym+1);        // Allocate space in symbol index translation table
  312.  
  313.    // Loop through external symbol names
  314.    for (iextsym = 1; iextsym < NumExtSym; iextsym++) {
  315.  
  316.       // Get name
  317.       const char * Name = GetSymbolName(iextsym);
  318.  
  319.       // Define symbol
  320.       isymo = Disasm.AddSymbol(0, 0, 0, 0, 0x20, 0, Name);
  321.  
  322.       // Update table for translating old EXTDEF number to disassembler symbol index
  323.       ExtdefTranslation[iextsym] = isymo;
  324.    }
  325. }
  326.  
  327.  
  328. void COMF2ASM::MakePublicSymbolsTable() {
  329.    // Make symbol table entries for public symbols
  330.    uint32 i;                                     // Record index
  331.    char * string;                                // Symbol name
  332.    uint32 Segment;                               // Segment
  333.    uint32 Offset;                                // Offset
  334.    uint32 isymo;                                 // Symbol number in disasm
  335.    uint32 CommunalSection = FirstComDatSection;  // Index to communal section
  336.  
  337.    PubdefTranslation.Push(0);                    // Make index 0 = 0
  338.  
  339.    // Search for PUBDEF records
  340.    for (i = 0; i < NumRecords; i++) {
  341.       if (Records[i].Type2 == OMF_PUBDEF) {
  342.          // PUBDEF record
  343.  
  344.          Records[i].Index = 3;
  345.          Records[i].GetIndex();                  // Group. Ignore
  346.          Segment = Records[i].GetIndex();        // Segment
  347.          if (Segment == 0) Records[i].GetWord(); // Base frame. Ignore
  348.  
  349.          // Loop through strings in record
  350.          while (Records[i].Index < Records[i].End) {
  351.             string = Records[i].GetString();     // Symbol name
  352.             Offset = Records[i].GetNumeric();    // Offset to segment
  353.             Records[i].GetIndex();               // Type index. Ignore
  354.  
  355.             // Define symbol
  356.             isymo = Disasm.AddSymbol(Segment, Offset, 0, 0, 4, 0, string);
  357.  
  358.             // Update table for translating old PUBDEF number to disassembler symbol index
  359.             PubdefTranslation.Push(isymo);
  360.          }
  361.          if (Records[i].Index != Records[i].End) err.submit(1203);   // Check for consistency
  362.       }
  363.    }
  364.  
  365.    // Search for OMF_COMDEF records
  366.    for (i = 0; i < NumRecords; i++) {
  367.       if (Records[i].Type2 == OMF_COMDEF) {
  368.          // COMDEF record, Borland communal name
  369.          uint32 DType;
  370.          //uint32 DSize;
  371.          //uint32 DNum;
  372.          Records[i].Index = 3;
  373.  
  374.          // Loop through possibly multiple entries in record
  375.          while (Records[i].Index < Records[i].End) {
  376.             string = Records[i].GetString();
  377.             Records[i].GetByte(); // Type index, should be 0, ignore
  378.             DType = Records[i].GetByte(); // Data type            
  379.             switch (DType) {
  380.             case 0x61:
  381.                //DNum  = Records[i].GetLength();
  382.                //DSize = Records[i].GetLength();
  383.                continue; // Don't know what to do with this type. Ignore
  384.             case 0x62:
  385.                //DSize = Records[i].GetLength();
  386.                continue; // Don't know what to do with this type. Ignore
  387.             default:
  388.                //DSize = Records[i].GetLength();
  389.                if (DType < 0x60) { // Borland segment index
  390.                   break;
  391.                }
  392.                continue; // Unknown type. Ignore
  393.             }
  394.             // Define symbol
  395.             Segment = CommunalSection;
  396.             isymo = Disasm.AddSymbol(Segment, 0, 0, 0, 0x10, 0, string);
  397.  
  398.             // Update table for translating old PUBDEF number to disassembler symbol index
  399.             PubdefTranslation.Push(isymo);
  400.          }
  401.          CommunalSection++;
  402.  
  403.          if (Records[i].Index != Records[i].End) err.submit(1203);   // Check for consistency
  404.       }
  405.    }
  406. }
  407.  
  408.  
  409. void COMF2ASM::MakeCommunalSymbolsTable() {
  410.    // Make symbol table entries for communal symbols
  411.    char * string;                                // Symbol name
  412.  
  413.    // Search for communal records
  414.    for (uint32 i = 0; i < NumRecords; i++) {
  415.       // Count communal records
  416.       if (Records[i].Type2 == OMF_CEXTDEF) {
  417.          Records[i].Index = 3;
  418.          // Loop through strings in record
  419.          while (Records[i].Index < Records[i].End) {                     
  420.             uint32 LIndex = Records[i].GetIndex();
  421.             Records[i].GetIndex(); // Group. Ignore
  422.             string = GetLocalName(LIndex);
  423.  
  424.             // find section with same name
  425.             int32 section = 0;
  426.             for (uint32 j = 0; j < Segments.GetNumEntries(); j++) {
  427.                if (Segments[j].NameIndex == LIndex) {
  428.                   section = (int32)j; break;
  429.                }
  430.             }
  431.  
  432.             // Define symbol
  433.             Disasm.AddSymbol(section, 0, 0, 0, 0x10, 0, string);
  434.          }
  435.       }
  436.    }
  437. }
  438.  
  439.  
  440. void COMF2ASM::MakeGroupDefinitions() {
  441.    // Make segment group definitions
  442.    uint32 i;                                     // Record index
  443.  
  444.    // Search for group records
  445.    for (i = 0; i < NumRecords; i++) {
  446.       if (Records[i].Type2 == OMF_GRPDEF) {
  447.          // GRPDEF record
  448.          Records[i].Index = 3;
  449.          // Get group name
  450.          uint32 ClassIndex = Records[i].GetIndex();
  451.          char * GroupName = GetLocalName(ClassIndex);
  452.  
  453.          // Define group
  454.          Disasm.AddSectionGroup(GroupName, 0);
  455.  
  456.          // Loop through remaining entries in record
  457.          while (Records[i].Index < Records[i].End) {
  458.             // Entry type should be 0xFF
  459.             uint8 Type = Records[i].GetByte();
  460.             // Get member name
  461.             int32 NameIndex = Records[i].GetIndex();
  462.             // Check if type valid
  463.             if (Type == 0xFF && NameIndex > 0) {
  464.                // A group member is found. Add member to group
  465.                Disasm.AddSectionGroup(GroupName, NameIndex);
  466.             }
  467.          }
  468.          if (Records[i].Index != Records[i].End) err.submit(1203);   // Check for consistency
  469.       }
  470.    }
  471. }
  472.  
  473.  
  474. // MakeSegmentList
  475. void COMF2ASM::MakeSegmentList() {
  476.    // Make Sections list in Disasm
  477.    int32  SegNum;                                // Segment number
  478.    int32  Segment = 0;                           // Segment number in OMF record
  479.    uint32 RecNum;                                // OMF record number
  480.    uint32 LastDataRecord;                        // OMF record number of last LEDATA record
  481.    uint32 RecOffset;                             // Segment offset of LEDATA, LIDATA record
  482.    uint32 RecSize;                               // Data size of LEDATA, LIDATA record
  483.    uint32 LastDataRecordSize;                    // Last RecSize
  484.    uint32 LastOffset;                            // Last RecOffset
  485.    int8 * LastDataRecordPointer;                 // Point to last raw data
  486.    uint32 BufOffset;                             // Offset of segment into SegmentData buffer
  487.    CMemoryBuffer TempBuf;                        // Temporary buffer for building raw data
  488.  
  489.    // Loop through segments
  490.    for (SegNum = 1; SegNum <= NumSegments; SegNum++) {
  491.  
  492.       // Get size
  493.       uint32 SegmentSize = Segments[SegNum].Size;
  494.       if (SegmentSize == 0) continue;            // Empty segment
  495.  
  496.       // Allocate temporary data buffer and reset it
  497.       TempBuf.SetSize(SegmentSize + 16);
  498.       int FillByte = 0;                          // Byte to fill memory with
  499.       if (Segments[SegNum].Type == 1) {
  500.          // Code segment. Fill any unused bytes with NOP opcode = 0x90
  501.          FillByte = 0x90;
  502.       }
  503.       memset(TempBuf.Buf(), FillByte, SegmentSize + 16);// Reset to all 0 or NOP
  504.  
  505.       LastDataRecord = 0;
  506.       LastDataRecordSize = 0;
  507.       LastDataRecordPointer = 0;
  508.       LastOffset = 0;
  509.       int comdatsSoFar = 0;
  510.  
  511.       // Search for LEDATA, LIDATA and FIXUPP records for this segment
  512.       for (RecNum = 0; RecNum < NumRecords; RecNum++) {
  513.  
  514.          if (Records[RecNum].Type2 == OMF_LEDATA) {
  515.  
  516.             // LEDATA record
  517.             Records[RecNum].Index = 3;           // Initialize record reading
  518.             Segment = Records[RecNum].GetIndex();// Read segment number
  519.  
  520.             if ((Segment & 0xC000) == 0x4000) {
  521.                // Refers to Borland communal section
  522.                Segment = (Segment & ~0x4000) + FirstComDatSection - 1;
  523.             }
  524.  
  525.             if (Segment != SegNum) continue; // Does not refer to this segment
  526.  
  527.             RecOffset = Records[RecNum].GetNumeric();// Read offset of this record
  528.             RecSize = Records[RecNum].End - Records[RecNum].Index; // Calculate size of data
  529.             LastDataRecord = RecNum;             // Save for later FIXUPP that refers to this record
  530.  
  531.             if (RecOffset < LastOffset + LastDataRecordSize && LastOffset < RecOffset + RecSize) {
  532.                // Overlapping data records
  533.                if (RecOffset + 8 < LastOffset + LastDataRecordSize || Segments[SegNum].Type != 1) {
  534.                   // Overlapping data by more than 7 bytes or not executable code
  535.                   err.submit(1207);
  536.                }
  537.                else {
  538.                   // Possibly backpatched code
  539.                   err.submit(1208);              // Warning
  540.                   err.ClearError(1208);          // Report only once
  541.                }
  542.             }
  543.  
  544.             LastDataRecordSize = RecSize;
  545.             LastDataRecordPointer = Records[RecNum].buffer + Records[RecNum].FileOffset + Records[RecNum].Index;
  546.             LastOffset = RecOffset;                 // Save offset for subsequent FIXUPP records
  547.  
  548.             // Check if data within segment
  549.             if (RecOffset + RecSize > SegmentSize) {
  550.                err.submit(2309, GetSegmentName(Segment));
  551.                continue;
  552.             }
  553.  
  554.             // Put raw data into temporary buffer
  555.             memcpy(TempBuf.Buf() + RecOffset, LastDataRecordPointer, RecSize);
  556.  
  557.          } // Finished with LEDATA record
  558.  
  559.          if (Records[RecNum].Type2 == OMF_LIDATA) {
  560.             // LIDATA record
  561.             Records[RecNum].Index = 3;           // Initialize record reading
  562.             Segment = Records[RecNum].GetIndex();
  563.  
  564.             if (Segment != SegNum) continue; // Does not refer to this segment
  565.  
  566.             LastDataRecord = RecNum;             // Save for later FIXUPP that refers to this record
  567.  
  568.             RecOffset = Records[RecNum].GetNumeric();// Read offset
  569.  
  570.             if (RecOffset > SegmentSize) {
  571.                err.submit(2310); continue;       // Error: outside bounds
  572.             }
  573.  
  574.             // Unpack LIDATA blocks recursively
  575.             RecSize = Records[RecNum].UnpackLIDATABlock(TempBuf.Buf() + RecOffset, SegmentSize - RecOffset);
  576.  
  577.             if (RecOffset < LastOffset + LastDataRecordSize && LastOffset < RecOffset + RecSize) {
  578.                // Overlapping data records
  579.                err.submit(1207);                 // Warning
  580.             }
  581.             LastDataRecordSize = RecSize;           // Save data size
  582.             LastOffset = RecOffset;                 // Save offset for subsequent FIXUPP records
  583.  
  584.          } // Finished with LIDATA record
  585.  
  586.          if (Records[RecNum].Type2 == OMF_COMDAT) {
  587.             // COMDAT record.
  588.  
  589.             Records[RecNum].Index = 3;           // Initialize record reading
  590.             uint16 flags = Records[RecNum].GetByte();
  591.             if ((flags&1)==0) { // not a continuation
  592.                ++comdatsSoFar;
  593.                LastDataRecord = RecNum;             // Save for later FIXUPP that refers to this record
  594.             }
  595.             Segment = FirstComDatSection + comdatsSoFar-1;
  596.             if (SegNum != Segment) continue;
  597.  
  598.             uint16 attribs = Records[RecNum].GetByte();
  599.             Records[RecNum].GetByte(); // align (ignore)
  600.             RecOffset = Records[RecNum].GetNumeric();
  601.             Records[RecNum].GetIndex(); // type (ignore)
  602.             if ((attribs&0xF)==0) {
  603.                Records[RecNum].GetIndex(); // public base
  604.                uint16 publicSegment = Records[RecNum].GetIndex();
  605.                if (publicSegment==0) Records[RecNum].GetIndex(); // public frame (ignore)
  606.             }
  607.             Records[RecNum].GetIndex(); // public name (ignore)
  608.             RecSize = Records[RecNum].End - Records[RecNum].Index; // Calculate size of data
  609.  
  610.             LastDataRecord = RecNum;             // Save for later FIXUPP that refers to this record
  611.             LastDataRecordSize = RecSize;
  612.             LastDataRecordPointer = Records[RecNum].buffer + Records[RecNum].Index+Records[RecNum].FileOffset;
  613.             LastOffset = RecOffset;
  614.             // Put raw data into temporary buffer
  615.             memcpy(TempBuf.Buf() + RecOffset, LastDataRecordPointer, RecSize);
  616.          } // Finished with COMDAT record
  617.  
  618.          if (Records[RecNum].Type2 == OMF_FIXUPP) {
  619.             // FIXUPP record
  620.             if (Segment != SegNum) continue; // Does not refer to this segment
  621.             Records[RecNum].Index = 3;
  622.  
  623.             if (Records[LastDataRecord].Type2 == OMF_LEDATA) {
  624.                // FIXUPP for last LEDATA record
  625.                // Make relocation records
  626.                MakeRelocations(Segment, RecNum, LastOffset, LastDataRecordSize, (uint8*)TempBuf.Buf());
  627.             }
  628.             else if (Records[RecNum].Index < Records[RecNum].End) {
  629.                // Non-empty FIXUPP record does not refer to LEDATA record
  630.                if (Records[LastDataRecord].Type2 == OMF_COMDAT) {
  631.                   // FIXUPP for last COMDAT record
  632.                   // Make relocation records
  633.                   MakeRelocations(Segment, RecNum, LastOffset, LastDataRecordSize, (uint8*)TempBuf.Buf());
  634.                }
  635.                else if (Records[LastDataRecord].Type2 == OMF_LIDATA) {
  636.                   err.submit(2311);              // Error: Relocation of iterated data not supported
  637.                }
  638.                else {
  639.                   err.submit(2312);              // Does not refer to data record
  640.                }
  641.             }
  642.          }
  643.       } // End of loop to search for LEDATA, LIDATA and FIXUPP records for this segment
  644.  
  645.       // Transfer raw data from TempBuf to SegmentData buffer
  646.       BufOffset = SegmentData.Push(TempBuf.Buf(), SegmentSize);
  647.  
  648.       // Remember offset into SegmentData
  649.       Segments[SegNum].BufOffset = BufOffset;
  650.  
  651.    } // End of first loop through segments
  652.  
  653.    // We must put all segments into SegmentData buffer before we assign pointers to
  654.    // the raw data because otherwise the SegmentData buffer might me reallocated
  655.    // when it grows and the pointers become invalid. This is the reasons why we
  656.    // have two loops through the segments here.
  657.  
  658.    // Second loop through segments
  659.    int totalcodesize=0;
  660.    for (SegNum = 1; SegNum <= NumSegments; SegNum++) {
  661.  
  662.       // Pointer to merged raw data
  663.       uint8 * RawDatap = (uint8*)SegmentData.Buf() + Segments[SegNum].BufOffset;
  664.  
  665.       // Size of raw data
  666.       uint32 InitSize = (Segments[SegNum].Type == 3) ? 0 : Segments[SegNum].Size;
  667.  
  668.       // Define segment
  669.       const char * SegmentName = NameBuffer.Buf() + Segments[SegNum].NameO;
  670.       Disasm.AddSection(RawDatap, InitSize, Segments[SegNum].Size, Segments[SegNum].Offset,
  671.          Segments[SegNum].Type, Segments[SegNum].Align, Segments[SegNum].WordSize, SegmentName);
  672.       if (Segments[SegNum].Type == 1 || Segments[SegNum].Type == 0x1001) {
  673.          totalcodesize += Segments[SegNum].Size;
  674.       }
  675.    }
  676. }
  677.  
  678.  
  679. // MakeRelocations
  680. void COMF2ASM::MakeRelocations(int32 Segment, uint32 RecNum, uint32 SOffset, uint32 RSize, uint8 * SData) {
  681.    // Make relocations for object and executable files
  682.    // Parameters:
  683.    // Segment = segment index of last LEDATA record
  684.    // RecNum = FIXUPP record number
  685.    // SOffset = segment relative offset of last LEDATA record
  686.    // RSize = Size of last LEDATA record
  687.    // SData = pointer to raw segment data
  688.  
  689.    uint32 Frame, Target, TargetDisplacement; // Contents of FIXUPP record
  690.    uint8  byte1, byte2;                // First two bytes of subrecord
  691.    int32  Inline;                      // Inline address or addend in relocation source
  692.    //int16  InlineSeg;                   // Segment address stored in relocation source
  693.    int32  Addend;                      // Correction to add to target address
  694.    int32  SourceSize;                  // Size of relocation source
  695.    uint32 RelType;                     // Relocation type, as defined in disasm.h
  696.    int32  TargetSegment;               // Target segment or group
  697.    uint32 TargetOffset;                // Target offset
  698.    uint32 TargetSymbol;                // Symbol index of target
  699.    uint32 ReferenceIndex;              // Segment/group index of reference frame
  700.  
  701.    // Bitfields in subrecords
  702.    OMF_SLocat Locat;         // Structure of first two bytes of FIXUP subrecord swapped = Locat field
  703.    OMF_SFixData FixData;     // Structure of FixData field in FIXUP subrecord of FIXUPP record
  704.    OMF_STrdDat TrdDat;       // Structure of Thread Data field in THREAD subrecord of FIXUPP record
  705.  
  706.    Records[RecNum].Index = 3;
  707.  
  708.    // Loop through entries in record
  709.    while (Records[RecNum].Index < Records[RecNum].End) {
  710.  
  711.       // Read first byte
  712.       byte1 = Records[RecNum].GetByte();
  713.       if (byte1 & 0x80) {
  714.  
  715.          // This is a FIXUP subrecord
  716.          Frame = 0; Target = 0; TargetDisplacement = 0;  Addend = 0;  ReferenceIndex = 0;
  717.  
  718.          // read second byte
  719.          byte2 = Records[RecNum].GetByte();
  720.          // swap bytes and put into byte12 bitfield
  721.          Locat.bytes[1] = byte1;
  722.          Locat.bytes[0] = byte2;
  723.  
  724.          // Read FixData
  725.          FixData.b = Records[RecNum].GetByte();
  726.  
  727.          // Read conditional fields
  728.          if (FixData.s.F) {
  729.             // Frame specified by previously define thread
  730.             // Does anybody still use compression of repeated fixup targets?
  731.             // I don't care to support this if it is never used
  732.             err.submit(2313);           // Error message: not supported
  733.             continue;
  734.          }
  735.          else {
  736.             if (FixData.s.Frame < 4) {
  737.                // Frame datum field present
  738.                Frame = Records[RecNum].GetIndex();
  739.             }
  740.             else Frame = 0;
  741.  
  742.             switch (FixData.s.Frame) { // Frame method
  743.             case 0:  // F0: segment
  744.                ReferenceIndex = Frame;
  745.                break;
  746.  
  747.             case 1:  // F1: group
  748.                // Groups defined after segments. Add number of segments to get group index
  749.                ReferenceIndex = Frame + NumSegments;
  750.                break;
  751.  
  752.             default:
  753.             case 2:  // F2: external symbol
  754.                ReferenceIndex = 0;
  755.                break;
  756.  
  757.             case 4:  // F4: traget frame = source frame
  758.                Frame = Segment;
  759.                break;
  760.  
  761.             case 5:  // F5: target frame = target segment
  762.                Frame = 0;
  763.                break;
  764.             }
  765.          }
  766.  
  767.          if (FixData.s.T == 0) {
  768.             // Target specified
  769.             Target = Records[RecNum].GetIndex();
  770.             if ((Target & 0xC000) == 0x4000) {
  771.                // Refers to Borland communal section
  772.                Target = (Target & ~0x4000) + FirstComDatSection - 1;
  773.             }
  774.             //uint32 TargetMethod = FixData.s.Target + FixData.s.P * 4;
  775.          }
  776.          else {
  777.             // Target specified in previous thread
  778.             // Does anybody still use compression of repeated fixup targets?
  779.             // I don't care to support this if it is never used
  780.             err.submit(2313);           // Error message: not supported
  781.             continue;
  782.          }
  783.  
  784.          if (FixData.s.P == 0) {
  785.             TargetDisplacement = Records[RecNum].GetNumeric();
  786.          }
  787.  
  788.          if (!SData || Locat.s.Offset > RSize) {
  789.             err.submit(2032); // Relocation points outside segment
  790.             return;
  791.          }
  792.          // Get inline addend and check relocation method
  793.  
  794.          // Pointer to relocation source inline in raw data:
  795.          uint8 * inlinep = SData + SOffset + Locat.s.Offset;
  796.          Inline = 0;  SourceSize = 0;
  797.          //InlineSeg = 0;  
  798.          TargetSegment = 0;  TargetOffset = 0;  TargetSymbol = 0;
  799.  
  800.          // Relocation type
  801.          if (Locat.s.M) {
  802.             // Segment relative
  803.             RelType = 8;
  804.          }
  805.          else {
  806.             // (E)IP relative
  807.             RelType = 2;
  808.          }
  809.  
  810.          switch (Locat.s.Location) {// Relocation method
  811.          case OMF_Fixup_8bit:       // 8 bit
  812.             SourceSize = 1;
  813.             Inline = *(int8*)inlinep;
  814.             break;
  815.  
  816.          case OMF_Fixup_16bit:      // 16 bit
  817.             SourceSize = 2;
  818.             Inline = *(int16*)inlinep;
  819.             break;
  820.  
  821.          case OMF_Fixup_32bit:      // 32 bit
  822.             SourceSize = 4;
  823.             Inline = *(int32*)inlinep;
  824.             break;
  825.  
  826.          case OMF_Fixup_Far:        // far 16+16 bit
  827.             RelType = 0x400;
  828.             SourceSize = 4;
  829.             Inline = *(int16*)inlinep;
  830.             break;
  831.  
  832.          case OMF_Fixup_Farword:    // far 32+16 bit
  833.          case OMF_Fixup_Pharlab48:
  834.             RelType = 0x400;
  835.             SourceSize = 6;
  836.             Inline = *(int32*)inlinep;
  837.             break;
  838.  
  839.          case OMF_Fixup_Segment:    // segment selector
  840.             if (TargetDisplacement || FixData.s.Target == 2) {
  841.                // An offset is specified or an external symbol.
  842.                // Segment of symbol is required (seg xxx)
  843.                RelType = 0x200;
  844.             }
  845.             else {
  846.                // A segment name or group name is required
  847.                RelType = 0x100;
  848.             };
  849.             SourceSize = 2;
  850.             Inline = *(int16*)inlinep;
  851.             break;
  852.  
  853.          case OMF_Fixup_16bitLoader: // 16-bit loader resolved
  854.             RelType = 0x21;
  855.             SourceSize = 2;
  856.             Inline = *(int16*)inlinep;
  857.             break;
  858.  
  859.          case OMF_Fixup_32bitLoader: // 32-bit loader resolved
  860.             RelType = 0x21;
  861.             SourceSize = 4;
  862.             Inline = *(int32*)inlinep;
  863.             break;
  864.  
  865.          default:                   // unknown or not supported
  866.             RelType = 0;
  867.             SourceSize = 0;
  868.             Inline = 0;
  869.          } // end switch
  870.  
  871.  
  872.          // Offset of relocation source
  873.          uint32 SourceOffset = SOffset + Locat.s.Offset;
  874.  
  875.          // Relocation type: direct or (E)IP-relative
  876.          if (RelType == 2) {
  877.             // (E)IP-relative
  878.             // Correct for difference between source address and end of instruction
  879.             Addend = -SourceSize;
  880.          }
  881.  
  882.          // Check target method
  883.          switch (FixData.s.Target) {             // = Target method modulo 4
  884.          case 0: // T0 and T4: Target = segment
  885.             // Local or public symbol
  886.             TargetSegment = Target;              // Target segment
  887.             TargetOffset = TargetDisplacement;   // Target offset
  888.             if (RelType != 0x100) {
  889.                // Add inline to target address, except if target is a segment only
  890.                TargetOffset += Inline;
  891.                Addend -= Inline;                 // Avoid adding Inline twice
  892.             }
  893.             break;
  894.  
  895.          case 1: // T1 and T5: Target = segment group
  896.             // Warning: this method has not occurred. Not tested!
  897.             // Groups are numbered in sequence after segments in Disasm. Add number of segments to group index
  898.             TargetSegment = Target + NumSegments;// Target group
  899.             TargetOffset = TargetDisplacement;   // Target offset
  900.             if (RelType != 0x100) {
  901.                // Add inline to target address, except if target is a segment only
  902.                TargetOffset += Inline;
  903.                Addend -= Inline;                 // Avoid adding Inline twice
  904.             }
  905.             break;
  906.  
  907.          case 2: // T2 and T6: Target = external symbol
  908.             // Translate old EXTDEF index to new symbol table index
  909.             if (Target < ExtdefTranslation.GetNumEntries()) {
  910.                TargetSymbol = ExtdefTranslation[Target];
  911.             }
  912.             break;
  913.  
  914.          default: // Unknown method
  915.             err.submit(2314, FixData.s.Target + FixData.s.P * 4);
  916.          }
  917.  
  918.          if (TargetSymbol == 0) {
  919.             // Make symbol record for target
  920.             TargetSymbol = Disasm.AddSymbol(TargetSegment, TargetOffset, 0, 0, 2, 0, 0);
  921.          }
  922.  
  923.          if (FixData.s.Frame == 4 && FixData.s.Target + FixData.s.P*4 == 6) {
  924.             // Note:
  925.             // Frame method F4 is apparently used by 16-bit Borland compiler for
  926.             // indicating floating point instructions that can be emulated if no
  927.             // 8087 processor is present. I can't find this documented anywhere.
  928.             // I don't know what the exact criterion is for indicating that a FIXUP
  929.             // subrecord is not a relocation record but a f.p. emulating record.
  930.             // I have chosen to consider all subrecords with frame method F4 and
  931.             // target method T6 to be ignored.
  932.             ;
  933.          }
  934.          else {
  935.             // This is a proper relocation subrecord
  936.             Disasm.AddRelocation(Segment, SourceOffset, Addend, RelType, SourceSize, TargetSymbol, ReferenceIndex);
  937.          }
  938.       }
  939.       else {
  940.          // This is a THREAD subrecord.
  941.          // I don't think this feature for compressing fixup data is
  942.          // used any more, if it ever was. I am not supporting it here.
  943.          // Frame threads can be safely ignored. A target thread cannot
  944.          // be ignored if there is any reference to it. The error is
  945.          // reported above at the reference to a target thread, not here.
  946.          TrdDat.b = byte1;              // Put byte into bitfield
  947.          if (TrdDat.s.Method < 4) {     // Make sure we read this correctly, even if ignored
  948.             Records[RecNum].GetIndex(); // has index field if method < 4 ?
  949.          }
  950.       }
  951.    } // Finished loop through subrecords
  952.  
  953.    if (Records[RecNum].Index != Records[RecNum].End) err.submit(1203);   // Check for consistency
  954. }
  955.