1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
|
/**************************** 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_t 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_t 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
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_t 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_t CMAC2MAC<MACSTRUCTURES>::NewFileOffset(uint32_t 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_t OldSymtabEnd; // End of old symbol table
uint32_t 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_t FileOffset; // Current offset into file
uint32_t lcmd; // Load command
uint32_t cmdsize = 0; // Command size
uint32_t 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_t HeaderOffset, uint32_t 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_t isec1; // Section index
TMAC_section * secp; // Pointer to section header
uint32_t 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_t FileOffset, uint32_t Num) {
// Convert subfunction: Change symbol indices in import table if needed
uint32_t i; // Index
uint32_t * p; // pointer to current entry
// Find first entry
p = (uint32_t*)(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>;
|