File: mac2mac.cpp

package info (click to toggle)
objconv 2.56%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,300 kB
  • sloc: cpp: 27,039; makefile: 4; sh: 2
file content (403 lines) | stat: -rw-r--r-- 16,236 bytes parent folder | download | duplicates (2)
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>;