File: elf2asm.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 (526 lines) | stat: -rw-r--r-- 20,209 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
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
/****************************  elf2asm.cpp   *********************************
* Author:        Agner Fog
* Date created:  2007-04-22
* Last modified: 2016-11-06
* Project:       objconv
* Module:        elf2asm.cpp
* Description:
* Module for disassembling ELF
*
* Copyright 2007-2016 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>
CELF2ASM<ELFSTRUCTURES>::CELF2ASM() {
}


// FindImageBase()
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2ASM<ELFSTRUCTURES>::FindImageBase() {
   // Find image base if executable file

   // Check if executable
   switch (this->FileHeader.e_type) {
   case ET_REL: default:
      // Not an executable file
      ExeType = 0;  ImageBase = 0;
      return;
   case ET_DYN: // Shared object
      ExeType = 1;
      break;
   case ET_EXEC: // Executable file
      ExeType = 2;
      break;
   }

   // Loop through sections to find the first allocated section
   for (uint32_t sc = 0; sc < this->NSections; sc++) {
      if (this->SectionHeaders[sc].sh_type == SHT_PROGBITS    // Must be code or data section
      && (this->SectionHeaders[sc].sh_flags & SHF_ALLOC)      // Must be allocated
      && this->SectionHeaders[sc].sh_offset <= this->SectionHeaders[sc].sh_addr) { // Avoid negative
         // Image base can be calculated from this section
         ImageBase = this->SectionHeaders[sc].sh_addr - this->SectionHeaders[sc].sh_offset;
         // Make sure ImageBase is divisible by page size
         ImageBase = ImageBase & - 0x1000;
         // Stop searching
         return;
      }
   }
   // Failure. Cannot compute image base from any of the sections
   ImageBase = 0;
   return;    
}


// Convert
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2ASM<ELFSTRUCTURES>::Convert() {
   // Do the conversion

   // Find image base and executable type
   FindImageBase();

   // Tell disassembler
   Disasm.Init(ExeType, ImageBase);                       // Set image base

   // Make Sections list in Disasm
   MakeSectionList();

   // Make Symbols list in Disasm
   MakeSymbolList();

   // Make relocations for object and executable files
   MakeRelocations();

   if (ImageBase) {
      // Executable file
      MakeImportList();                          // Make imported symbols for executable files
      MakeExportList();                          // Make exported symbols for executable files
      MakeListLabels();                          // Put labels on all image directory tables
   }
   Disasm.Go();                                  // Disassemble
   *this << Disasm.OutFile;                      // Take over output file from Disasm
}

// MakeSectionList
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2ASM<ELFSTRUCTURES>::MakeSectionList() {
   // Make Sections list and Relocations list in Disasm

   // Allocate array for translating oroginal section numbers to new index
   SectionNumberTranslate.SetNum(this->NSections + 1);
   uint32_t NewSectionIndex = 0;

   for (uint32_t sc = 0; sc < this->NSections; sc++) {
      // Get copy of 32-bit header or converted 64-bit header
      TELF_SectionHeader sheader = this->SectionHeaders[sc];
      //int entrysize = (uint32_t)(sheader.sh_entsize);
      uint32_t namei = sheader.sh_name;
      if (namei >= this->SecStringTableLen) {err.submit(2112); break;}

//      if (sheader.sh_type == SHT_PROGBITS || sheader.sh_type == SHT_NOBITS) {
//         // This is a code, data or bss section

      if (sheader.sh_flags & SHF_ALLOC) {
         // This is an allocated section

         // Give it a new index
         SectionNumberTranslate[sc] = ++NewSectionIndex;

         // Get section parameters
         uint8_t * Buffer = (uint8_t*)(this->Buf()) + (uint32_t)sheader.sh_offset;
         uint32_t  InitSize = (sheader.sh_type == SHT_NOBITS) ? 0 : (uint32_t)sheader.sh_size;
         uint32_t  TotalSize = (uint32_t)sheader.sh_size;
         uint32_t  SectionAddress = (uint32_t)sheader.sh_addr - (uint32_t)ImageBase;
         uint32_t  Align = FloorLog2((uint32_t)sheader.sh_addralign);
         const char * Name = this->SecStringTableLen ? this->SecStringTable + namei : "???";

         // Detect segment type
         uint32_t  Type = 0;
         if (sheader.sh_flags & SHF_ALLOC) {
            // Allocate
            if (sheader.sh_type == SHT_NOBITS) {
               // Uninitialized data
               Type = 3;
            }
            else if (sheader.sh_flags & SHF_EXECINSTR) {
               // Executable
               Type = 1;
            }
            else if (!(sheader.sh_flags & SHF_WRITE)) {
               // Not writeable
               Type = 4;
            }
            else {
               // Initialized writeable data
               Type = 2;
            }
         }

         // Save section record
         Disasm.AddSection(Buffer, InitSize, TotalSize, SectionAddress, Type, Align, this->WordSize, Name);
      }
   }
}

// MakeSymbolList
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2ASM<ELFSTRUCTURES>::MakeSymbolList() {
   // Make Symbols list in Disasm

   // Allocate array for translate symbol indices for multiple symbol tables in
   // source file to a single symbol table in disassembler
   SymbolTableOffset.SetNum(this->NSections + 1);
   NumSymbols = 0;

   for (uint32_t sc = 0; sc < this->NSections; sc++) {
      // Get copy of 32-bit header or converted 64-bit header
      TELF_SectionHeader sheader = this->SectionHeaders[sc];
      int entrysize = (uint32_t)(sheader.sh_entsize);

      if (sheader.sh_type==SHT_SYMTAB || sheader.sh_type==SHT_DYNSYM) {
         // This is a symbol table

         // Offset for symbols in this symbol table = number of preceding symbols from other symbol tables
         SymbolTableOffset[sc] = NumSymbols;

         // Find associated string table
         if (sheader.sh_link >= this->NSections) {err.submit(2035); sheader.sh_link = 0;}
         char * strtab = (char*)(this->Buf()) + uint32_t(this->SectionHeaders[sheader.sh_link].sh_offset);

         // Find symbol table
         uint32_t symtabsize = (uint32_t)(sheader.sh_size);
         int8_t * symtab = this->Buf() + uint32_t(sheader.sh_offset);
         int8_t * symtabend = symtab + symtabsize;
         if (entrysize < (int)sizeof(TELF_Symbol)) {err.submit(2033); entrysize = (int)sizeof(TELF_Symbol);}

         // Loop through symbol table
         uint32_t symi1;                           // Symbol number in this table
         uint32_t symi2;                           // Symbol number in joined table
         symtab += entrysize;                    // Skip symbol number 0
         for (symi1 = 1; symtab < symtabend; symtab += entrysize, symi1++) {

            // Symbol number in joined table = symi1 + number of symbols in preceding tables
            symi2 = SymbolTableOffset[sc] + symi1;
            
            // Copy 32 bit symbol table entry or convert 64 bit entry
            TELF_Symbol sym = *(TELF_Symbol*)symtab;

            // Parameters
            uint32_t Offset = uint32_t(sym.st_value);
            uint32_t Size = (uint32_t)sym.st_size;

            // Get section
            int32_t Section = int16_t(sym.st_shndx);
            if (Section >= (int32_t)(this->NSections)) {
               // Error. wrong section
               Section = 0;
            }
            if (Section > 0) {
               // Translate to new section index
               Section = SectionNumberTranslate[Section];
            }
            else if ((int16_t)Section < 0) {
               // Special section values
               if ((int16_t)Section == SHN_ABS) {
                  // Absolute symbol
                  Section = ASM_SEGMENT_ABSOLUTE;
               }
               else {
                  // Other special values
                  Section = ASM_SEGMENT_ERROR;
               }
            }

            // Get name
            const char * Name = 0;
            if (*(strtab + sym.st_name)) {
               Name = strtab + sym.st_name;
            }
            
            // Get import .so name
            const char * DLLName = 0;
            if (sheader.sh_type==SHT_DYNSYM && sym.st_value == 0 
            && sym.st_shndx == 0 && sym.st_size > 0) {
               // I don't know how to find out which .so the symbol is imported from
               // It must be something in the .dynamic section.
               DLLName = "?.so";
            }

            // Get scope
            uint32_t Scope = 0;
            switch (sym.st_bind) {
            case STB_LOCAL:
               Scope = 2;
               break;
            case STB_WEAK:
               Scope = 8;
               if (Section > 0) break;
               // Section == 0: continue as global
            case STB_GLOBAL:
               // Public or external
               Scope = (sym.st_shndx > 0) ? 4 : 0x20;
               break;
            }
            // Get type
            uint32_t Type = 0;

            if (sym.st_type == STT_FUNC) {
               // Function
               Type = 0x83;
            }
            else if (sym.st_type == STT_GNU_IFUNC) {
               // Gnu indirect function
               Type = 0x40000083;
            }
            else if (sym.st_type == STT_OBJECT) {
               // Probably a data object
               switch (Size) {
               case 1:
                  Type = 1; 
                  break;
               case 2:
                  Type = 2; 
                  break;
               case 4:
                  Type = 3;
                  break;
               case 8:
                  Type = 4;
                  break;
               default:
                  Type = 1;
                  break;
               }
            }
            else if (sym.st_type == STT_COMMON) {
               // Communal?
               Type = 0;
               Scope = 0x10;
            }
            else if (sym.st_type == STT_SECTION) {
               // This is a section
               Type = 0x80000082;
               Scope = 0;
            }
            else if (sym.st_type == STT_NOTYPE) {
               Type = 0;
            }
            else if (sym.st_type == STT_FILE) {
               // file name. ignore
               continue;
            }            
            else {
               // unknown type. warning
               err.submit(1062, Name);
               Type = 0;
               //continue;
            }

            if (Scope != 0x20) {
               // Not external
               // Check if offset is absolute or section relative
               if (ExeType && Offset >= (uint32_t)ImageBase) {
                  // Offset is absolute address
                  if (Section >= 0 
                     && (uint32_t)Section < this->NSections 
                     && Offset >= (uint32_t)this->SectionHeaders[Section].sh_addr
                     && Offset - (uint32_t)this->SectionHeaders[Section].sh_addr < (uint32_t)(this->SectionHeaders[Section].sh_size)) {
                        // Change to section relative offset
                        Offset -= (uint32_t)(this->SectionHeaders[Section].sh_addr);
                     }
                  else {
                     // Address is outside specified section or otherwise inconsistent. 
                     // Let Disasm try to find the address
                     Section = ASM_SEGMENT_IMGREL;
                     Offset -= (uint32_t)ImageBase;
                  }
               }
            }

            // Store new symbol record
            Disasm.AddSymbol(Section, Offset, Size, Type, Scope, symi2, Name, DLLName);

            // Count symbols
            NumSymbols++;
         }
      }
   }
}

// MakeRelocations
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2ASM<ELFSTRUCTURES>::MakeRelocations() {
   // Make relocations for object and executable files

   int32_t Section;                                // Source section new index

   // Loop through sections
   for (uint32_t sc = 0; sc < this->NSections; sc++) {
      // Get copy of 32-bit header or converted 64-bit header
      TELF_SectionHeader sheader = this->SectionHeaders[sc];
      int entrysize = (uint32_t)(sheader.sh_entsize);

      if (sheader.sh_type == SHT_REL || sheader.sh_type == SHT_RELA) {
         // Relocations section
         int8_t * reltab = this->Buf() + uint32_t(sheader.sh_offset);
         int8_t * reltabend = reltab + uint32_t(sheader.sh_size);
         int expectedentrysize = sheader.sh_type == SHT_RELA ? 
            sizeof(TELF_Relocation) :              // Elf32_Rela, Elf64_Rela
            sizeof(TELF_Relocation) - this->WordSize/8;  // Elf32_Rel,  Elf64_Rel
         if (entrysize < expectedentrysize) {err.submit(2033); entrysize = expectedentrysize;}

         // Loop through entries
         for (; reltab < reltabend; reltab += entrysize) {
            // Copy relocation table entry with or without addend
            TELF_Relocation rel;  rel.r_addend = 0;
            memcpy(&rel, reltab, entrysize);

            // Get section-relative or absolute address
            uint32_t  Offset = (uint32_t)rel.r_offset;

            // Get addend, if any
            int32_t   Addend = (uint32_t)rel.r_addend;

            // Find target symbol
            uint32_t  TargetIndex = rel.r_sym;
            if (sheader.sh_link < this->NSections) {
               // sh_link indicates which symbol table r_sym refers to
               TargetIndex += SymbolTableOffset[sheader.sh_link];
            }

            // Find section
            if (sheader.sh_info < this->NSections) {            
               Section = SectionNumberTranslate[sheader.sh_info];
            }
            else {
               // Not found. Try to let disasm find by absolute address
               Section = ASM_SEGMENT_IMGREL;
               if (Offset < (uint32_t)ImageBase) Offset += (uint32_t)ImageBase;
            }

            // Get relocation type and size
            uint32_t  Type = 0;
            uint32_t  Size = 0;
            if (this->WordSize == 32) {
               switch (rel.r_type) {
               case R_386_RELATIVE: // Adjust by program base
                  Type = 0x21;  Size = 4;
                  break;
               case R_386_JMP_SLOT: // Create PLT entry
                  Type = 0x41;  Size = 4;
                  break;
               case R_386_PLT32: // Self-relative to PLT
                  Type = 0x2002;  Size = 4;
                  break;
               case R_386_32:
                  // Direct 32 bit
                  Type = 1;  Size = 4;
                  break;
               case R_386_PC32:
                  // Self-relative 32 bit
                  Type = 2;  Size = 4;
                  break;
               case R_386_GOTPC:
                  // Self-relative offset to GOT
                  Type = 0x1002;  Size = 4;
                  break;
               case R_386_IRELATIVE:
                  // Reference to Gnu indirect function
                  Type = 0x81;  Size = 4;
                  break;
               case R_386_GLOB_DAT: 
               case R_386_GOT32:
               case R_386_GOTOFF:
                  // Create GOT entry
                  Type = 0x1001;  Size = 4;
                  break;
               }
            }
            else {
               // 64 bit
               switch (rel.r_type) {
               case R_X86_64_RELATIVE:  // Adjust by program base
                  Type = 0x21;  Size = 8;
                  break;
               case R_X86_64_JUMP_SLOT: // Create PLT entry
                  Type = 0x41;  Size = 8;
                  break;
               case R_X86_64_64: 
                  // Direct 64 bit
                  Type = 1;  Size = 8;
                  break;
               case R_X86_64_PC32:
                  // Self relative 32 bit signed
                  Type = 2;  Size = 4;
                  break;
               case R_X86_64_32: case R_X86_64_32S:
                  // Direct 32 bit zero extended or sign extend
                  Type = 1;  Size = 4;
                  break;
               case R_X86_64_16:
                  // Direct 16 bit zero extended
                  Type = 1;  Size = 2;
                  break;
               case R_X86_64_PC16:
                  // 16 bit sign extended pc relative
                  Type = 2;  Size = 2;
                  break;
               case R_X86_64_8:
                  // Direct 8 bit sign extended
                  Type = 1;  Size = 1;
                  break;
               case R_X86_64_PC8:
                  // 8 bit sign extended pc relative
                  Type = 2;  Size = 1;
                  break;
               case R_X86_64_GOTPCREL:
                  // Self relative 32 bit signed offset to GOT entry
                  Type = 0x1002;  Size = 4;
                  break;
               case R_X86_64_IRELATIVE:
                  // Reference to Gnu indirect function
                  Type = 0x81;  Size = 4;
                  break;
               case R_X86_64_PLT32:  // Self-relative to PLT
                  Type = 0x2002;  Size = 4;
                  break;
               case R_X86_64_GLOB_DAT:  // Create GOT entry
               case R_X86_64_GOT32:
                  Type = 0x1001;  Size = 4;
                  break;
               }
            }

            // Check if offset is absolute or section relative
            if (ImageBase && Offset > (uint32_t)ImageBase) {
               // Offset is absolute address
               if (Section > 0 && (uint32_t)Section < this->NSections 
               && Offset >= (uint32_t)(this->SectionHeaders[Section].sh_addr)
               && Offset - (uint32_t)(this->SectionHeaders[Section].sh_addr) < (uint32_t)(this->SectionHeaders[Section].sh_size)) {
                  // Change to section relative offset
                  Offset -= (uint32_t)(this->SectionHeaders[Section].sh_addr);
               }
               else {
                  // Inconsistent. Let Disasm try to find the address
                  Section = ASM_SEGMENT_IMGREL;
                  Offset -= (uint32_t)ImageBase;
               }
            }

            // Save relocation record
            Disasm.AddRelocation(Section, Offset, Addend, Type, Size, TargetIndex);
         }
      }
   }
}


// MakeImportList
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2ASM<ELFSTRUCTURES>::MakeImportList() {
   // Make imported symbols for executable files
}

// MakeExportList
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2ASM<ELFSTRUCTURES>::MakeExportList() {
   // Make exported symbols for executable files
}

// MakeListLabels
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2ASM<ELFSTRUCTURES>::MakeListLabels() {
   // Attach names to all image directories
}


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