forked from KolibriOS/kolibrios
Added objconv port.
git-svn-id: svn://kolibrios.org@9683 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
306
programs/develop/objconv/cof2cof.cpp
Normal file
306
programs/develop/objconv/cof2cof.cpp
Normal file
@@ -0,0 +1,306 @@
|
||||
/**************************** cof2cof.cpp *********************************
|
||||
* Author: Agner Fog
|
||||
* Date created: 2006-07-28
|
||||
* Last modified: 2006-07-28
|
||||
* Project: objconv
|
||||
* Module: cof2cof.cpp
|
||||
* Description:
|
||||
* Module for changing symbol names in PE/COFF file
|
||||
*
|
||||
* Copyright 2006-2008 GNU General Public License http://www.gnu.org/licenses
|
||||
*****************************************************************************/
|
||||
#include "stdafx.h"
|
||||
|
||||
|
||||
CCOF2COF::CCOF2COF () {
|
||||
// Constructor
|
||||
}
|
||||
|
||||
void CCOF2COF::Convert() {
|
||||
// Do the conversion
|
||||
|
||||
// Call the subfunctions
|
||||
MakeSymbolTable(); // Symbol table and string tables
|
||||
MakeBinaryFile(); // Putting sections together
|
||||
*this << ToFile; // Take over new file buffer
|
||||
}
|
||||
|
||||
|
||||
void CCOF2COF::MakeSymbolTable() {
|
||||
// Convert subfunction: Make symbol table and string tables
|
||||
int isym; // current symbol table entry
|
||||
int numaux; // Number of auxiliary entries in source record
|
||||
int symboltype = 0; // Symbol type
|
||||
int action = 0; // Symbol change action
|
||||
int isec; // Section number
|
||||
|
||||
const char * name1; // Old name of symbol
|
||||
const char * name2; // Changed name of symbol
|
||||
const char * name3; // New name to store
|
||||
|
||||
// Pointer to old symbol table
|
||||
union {
|
||||
SCOFF_SymTableEntry * p; // Symtab entry pointer
|
||||
int8 * b; // Used for increment
|
||||
} OldSymtab;
|
||||
|
||||
// Initialize new string table. Make space for size
|
||||
NewStringTable.Push(0, 4);
|
||||
|
||||
// Loop through source symbol table
|
||||
OldSymtab.p = SymbolTable; // Pointer to source symbol table
|
||||
for (isym = 0; isym < NumberOfSymbols; isym += numaux+1, OldSymtab.b += SIZE_SCOFF_SymTableEntry*(numaux+1)) {
|
||||
|
||||
// Number of auxiliary records belonging to same symbol
|
||||
numaux = OldSymtab.p->s.NumAuxSymbols; if (numaux < 0) numaux = 0;
|
||||
|
||||
// Get first aux record if numaux > 0
|
||||
SCOFF_SymTableEntry * sa = (SCOFF_SymTableEntry *)(OldSymtab.b + SIZE_SCOFF_SymTableEntry);
|
||||
|
||||
// Check symbol type
|
||||
if (numaux && OldSymtab.p->s.StorageClass == COFF_CLASS_STATIC) {
|
||||
// This is a section definition record
|
||||
// aux record contains length and number of relocations. Ignore aux record
|
||||
symboltype = SYMT_SECTION;
|
||||
name1 = GetSymbolName(OldSymtab.p->s.Name);
|
||||
}
|
||||
else if (OldSymtab.p->s.StorageClass == COFF_CLASS_FILE) {
|
||||
// This is a filename record
|
||||
symboltype = SYMT_OTHER;
|
||||
name1 = GetShortFileName(OldSymtab.p);
|
||||
// or long file name ?!
|
||||
}
|
||||
else if (OldSymtab.p->s.Type == 0 && OldSymtab.p->s.StorageClass == COFF_CLASS_FUNCTION) {
|
||||
// This is a .bf, .lf, or .ef record following a function record
|
||||
// Contains line number information etc. Ignore this record
|
||||
name1 = 0;
|
||||
}
|
||||
else {
|
||||
// This is a symbol record
|
||||
// Symbol name
|
||||
name1 = GetSymbolName(OldSymtab.p->s.Name);
|
||||
if (OldSymtab.p->s.StorageClass == COFF_CLASS_EXTERNAL) {
|
||||
// This is a public or external symbol
|
||||
if (OldSymtab.p->s.SectionNumber <= 0) {
|
||||
// This is an external symbol
|
||||
symboltype = SYMT_EXTERNAL;
|
||||
}
|
||||
else {
|
||||
// This is a public symbol
|
||||
symboltype = SYMT_PUBLIC;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// This is a local symbol
|
||||
symboltype = SYMT_LOCAL;
|
||||
}
|
||||
}
|
||||
name3 = name1;
|
||||
// Check if any change required for this symbol
|
||||
action = cmd.SymbolChange(name1, &name2, symboltype);
|
||||
|
||||
switch (action) {
|
||||
case SYMA_NOCHANGE:
|
||||
// No change
|
||||
break;
|
||||
|
||||
case SYMA_MAKE_WEAK:
|
||||
// Make symbol weak
|
||||
if (cmd.OutputType == FILETYPE_COFF) {
|
||||
// PE/COFF format does not support weak publics. Use this only when converting to ELF
|
||||
err.submit(2200);
|
||||
}
|
||||
// Make weak when converting to ELF
|
||||
OldSymtab.p->s.StorageClass = COFF_CLASS_WEAK_EXTERNAL;
|
||||
break;
|
||||
|
||||
case SYMA_MAKE_LOCAL:
|
||||
// Make public symbol local, make external symbol ignored
|
||||
OldSymtab.p->s.StorageClass = COFF_CLASS_STATIC;
|
||||
break;
|
||||
|
||||
case SYMA_CHANGE_NAME:
|
||||
// Change name of symbol
|
||||
if (OldSymtab.p->s.StorageClass == COFF_CLASS_FILE) {
|
||||
// File name is stored in aux records, not in symbol table
|
||||
if ((uint32)strlen(name2) > (uint32)numaux * SIZE_SCOFF_SymTableEntry) {
|
||||
// Name too long. I don't want to add more aux records
|
||||
err.submit(2201, name2);
|
||||
}
|
||||
else {
|
||||
// Insert new file name in aux records
|
||||
memset(sa, 0, numaux * SIZE_SCOFF_SymTableEntry);
|
||||
memcpy(sa, name2, strlen(name2));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Symbol name stored in normal way
|
||||
name3 = name2;
|
||||
}
|
||||
break;
|
||||
|
||||
case SYMA_ALIAS: {
|
||||
// Make alias and keep old name
|
||||
SCOFF_SymTableEntry AliasEntry = *OldSymtab.p;
|
||||
AliasEntry.s.Type = 0; // Make alias a label, not a function
|
||||
AliasEntry.s.NumAuxSymbols = 0; // No auxiliary .bf and .ef records
|
||||
// Put new name into AliasEntry
|
||||
memset(AliasEntry.s.Name, 0, 8);
|
||||
if (strlen(name2) > 8) {
|
||||
// Long name. use string table
|
||||
// Store string table offset
|
||||
((uint32 *)(AliasEntry.s.Name))[1] = NewStringTable.GetDataSize();
|
||||
// Put name into new string table
|
||||
NewStringTable.PushString(name2);
|
||||
}
|
||||
else {
|
||||
// Short name. Store in record
|
||||
memcpy(AliasEntry.s.Name, name2, strlen(name2));
|
||||
}
|
||||
// Add new entry to extra symbol table
|
||||
NewSymbolTable.Push(&AliasEntry, SIZE_SCOFF_SymTableEntry);
|
||||
break;}
|
||||
|
||||
default:
|
||||
err.submit(9000); // unknown error
|
||||
}
|
||||
|
||||
if (name3 && OldSymtab.p->s.StorageClass != COFF_CLASS_FILE) {
|
||||
// Store old or new name
|
||||
if (strlen(name3) > 8) {
|
||||
// Name is long. use string table
|
||||
// Type-case Name field to string table entry
|
||||
uint32 * LongNameStorage = (uint32 *)(OldSymtab.p->s.Name);
|
||||
// Start with 0 to indicate long name
|
||||
LongNameStorage[0] = 0;
|
||||
// Index into new string table
|
||||
LongNameStorage[1] = NewStringTable.GetDataSize();
|
||||
// Put name into new string table
|
||||
NewStringTable.PushString(name3);
|
||||
}
|
||||
else {
|
||||
if (name3 != name1) {
|
||||
// Store new name in Name field
|
||||
memset(OldSymtab.p->s.Name, 0, 8);
|
||||
memcpy(OldSymtab.p->s.Name, name3, strlen(name3));
|
||||
}
|
||||
}
|
||||
}
|
||||
} // End symbol table loop
|
||||
|
||||
// Loop through section headers to search for section names
|
||||
uint32 SectionOffset = sizeof(SCOFF_FileHeader) + FileHeader->SizeOfOptionalHeader;
|
||||
for (isec = 0; isec < NSections; isec++) {
|
||||
SCOFF_SectionHeader * pSectHeader;
|
||||
pSectHeader = &Get<SCOFF_SectionHeader>(SectionOffset);
|
||||
SectionOffset += sizeof(SCOFF_SectionHeader);
|
||||
|
||||
// Get section name
|
||||
name1 = GetSectionName(pSectHeader->Name);
|
||||
|
||||
// Check if change required
|
||||
action = cmd.SymbolChange(name1, &name2, SYMT_SECTION);
|
||||
if (action == SYMA_CHANGE_NAME) name1 = name2;
|
||||
|
||||
// Store name (changed or unchanged)
|
||||
memset(pSectHeader->Name, 0, 8);
|
||||
if (strlen(name1) <= 8) {
|
||||
// Short name. Store in section header
|
||||
memcpy(pSectHeader->Name, name1, strlen(name1));
|
||||
}
|
||||
else {
|
||||
// Long name. Store in string table
|
||||
sprintf(pSectHeader->Name, "/%i", NewStringTable.GetDataSize());
|
||||
//pSectHeader->Name[0] = '/';
|
||||
//itoa(NewStringTable.GetDataSize(), pSectHeader->Name+1, 10);
|
||||
NewStringTable.PushString(name1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CCOF2COF::MakeBinaryFile() {
|
||||
// Convert subfunction: Combine everything into the new binary file
|
||||
int i;
|
||||
|
||||
// New file header = copy of old file header
|
||||
SCOFF_FileHeader NewFileHeader = *FileHeader;
|
||||
|
||||
ToFile.SetFileType(FILETYPE_COFF); // Set type of output file
|
||||
ToFile.WordSize = WordSize;
|
||||
ToFile.FileName = FileName;
|
||||
|
||||
// Copy file header, section headers and sections to new file
|
||||
ToFile.Push(Buf(), NewFileHeader.PSymbolTable);
|
||||
|
||||
// Copy symbol table
|
||||
ToFile.Push(SymbolTable, NumberOfSymbols * SIZE_SCOFF_SymTableEntry);
|
||||
|
||||
// Additions to symbol table
|
||||
int NumAddedSymbols = NewSymbolTable.GetNumEntries();
|
||||
if (NumAddedSymbols) {
|
||||
// Append to symbols table
|
||||
ToFile.Push(NewSymbolTable.Buf(), NumAddedSymbols * SIZE_SCOFF_SymTableEntry);
|
||||
// Update NumberOfSymbols in file header
|
||||
NewFileHeader.NumberOfSymbols += NumAddedSymbols;
|
||||
}
|
||||
|
||||
// Insert new string table
|
||||
uint32 NewStringTableSize = NewStringTable.GetDataSize();
|
||||
// First 4 bytes = size
|
||||
ToFile.Push(&NewStringTableSize, sizeof(uint32));
|
||||
// Then the string table itself, except the first 4 bytes
|
||||
if (NewStringTableSize > 4)
|
||||
ToFile.Push(NewStringTable.Buf() + 4, NewStringTableSize - 4);
|
||||
|
||||
// Find end of old and new string tables
|
||||
uint32 EndOfOldStringTable = FileHeader->PSymbolTable
|
||||
+ NumberOfSymbols * SIZE_SCOFF_SymTableEntry + StringTableSize;
|
||||
|
||||
uint32 EndOfNewStringTable = FileHeader->PSymbolTable
|
||||
+ (NumberOfSymbols + NumAddedSymbols) * SIZE_SCOFF_SymTableEntry + NewStringTableSize;
|
||||
|
||||
// Check if there is anything after the string table
|
||||
if (GetDataSize() > EndOfOldStringTable) {
|
||||
// Old file has something after the string table
|
||||
|
||||
if (EndOfNewStringTable < EndOfOldStringTable) {
|
||||
// New symboltable + string table smaller than old
|
||||
// Fill the space with zeroes so that the data that come after the string table
|
||||
// will have the same address as before
|
||||
ToFile.Push(0, EndOfOldStringTable - EndOfNewStringTable);
|
||||
EndOfNewStringTable = EndOfOldStringTable;
|
||||
}
|
||||
|
||||
// Copy the data that come after the string table
|
||||
ToFile.Push(Buf() + EndOfOldStringTable, GetDataSize() - EndOfOldStringTable);
|
||||
|
||||
if (EndOfNewStringTable > EndOfOldStringTable) {
|
||||
// New symboltable + string table bigger than old
|
||||
// Find all references to the data that come after the string table and fix them
|
||||
// Search all section headers
|
||||
uint32 SectionOffset = sizeof(SCOFF_FileHeader) + NewFileHeader.SizeOfOptionalHeader;
|
||||
for (i = 0; i < NSections; i++) {
|
||||
SCOFF_SectionHeader * pSectHeader;
|
||||
pSectHeader = &Get<SCOFF_SectionHeader>(SectionOffset);
|
||||
SectionOffset += sizeof(SCOFF_SectionHeader);
|
||||
if (pSectHeader->PRawData >= EndOfOldStringTable && pSectHeader->PRawData <= GetDataSize()) {
|
||||
pSectHeader->PRawData += EndOfNewStringTable - EndOfOldStringTable;
|
||||
}
|
||||
if (pSectHeader->PRelocations >= EndOfOldStringTable && pSectHeader->PRawData <= GetDataSize()) {
|
||||
pSectHeader->PRelocations += EndOfNewStringTable - EndOfOldStringTable;
|
||||
} if (pSectHeader->PLineNumbers >= EndOfOldStringTable && pSectHeader->PRawData <= GetDataSize()) {
|
||||
pSectHeader->PLineNumbers += EndOfNewStringTable - EndOfOldStringTable;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Update file header
|
||||
memcpy(ToFile.Buf(), &NewFileHeader, sizeof(NewFileHeader));
|
||||
|
||||
// Note: The checksum in the optional header may need to be updated.
|
||||
// This is relevant for DLL's only. The checksum algorithm is undisclosed and
|
||||
// must be calculated with IMAGHELP.DLL. You may add a calculation of the checksum
|
||||
// here if you want the program to be able to change names in a Windows DLL,
|
||||
// but the program will then only be able to compile under Windows.
|
||||
}
|
||||
Reference in New Issue
Block a user