/**************************** omf2asm.cpp ********************************* * Author: Agner Fog, modified by Don Clugston * Date created: 2007-05-27 * Last modified: 2014-05-32 * Project: objconv * Module: omf2asm.cpp * Description: * Module for disassembling OMF object files * * (c) 2007-2014 GNU General Public License www.gnu.org/copyleft/gpl.html *****************************************************************************/ #include "stdafx.h" // Constructor COMF2ASM::COMF2ASM() { } // Convert void COMF2ASM::Convert() { // Do the conversion // Tell disassembler Disasm.Init(0, 0); // Make temporary Segments table CountSegments(); // Make external symbols in Disasm MakeExternalSymbolsTable(); // Make public symbols in Disasm MakePublicSymbolsTable(); // Make symbol table entries for communal symbols. MakeCommunalSymbolsTable(); // Make Segment list and relocations list MakeSegmentList(); // Make group definitions MakeGroupDefinitions(); // Disassemble Disasm.Go(); // Take over output file from Disasm *this << Disasm.OutFile; } void COMF2ASM::CountSegments() { // Make temporary Segments table uint32 i; // Record number uint32 NameIndex; // Name index uint32 ClassIndex; // Class name index SOMFSegment SegRecord; // Segment record // Define structure of attributes OMF_SAttrib Attributes; // Initialize temporary list of segments. Entry 0 is blank Segments.PushZero(); // Search for SEGDEF records for (i = 0; i < NumRecords; i++) { if (Records[i].Type2 == OMF_SEGDEF) { // SEGDEF record Records[i].Index = 3; // Loop through entries in record. There should be only 1 while (Records[i].Index < Records[i].End) { // Read segment attributes Attributes.b = Records[i].GetByte(); if (Attributes.u.A == 0) { // Frame and Offset only included if A = 0 Records[i].GetWord(); // Frame ignored SegRecord.Offset = Records[i].GetByte(); } else SegRecord.Offset = 0; SegRecord.Size = Records[i].GetNumeric(); NameIndex = Records[i].GetIndex(); ClassIndex = Records[i].GetIndex(); // Class index Records[i].GetIndex(); // Overlay index ignored SegRecord.NameO = GetLocalNameO(NameIndex); // Segment name if (Attributes.u.B) { // Segment is big if (Attributes.u.P) { // 32 bit segment. Big means 2^32 bytes! err.submit(2306); } else { // 16 bit segment. Big means 2^16 bytes SegRecord.Size = 0x10000; } } // Get word size SegRecord.WordSize = Attributes.u.P ? 32 : 16; // Get alignment switch (Attributes.u.A) { case 0: // Absolute segment case 1: // Byte alignment SegRecord.Align = 0; break; case 2: // Word alignment SegRecord.Align = 1; break; case 3: // Paragraph alignment SegRecord.Align = 4; break; case 4: // Page alignment SegRecord.Align = 16; break; case 5: // DWord alignment SegRecord.Align = 2; break; default: // Unknown SegRecord.Align = 3; // Arbitrary value break; } // Get further attributes from class name char * ClassName = GetLocalName(ClassIndex); // Convert class name to upper case uint32 n = (uint32)strlen(ClassName); for (uint32 j = 0; j < n; j++) ClassName[j] &= ~0x20; // Search for known class names. // Standard names are CODE, DATA, BSS, CONST, STACK if (strstr(ClassName, "CODE") || strstr(ClassName, "TEXT")) { // Code segment SegRecord.Type = 1; } else if (strstr(ClassName, "DATA")) { // Data segment SegRecord.Type = 2; } else if (strstr(ClassName, "BSS")) { // Unitialized data segment SegRecord.Type = 3; } else if (strstr(ClassName, "CONST")) { // Constant data segment SegRecord.Type = 4; } else if (strstr(ClassName, "STACK")) { // Stack segment. SegRecord.Type = 0; } else { // Unknown/user defined class. Assume data segment SegRecord.Type = 2; } // Store temporary segment record Segments.Push(SegRecord); } if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency } } FirstComDatSection = Segments.GetNumEntries(); // Communal sections (as used by Digital Mars): // This part by Don Clugston for (i = 0; i < NumRecords; i++) { if (Records[i].Type2 == OMF_COMDAT) { Records[i].Index = 3; uint8 flags = Records[i].GetByte(); if ((flags & 2) != 0) { // don't support iterated data yet err.submit(2318); // Error message: not supported continue; } uint8 attribs = Records[i].GetByte(); uint8 align = Records[i].GetByte(); uint32 ofs = Records[i].GetNumeric(); Records[i].GetIndex(); // type (ignore) //uint16 publicBase = 0; uint16 publicSegment = 0; // From the OMF Spec 1.1: "If alloc type is EXPLICIT, public base is present and is // identical to public base fields BaseGroup, Base Segment & BaseFrame in the PUBDEF." // BUT: In the diagram in the spec it is described as 1-2 bytes (ie, an Index field). // but in PUBDEF, those fields are Index, Index, or Index, zero, Index. (2-5 bytes) // The diagram appears to be erroneous. if ((attribs & 0xF) == 0){ //publicBase = Records[i].GetIndex(); publicSegment = Records[i].GetIndex(); if (publicSegment == 0) { //Records[i].GetIndex(); // skip frame in this case // I don't have the Digital Mars obj spec, but this seems to help ?? publicSegment = Records[i].GetIndex(); // ?? } } uint16 publicName = Records[i].GetIndex(); uint32 RecSize = Records[i].End - Records[i].Index; // Calculate size of data if (attribs & 0xF) { SegRecord.Type = 0x1000 | (attribs & 0xFF); SegRecord.WordSize = (attribs & 0x2) ? 32 : 16; } else { // use value from segdef SegRecord.Type = 0x1000 | Segments[publicSegment].Type; SegRecord.WordSize = Segments[publicSegment].WordSize; } //SegRecord.Type |= 1;//!! if (align != 0) { // alignment: (none), byte, word, paragraph, page, dword, arbitrary, arbitrary. static const int alignvalues[] = {0, 0, 1, 4, 16, 2, 3, 3}; SegRecord.Align = alignvalues[align & 0x7]; } else { // use value from segdef SegRecord.Align = Segments[publicSegment].Align; } SegRecord.Size = RecSize; // Get function name const char * name = GetLocalName(publicName); // Make a section name by putting _text$ before function name uint32 ComdatSectionNameIndex = NameBuffer.Push("_text$", 6); NameBuffer.PushString(name); // append function name SegRecord.NameO = ComdatSectionNameIndex; SegRecord.NameIndex = publicName; if (flags & 1) { // continuation. // Add to the length to the previous entry. Segments[Segments.GetNumEntries()-1].Size += RecSize; } else { SegRecord.Offset = ofs; Segments.Push(SegRecord); } } } // Communal sections (as used by Borland): for (i = 0; i < NumRecords; i++) { if (Records[i].Type2 == OMF_COMDEF) { uint32 DType, DSize = 0, DNum; uint16 Segment = 0; const char * FuncName = 0; // Loop through possibly multiple entries in record while (Records[i].Index < Records[i].End) { // Get function name FuncName = Records[i].GetString(); Records[i].GetByte(); // Type index, should be 0, ignored DType = Records[i].GetByte(); // Data type switch (DType) { case 0x61: DNum = Records[i].GetLength(); DSize = Records[i].GetLength() * DNum; break; case 0x62: DSize = Records[i].GetLength(); break; default: DSize = Records[i].GetLength(); if (DType < 0x60) { // Borland segment index Segment = DType; break; } err.submit(2016); // unknown type break; } } if (Segment >= Segments.GetNumEntries()) {err.submit(2016); return;} // Copy segment record SegRecord = Segments[Segment]; // Make a section name as SEGMENTNAME$FUNCTIONNAME const char * SegmentName = NameBuffer.Buf() + SegRecord.NameO; uint32 ComdatSectionNameIndex = NameBuffer.Push(SegmentName, strlen(SegmentName)); NameBuffer.Push("$", 1); NameBuffer.PushString(FuncName); // append function name SegRecord.NameO = ComdatSectionNameIndex; SegRecord.Size = DSize; SegRecord.Type |= 0x1000; //SegRecord.BufOffset = ?? // Store segment Segments.Push(SegRecord); if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency } } // Number of segments, not including blank zero entry NumSegments = Segments.GetNumEntries() - 1; } void COMF2ASM::MakeExternalSymbolsTable() { // Make symbol table and string table entries for external symbols uint32 iextsym; // External symbol index uint32 isymo; // Symbol index in disassembler uint32 NumExtSym = SymbolNameOffset.GetNumEntries(); // Number of external symbols ExtdefTranslation.SetNum(NumExtSym+1); // Allocate space in symbol index translation table // Loop through external symbol names for (iextsym = 1; iextsym < NumExtSym; iextsym++) { // Get name const char * Name = GetSymbolName(iextsym); // Define symbol isymo = Disasm.AddSymbol(0, 0, 0, 0, 0x20, 0, Name); // Update table for translating old EXTDEF number to disassembler symbol index ExtdefTranslation[iextsym] = isymo; } } void COMF2ASM::MakePublicSymbolsTable() { // Make symbol table entries for public symbols uint32 i; // Record index char * string; // Symbol name uint32 Segment; // Segment uint32 Offset; // Offset uint32 isymo; // Symbol number in disasm uint32 CommunalSection = FirstComDatSection; // Index to communal section PubdefTranslation.Push(0); // Make index 0 = 0 // Search for PUBDEF records for (i = 0; i < NumRecords; i++) { if (Records[i].Type2 == OMF_PUBDEF) { // PUBDEF record Records[i].Index = 3; Records[i].GetIndex(); // Group. Ignore Segment = Records[i].GetIndex(); // Segment if (Segment == 0) Records[i].GetWord(); // Base frame. Ignore // Loop through strings in record while (Records[i].Index < Records[i].End) { string = Records[i].GetString(); // Symbol name Offset = Records[i].GetNumeric(); // Offset to segment Records[i].GetIndex(); // Type index. Ignore // Define symbol isymo = Disasm.AddSymbol(Segment, Offset, 0, 0, 4, 0, string); // Update table for translating old PUBDEF number to disassembler symbol index PubdefTranslation.Push(isymo); } if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency } } // Search for OMF_COMDEF records for (i = 0; i < NumRecords; i++) { if (Records[i].Type2 == OMF_COMDEF) { // COMDEF record, Borland communal name uint32 DType; //uint32 DSize; //uint32 DNum; Records[i].Index = 3; // Loop through possibly multiple entries in record while (Records[i].Index < Records[i].End) { string = Records[i].GetString(); Records[i].GetByte(); // Type index, should be 0, ignore DType = Records[i].GetByte(); // Data type switch (DType) { case 0x61: //DNum = Records[i].GetLength(); //DSize = Records[i].GetLength(); continue; // Don't know what to do with this type. Ignore case 0x62: //DSize = Records[i].GetLength(); continue; // Don't know what to do with this type. Ignore default: //DSize = Records[i].GetLength(); if (DType < 0x60) { // Borland segment index break; } continue; // Unknown type. Ignore } // Define symbol Segment = CommunalSection; isymo = Disasm.AddSymbol(Segment, 0, 0, 0, 0x10, 0, string); // Update table for translating old PUBDEF number to disassembler symbol index PubdefTranslation.Push(isymo); } CommunalSection++; if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency } } } void COMF2ASM::MakeCommunalSymbolsTable() { // Make symbol table entries for communal symbols char * string; // Symbol name // Search for communal records for (uint32 i = 0; i < NumRecords; i++) { // Count communal records if (Records[i].Type2 == OMF_CEXTDEF) { Records[i].Index = 3; // Loop through strings in record while (Records[i].Index < Records[i].End) { uint32 LIndex = Records[i].GetIndex(); Records[i].GetIndex(); // Group. Ignore string = GetLocalName(LIndex); // find section with same name int32 section = 0; for (uint32 j = 0; j < Segments.GetNumEntries(); j++) { if (Segments[j].NameIndex == LIndex) { section = (int32)j; break; } } // Define symbol Disasm.AddSymbol(section, 0, 0, 0, 0x10, 0, string); } } } } void COMF2ASM::MakeGroupDefinitions() { // Make segment group definitions uint32 i; // Record index // Search for group records for (i = 0; i < NumRecords; i++) { if (Records[i].Type2 == OMF_GRPDEF) { // GRPDEF record Records[i].Index = 3; // Get group name uint32 ClassIndex = Records[i].GetIndex(); char * GroupName = GetLocalName(ClassIndex); // Define group Disasm.AddSectionGroup(GroupName, 0); // Loop through remaining entries in record while (Records[i].Index < Records[i].End) { // Entry type should be 0xFF uint8 Type = Records[i].GetByte(); // Get member name int32 NameIndex = Records[i].GetIndex(); // Check if type valid if (Type == 0xFF && NameIndex > 0) { // A group member is found. Add member to group Disasm.AddSectionGroup(GroupName, NameIndex); } } if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency } } } // MakeSegmentList void COMF2ASM::MakeSegmentList() { // Make Sections list in Disasm int32 SegNum; // Segment number int32 Segment = 0; // Segment number in OMF record uint32 RecNum; // OMF record number uint32 LastDataRecord; // OMF record number of last LEDATA record uint32 RecOffset; // Segment offset of LEDATA, LIDATA record uint32 RecSize; // Data size of LEDATA, LIDATA record uint32 LastDataRecordSize; // Last RecSize uint32 LastOffset; // Last RecOffset int8 * LastDataRecordPointer; // Point to last raw data uint32 BufOffset; // Offset of segment into SegmentData buffer CMemoryBuffer TempBuf; // Temporary buffer for building raw data // Loop through segments for (SegNum = 1; SegNum <= NumSegments; SegNum++) { // Get size uint32 SegmentSize = Segments[SegNum].Size; if (SegmentSize == 0) continue; // Empty segment // Allocate temporary data buffer and reset it TempBuf.SetSize(SegmentSize + 16); int FillByte = 0; // Byte to fill memory with if (Segments[SegNum].Type == 1) { // Code segment. Fill any unused bytes with NOP opcode = 0x90 FillByte = 0x90; } memset(TempBuf.Buf(), FillByte, SegmentSize + 16);// Reset to all 0 or NOP LastDataRecord = 0; LastDataRecordSize = 0; LastDataRecordPointer = 0; LastOffset = 0; int comdatsSoFar = 0; // Search for LEDATA, LIDATA and FIXUPP records for this segment for (RecNum = 0; RecNum < NumRecords; RecNum++) { if (Records[RecNum].Type2 == OMF_LEDATA) { // LEDATA record Records[RecNum].Index = 3; // Initialize record reading Segment = Records[RecNum].GetIndex();// Read segment number if ((Segment & 0xC000) == 0x4000) { // Refers to Borland communal section Segment = (Segment & ~0x4000) + FirstComDatSection - 1; } if (Segment != SegNum) continue; // Does not refer to this segment RecOffset = Records[RecNum].GetNumeric();// Read offset of this record RecSize = Records[RecNum].End - Records[RecNum].Index; // Calculate size of data LastDataRecord = RecNum; // Save for later FIXUPP that refers to this record if (RecOffset < LastOffset + LastDataRecordSize && LastOffset < RecOffset + RecSize) { // Overlapping data records if (RecOffset + 8 < LastOffset + LastDataRecordSize || Segments[SegNum].Type != 1) { // Overlapping data by more than 7 bytes or not executable code err.submit(1207); } else { // Possibly backpatched code err.submit(1208); // Warning err.ClearError(1208); // Report only once } } LastDataRecordSize = RecSize; LastDataRecordPointer = Records[RecNum].buffer + Records[RecNum].FileOffset + Records[RecNum].Index; LastOffset = RecOffset; // Save offset for subsequent FIXUPP records // Check if data within segment if (RecOffset + RecSize > SegmentSize) { err.submit(2309, GetSegmentName(Segment)); continue; } // Put raw data into temporary buffer memcpy(TempBuf.Buf() + RecOffset, LastDataRecordPointer, RecSize); } // Finished with LEDATA record if (Records[RecNum].Type2 == OMF_LIDATA) { // LIDATA record Records[RecNum].Index = 3; // Initialize record reading Segment = Records[RecNum].GetIndex(); if (Segment != SegNum) continue; // Does not refer to this segment LastDataRecord = RecNum; // Save for later FIXUPP that refers to this record RecOffset = Records[RecNum].GetNumeric();// Read offset if (RecOffset > SegmentSize) { err.submit(2310); continue; // Error: outside bounds } // Unpack LIDATA blocks recursively RecSize = Records[RecNum].UnpackLIDATABlock(TempBuf.Buf() + RecOffset, SegmentSize - RecOffset); if (RecOffset < LastOffset + LastDataRecordSize && LastOffset < RecOffset + RecSize) { // Overlapping data records err.submit(1207); // Warning } LastDataRecordSize = RecSize; // Save data size LastOffset = RecOffset; // Save offset for subsequent FIXUPP records } // Finished with LIDATA record if (Records[RecNum].Type2 == OMF_COMDAT) { // COMDAT record. Records[RecNum].Index = 3; // Initialize record reading uint16 flags = Records[RecNum].GetByte(); if ((flags&1)==0) { // not a continuation ++comdatsSoFar; LastDataRecord = RecNum; // Save for later FIXUPP that refers to this record } Segment = FirstComDatSection + comdatsSoFar-1; if (SegNum != Segment) continue; uint16 attribs = Records[RecNum].GetByte(); Records[RecNum].GetByte(); // align (ignore) RecOffset = Records[RecNum].GetNumeric(); Records[RecNum].GetIndex(); // type (ignore) if ((attribs&0xF)==0) { Records[RecNum].GetIndex(); // public base uint16 publicSegment = Records[RecNum].GetIndex(); if (publicSegment==0) Records[RecNum].GetIndex(); // public frame (ignore) } Records[RecNum].GetIndex(); // public name (ignore) RecSize = Records[RecNum].End - Records[RecNum].Index; // Calculate size of data LastDataRecord = RecNum; // Save for later FIXUPP that refers to this record LastDataRecordSize = RecSize; LastDataRecordPointer = Records[RecNum].buffer + Records[RecNum].Index+Records[RecNum].FileOffset; LastOffset = RecOffset; // Put raw data into temporary buffer memcpy(TempBuf.Buf() + RecOffset, LastDataRecordPointer, RecSize); } // Finished with COMDAT record if (Records[RecNum].Type2 == OMF_FIXUPP) { // FIXUPP record if (Segment != SegNum) continue; // Does not refer to this segment Records[RecNum].Index = 3; if (Records[LastDataRecord].Type2 == OMF_LEDATA) { // FIXUPP for last LEDATA record // Make relocation records MakeRelocations(Segment, RecNum, LastOffset, LastDataRecordSize, (uint8*)TempBuf.Buf()); } else if (Records[RecNum].Index < Records[RecNum].End) { // Non-empty FIXUPP record does not refer to LEDATA record if (Records[LastDataRecord].Type2 == OMF_COMDAT) { // FIXUPP for last COMDAT record // Make relocation records MakeRelocations(Segment, RecNum, LastOffset, LastDataRecordSize, (uint8*)TempBuf.Buf()); } else if (Records[LastDataRecord].Type2 == OMF_LIDATA) { err.submit(2311); // Error: Relocation of iterated data not supported } else { err.submit(2312); // Does not refer to data record } } } } // End of loop to search for LEDATA, LIDATA and FIXUPP records for this segment // Transfer raw data from TempBuf to SegmentData buffer BufOffset = SegmentData.Push(TempBuf.Buf(), SegmentSize); // Remember offset into SegmentData Segments[SegNum].BufOffset = BufOffset; } // End of first loop through segments // We must put all segments into SegmentData buffer before we assign pointers to // the raw data because otherwise the SegmentData buffer might me reallocated // when it grows and the pointers become invalid. This is the reasons why we // have two loops through the segments here. // Second loop through segments int totalcodesize=0; for (SegNum = 1; SegNum <= NumSegments; SegNum++) { // Pointer to merged raw data uint8 * RawDatap = (uint8*)SegmentData.Buf() + Segments[SegNum].BufOffset; // Size of raw data uint32 InitSize = (Segments[SegNum].Type == 3) ? 0 : Segments[SegNum].Size; // Define segment const char * SegmentName = NameBuffer.Buf() + Segments[SegNum].NameO; Disasm.AddSection(RawDatap, InitSize, Segments[SegNum].Size, Segments[SegNum].Offset, Segments[SegNum].Type, Segments[SegNum].Align, Segments[SegNum].WordSize, SegmentName); if (Segments[SegNum].Type == 1 || Segments[SegNum].Type == 0x1001) { totalcodesize += Segments[SegNum].Size; } } } // MakeRelocations void COMF2ASM::MakeRelocations(int32 Segment, uint32 RecNum, uint32 SOffset, uint32 RSize, uint8 * SData) { // Make relocations for object and executable files // Parameters: // Segment = segment index of last LEDATA record // RecNum = FIXUPP record number // SOffset = segment relative offset of last LEDATA record // RSize = Size of last LEDATA record // SData = pointer to raw segment data uint32 Frame, Target, TargetDisplacement; // Contents of FIXUPP record uint8 byte1, byte2; // First two bytes of subrecord int32 Inline; // Inline address or addend in relocation source //int16 InlineSeg; // Segment address stored in relocation source int32 Addend; // Correction to add to target address int32 SourceSize; // Size of relocation source uint32 RelType; // Relocation type, as defined in disasm.h int32 TargetSegment; // Target segment or group uint32 TargetOffset; // Target offset uint32 TargetSymbol; // Symbol index of target uint32 ReferenceIndex; // Segment/group index of reference frame // Bitfields in subrecords OMF_SLocat Locat; // Structure of first two bytes of FIXUP subrecord swapped = Locat field OMF_SFixData FixData; // Structure of FixData field in FIXUP subrecord of FIXUPP record OMF_STrdDat TrdDat; // Structure of Thread Data field in THREAD subrecord of FIXUPP record Records[RecNum].Index = 3; // Loop through entries in record while (Records[RecNum].Index < Records[RecNum].End) { // Read first byte byte1 = Records[RecNum].GetByte(); if (byte1 & 0x80) { // This is a FIXUP subrecord Frame = 0; Target = 0; TargetDisplacement = 0; Addend = 0; ReferenceIndex = 0; // read second byte byte2 = Records[RecNum].GetByte(); // swap bytes and put into byte12 bitfield Locat.bytes[1] = byte1; Locat.bytes[0] = byte2; // Read FixData FixData.b = Records[RecNum].GetByte(); // Read conditional fields if (FixData.s.F) { // Frame specified by previously define thread // Does anybody still use compression of repeated fixup targets? // I don't care to support this if it is never used err.submit(2313); // Error message: not supported continue; } else { if (FixData.s.Frame < 4) { // Frame datum field present Frame = Records[RecNum].GetIndex(); } else Frame = 0; switch (FixData.s.Frame) { // Frame method case 0: // F0: segment ReferenceIndex = Frame; break; case 1: // F1: group // Groups defined after segments. Add number of segments to get group index ReferenceIndex = Frame + NumSegments; break; default: case 2: // F2: external symbol ReferenceIndex = 0; break; case 4: // F4: traget frame = source frame Frame = Segment; break; case 5: // F5: target frame = target segment Frame = 0; break; } } if (FixData.s.T == 0) { // Target specified Target = Records[RecNum].GetIndex(); if ((Target & 0xC000) == 0x4000) { // Refers to Borland communal section Target = (Target & ~0x4000) + FirstComDatSection - 1; } //uint32 TargetMethod = FixData.s.Target + FixData.s.P * 4; } else { // Target specified in previous thread // Does anybody still use compression of repeated fixup targets? // I don't care to support this if it is never used err.submit(2313); // Error message: not supported continue; } if (FixData.s.P == 0) { TargetDisplacement = Records[RecNum].GetNumeric(); } if (!SData || Locat.s.Offset > RSize) { err.submit(2032); // Relocation points outside segment return; } // Get inline addend and check relocation method // Pointer to relocation source inline in raw data: uint8 * inlinep = SData + SOffset + Locat.s.Offset; Inline = 0; SourceSize = 0; //InlineSeg = 0; TargetSegment = 0; TargetOffset = 0; TargetSymbol = 0; // Relocation type if (Locat.s.M) { // Segment relative RelType = 8; } else { // (E)IP relative RelType = 2; } switch (Locat.s.Location) {// Relocation method case OMF_Fixup_8bit: // 8 bit SourceSize = 1; Inline = *(int8*)inlinep; break; case OMF_Fixup_16bit: // 16 bit SourceSize = 2; Inline = *(int16*)inlinep; break; case OMF_Fixup_32bit: // 32 bit SourceSize = 4; Inline = *(int32*)inlinep; break; case OMF_Fixup_Far: // far 16+16 bit RelType = 0x400; SourceSize = 4; Inline = *(int16*)inlinep; break; case OMF_Fixup_Farword: // far 32+16 bit case OMF_Fixup_Pharlab48: RelType = 0x400; SourceSize = 6; Inline = *(int32*)inlinep; break; case OMF_Fixup_Segment: // segment selector if (TargetDisplacement || FixData.s.Target == 2) { // An offset is specified or an external symbol. // Segment of symbol is required (seg xxx) RelType = 0x200; } else { // A segment name or group name is required RelType = 0x100; }; SourceSize = 2; Inline = *(int16*)inlinep; break; case OMF_Fixup_16bitLoader: // 16-bit loader resolved RelType = 0x21; SourceSize = 2; Inline = *(int16*)inlinep; break; case OMF_Fixup_32bitLoader: // 32-bit loader resolved RelType = 0x21; SourceSize = 4; Inline = *(int32*)inlinep; break; default: // unknown or not supported RelType = 0; SourceSize = 0; Inline = 0; } // end switch // Offset of relocation source uint32 SourceOffset = SOffset + Locat.s.Offset; // Relocation type: direct or (E)IP-relative if (RelType == 2) { // (E)IP-relative // Correct for difference between source address and end of instruction Addend = -SourceSize; } // Check target method switch (FixData.s.Target) { // = Target method modulo 4 case 0: // T0 and T4: Target = segment // Local or public symbol TargetSegment = Target; // Target segment TargetOffset = TargetDisplacement; // Target offset if (RelType != 0x100) { // Add inline to target address, except if target is a segment only TargetOffset += Inline; Addend -= Inline; // Avoid adding Inline twice } break; case 1: // T1 and T5: Target = segment group // Warning: this method has not occurred. Not tested! // Groups are numbered in sequence after segments in Disasm. Add number of segments to group index TargetSegment = Target + NumSegments;// Target group TargetOffset = TargetDisplacement; // Target offset if (RelType != 0x100) { // Add inline to target address, except if target is a segment only TargetOffset += Inline; Addend -= Inline; // Avoid adding Inline twice } break; case 2: // T2 and T6: Target = external symbol // Translate old EXTDEF index to new symbol table index if (Target < ExtdefTranslation.GetNumEntries()) { TargetSymbol = ExtdefTranslation[Target]; } break; default: // Unknown method err.submit(2314, FixData.s.Target + FixData.s.P * 4); } if (TargetSymbol == 0) { // Make symbol record for target TargetSymbol = Disasm.AddSymbol(TargetSegment, TargetOffset, 0, 0, 2, 0, 0); } if (FixData.s.Frame == 4 && FixData.s.Target + FixData.s.P*4 == 6) { // Note: // Frame method F4 is apparently used by 16-bit Borland compiler for // indicating floating point instructions that can be emulated if no // 8087 processor is present. I can't find this documented anywhere. // I don't know what the exact criterion is for indicating that a FIXUP // subrecord is not a relocation record but a f.p. emulating record. // I have chosen to consider all subrecords with frame method F4 and // target method T6 to be ignored. ; } else { // This is a proper relocation subrecord Disasm.AddRelocation(Segment, SourceOffset, Addend, RelType, SourceSize, TargetSymbol, ReferenceIndex); } } else { // This is a THREAD subrecord. // I don't think this feature for compressing fixup data is // used any more, if it ever was. I am not supporting it here. // Frame threads can be safely ignored. A target thread cannot // be ignored if there is any reference to it. The error is // reported above at the reference to a target thread, not here. TrdDat.b = byte1; // Put byte into bitfield if (TrdDat.s.Method < 4) { // Make sure we read this correctly, even if ignored Records[RecNum].GetIndex(); // has index field if method < 4 ? } } } // Finished loop through subrecords if (Records[RecNum].Index != Records[RecNum].End) err.submit(1203); // Check for consistency }