File: elf2elf.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 (430 lines) | stat: -rw-r--r-- 17,917 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
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
/****************************    elf2elf.cpp    *****************************
* Author:        Agner Fog
* Date created:  2006-01-13
* Last modified: 2022-08-31
* Project:       objconv
* Module:        elf2elf.cpp
* Description:
* Module for changing symbol names in ELF file
*
* Copyright 2006-2022 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 TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
CELF2ELF<ELFSTRUCTURES>::CELF2ELF() {
   // Initialize everything
   memset(this, 0, sizeof(*this));
}


// Convert()
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2ELF<ELFSTRUCTURES>::Convert() {
   // Some compilers require this-> for accessing members of template base class,
   // according to the so-called two-phase lookup rule.
   MakeSymbolTable();        // Remake symbol tables and string tables
   ChangeSections();         // Modify section names and relocation table symbol indices
   MakeBinaryFile();         // Put everyting together into ToFile
   *this << ToFile;          // Take over new file buffer
}


// MakeSymbolTable()
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2ELF<ELFSTRUCTURES>::MakeSymbolTable() {
   uint32_t SectionNumber;   // Section number
   char * SectionName;       // Section name
   uint32_t SecNamei;        // Section name index
   uint32_t OldSymi;         // Old symbol index
   uint32_t NewSymi;         // New symbol index
   int isymt;                // 0 = symtab, 1 = dynsym
   const char * name1;       // Old name of symbol
   const char * name2;       // Changed name of symbol
   int SymbolType;           // Symbol type for cmd.SymbolChange
   int action;               // Symbol change action
   int binding;              // Symbol binding
   TELF_Symbol sym;          // Symbol table entry
   TELF_Symbol AliasEntry;   // Symbol table alias entry
   uint32_t symnamei;        // New symbol name index
   CMemoryBuffer TempGlobalSymbolTable; // Temporary storage of public and external symbols

   // Find symbol table and string tables
   for (SectionNumber = 0; SectionNumber < this->NSections; SectionNumber++) {
      // Get copy of 32-bit header or converted 64-bit header
      TELF_SectionHeader sheader = this->SectionHeaders[SectionNumber];
      switch (sheader.sh_type) {
      case SHT_SYMTAB:
         isymtab[0] = SectionNumber;        // Symbol table found
         istrtab[0] = this->SectionHeaders[SectionNumber].sh_link; // Associated string table
         break;

      case SHT_DYNSYM:
         isymtab[1] = SectionNumber;        // Dynamic symbol table found
         istrtab[1] = this->SectionHeaders[SectionNumber].sh_link; // Associated string table
         break;

      case SHT_STRTAB:
         SecNamei = sheader.sh_name;
         if (SecNamei >= this->SecStringTableLen) {
             err.submit(2112); return;}
         SectionName = this->SecStringTable + SecNamei;
         if (SectionNumber == this->FileHeader.e_shstrndx || !strcmp(SectionName,".shstrtab")) {
            istrtab[2] = SectionNumber;     // Section header string table found
         }
         else if (!strcmp(SectionName,".strtab") && !istrtab[0]) {
            istrtab[0] = SectionNumber;     // Symbol string table found
         }
         else if (!strcmp(SectionName,".stabstr")) {
            istrtab[3] = SectionNumber;     // Debug string table found
         }
         break;
      }
   }

   // Make new symbol tables and string tables
   // Loop through possibly two symbol tables
   for (isymt = 0; isymt < 2; isymt++) {

      if (isymtab[isymt] && isymtab[isymt] < this->NSections 
      &&  istrtab[isymt] && istrtab[isymt] < this->NSections) {
         
         // Symbol table header
         uint32_t SymTabHeaderOffset = uint32_t(this->FileHeader.e_shoff + isymtab[isymt] * this->SectionHeaderSize);
         //TELF_SectionHeader SymTabHeader = this->Get<TELF_SectionHeader>(SymTabHeaderOffset);
         // Some compilers fail with the double template here. Avoid the template:
         TELF_SectionHeader SymTabHeader = *(TELF_SectionHeader*)(this->Buf() + SymTabHeaderOffset);

         // Find symbol table
         uint32_t symtabsize = (uint32_t)(SymTabHeader.sh_size);
         int8_t * symtab = this->Buf() + SymTabHeader.sh_offset;
         int8_t * symtabend = symtab + symtabsize;
         int entrysize = (int)(SymTabHeader.sh_entsize);
         if (entrysize <= 0) entrysize = sizeof(TELF_Symbol);

         // Find string table
         char * StringTable = (char*)this->Buf() + this->SectionHeaders[istrtab[isymt]].sh_offset;
         uint32_t StringTableLen = uint32_t(this->SectionHeaders[istrtab[isymt]].sh_size);

         NewStringTable[isymt].Push(0, 1); // Initialize new string table, first entry 0

         if (isymt == 0) {
            // Allocate NewSymbolIndex
            NumOldSymbols = (symtabsize + entrysize - 1) / entrysize; // round up to nearest integer to be safe
            NewSymbolIndex.SetNum(NumOldSymbols);   // Allocate array
            NewSymbolIndex.SetZero();               // Initialize
         }

         // Loop through old symbol table
         for (OldSymi = 0; symtab < symtabend; symtab += entrysize, OldSymi++) {

            // Symbol table entry
            sym = *(TELF_Symbol*)symtab;

            // Symbol name
            if (sym.st_name < StringTableLen) {
               name1 = StringTable + sym.st_name;}
            else {
               err.submit(2035);  name1 = 0;
            }
            name2 = 0;

            // Symbol type
            int type = sym.st_type;
            binding = sym.st_bind;
            if (binding == STB_LOCAL) {
               SymbolType = SYMT_LOCAL;    // Symbol is local
            }
            else if (type == STT_OBJECT || type == STT_FUNC || type == STT_NOTYPE) {
               if (int16_t(sym.st_shndx) > 0) { // Check section number
                  SymbolType = SYMT_PUBLIC;  // Symbol is public
               }
               else {
                  SymbolType = SYMT_EXTERNAL; // Symbol is external
               }
            }
            else {
               SymbolType = SYMT_OTHER; // Symbol is section or filename or debug
            }

            // 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
               binding = STB_WEAK;
               sym.st_bind = binding;
               sym.st_type = type ;
               break;

            case SYMA_MAKE_LOCAL:
               // Make public symbol local, make external symbol ignored
               binding = STB_LOCAL;  SymbolType = SYMT_LOCAL;
               sym.st_bind = binding;
               sym.st_type = type ;
               break;

            case SYMA_CHANGE_NAME:
               // Change name of symbol
               name1 = name2;  name2 = 0;
               break;

            case SYMA_ALIAS: 
               // Make alias and keep old name
               if (isymt != 0) err.submit(1033, name1); // alias in dynsym not supported yet
               AliasEntry = sym;
               break;

            default:
               err.submit(9000); // unknown error
            }

            // Add entry to new string table
            if (name1 && *name1) {
               symnamei = NewStringTable[isymt].PushString(name1);
            }
            else {
               symnamei = 0;
            }
            sym.st_name = symnamei;

            if (isymt == 0) {
               // The symtab symbol table must be ordered with local symbols first.
               // Therefore the public and external symbols are temporarily stored
               // in TempGlobalSymbolTable and the high bit of NewSymi is set.
               // The two tables are joined together when the number of local symbols
               // is known and the indexes into TempGlobalSymbolTable are adjusted
               // to indexes into the joined table.
               if (SymbolType == SYMT_LOCAL) {
                  NewSymbolTable[isymt].Push(&sym, entrysize);
                  NewSymi = NewSymbolTable[isymt].GetLastIndex();
               }
               else {
                  TempGlobalSymbolTable.Push(&sym, entrysize);
                  NewSymi = TempGlobalSymbolTable.GetLastIndex() | 0x80000000;
               }
               // Insert into symbol index translation table
               NewSymbolIndex[OldSymi] = NewSymi;

               if (action == SYMA_ALIAS && name2 && *name2) {
                  // Make one more entry for new alias
                  symnamei = NewStringTable[isymt].PushString(name2);
                  AliasEntry.st_name = symnamei;
                  TempGlobalSymbolTable.Push(&AliasEntry, entrysize);
               }
            }
            else {
               // dynsym table has no local symbols
               // no index translation table is currently needed
               NewSymbolTable[isymt].Push(&sym, entrysize);
            }

         } // End of loop through old symbol table

         if (isymt == 0) {
            // The symbol table has been temporarily split into local and non-local
            // Save index to first nonlocal symbol
            FirstGlobalSymbol = NewSymbolTable[isymt].GetNumEntries();

            // Adjust symbol index translation table
            for (OldSymi = 0; OldSymi < NumOldSymbols; OldSymi++) {
               if (NewSymbolIndex[OldSymi] & 0x80000000) {
                  // Translate index into TempGlobalSymbolTable to index into joined table
                  NewSymbolIndex[OldSymi] = (NewSymbolIndex[OldSymi] & ~0x80000000) + FirstGlobalSymbol;
               }
            }

            // Join the two tables
            NewSymbolTable[isymt].Push(TempGlobalSymbolTable.Buf(), TempGlobalSymbolTable.GetDataSize());
         }
      }
   } // End of isymt loop through possibly two symbol tables
}


// ChangeSections()
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2ELF<ELFSTRUCTURES>::ChangeSections() {
   // Convert subfunction: Change section names if needed and adjust all relocation tables
   uint32_t SectionNumber;        // Section number
   const char * name1;          // Section name
   const char * name2;          // Changed section name
   int action;                  // Name change action
   TELF_SectionHeader * sheaderp;   // Pointer to section header
   uint32_t SectionHeaderOffset;  // File offset to section header
   uint32_t namei;                // Section name index into string table
   TELF_Relocation * relocp;        // Pointer to relocation entry
   uint32_t oldsymi, newsymi;     // Relocation symbol index

   uint32_t sectionSymtab = 2;     // section string table index into NewStringTable

   if (istrtab[2] == istrtab[0]) {
       sectionSymtab = 0;              // sections and symbols use same table
   }

   // Initialize section header string table .shstrtab. First entry = 0
   NewStringTable[sectionSymtab].Push(0, 1);

   // Loop through sections
   SectionHeaderOffset = uint32_t(this->FileHeader.e_shoff);
   for (SectionNumber = 0; SectionNumber < this->NSections; SectionNumber++, SectionHeaderOffset += this->FileHeader.e_shentsize) {

      // Get section header
      sheaderp = (TELF_SectionHeader*)(this->Buf() + SectionHeaderOffset);

      // Section name
      namei = sheaderp->sh_name;
      if (namei >= this->SecStringTableLen) {
          err.submit(2112); sheaderp->sh_name = 0; return;}
      name1 = this->SecStringTable + namei;

      // Check if name change
      action = cmd.SymbolChange(name1, &name2, SYMT_SECTION);
      if (action == SYMA_CHANGE_NAME) name1 = name2;

      // Store name in .shstrtab string table
      if (name1 && *name1) {
         namei = NewStringTable[sectionSymtab].PushString(name1);
      }
      else {
         namei = 0;
      }
      sheaderp->sh_name = namei;   // Put new string index into section header

      if (sheaderp->sh_type == SHT_REL || sheaderp->sh_type == SHT_RELA) {
         // This is a relocation section. Update all symbol indices

         int8_t * reltab = this->Buf() + sheaderp->sh_offset;
         int8_t * reltabend = reltab + sheaderp->sh_size;
         int entrysize = (int)(sheaderp->sh_entsize);
         if (entrysize <= 0) entrysize = sizeof(TELF_Relocation);

         // Loop through entries
         for (; reltab < reltabend; reltab += entrysize) {
            relocp = (TELF_Relocation*)reltab;

            oldsymi = relocp->r_sym;

            if (oldsymi >= NumOldSymbols) {
               err.submit(2040);  oldsymi = 0;
            }
            // Translate symbol index
            newsymi = NewSymbolIndex[oldsymi];

            // Put back into relocation entry
            relocp->r_sym = newsymi;
         }
      }
   }
}


// MakeBinaryFile()
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2ELF<ELFSTRUCTURES>::MakeBinaryFile() {

   uint32_t SectionNumber;               // Section number
   CMemoryBuffer NewSectionHeaders;    // Temporary storage of section headers

   // Copy file header
   ToFile.Push(this->Buf(), sizeof(TELF_Header));

   // Copy program header if any
   if (this->FileHeader.e_phnum) {
      ToFile.Push(this->Buf() + this->FileHeader.e_phoff, this->FileHeader.e_phentsize * this->FileHeader.e_phnum);
      ((TELF_Header*)ToFile.Buf())->e_phoff = sizeof(TELF_Header);
   }

   // Copy section data
   uint32_t SectionHeaderOffset = uint32_t(this->FileHeader.e_shoff);
   TELF_SectionHeader sheader;                     // Section header

   // Loop through sections
   for (SectionNumber = 0; SectionNumber < this->NSections; SectionNumber++, SectionHeaderOffset += this->FileHeader.e_shentsize) {

      // Get section header
      //sheader = this->Get<TELF_SectionHeader>(SectionHeaderOffset);
      // Some compilers fail with the double template here. Avoid the template:
      sheader = *(TELF_SectionHeader*)(this->Buf() + SectionHeaderOffset);

      // Check for null section
      if (SectionNumber == 0 && sheader.sh_type != 0) {
         // First section must be null
         err.submit(2036, 0);
      }

      // Align
      ToFile.Align(16);

      // Check for sections that have been modified
      if (SectionNumber == isymtab[0]) {
         // Static symbol table .symtab
         sheader.sh_offset = ToFile.Push(NewSymbolTable[0].Buf(), NewSymbolTable[0].GetDataSize());
         sheader.sh_size = NewSymbolTable[0].GetDataSize();
         sheader.sh_info = FirstGlobalSymbol;
      }
      else if (SectionNumber == isymtab[1]) {
         // Dynamic symbol table .dynsym
         sheader.sh_offset = ToFile.Push(NewSymbolTable[1].Buf(), NewSymbolTable[1].GetDataSize());
         sheader.sh_size = NewSymbolTable[1].GetDataSize();
      }
      else if (SectionNumber == istrtab[0]) {
         // Symbol string table .strtab
         sheader.sh_offset = ToFile.Push(NewStringTable[0].Buf(), NewStringTable[0].GetDataSize());
         sheader.sh_size = NewStringTable[0].GetDataSize();
      }
      else if (SectionNumber == istrtab[1] && SectionNumber != istrtab[0]) {
         // Dynamic symbol string table if different from .strtab
         sheader.sh_offset = ToFile.Push(NewStringTable[1].Buf(), NewStringTable[1].GetDataSize());
         sheader.sh_size = NewStringTable[1].GetDataSize();
      }
      else if (SectionNumber == istrtab[2]) {
         // Section name string table .shstrtab
         sheader.sh_offset = ToFile.Push(NewStringTable[2].Buf(), NewStringTable[2].GetDataSize());
         sheader.sh_size = NewStringTable[2].GetDataSize();
      }
      else if (sheader.sh_type == SHT_NOBITS) {
         // BSS section. Nothing
         ;
      }
      else {
         // Any other section (including istrtab[3] = .stabstr)
         sheader.sh_offset = ToFile.Push(this->Buf() + (uint32_t)sheader.sh_offset, (uint32_t)sheader.sh_size);
      }

      // Store section header
      NewSectionHeaders.Push(&sheader, sizeof(sheader));

   } // End of section loop

   // Align
   ToFile.Align(16);

   // Store section headers
   uint32_t SectionHeadersOffset = ToFile.Push(NewSectionHeaders.Buf(), NewSectionHeaders.GetDataSize());

   // Update file header
   ((TELF_Header*)ToFile.Buf())->e_shoff = SectionHeadersOffset;
   ((TELF_Header*)ToFile.Buf())->e_shentsize = sizeof(TELF_SectionHeader);
   ((TELF_Header*)ToFile.Buf())->e_shnum = NewSectionHeaders.GetNumEntries();
   ((TELF_Header*)ToFile.Buf())->e_shstrndx = istrtab[2];
}


// Make template instances for 32 and 64 bits
template class CELF2ELF<ELF32STRUCTURES>;
template class CELF2ELF<ELF64STRUCTURES>;