kolibrios/programs/develop/objconv/cof2cof.cpp

307 lines
12 KiB
C++

/**************************** 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.
}