File: cof2cof.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 (306 lines) | stat: -rw-r--r-- 12,281 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
/****************************   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_t * 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_t)strlen(name2) > (uint32_t)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_t *)(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_t * LongNameStorage = (uint32_t *)(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_t 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_t NewStringTableSize = NewStringTable.GetDataSize();
   // First 4 bytes = size
   ToFile.Push(&NewStringTableSize, sizeof(uint32_t));
   // 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_t EndOfOldStringTable = FileHeader->PSymbolTable 
      + NumberOfSymbols * SIZE_SCOFF_SymTableEntry + StringTableSize;

   uint32_t 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_t 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.
}