kolibrios-fun/programs/develop/objconv/mac2mac.cpp

407 lines
16 KiB
C++
Raw Permalink Normal View History

/**************************** mac2mac.cpp *****************************
* Author: Agner Fog
* Date created: 2008-05-25
* Last modified: 2008-05-25
* Project: objconv
* Module: mac2mac.cpp
* Description:
* Module for changing symbol names in Mach-O file
*
* Copyright 2008 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
#include "stdafx.h"
// All functions in this module are templated to make two versions: 32 and 64 bits.
// See instantiations at the end of this file.
// Constructor
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
CMAC2MAC<MACSTRUCTURES>::CMAC2MAC() {
// Initialize everything
memset(this, 0, sizeof(*this));
}
// Convert()
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
void CMAC2MAC<MACSTRUCTURES>::Convert() {
MakeSymbolTable(); // Remake symbol tables and string tables
MakeBinaryFile(); // Put everyting together into ToFile
ChangeSegments(); // Modify section names and relocation table symbol indices
*this << ToFile; // Take over new file buffer
}
// MakeSymbolTable()
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
void CMAC2MAC<MACSTRUCTURES>::MakeSymbolTable() {
// Remake symbol tables and string table
int OldScope = 0; // Old scope of symbol. 0=local, 1=public, 2=external
int NewScope; // New scope of symbol. 0=local, 1=public, 2=external
uint32 symi; // Old index of symbol
const char * Name1; // Old symbol name
const char * Name2; // New symbol name
int action; // Action to take on symbol
int SymType; // Symbol type
int SymDesc; // Symbol descriptor
uint8 Section; // Symbol section
// pointer to symbol table
TMAC_nlist * symp = (TMAC_nlist*)(this->Buf() + this->SymTabOffset);
// pointer to string table
char * strtab = (char*)(this->Buf() + this->StringTabOffset);
// loop through symbol table
for (symi = 0; symi < this->SymTabNumber; symi++, symp++) {
// Check indices for first symbol of each scope category
if (symi == this->iextdefsym && this->nextdefsym) OldScope = 1;
if (symi == this->iundefsym && this->nundefsym) OldScope = 2;
NewScope = OldScope;
if (symp->n_strx >= this->StringTabSize) {
// Index out of range
err.submit(2112); continue;
}
// Get symbol name
Name1 = strtab + symp->n_strx;
// Get type, descriptor and section
SymType = symp->n_type; // Symbol type
SymDesc = symp->n_desc; // Symbol descriptor
Section = symp->n_sect; // Symbol section
// Check if any change required for this symbol
action = cmd.SymbolChange(Name1, &Name2, SYMT_LOCAL + OldScope);
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
err.submit(2200);
}
// Make weak
if (OldScope == 1) {
SymDesc |= MAC_N_WEAK_DEF; // Weak public. Allowed only in coalesced (communal) section
}
else if (OldScope == 2) {
SymDesc |= MAC_N_WEAK_REF; // Weak external
}
else {
err.submit(1020, Name1); // Local symbol
}
break;
case SYMA_MAKE_LOCAL:
// Make public symbol local, make external symbol ignored
if (OldScope == 1) {
NewScope = 0; // Public changed to local
SymType &= ~MAC_N_EXT;
}
else if (OldScope == 2) {
Section = MAC_NO_SECT; // External symbol. Set to 0
SymDesc = 0;
SymType = MAC_N_UNDF;
}
else err.submit(1021, Name1);
break;
case SYMA_CHANGE_NAME:
// Change name of symbol
Name1 = Name2; Name2 = 0;
break;
case SYMA_ALIAS:
// Make alias and keep old name
if (OldScope != 1) {
err.submit(1022, Name1); break;
}
// Make alias
NewSymbols[1].AddSymbol(-1, Name2, SymType, SymDesc, Section, symp->n_value);
break;
default:
err.submit(9000); // unknown error
}
// Store symbol, possibly modified
NewSymbols[NewScope].AddSymbol(symi, Name1, SymType, SymDesc, Section, symp->n_value);
}
// Put everything into symbol table and string table
if (this->SymTabNumber) {
NewStringTable.SetDataSize(1); // First record must indicate empty string (see nlist.n_un in Mach-O File Format Reference)
}
for (NewScope = 0; NewScope < 3; NewScope++) {
NewSymbols[NewScope].SortList(); // Sort each list alphabetically
NewSymbols[NewScope].StoreList(&NewSymbolTable, &NewStringTable);
}
// Indices to local, public and external symbols
NewIlocalsym = 0; // index to local symbols
NewNlocalsym = NewSymbols[0].GetNumEntries(); // number of local symbols
NewIextdefsym = NewNlocalsym; // index to public symbols
NewNextdefsym = NewSymbols[1].GetNumEntries();// number of public symbols
NewIundefsym = NewNlocalsym + NewNextdefsym; // index to external symbols
NewNundefsym = NewSymbols[2].GetNumEntries(); // number of external symbols
// Calculate difference in size of new tables versus old tables
// (this calculation is moved to MakeBinaryFile)
// SizeDifference = NewSymbolTable.GetDataSize + NewStringTable.GetDataSize()
// - this->SymTabNumber * sizeof(TMAC_nlist) - this->StringTabSize;
}
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
int CMAC2MAC<MACSTRUCTURES>::NewSymbolIndex(int32 OldIndex) {
// Convert subfunction: Translate old to new symbol index
int NewIndex;
int Scope;
// Search for symbol in all scopes
for (Scope = 0; Scope < 3; Scope++) {
NewIndex = NewSymbols[Scope].TranslateIndex(OldIndex);
if (NewIndex >= 0) {
// OldIndex found. Add offset into appropriate table
if (Scope == 1) NewIndex += NewIextdefsym;
else if (Scope == 2) NewIndex += NewIundefsym;
return NewIndex;
}
}
//err.submit(2031);
return -1;
}
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
uint32 CMAC2MAC<MACSTRUCTURES>::NewFileOffset(uint32 OldOffset) {
// Convert subfunction: Translate old to new file offset
if (OldOffset <= NewSymtabOffset) {
// Before symbol table. No change
return OldOffset;
}
if (OldOffset >= OldTablesEnd) {
// After string table. Add size difference
return OldOffset + SizeDifference;
}
// Between symbol table and string table.
// The possibility of something between these two tables has not been accounted for
err.submit(2052);
return 0;
}
// MakeBinaryFile()
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
void CMAC2MAC<MACSTRUCTURES>::MakeBinaryFile() {
uint32 OldSymtabEnd; // End of old symbol table
uint32 OldStringtabEnd; // End of old string table
const int WordSize = sizeof(MInt) * 8; // Word size, 32 or 64 bits
// Offset to symbol table and string table
NewSymtabOffset = this->SymTabOffset;
if (this->StringTabOffset && this->StringTabOffset < NewSymtabOffset) NewSymtabOffset = this->StringTabOffset;
if (NewSymtabOffset == 0) NewSymtabOffset = this->GetDataSize();
// Copy all headers and all data until TablesOffset
ToFile.Push(this->Buf(), NewSymtabOffset);
ToFile.Align(WordSize/8);
NewSymtabOffset = ToFile.GetDataSize();
// Copy new symbol table
ToFile.Push(NewSymbolTable.Buf(), NewSymbolTable.GetDataSize());
// Copy new string table
NewStringtabOffset = ToFile.GetDataSize();
ToFile.Push(NewStringTable.Buf(), NewStringTable.GetDataSize());
ToFile.Align(2);
NewStringtabEnd = ToFile.GetDataSize();
// Find end of old tables
OldSymtabEnd = this->SymTabOffset + this->SymTabNumber * sizeof(TMAC_nlist);
OldStringtabEnd = this->StringTabOffset + this->StringTabSize;
OldTablesEnd = OldStringtabEnd;
if (OldSymtabEnd > OldTablesEnd) OldTablesEnd = OldSymtabEnd;
if (OldTablesEnd == 0) OldTablesEnd = this->GetDataSize();
// Size difference between new and old tables
SizeDifference = NewStringtabEnd - OldTablesEnd;
// Is there anything in the old file after these tables?
if (OldTablesEnd && this->GetDataSize() > OldTablesEnd) {
// There is something after these tables. Copy it
ToFile.Push(this->Buf() + OldTablesEnd, this->GetDataSize() - OldTablesEnd);
}
}
// ChangeSegments()
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
void CMAC2MAC<MACSTRUCTURES>::ChangeSegments() {
// Convert subfunction: Change section names if needed and adjust all relocation tables
uint32 FileOffset; // Current offset into file
uint32 lcmd; // Load command
uint32 cmdsize = 0; // Command size
uint32 icmd; // Loop counter
int action; // Name change action
char * Name1; // Old name
const char * Name2; // New name
FileOffset = sizeof(TMAC_header);
// Loop through file commands
for (icmd = 1; icmd <= this->FileHeader.ncmds; icmd++, FileOffset += cmdsize) {
lcmd = ((MAC_load_command*)(ToFile.Buf() + FileOffset)) -> cmd;
cmdsize = ((MAC_load_command*)(ToFile.Buf() + FileOffset)) -> cmdsize;
// Interpret specific command type
switch(lcmd) {
case MAC_LC_SEGMENT: { // 32-bit segment
MAC_segment_command_32 * sh = (MAC_segment_command_32*)(ToFile.Buf() + FileOffset);
Name1 = sh->segname;
// Check if any change required for this symbol
action = cmd.SymbolChange(Name1, &Name2, SYMT_SECTION);
if (action == SYMA_CHANGE_NAME) {
// Change segment name
if (strlen(Name2) > 16) err.submit(1040);
strncpy(Name1, Name2, 16);
}
// Change section names and relocations in all sections under this segment
ChangeSections(FileOffset + sizeof(MAC_segment_command_32), sh->nsects);
break;}
case MAC_LC_SEGMENT_64: { // 64-bit segment
MAC_segment_command_64 * sh = (MAC_segment_command_64*)(ToFile.Buf() + FileOffset);
Name1 = sh->segname;
// Check if any change required for this symbol
action = cmd.SymbolChange(Name1, &Name2, SYMT_SECTION);
if (action == SYMA_CHANGE_NAME) {
// Change segment name
if (strlen(Name2) > 16) err.submit(1040);
strncpy(Name1, Name2, 16);
}
// Change section names and relocations in all sections under this segment
ChangeSections(FileOffset + sizeof(MAC_segment_command_64), sh->nsects);
break;}
case MAC_LC_SYMTAB: { // Symbol table header
MAC_symtab_command * sh = (MAC_symtab_command*)(ToFile.Buf() + FileOffset);
// Change table addresses
sh->symoff = NewSymtabOffset;
sh->nsyms = NewSymbolTable.GetDataSize() / sizeof(TMAC_nlist);
sh->stroff = NewStringtabOffset;
sh->strsize = NewStringtabEnd - NewStringtabOffset;
break;}
case MAC_LC_DYSYMTAB: { // dynamic link-edit symbol table
MAC_dysymtab_command * sh = (MAC_dysymtab_command*)(ToFile.Buf() + FileOffset);
// Change indices to symbol tables
sh->ilocalsym = NewIlocalsym;
sh->nlocalsym = NewNlocalsym;
sh->iextdefsym = NewIextdefsym;
sh->nextdefsym = NewNextdefsym;
sh->iundefsym = NewIundefsym;
sh->nundefsym = NewNundefsym;
// Change table addresses
sh->tocoff = NewFileOffset(sh->tocoff);
sh->modtaboff = NewFileOffset(sh->modtaboff);
sh->extrefsymoff = NewFileOffset(sh->extrefsymoff);
sh->indirectsymoff = NewFileOffset(sh->indirectsymoff);
sh->extreloff = NewFileOffset(sh->extreloff);
sh->locreloff = NewFileOffset(sh->locreloff);
if (sh->nindirectsyms) {
// Change symbol indices in import table
ChangeImportTable(sh->indirectsymoff, sh->nindirectsyms);
}
break;}
}
}
}
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
void CMAC2MAC<MACSTRUCTURES>::ChangeSections(uint32 HeaderOffset, uint32 Num) {
// Convert subfunction: Change section names and relocation records if needed
int action; // Name change action
char * Name1; // Old name
const char * Name2; // New name
uint32 isec1; // Section index
TMAC_section * secp; // Pointer to section header
uint32 irel; // Relocation index
MAC_relocation_info * relp; // Pointer to relocation record
// Loop through section headers
for (isec1 = 0; isec1 < Num; isec1++) {
// Find section header
secp = (TMAC_section*)(ToFile.Buf() + HeaderOffset + isec1*sizeof(TMAC_section));
// Segment name
Name1 = secp->segname;
action = cmd.SymbolChange(Name1, &Name2, SYMT_SECTION);
if (action == SYMA_CHANGE_NAME) {
// Change segment name
if (strlen(Name2) > 16) err.submit(1040);
strncpy(Name1, Name2, 16);
}
// Section name
Name1 = secp->sectname;
action = cmd.SymbolChange(Name1, &Name2, SYMT_SECTION);
if (action == SYMA_CHANGE_NAME) {
// Change section name
if (strlen(Name2) > 16) err.submit(1040);
strncpy(Name1, Name2, 16);
}
// Update file offset
secp->offset = NewFileOffset(secp->offset);
if (secp->nreloc) {
// This section has relocations
// Update relocations offset
secp->reloff = NewFileOffset(secp->reloff);
// Pointer to relocation records
relp = (MAC_relocation_info*)(ToFile.Buf() + secp->reloff);
// Loop through relocations, if any
for (irel = 0; irel < secp->nreloc; irel++, relp++) {
// Only non-scattered r_extern relocations have symbol index
if (!(relp->r_address & R_SCATTERED) && relp->r_extern) {
// Update symbol index
relp->r_symbolnum = NewSymbolIndex(relp->r_symbolnum);
}
}
}
}
}
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
void CMAC2MAC<MACSTRUCTURES>::ChangeImportTable(uint32 FileOffset, uint32 Num) {
// Convert subfunction: Change symbol indices in import table if needed
uint32 i; // Index
uint32 * p; // pointer to current entry
// Find first entry
p = (uint32*)(ToFile.Buf() + FileOffset);
// Loop through table
for (i = 0; i < Num; i++, p++) {
// Translate symbol index
*p = NewSymbolIndex(*p);
}
}
// Make template instances for 32 and 64 bits
template class CMAC2MAC<MAC32STRUCTURES>;
template class CMAC2MAC<MAC64STRUCTURES>;