forked from KolibriOS/kolibrios
Added objconv port.
git-svn-id: svn://kolibrios.org@9683 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
803
programs/develop/objconv/cof2omf.cpp
Normal file
803
programs/develop/objconv/cof2omf.cpp
Normal file
@@ -0,0 +1,803 @@
|
||||
/**************************** cof2omf.cpp ********************************
|
||||
* Author: Agner Fog
|
||||
* Date created: 2007-02-03
|
||||
* Last modified: 2007-02-03
|
||||
* Project: objconv
|
||||
* Module: cof2omf.cpp
|
||||
* Description:
|
||||
* Module for converting 32 bit PE/COFF file to OMF file
|
||||
*
|
||||
* Copyright 2007-2008 GNU General Public License http://www.gnu.org/licenses
|
||||
*****************************************************************************/
|
||||
#include "stdafx.h"
|
||||
|
||||
CCOF2OMF::CCOF2OMF () {
|
||||
// Constructor
|
||||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
|
||||
void CCOF2OMF::Convert() {
|
||||
// Do the conversion
|
||||
if (WordSize != 32) {
|
||||
err.submit(2317, WordSize); // Wrong word size
|
||||
return;
|
||||
}
|
||||
|
||||
// Allocate variable size buffers
|
||||
SectionBuffer.SetNum(NSections + 2); // Allocate buffer for section translation list
|
||||
SectionBuffer.SetZero(); // Initialize
|
||||
SymbolBuffer.SetNum(NumberOfSymbols + 1); // Allocate buffer for symbol translation list
|
||||
SymbolBuffer.SetZero(); // Initialize
|
||||
NameBuffer.Push(0, 1); // Make first entry in NameBuffer empty
|
||||
|
||||
// Call the subfunctions
|
||||
ToFile.SetFileType(FILETYPE_OMF); // Set type of output file
|
||||
MakeSegmentList(); // Make temporary segment conversion list
|
||||
MakeSymbolList(); // Make temporary symbol conversion list
|
||||
MakeRelocationsList(); // Make temporary list of relocations (fixups) and sort it
|
||||
MakeLNAMES(); // Make THEADR and LNAMES records
|
||||
MakeSEGDEF(); // Make SEGDEF and GRPDEF records
|
||||
MakeEXTDEF(); // Make EXTDEF records
|
||||
MakePUBDEF(); // Make PUBDEF records
|
||||
MakeLEDATA(); // Make LEDATA, LIDATA and FIXUPP records
|
||||
MakeMODEND(); // Finish output file
|
||||
*this << ToFile; // Take over new file buffer containing the converted file
|
||||
}
|
||||
|
||||
|
||||
void CCOF2OMF::MakeSegmentList() {
|
||||
// Make temporary segment conversion list
|
||||
const char * oldname; // Old name of section
|
||||
uint32 namei; // Name index into NameBuffer
|
||||
uint32 align; // Segment alignment = 2^align
|
||||
int32 align2; // align2 = 2^align
|
||||
uint32 flags; // Old flags
|
||||
int i, j; // Loop counters
|
||||
int oldsec; // Old section number
|
||||
|
||||
// Loop through old sections
|
||||
for (j = 0; j < NSections; j++) {
|
||||
// Old section number
|
||||
oldsec = j + 1;
|
||||
|
||||
// Get old section header
|
||||
SCOFF_SectionHeader * pSectionHeader = &SectionHeaders[j];
|
||||
|
||||
// Get name
|
||||
oldname = GetSectionName(pSectionHeader->Name);
|
||||
|
||||
// Check for debug sections
|
||||
if (strnicmp(oldname,"debug",5) == 0 || strnicmp(oldname+1,"debug",5) == 0) {
|
||||
// This is a debug section
|
||||
if (cmd.DebugInfo == CMDL_DEBUG_STRIP) {
|
||||
// Remove debug info
|
||||
SectionBuffer[oldsec].NewNumber = 0;
|
||||
cmd.CountDebugRemoved();
|
||||
continue;
|
||||
}
|
||||
else if (cmd.InputType != cmd.OutputType) {
|
||||
err.submit(1029); // Warn that debug information is incompatible
|
||||
}
|
||||
}
|
||||
|
||||
// Check for directive sections
|
||||
if (strnicmp(oldname,".drectve",8) == 0 || (pSectionHeader->Flags & (PE_SCN_LNK_INFO | PE_SCN_LNK_REMOVE))) {
|
||||
// This is a directive section
|
||||
if (cmd.ExeptionInfo) {
|
||||
// Remove directive section
|
||||
SectionBuffer[oldsec].NewNumber = 0;
|
||||
cmd.CountExceptionRemoved();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Get alignment
|
||||
align = (pSectionHeader->Flags & PE_SCN_ALIGN_MASK) / PE_SCN_ALIGN_1;
|
||||
if (align > 0) align--; // Alignment = 2^align
|
||||
align2 = 1 << align; // 2^align
|
||||
|
||||
// Check for previous sections with same name
|
||||
for (i = 0; i < SectionBufferNum; i++) {
|
||||
if (strcmp(oldname, NameBuffer.Buf() + SectionBuffer[i].OldName) == 0) break; // Found same name
|
||||
}
|
||||
if (i < SectionBufferNum) {
|
||||
// Previous section with same name found.
|
||||
// i = first section with this name, oldsec = current section with this name
|
||||
SectionBuffer[oldsec] = SectionBuffer[i]; // Copy record
|
||||
SectionBuffer[oldsec].NewNameI = 0; // Indicate this is not the first record
|
||||
|
||||
// Check if alignment is the same
|
||||
if (align != SectionBuffer[i].Align) {
|
||||
err.submit(1060, oldname); // Warning different alignments
|
||||
if (align > SectionBuffer[i].Align) SectionBuffer[i].Align = align; // Use highest alignment
|
||||
}
|
||||
|
||||
// Get section header
|
||||
SectionBuffer[oldsec].psechdr = pSectionHeader;
|
||||
|
||||
// Get size of this section
|
||||
SectionBuffer[oldsec].Size = pSectionHeader->SizeOfRawData;
|
||||
|
||||
// Get offset relative to first section with same name
|
||||
SectionBuffer[oldsec].Offset = SectionBuffer[i].Offset + SectionBuffer[i].SegmentSize;
|
||||
|
||||
// Align this section (We are aligning each section in the segment)
|
||||
SectionBuffer[oldsec].Offset = (SectionBuffer[oldsec].Offset + align2 - 1) & (- align2);
|
||||
|
||||
// Update total size of all sections with same name
|
||||
SectionBuffer[i].SegmentSize = SectionBuffer[oldsec].Offset + SectionBuffer[oldsec].Size;
|
||||
}
|
||||
else {
|
||||
// No previous section found with same name. Make SOMFSegmentList record
|
||||
SectionBufferNum = oldsec + 1; // End of entries in SectionBuffer
|
||||
|
||||
// Assign a number to this segment
|
||||
SectionBuffer[oldsec].NewNumber = ++NumSegments;
|
||||
SectionBuffer[oldsec].NewNameI = NumSegments + OMF_LNAME_LAST;
|
||||
|
||||
// Point to old section header
|
||||
SectionBuffer[oldsec].psechdr = pSectionHeader;
|
||||
|
||||
// Give it a name
|
||||
namei = NameBuffer.PushString(oldname); // Save name in buffer, because it is volatile
|
||||
SectionBuffer[oldsec].OldName = namei; // Index to name
|
||||
// Segment names like .text and _TEXT are both common. No need to convert the name
|
||||
// Only restriction is length < 256.
|
||||
// Do we need a unique segment name if the alignment is different from segments
|
||||
// with same name in another module?
|
||||
if (strlen(oldname) > 255) {
|
||||
// Segment name too long. This is very unlikely
|
||||
namei = NameBuffer.Push(oldname, 255); // Make truncated name
|
||||
NameBuffer.Push(0, 1); // Terminate by zero
|
||||
}
|
||||
SectionBuffer[oldsec].NewName = namei; // Index to name
|
||||
|
||||
// Size
|
||||
SectionBuffer[oldsec].Size = pSectionHeader->SizeOfRawData;
|
||||
SectionBuffer[oldsec].SegmentSize = pSectionHeader->SizeOfRawData;
|
||||
SectionBuffer[oldsec].Offset = 0;
|
||||
|
||||
// Alignment
|
||||
SectionBuffer[oldsec].Align = align;
|
||||
|
||||
// Segment type
|
||||
flags = pSectionHeader->Flags;
|
||||
|
||||
// Get segment class
|
||||
if (flags & (PE_SCN_CNT_CODE | PE_SCN_MEM_EXECUTE)) {
|
||||
// Code segment
|
||||
SectionBuffer[oldsec].Class = OMF_LNAME_CODE;
|
||||
}
|
||||
else if (flags & PE_SCN_CNT_UNINIT_DATA) {
|
||||
// Uninitialized data
|
||||
SectionBuffer[oldsec].Class = OMF_LNAME_BSS;
|
||||
}
|
||||
else if (!(flags & PE_SCN_MEM_WRITE)) {
|
||||
// Read only
|
||||
SectionBuffer[oldsec].Class = OMF_LNAME_CONST;
|
||||
}
|
||||
else {
|
||||
// Normal data
|
||||
SectionBuffer[oldsec].Class = OMF_LNAME_DATA;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add 1 to section count because new section numbers are 1-based
|
||||
SectionBufferNum = NSections + 1;
|
||||
}
|
||||
|
||||
|
||||
void CCOF2OMF::MakeSymbolList() {
|
||||
// Make temporary symbol conversion list
|
||||
int isym = 0; // current symbol table entry
|
||||
//int jsym = 0; // auxiliary entry number
|
||||
union { // Pointer to symbol table
|
||||
SCOFF_SymTableEntry * p; // Normal pointer
|
||||
int8 * b; // Used for address calculation
|
||||
} Symtab;
|
||||
|
||||
Symtab.p = SymbolTable; // Set pointer to begin of SymbolTable
|
||||
|
||||
// Loop through symbol table
|
||||
while (isym < NumberOfSymbols) {
|
||||
// Check scope
|
||||
if (Symtab.p->s.StorageClass == COFF_CLASS_EXTERNAL) {
|
||||
// Scope is public or external
|
||||
|
||||
if (Symtab.p->s.SectionNumber > 0) {
|
||||
|
||||
// Symbol is public
|
||||
SymbolBuffer[isym].Scope = S_PUBLIC; // Scope = public
|
||||
SymbolBuffer[isym].NewIndex = ++NumPublicSymbols; // Public symbol number
|
||||
// Get name
|
||||
SymbolBuffer[isym].Name = NameBuffer.PushString(GetSymbolName(Symtab.p->s.Name));
|
||||
|
||||
// Find section in SectionBuffer
|
||||
uint32 OldSection = Symtab.p->s.SectionNumber;
|
||||
SymbolBuffer[isym].Segment = SectionBuffer[OldSection].NewNumber; // New segment number
|
||||
|
||||
// Calculate offset = offset into old section + offset of old section to first section with same name
|
||||
SymbolBuffer[isym].Offset = Symtab.p->s.Value + SectionBuffer[OldSection].Offset;
|
||||
}
|
||||
else if (Symtab.p->s.SectionNumber == 0) {
|
||||
|
||||
// Symbol is external
|
||||
SymbolBuffer[isym].Scope = S_EXTERNAL; // Scope = external
|
||||
SymbolBuffer[isym].NewIndex = ++NumExternalSymbols; // External symbol number
|
||||
SymbolBuffer[isym].Name = NameBuffer.PushString(GetSymbolName(Symtab.p->s.Name));
|
||||
}
|
||||
else if (Symtab.p->s.SectionNumber == COFF_SECTION_ABSOLUTE) {
|
||||
|
||||
// Symbol is public, absolute
|
||||
SymbolBuffer[isym].Scope = S_PUBLIC; // Scope = public
|
||||
SymbolBuffer[isym].NewIndex = ++NumPublicSymbols; // Public symbol number
|
||||
// Get name
|
||||
SymbolBuffer[isym].Name = NameBuffer.PushString(GetSymbolName(Symtab.p->s.Name));
|
||||
|
||||
SymbolBuffer[isym].Segment = 0; // 0 indicates absolute
|
||||
|
||||
SymbolBuffer[isym].Offset = Symtab.p->s.Value; // Store value in Offset
|
||||
}
|
||||
else {
|
||||
// COFF_SECTION_DEBUG, COFF_SECTION_N_TV, COFF_SECTION_P_TV
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
// Skip auxiliary symbol table entries and increment pointer
|
||||
isym += Symtab.p->s.NumAuxSymbols + 1;
|
||||
Symtab.b += (Symtab.p->s.NumAuxSymbols + 1) * SIZE_SCOFF_SymTableEntry;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CCOF2OMF::MakeRelocationsList() {
|
||||
// Make temporary list of relocations (fixups) and sort it
|
||||
uint32 i; // Relocation number in old file
|
||||
int j; // Section number of relocation source in old file
|
||||
int isym; // Symbol table index in old file
|
||||
//int32 * paddend = 0; // Pointer to inline addend
|
||||
uint32 TargetOldSection; // Section number of relocation target in old file
|
||||
|
||||
SOMFRelocation NewRel; // Entry in RelocationBuffer
|
||||
|
||||
union { // Pointer to symbol table
|
||||
SCOFF_SymTableEntry * p; // Normal pointer
|
||||
int8 * b; // Used for address calculation
|
||||
} Symtab;
|
||||
|
||||
union { // Pointer to relocation entry
|
||||
SCOFF_Relocation * p; // pointer to record
|
||||
int8 * b; // used for address calculation and incrementing
|
||||
} Reloc;
|
||||
|
||||
// Loop through section headers of old file
|
||||
for (j = 0; j < NSections; j++) {
|
||||
SCOFF_SectionHeader * SectionHeaderp = &SectionHeaders[j];
|
||||
|
||||
// Pointer to first relocation entry in section
|
||||
Reloc.b = Buf() + SectionHeaderp->PRelocations;
|
||||
|
||||
// Loop through relocations in section
|
||||
for (i = 0; i < SectionHeaderp->NRelocations; i++) {
|
||||
|
||||
// Find symbol table entry
|
||||
isym = Reloc.p->SymbolTableIndex;
|
||||
if ((uint32)isym >= (uint32)NumberOfSymbols) {
|
||||
err.submit(2040); // SymbolTableIndex points outside Symbol Table
|
||||
isym = 0;
|
||||
}
|
||||
Symtab.p = SymbolTable; // Set pointer to begin of SymbolTable
|
||||
Symtab.b += SIZE_SCOFF_SymTableEntry * isym; // Calculate address of entry isym
|
||||
|
||||
// Find inline addend
|
||||
if (Reloc.p->Type < COFF32_RELOC_SEG12) {
|
||||
//paddend = (int32*)(Buf()+SectionHeaderp->PRawData+Reloc.p->VirtualAddress);
|
||||
}
|
||||
//else paddend = 0;
|
||||
|
||||
// Make entry in RelocationBuffer
|
||||
// Relocation type
|
||||
switch (Reloc.p->Type) {
|
||||
case COFF32_RELOC_DIR32: // Direct 32 bit
|
||||
NewRel.Mode = 1; break; // 0 = EIP-relative, 1 = direct
|
||||
|
||||
case COFF32_RELOC_REL32: // 32 bit EIP relative
|
||||
NewRel.Mode = 0; break; // 0 = EIP-relative, 1 = direct
|
||||
|
||||
case COFF32_RELOC_ABS: // Ignore
|
||||
continue;
|
||||
|
||||
default: // Other. Not supported
|
||||
NewRel.Mode = -1; // -1 = unsupported.
|
||||
// Postpone error message in case it refers to a debug section that is being removed
|
||||
NewRel.TargetOffset = Reloc.p->Type; // Remember relocation type
|
||||
//err.submit(2030, Reloc.p->Type); continue; // Unsupported relocation type
|
||||
break;
|
||||
}
|
||||
// Get source
|
||||
NewRel.Section = j + 1; // Section number in old file
|
||||
NewRel.SourceOffset = Reloc.p->VirtualAddress;// Offset of source relative to section
|
||||
|
||||
// Get target
|
||||
if (Symtab.p->s.SectionNumber > 0) {
|
||||
// Local
|
||||
NewRel.Scope = S_LOCAL; // 0 = local, 2 = external
|
||||
TargetOldSection = Symtab.p->s.SectionNumber; // Target section
|
||||
if (TargetOldSection > uint32(NSections)) {
|
||||
// SectionNumber out of range
|
||||
err.submit(2035); continue;
|
||||
}
|
||||
// Segment index of target in new file:
|
||||
NewRel.TargetSegment = SectionBuffer[TargetOldSection].NewNumber;
|
||||
// Offset relative to old section
|
||||
NewRel.TargetOffset = Symtab.p->s.Value;
|
||||
// Add offset relative to first section with same name to get offset relative to new segment
|
||||
NewRel.TargetOffset += SectionBuffer[TargetOldSection].Offset;
|
||||
}
|
||||
else {
|
||||
// External
|
||||
NewRel.Scope = S_EXTERNAL; // 0 = local, 2 = external
|
||||
NewRel.TargetOffset = 0; // Any addend is inline
|
||||
// Find EXTDEF index in SymbolBuffer
|
||||
NewRel.TargetSegment = SymbolBuffer[isym].NewIndex;
|
||||
}
|
||||
|
||||
// Put NewRel into RelocationBuffer
|
||||
RelocationBuffer.Push(NewRel);
|
||||
|
||||
// Increment pointer to relocation record
|
||||
Reloc.b += SIZE_SCOFF_Relocation; // Next relocation record
|
||||
}
|
||||
}
|
||||
// Sort RelocationBuffer
|
||||
RelocationBuffer.Sort();
|
||||
|
||||
// Store number of relocations
|
||||
NumRelocations = RelocationBuffer.GetNumEntries();
|
||||
|
||||
// Check for overlapping relocation sources
|
||||
for (uint32 i = 1; i < RelocationBuffer.GetNumEntries(); i++) {
|
||||
if (RelocationBuffer[i].Section == RelocationBuffer[i-1].Section
|
||||
&& RelocationBuffer[i].SourceOffset >= RelocationBuffer[i-1].SourceOffset
|
||||
&& RelocationBuffer[i].SourceOffset < RelocationBuffer[i-1].SourceOffset + 4
|
||||
&& (RelocationBuffer[i].Mode == 0 || RelocationBuffer[i].Mode == 1)) {
|
||||
err.submit(2210); // Error: overlapping relocation sources
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CCOF2OMF::MakeLNAMES() {
|
||||
// Make THEADR and LNAMES records
|
||||
int Sec; // Loop counter
|
||||
uint32 NameI; // Name index
|
||||
|
||||
// Make first record in output file = Translator header
|
||||
ToFile.StartRecord(OMF_THEADR);
|
||||
// Remove path from file name and limit length
|
||||
char * ShortName = CLibrary::ShortenMemberName(OutputFileName);
|
||||
ToFile.PutString(ShortName);
|
||||
ToFile.EndRecord();
|
||||
|
||||
// Make LNAMES record containing names of segments, groups and classes
|
||||
ToFile.StartRecord(OMF_LNAMES);
|
||||
|
||||
// Store default group and class names
|
||||
ToFile.PutString("FLAT"); // 1: FLAT = group name
|
||||
ToFile.PutString("CODE"); // 2: CODE = class name for code
|
||||
ToFile.PutString("DATA"); // 3: DATA = class name for data segment
|
||||
ToFile.PutString("BSS"); // 4: BSS = class name for uninitialized data
|
||||
ToFile.PutString("CONST"); // 5: CONST = class name for readonly data
|
||||
|
||||
NameI = OMF_LNAME_LAST + 1; // Index of next name
|
||||
|
||||
// Get segment names
|
||||
for (Sec = 0; Sec < SectionBufferNum; Sec++) {
|
||||
if (SectionBuffer[Sec].NewNameI == NameI) {
|
||||
// Found next segment name to add
|
||||
// Check if current record too big
|
||||
if (ToFile.GetSize() >= 1024 - 256) { // Max size = 1024
|
||||
ToFile.EndRecord(); // End current record
|
||||
ToFile.StartRecord(OMF_LNAMES); // Start new LNAMES record
|
||||
}
|
||||
// Store name of this segment
|
||||
ToFile.PutString(NameBuffer.Buf() + SectionBuffer[Sec].NewName);
|
||||
NameI++; // Ready for next name
|
||||
}
|
||||
}
|
||||
// End LNAMES record
|
||||
ToFile.EndRecord();
|
||||
}
|
||||
|
||||
|
||||
void CCOF2OMF::MakeSEGDEF() {
|
||||
// Make SEGDEF and GRPDEF records
|
||||
int Sec; // Index into SectionBuffer
|
||||
uint32 SegNum = 0; // Segment number in new file
|
||||
OMF_SAttrib Attr; // Segment attributes bitfield
|
||||
uint32 align; // Alignment in new file
|
||||
|
||||
// Loop through SectionBuffer
|
||||
for (Sec = 0; Sec < SectionBufferNum; Sec++) {
|
||||
|
||||
if (SectionBuffer[Sec].NewNumber == SegNum+1 && SectionBuffer[Sec].NewNameI) {
|
||||
|
||||
// New segment found
|
||||
SegNum++; // Segment number
|
||||
|
||||
// Make a SEGDEF record for this segment
|
||||
ToFile.StartRecord(OMF_SEGDEF + 1); // Odd record number = 32 bit
|
||||
|
||||
// Attributes bitfield
|
||||
Attr.u.P = 1; // Indicate 32 bit segment
|
||||
Attr.u.B = 0; // 1 indicates 4 Gbytes
|
||||
Attr.u.C = 2; // Indicates public combination
|
||||
|
||||
// Translate alignment
|
||||
switch(SectionBuffer[Sec].Align) {
|
||||
case 0: // Align by 1
|
||||
align = 1; break;
|
||||
|
||||
case 1: // Align by 2
|
||||
align = 2; break;
|
||||
|
||||
case 2: // Align by 4
|
||||
align = 5; break;
|
||||
|
||||
case 3: // Align by 8 not supported, use 16
|
||||
case 4: // Align by 16
|
||||
align = 3; break;
|
||||
|
||||
default: // 32 or higher. Use 'page' alignment
|
||||
// Note: this gives 256 on some systems, 4096 on other systems
|
||||
align = 4;
|
||||
if (SectionBuffer[Sec].Align > 8) {
|
||||
err.submit(1205, 1 << SectionBuffer[Sec].Align); // Warning: alignment not supported
|
||||
}
|
||||
}
|
||||
Attr.u.A = align; // Put alignment into bitfield
|
||||
|
||||
ToFile.PutByte(Attr.b); // Save attributes bitfield
|
||||
|
||||
// Segment length
|
||||
ToFile.PutNumeric(SectionBuffer[Sec].SegmentSize);
|
||||
|
||||
// Segment name given by index into LNAMES record
|
||||
ToFile.PutIndex(SectionBuffer[Sec].NewNameI);
|
||||
|
||||
// Class name index
|
||||
ToFile.PutIndex(SectionBuffer[Sec].Class);
|
||||
|
||||
// Overlay index (ignored)
|
||||
ToFile.PutIndex(0);
|
||||
|
||||
// End SEGDEF record
|
||||
ToFile.EndRecord();
|
||||
}
|
||||
}
|
||||
|
||||
// Make GRPDEF record for the FLAT group
|
||||
ToFile.StartRecord(OMF_GRPDEF); // Strart GRPDEF record
|
||||
ToFile.PutIndex(OMF_LNAME_FLAT); // Index of name "FLAT"
|
||||
// No need to put segment indices into the GRPDEF record when group is FLAT
|
||||
// End GRPDEF record
|
||||
ToFile.EndRecord();
|
||||
}
|
||||
|
||||
|
||||
void CCOF2OMF::MakeEXTDEF() {
|
||||
// Make EXTDEF records
|
||||
uint32 j; // SymbolBuffer entry index
|
||||
uint32 ExtSymNum = 0; // External symbol number
|
||||
|
||||
if (NumExternalSymbols > 0) { // Are there any external symbols?
|
||||
|
||||
// Make EXTDEF record for one or more symbols
|
||||
ToFile.StartRecord(OMF_EXTDEF); // Start record
|
||||
|
||||
// Loop through SymbolBuffer
|
||||
for (j = 0; j < SymbolBuffer.GetNumEntries(); j++) {
|
||||
if (SymbolBuffer[j].Scope == S_EXTERNAL && SymbolBuffer[j].NewIndex == ExtSymNum+1) {
|
||||
// Found external symbol
|
||||
ExtSymNum++; // Symbol number
|
||||
|
||||
// Check if current record too big
|
||||
if (ToFile.GetSize() >= 1024 - 257) {// Max size = 1024
|
||||
ToFile.EndRecord(); // End current record
|
||||
ToFile.StartRecord(OMF_EXTDEF); // Start new EXTDEF record
|
||||
}
|
||||
// Put symbol name in record
|
||||
ToFile.PutString(NameBuffer.Buf() + SymbolBuffer[j].Name);
|
||||
|
||||
// Type index
|
||||
ToFile.PutIndex(0); // Not used any more
|
||||
}
|
||||
}
|
||||
ToFile.EndRecord(); // End EXTDEF record
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CCOF2OMF::MakePUBDEF() {
|
||||
// Make PUBDEF records
|
||||
uint32 j; // SymbolBuffer entry index
|
||||
uint32 PubSymNum = 0; // Public symbol number
|
||||
|
||||
// Loop through SymbolBuffer
|
||||
for (j = 0; j < SymbolBuffer.GetNumEntries(); j++) {
|
||||
if (SymbolBuffer[j].Scope == S_PUBLIC && SymbolBuffer[j].NewIndex == PubSymNum+1) {
|
||||
// Found public symbol
|
||||
PubSymNum++; // Symbol number
|
||||
|
||||
// Make PUBDEF record for this symbol
|
||||
ToFile.StartRecord(OMF_PUBDEF + 1); // Start new PUBDEF record, 32 bit
|
||||
|
||||
// Group index
|
||||
uint32 Group = SymbolBuffer[j].Segment ? OMF_LNAME_FLAT : 0; // Group = FLAT, except for absolute symbols
|
||||
ToFile.PutIndex(Group); // Group name index
|
||||
|
||||
// Segment index
|
||||
ToFile.PutIndex(SymbolBuffer[j].Segment);
|
||||
|
||||
// Base frame field if segment = 0
|
||||
if (SymbolBuffer[j].Segment == 0) ToFile.PutWord(0);
|
||||
|
||||
// Put symbol name in record
|
||||
ToFile.PutString(NameBuffer.Buf() + SymbolBuffer[j].Name);
|
||||
|
||||
// Offset relative to segment
|
||||
ToFile.PutNumeric(SymbolBuffer[j].Offset);
|
||||
|
||||
// Type index
|
||||
ToFile.PutIndex(0); // Not used any more
|
||||
|
||||
// End record
|
||||
ToFile.EndRecord(); // End PUBDEF record
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CCOF2OMF::MakeLEDATA() {
|
||||
/*
|
||||
This function makes both LEDATA records, containing binary data, and FIXUPP
|
||||
records, containing relocations.
|
||||
|
||||
The function is quite complicated because the LEDATA and FIXUPP records are
|
||||
mutually interdependent. Some explanation is in place here.
|
||||
|
||||
I am using the word segment for the collection of all sections in the old file
|
||||
having the same name. A section is a record of binary data in the old file.
|
||||
Each section is stored as one or more LEDATA records in the new file.
|
||||
A segment may thus be split into multiple sections, which again may be split
|
||||
into multiple LEDATA records. The sections must be aligned according to the
|
||||
specified alignment for the segment. The LEDATA records need not be aligned,
|
||||
and they may be misaligned for reasons explained below.
|
||||
|
||||
Each LEDATA record is followed by a FIXUPP record containing all relocations
|
||||
referring to a source in the LEDATA record, if any.
|
||||
|
||||
The size of a LEDATA record is limited to 1024 bytes because each entry in
|
||||
the FIXUPP record has only 10 bits for addressing it. Some linkers impose
|
||||
the 1024 bytes size limit to all OMF records, although this limitation is
|
||||
strictly necessary only for LEDATA records. If the code has many relocations
|
||||
then it may be necessary to make a LEDATA record smaller than 1024 bytes
|
||||
in order to avoid that the corresponding FIXUPP record becomes bigger than
|
||||
1024 bytes. Furthermore, the size of a LEDATA record may need adjustment to
|
||||
avoid that a relocation source crosses a LEDATA record boundary.
|
||||
|
||||
I have stored all relocations in a temporary list RelocationBuffer which is
|
||||
sorted by relocation source address in order to make it easier to find all
|
||||
relocations with a source address in the current LEDATA record.
|
||||
*/
|
||||
int Segment; // Segment index in new file
|
||||
int OldSection; // Section index in old file
|
||||
uint32 SegOffset; // Offset of section relative to segment
|
||||
uint32 SectOffset; // Offset of LEDATA record relative to section
|
||||
uint32 CutOff; // Size limit for splitting section into multiple LEDATA records
|
||||
uint32 RelFirst; // Index into RelocationBuffer of first relocation for section/record
|
||||
uint32 RelLast; // Index into RelocationBuffer of last relocation for record + 1
|
||||
uint32 Rel; // Current index into RelocationBuffer
|
||||
uint32 FrameDatum; // Frame datum field in FIXUPP record
|
||||
uint32 TargetDatum; // Target datum field in FIXUPP record
|
||||
uint32 TargetDisplacement; // Target displacement field in FIXUPP record
|
||||
uint32 AlignmentFiller; // Number of unused bytes from end of one section to begin of next section due to alignment
|
||||
|
||||
SOMFRelocation Reloc0; // Reference relocation record for compare and search
|
||||
OMF_SLocat Locat; // Locat bitfield for FIXUPP record
|
||||
OMF_SFixData FixData; // FixData bitfield for FIXUPP record
|
||||
|
||||
// Loop through segment numbers
|
||||
for (Segment = 1; Segment <= NumSegments; Segment++) {
|
||||
SegOffset = 0; // SegOffset = 0 for first section in segment
|
||||
|
||||
// Search through SectionBuffer for old sections contributing to this segment
|
||||
for (OldSection = 0; OldSection < SectionBufferNum; OldSection++) {
|
||||
|
||||
if (SectionBuffer[OldSection].NewNumber == (uint32)Segment && SectionBuffer[OldSection].Size) {
|
||||
// This section contributes to Segment. Make LEDATA record(s)
|
||||
|
||||
if (SectionBuffer[OldSection].Offset > SegOffset) {
|
||||
// Fillers needed for alignment after previous section
|
||||
AlignmentFiller = SectionBuffer[OldSection].Offset - SegOffset;
|
||||
}
|
||||
else {
|
||||
AlignmentFiller = 0;
|
||||
}
|
||||
SectOffset = 0; // Offset of LEDATA record relative to section start
|
||||
|
||||
if (AlignmentFiller > 0
|
||||
&& AlignmentFiller < 4096 && AlignmentFiller < (1u << SectionBuffer[OldSection].Align)
|
||||
&& SectionBuffer[OldSection].Class == OMF_LNAME_CODE) {
|
||||
// This is a code segment and there is a space from previous section
|
||||
// Fill the alignment space with NOP's
|
||||
// Make LIDATA record with NOP's
|
||||
ToFile.StartRecord(OMF_LIDATA); // Start new LEDATA record
|
||||
ToFile.PutIndex(Segment); // Segment index
|
||||
ToFile.PutNumeric(SegOffset); // Offset of LIDATA relative to segment
|
||||
ToFile.PutNumeric(AlignmentFiller); // Repeat count
|
||||
ToFile.PutWord(0); // Block count
|
||||
ToFile.PutByte(1); // Byte count
|
||||
ToFile.PutByte(0x90); // NOP opcode
|
||||
ToFile.EndRecord(); // End LIDATA record
|
||||
}
|
||||
|
||||
SegOffset = SectionBuffer[OldSection].Offset; // Offset of section to segment
|
||||
|
||||
// Search for relocations for this section
|
||||
Reloc0.Section = OldSection;
|
||||
Reloc0.SourceOffset = 0;
|
||||
RelFirst = RelocationBuffer.FindFirst(Reloc0); // Points to first relocation for this section
|
||||
RelLast = RelFirst;
|
||||
|
||||
// Loop for possibly more than one LEDATA records for this section
|
||||
while (SectOffset < SectionBuffer[OldSection].Size) {
|
||||
|
||||
CutOff = SectionBuffer[OldSection].Size - SectOffset; // Size of rest of section
|
||||
if (CutOff > 1024 && SectionBuffer[OldSection].Class != OMF_LNAME_BSS) {
|
||||
CutOff = 1024; // Maximum LEDATA size
|
||||
}
|
||||
|
||||
// Search for last relocation entry
|
||||
while (RelLast < NumRelocations) {
|
||||
if (RelocationBuffer[RelLast].Section != (uint32)OldSection) {
|
||||
break; // Reached end of relocations for this section
|
||||
}
|
||||
if (RelocationBuffer[RelLast].SourceOffset >= CutOff + SectOffset) {
|
||||
break; // Reached size limit of LEDATA record
|
||||
}
|
||||
if (RelocationBuffer[RelLast].SourceOffset + 4 > CutOff + SectOffset) {
|
||||
// Relocation crosses LEDATA boundary.
|
||||
// Reduce limit of LEDATA to before this relocation source
|
||||
CutOff = RelocationBuffer[RelLast].SourceOffset - SectOffset;
|
||||
if (CutOff == 0) {
|
||||
err.submit(2302); // Relocation source extends beyond end of section.
|
||||
CutOff = 4; // Prevent infinite loop
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (RelLast - RelFirst > 100) {
|
||||
// FIXUPP record will become too big. End LEDATA record here
|
||||
CutOff = RelocationBuffer[RelLast].SourceOffset - SectOffset;
|
||||
break;
|
||||
}
|
||||
RelLast++;
|
||||
} // End of search for last relocation entry for this LEDATA
|
||||
|
||||
if (SectionBuffer[OldSection].Class == OMF_LNAME_BSS) {
|
||||
// BSS: Unitialized data section needs no LEDATA record and no FIXUPP
|
||||
if (RelLast > RelFirst) {
|
||||
// Error: Relocation of uninitialized data
|
||||
err.submit(2041);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Section contains initialized data. Needs LEDATA and FIXUPP records
|
||||
|
||||
// Make LEDATA record for section data
|
||||
ToFile.StartRecord(OMF_LEDATA + 1);// Start new LEDATA record, 32 bit
|
||||
|
||||
// Segment index
|
||||
ToFile.PutIndex(Segment);
|
||||
|
||||
// Offset of LEDATA relative to segment
|
||||
ToFile.PutNumeric(SegOffset + SectOffset);
|
||||
|
||||
// Binary data
|
||||
ToFile.PutBinary(Buf() + SectionBuffer[OldSection].psechdr->PRawData + SectOffset, CutOff);
|
||||
|
||||
// End LEDATA record
|
||||
ToFile.EndRecord();
|
||||
|
||||
if (RelLast > RelFirst) { // If there are any relocations
|
||||
|
||||
// Make FIXUPP record with (RelLast-RelFirst) relocation entries
|
||||
ToFile.StartRecord(OMF_FIXUPP + 1); // Start FIXUPP record, 32 bit
|
||||
|
||||
// Loop through relocations
|
||||
for (Rel = RelFirst; Rel < RelLast; Rel++) {
|
||||
|
||||
if (RelocationBuffer[Rel].Mode < 0) {
|
||||
// Unsupported mode. Make error message
|
||||
err.submit(2030, RelocationBuffer[Rel].TargetOffset); // TargetOffset contains COFF relocation mode
|
||||
continue;
|
||||
}
|
||||
|
||||
// Make Locat word bitfield
|
||||
Locat.s.one = 1; // Indicates FIXUP subrecord
|
||||
Locat.s.M = RelocationBuffer[Rel].Mode; // Direct / EIP-relative
|
||||
Locat.s.Location = 9; // Indicates 32-bit offset
|
||||
|
||||
// Offset of source relative to section (10 bits)
|
||||
uint32 RelocOffset = RelocationBuffer[Rel].SourceOffset - SectOffset; // Offset of relocation source to begin of LEDATA record
|
||||
if (RelocOffset >= 1024) err.submit(9000); // Check that it fits into 10 bits
|
||||
Locat.s.Offset = RelocOffset;
|
||||
|
||||
// Make FixData byte bitfield
|
||||
FixData.b = 0; // Start with all bits 0
|
||||
|
||||
if (RelocationBuffer[Rel].Scope == S_LOCAL) {
|
||||
// Local target
|
||||
FixData.s.Target = 0; // Target method T0 or T4: Target = segment
|
||||
FixData.s.Frame = 1; // Frame method F1: specified by a group index (FLAT)
|
||||
FrameDatum = OMF_LNAME_FLAT; // Target frame = FLAT group
|
||||
TargetDatum = RelocationBuffer[Rel].TargetSegment; // Fixup target = segment
|
||||
TargetDisplacement = RelocationBuffer[Rel].TargetOffset; // Displacement or addend (?)
|
||||
}
|
||||
else {
|
||||
// External symbol target
|
||||
FixData.s.Frame = 5; // Frame method F5: Frame specified by target, not here
|
||||
FixData.s.Target = 2; // Target method T2 or T6: Target specified by EXTDEF index
|
||||
TargetDatum = RelocationBuffer[Rel].TargetSegment; // Index into EXTDEF
|
||||
TargetDisplacement = RelocationBuffer[Rel].TargetOffset; // This is zero. Any addend is inline
|
||||
}
|
||||
if (TargetDisplacement) {
|
||||
FixData.s.P = 0; // Displacement field present
|
||||
}
|
||||
else {
|
||||
FixData.s.P = 1; // Displacement field absent
|
||||
}
|
||||
|
||||
// Put these data into record
|
||||
// Locat bytes in reverse order:
|
||||
ToFile.PutByte(Locat.bytes[1]);
|
||||
ToFile.PutByte(Locat.bytes[0]);
|
||||
// FixData byte
|
||||
ToFile.PutByte(FixData.b);
|
||||
// Frame datum field only if FixData.F = 0 and Frame < 4
|
||||
if (FixData.s.Frame < 4) ToFile.PutIndex(FrameDatum);
|
||||
// Target datum field if FixData.T = 0, which it is here
|
||||
ToFile.PutIndex(TargetDatum);
|
||||
// Target displacement field if FixData.P = 0
|
||||
if (FixData.s.P == 0) ToFile.PutNumeric(TargetDisplacement);
|
||||
|
||||
} // End of loop through relocation for last LEDATA
|
||||
|
||||
// End FIXUPP record
|
||||
ToFile.EndRecord();
|
||||
}
|
||||
}
|
||||
// Update pointers to after this LEDATA
|
||||
SectOffset += CutOff;
|
||||
RelFirst = RelLast;
|
||||
|
||||
} // End of loop for multiple LEDATA records for one section
|
||||
|
||||
// Find end of section
|
||||
SegOffset += SectionBuffer[OldSection].Size; // End of section
|
||||
|
||||
} // End of if section in segment
|
||||
} // End of loop through multiple sections for same segment
|
||||
} // End of loop through segments
|
||||
}
|
||||
|
||||
|
||||
void CCOF2OMF::MakeMODEND() {
|
||||
// Make MODEND record and finish file
|
||||
ToFile.StartRecord(OMF_MODEND); // Start MODEND record
|
||||
ToFile.PutByte(0); // Module type field. 0 if not a startup module with start address
|
||||
ToFile.EndRecord(); // End MODEND record
|
||||
}
|
||||
Reference in New Issue
Block a user