/****************************  elf2cof.cpp   *********************************
* Author:        Agner Fog
* Date created:  2006-08-19
* Last modified: 2009-07-15
* Project:       objconv
* Module:        elf2cof.cpp
* Description:
* Module for converting ELF file to PE/COFF file
*
* Copyright 2006-2009 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>
CELF2COF<ELFSTRUCTURES>::CELF2COF() {
   // Reset all
   memset(this, 0, sizeof(*this));
}


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

   // Some compilers require this-> for accessing members of template base class,
   // according to the so-called two-phase lookup rule.

   // Allocate variable size buffers
   NewSectIndex.SetNum(this->NSections);// Allocate section translation table
   NewSectIndex.SetZero();              // Initialize

   // Call the subfunctions
   ToFile.SetFileType(FILETYPE_COFF);  // Set type of to file
   MakeFileHeader();                   // Make file header
   MakeSectionsIndex();                // Make sections index translation table
   MakeSymbolTable();                  // Make symbol table and string tables
   MakeSections();                     // Make sections and relocation tables
   HideUnusedSymbols();                // Hide unused symbols
   MakeBinaryFile();                   // Put sections together
   *this << ToFile;                    // Take over new file buffer
}


// MakeFileHeader(): Convert subfunction to make file header
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2COF<ELFSTRUCTURES>::MakeFileHeader() {
   
   // Make PE file header
   NewFileHeader.Machine = (this->WordSize == 32) ? PE_MACHINE_I386 : PE_MACHINE_X8664;
   NewFileHeader.TimeDateStamp = (uint32)time(0);
   NewFileHeader.SizeOfOptionalHeader = 0;
   NewFileHeader.Flags = 0;

   // Values inserted later:
   NewFileHeader.NumberOfSections = 0;
   NewFileHeader.PSymbolTable = 0;
   NewFileHeader.NumberOfSymbols = 0;

   // Put file header into file
   ToFile.Push(&NewFileHeader, sizeof(NewFileHeader));
}


// MakeSectionsIndex(): Make sections index translation table
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2COF<ELFSTRUCTURES>::MakeSectionsIndex() {
   // We must make this table before the segments, because it is needed for the
   // symbol table, and we must make the symbol table before the relocation table,
   // and we must make the relocation table together with the sections.

   uint32 oldsec;                     // Section number in old file
   uint32 newsec = 0;                 // Section number in new file

   // Loop through old sections
   for (oldsec = 0; oldsec < this->NSections; oldsec++) {

      // Get section name
      const char * sname = "";
      uint32 namei = this->SectionHeaders[oldsec].sh_name;
      if (namei >= this->SecStringTableLen) err.submit(2112);
      else sname = this->SecStringTable + namei;

      if (cmd.DebugInfo == CMDL_DEBUG_STRIP) {
         // Check for debug section names
         if (strncmp(sname, ".note",    5) == 0
         ||  strncmp(sname, ".comment", 8) == 0
         ||  strncmp(sname, ".stab",    5) == 0
         ||  strncmp(sname, ".debug",   6) == 0) {
            // Remove this section
            this->SectionHeaders[oldsec].sh_type = SHT_REMOVE_ME;
            cmd.CountDebugRemoved();
         }
      }

      if (cmd.ExeptionInfo == CMDL_EXCEPTION_STRIP) {
         // Check for exception section name
         if (strncmp(sname, ".eh_frame", 9) == 0) {
            // Remove this section
            this->SectionHeaders[oldsec].sh_type = SHT_REMOVE_ME;
            cmd.CountExceptionRemoved();
         }
      }

      // Search for program data sections only
      if (this->SectionHeaders[oldsec].sh_type == SHT_PROGBITS 
      ||  this->SectionHeaders[oldsec].sh_type == SHT_NOBITS) {
         // Section index translation table
         NewSectIndex[oldsec] = newsec++;
      }
      else {
         NewSectIndex[oldsec] = 0;
      }
   }
   // Store number of sections in new file
   NumSectionsNew = newsec;

   // Calculate file offset of raw data
   RawDataOffset = sizeof(SCOFF_FileHeader) + NumSectionsNew * sizeof(SCOFF_SectionHeader);
}


// MakeSections(): Convert subfunction to make sections and relocation tables
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2COF<ELFSTRUCTURES>::MakeSections() {
   uint32 oldsec;                   // Section number in old file
   uint32 relsec;                   // Relocation section in old file
   SCOFF_SectionHeader NewHeader;   // New section header
   TELF_SectionHeader OldHeader;        // Old section header
   TELF_SectionHeader OldRelHeader;     // Old relocation section header
   TELF_Relocation OldRelocation;       // Old relocation table entry
   SCOFF_Relocation NewRelocation;  // New relocation table entry

   // Loop through old sections
   for (oldsec = 0; oldsec < this->NSections; oldsec++) {

      // Copy old header for convenience
      OldHeader = this->SectionHeaders[oldsec];

      // Search for program data sections only
      if (OldHeader.sh_type == SHT_PROGBITS || OldHeader.sh_type == SHT_NOBITS) {

         // Reset new section header
         memset(&NewHeader, 0, sizeof(NewHeader));

         // Section name
         const char * sname = "";
         uint32 namei = OldHeader.sh_name;
         if (namei >= this->SecStringTableLen) err.submit(2112);
         else sname = this->SecStringTable + namei;

         // Check for special names
         if (strcmp(sname, ELF_CONSTRUCTOR_NAME)==0) {
            // This is the constructors segment
            sname = COFF_CONSTRUCTOR_NAME;
            OldHeader.sh_flags &= ~ SHF_WRITE;
         }

         // Store name in section header
         COFF_PutNameInSectionHeader(NewHeader, sname, NewStringTable);

         // Raw data
         NewHeader.SizeOfRawData = uint32(OldHeader.sh_size);  // section size in file
         if (OldHeader.sh_size) {
            // File ptr to raw data for section
            NewHeader.PRawData = NewRawData.GetDataSize() + RawDataOffset;

            // Copy raw data
            NewRawData.Push(this->Buf()+(uint32)(OldHeader.sh_offset), (uint32)(OldHeader.sh_size)); 
            NewRawData.Align(4);
         }

         // Section flags
         NewHeader.Flags = PE_SCN_MEM_READ;
         if (OldHeader.sh_flags & SHF_WRITE) NewHeader.Flags |= PE_SCN_MEM_WRITE;
         if (OldHeader.sh_flags & SHF_EXECINSTR) {
            NewHeader.Flags |= PE_SCN_MEM_EXECUTE | PE_SCN_CNT_CODE;
         }
         else {
            NewHeader.Flags |= (OldHeader.sh_type == SHT_PROGBITS) ? 
            PE_SCN_CNT_INIT_DATA : PE_SCN_CNT_UNINIT_DATA;
         }
         // Alignment
         int NewAlign = FloorLog2(uint32(OldHeader.sh_addralign)) + 1;
         if (NewAlign > 14) NewAlign = 14;   // limit for highest alignment
         NewHeader.Flags |= PE_SCN_ALIGN_1 * NewAlign;

         // Find relocation table for this section by searching through all sections
         for (relsec = 1; relsec < this->NSections; relsec++) {

            // Get section header
            OldRelHeader = this->SectionHeaders[relsec];

            // Check if this is a relocations section referring to oldsec
            if ((OldRelHeader.sh_type == SHT_REL || OldRelHeader.sh_type == SHT_RELA) // if section is relocation
            && OldRelHeader.sh_info == oldsec) { // and if section refers to current section

               // Found the right relocation table. Get pointer
               int8 * reltab = this->Buf() + uint32(OldRelHeader.sh_offset);
               int8 * reltabend = reltab + uint32(OldRelHeader.sh_size);

               // Get entry size
               int entrysize = uint32(OldRelHeader.sh_entsize);
               int expectedentrysize = (OldRelHeader.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;}

               // File pointer for new relocations
               NewHeader.PRelocations = NewRawData.GetDataSize() + RawDataOffset;   // file ptr to relocation entries

               // Loop through relocation table entries
               for (; reltab < reltabend; reltab += entrysize) {

                  // Copy relocation table entry with or without addend
                  OldRelocation.r_addend = 0;
                  memcpy(&OldRelocation, reltab, entrysize); 

                  // Find inline addend
                  uint32 InlinePosition = (uint32)(NewHeader.PRawData - RawDataOffset + OldRelocation.r_offset);

                  // Check that address is valid
                  if (InlinePosition >= this->GetDataSize()) {
                     // Address is invalid
                     err.submit(2032);
                     break;
                  }

                  // Pointer to inline addend
                  int32 * piaddend = (int32*)(NewRawData.Buf() + InlinePosition);

                  // Symbol offset
                  NewRelocation.VirtualAddress = uint32(OldRelocation.r_offset);

                  // Symbol table index
                  if (OldRelocation.r_sym < NewSymbolIndex.GetNumEntries()) { 
                     NewRelocation.SymbolTableIndex = NewSymbolIndex[OldRelocation.r_sym];
                  }
                  else {
                     NewRelocation.SymbolTableIndex = 0; // Symbol table index out of range
                  }

                  // Get relocation type and fix addend
                  if (this->WordSize == 32) {
                     switch(OldRelocation.r_type) {
                     case R_386_NONE:    // Ignored
                        NewRelocation.Type = COFF32_RELOC_ABS;  break;

                     case R_386_IRELATIVE:
                        err.submit(1063); // Warning: Gnu indirect function cannot be converted
                        // continue in next case?:
                     case R_386_32:      // 32-bit absolute virtual address
                        NewRelocation.Type = COFF32_RELOC_DIR32;  
                        *piaddend += uint32(OldRelocation.r_addend);  
                        break;

                     case R_386_PC32:   // 32-bit self-relative
                        NewRelocation.Type = COFF32_RELOC_REL32;  
                        // Difference between EIP-relative and self-relative relocation = size of address field
                        // Adjust inline addend for different relocation method:
                        *piaddend += 4 + uint32(OldRelocation.r_addend);
                        break;

                     case R_386_GOT32: case R_386_GLOB_DAT: case R_386_GOTOFF: case R_386_GOTPC:
                        // Global offset table
                        err.submit(2042);     // cannot convert position-independent code
                        err.ClearError(2042); // report this error only once
                        NewRelocation.Type = 0;
                        break;

                     case R_386_PLT32: case R_386_JMP_SLOT: 
                        // procedure linkage table
                        err.submit(2043);     // cannot convert import table
                        err.ClearError(2043); // report this error only once
                        NewRelocation.Type = 0;
                        break;

                     case R_386_RELATIVE:  // adjust by program base
                     default:              // Unknown or unsupported relocation method
                        err.submit(2030, OldRelocation.r_type); 
                        err.ClearError(2030); // report this error only once
                        NewRelocation.Type = 0; 
                        break;
                     }
                  }
                  else { // WordSize == 64
                     switch(OldRelocation.r_type) {
                     case R_X86_64_NONE:     // Ignored
                        NewRelocation.Type = COFF64_RELOC_ABS;  
                        break;

                     case R_X86_64_64:      // 64 bit absolute virtual addres
                        NewRelocation.Type = COFF64_RELOC_ABS64;  
                        *(int64*)piaddend += OldRelocation.r_addend;  
                        break;

                     case R_X86_64_IRELATIVE:
                        err.submit(1063); // Warning: Gnu indirect function cannot be converted
                        // continue in next case?:
                     case R_X86_64_32:      // 32 bit absolute virtual address
                        NewRelocation.Type = COFF64_RELOC_ABS32;  
                        *piaddend += uint32(OldRelocation.r_addend);  
                        break;

                     case R_X86_64_PC32:    // 32 bit, self-relative
                        // See COFF2ELF.cpp for an explanation of the difference between
                        // COFF and ELF relative relocation methods
                        *piaddend += uint32(OldRelocation.r_addend);
                        if (*piaddend >= -8 && *piaddend <= -4) {
                           NewRelocation.Type = (uint16)(COFF64_RELOC_REL32 - *piaddend - 4);  
                           *piaddend = 0;
                        }
                        else {
                           NewRelocation.Type = COFF64_RELOC_REL32;
                           *piaddend += 4;
                        }
                        break;

                     case R_X86_64_RELATIVE:  // Adjust by program base
                        err.submit(2030, OldRelocation.r_type); 
                        err.ClearError(2030); // report this error only once
                        NewRelocation.Type = 0;
                        break;

                     case R_X86_64_GOT32: case R_X86_64_GLOB_DAT: case R_X86_64_GOTPCREL:
                        // Global offset table
                        err.submit(2042);     // cannot convert position-independent code
                        err.ClearError(2042); // report this error only once
                        NewRelocation.Type = 0;
                        break;

                     case R_X86_64_PLT32: case R_X86_64_JUMP_SLOT: 
                        // procedure linkage table
                        err.submit(2042);     // cannot convert import table
                        err.ClearError(2043); // report this error only once
                        NewRelocation.Type = 0;
                        break;
                     }
                  }

                  // Store relocation entry
                  NewRawData.Push(&NewRelocation, SIZE_SCOFF_Relocation);
                  NewHeader.NRelocations++;

                  // Remember that symbol is used
                  if (OldRelocation.r_type) {
                     SymbolsUsed[NewRelocation.SymbolTableIndex]++;
                  }                                  

               } // End of relocations loop

            } // End of if right relocation table

         } // End of search for relocation table

         // Align raw data for next section
         NewRawData.Align(4);

         // Store section header in file
         ToFile.Push(&NewHeader, sizeof(NewHeader));

      } // End of if section has program data

   } // End of loop through old sections

} // End of function MakeSections


// Check for overflow when converting 64 bit symbol value to 32 bits.
// Value may be signed or unsigned
static int SymbolOverflow(uint64 x) {
   uint32 Upper = HighDWord(x);        // Upper 32 bits of 64 bit value
   if (Upper == 0xFFFFFFFF) {          // Check for signed overflow
      return int32(x) >= 0;            // Overflow if not signed
   }
   return Upper != 0;                  // Check for unsigned overflow
}
static int SymbolOverflow(uint32 x) {  // Overloaded 32 bit version
   return 0;                           // Cannot overflow if already 32 bits
}


// MakeSymbolTable(): Convert subfunction to make symbol table and string tables
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2COF<ELFSTRUCTURES>::MakeSymbolTable() {
   uint32 oldsec;                      // Section number in old file
   TELF_SectionHeader OldHeader;           // Old section header
   int FoundSymTab = 0;                // Found symbol table
   int8 * strtab;                      // Old symbol string table
   int8 * symtab;                      // Old symbol table
   uint32 symtabsize;                  // Size of old symbol table
   uint32 stringtabsize;               // Size of old string table
   int8 * symtabend;                   // End of old symbol table
   int entrysize;                      // Size of each entry in old symbol table
   uint32 OldSymI;                     // Symbol index in old symbol table
   uint32 NewSymI = 0;                 // Symbol index in new symbol table
   const char * symname = 0;           // Symbol name
   TELF_Symbol OldSym;                     // Old symbol table record
   SCOFF_SymTableEntry NewSym;         // New symbol table record
   SCOFF_SymTableEntry AuxSym;         // Auxiliary symbol table entry
   uint32 numaux;                      // Number of auxiliary records for new entry

   // Initialize new string table. make space for 4-bytes size
   NewStringTable.Push(0, 4);

   // Loop through old sections to find symbol table
   for (oldsec = 0; oldsec < this->NSections; oldsec++) {

      // Search for program data sections only
      if (this->SectionHeaders[oldsec].sh_type == SHT_SYMTAB 
      || this->SectionHeaders[oldsec].sh_type==SHT_DYNSYM) {
         FoundSymTab++;  numaux = 0;

         // Copy symbol table header for convenience
         OldHeader = this->SectionHeaders[oldsec];

         // Find associated string table
         if (OldHeader.sh_link >= this->NSections) {err.submit(2035); OldHeader.sh_link = 0;}
         strtab = this->Buf() + uint32(this->SectionHeaders[OldHeader.sh_link].sh_offset);
         stringtabsize = uint32(this->SectionHeaders[OldHeader.sh_link].sh_size);
            

         // Find old symbol table
         entrysize = uint32(OldHeader.sh_entsize);
         if (entrysize < sizeof(TELF_Symbol)) {err.submit(2033); entrysize = sizeof(TELF_Symbol);}

         symtab = this->Buf() + uint32(OldHeader.sh_offset);
         symtabsize = uint32(OldHeader.sh_size);
         symtabend = symtab + symtabsize;

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

            // Copy old symbol table entry
            OldSym = *(TELF_Symbol*)symtab;

            // Reset new symbol table entry
            memset(&NewSym, 0, sizeof(NewSym));

            // New symbol index
            NewSymI = NewSymbolTable.GetNumEntries(); 

            // Symbol type
            int type = OldSym.st_type;

            // Symbol storage class = binding
            int binding = OldSym.st_bind;

            // Get symbol name
            if (OldSym.st_name < stringtabsize) {
               symname = strtab + OldSym.st_name;
               if (symname && *symname && type != STT_FILE) {
                  // Symbol has a name that we want to store
                  COFF_PutNameInSymbolTable(NewSym, symname, NewStringTable);
               }
            }
            else { // points outside string table
               err.submit(2112); continue;
            }

            // Value
            NewSym.s.Value = uint32(OldSym.st_value);
            // Check for overflow if converting 64 bit symbol value to 32 bits
            if (SymbolOverflow(OldSym.st_value)) err.submit(2020, symname); 

            // Section
            if (OldSym.st_shndx == SHN_UNDEF) {
               NewSym.s.SectionNumber = COFF_SECTION_UNDEF; // External
            }
            else if ((int16)(OldSym.st_shndx) == SHN_ABS) {
               NewSym.s.SectionNumber = COFF_SECTION_ABSOLUTE; // Absolute symbol
            }
            else if (OldSym.st_shndx >= this->NSections) {
               err.submit(2036, OldSym.st_shndx); // Special/unknown section index or out of range
            }
            else {
               // Normal section index. 
               // Look up in section index translation table and add 1 because it is 1-based
               NewSym.s.SectionNumber = (int16)(NewSectIndex[OldSym.st_shndx] + 1);
            }

            // Convert binding/storage class
            switch (binding) {
            case STB_LOCAL:
               NewSym.s.StorageClass = COFF_CLASS_STATIC; break;

            case STB_GLOBAL:
               NewSym.s.StorageClass = COFF_CLASS_EXTERNAL; break;

            case STB_WEAK:
               err.submit(1051, symname); // Weak public symbol not supported
               NewSym.s.StorageClass = COFF_CLASS_WEAK_EXTERNAL; break;

            default: 
               err.submit(2037, binding); // Other. Not supported
            }

            // Make record depending on type
            switch (type) {
            case STT_OBJECT: case STT_NOTYPE:
               // Data object
               NewSym.s.Type = COFF_TYPE_NOT_FUNCTION;  
               if (OldSymI > 0) { // First symbol entry in ELF file is unused
                  NewSymbolTable.Push(&NewSym, SIZE_SCOFF_SymTableEntry);
               }
               break;

            case STT_GNU_IFUNC:
               err.submit(1063); // Warning: Gnu indirect function cannot be converted
               // continue in next case:
            case STT_FUNC:
               // Function
               NewSym.s.Type = COFF_TYPE_FUNCTION;  
               NewSymbolTable.Push(&NewSym, SIZE_SCOFF_SymTableEntry);
               // Aux records needed only if debug information included
               break;

            case STT_FILE: {
               // File name record
               memset(&NewSym, 0, sizeof(NewSym));
               strcpy(NewSym.s.Name, ".file");
               NewSym.s.StorageClass = COFF_CLASS_FILE;
               NewSym.s.SectionNumber = COFF_SECTION_DEBUG;
               // Remove path from file name
               const char * shortname = symname;
               uint32 len = (uint32)strlen(symname);
               if (len > 1) {
                  // Scan backwards for last '/'
                  for (int scan = len-2; scan >= 0; scan--) {
                     if (symname[scan] == '/') {
                        // Path found. Short name starts after this character
                        shortname = symname + scan + 1;
                        break;
                     }
                  }
               }
               len = (uint32)strlen(shortname);

               // Number of auxiliary records for storing file name
               numaux = (len + SIZE_SCOFF_SymTableEntry - 1) / SIZE_SCOFF_SymTableEntry;
               NewSym.s.NumAuxSymbols = (uint8)numaux;
               // Store regular record
               NewSymbolTable.Push(&NewSym, SIZE_SCOFF_SymTableEntry);               
               // Store numaux auxiliary records for file name
               if (numaux < 15) {
                  int8 * PointAux = NewSymbolTable.Buf() + NewSymbolTable.GetDataSize();
                  NewSymbolTable.Push(0, numaux * SIZE_SCOFF_SymTableEntry);
                  memcpy(PointAux, shortname, strlen(shortname));
               }
               break;}

            case STT_SECTION: {
               // Section name record
               NewSym.s.Value = 0;
               NewSym.s.Type = 0;
               NewSym.s.StorageClass = COFF_CLASS_STATIC;
               NewSym.s.NumAuxSymbols = (uint8)(numaux = 1);

               // Find corresponding section header
               TELF_SectionHeader * OldSecHdr = 0;
               if (OldSym.st_shndx < this->NSections) {
                  OldSecHdr = &(this->SectionHeaders[OldSym.st_shndx]);

                  // Find section name
                  char * sname;
                  if (OldSecHdr->sh_name < this->SecStringTableLen) {
                     sname = this->SecStringTable + OldSecHdr->sh_name;
                     // Put into symbol table
                     COFF_PutNameInSymbolTable(NewSym, sname, NewStringTable);
                  }
               }

               // Store regular record
               NewSymbolTable.Push(&NewSym, SIZE_SCOFF_SymTableEntry);               

               // Make auxiliary record
               memset(&AuxSym, 0, sizeof(AuxSym));
               if (OldSecHdr) {
                  AuxSym.section.Length = uint32(OldSecHdr->sh_size);
                  // Find corresponding relocation section header
                  // Assume that relocation section comes immediately after section record
                  if ((uint32)OldSym.st_shndx + 1 < this->NSections    // if not last section
                  && (OldSecHdr[1].sh_type == SHT_REL || OldSecHdr[1].sh_type == SHT_RELA) // and if next section is relocation
                  && OldSecHdr[1].sh_info == OldSym.st_shndx // and if next section refers to current section
                  && OldSecHdr[1].sh_entsize > 0) { // Avoid division by 0
                     // Calculate number of relocations
                     AuxSym.section.NumberOfRelocations = (uint16)(uint32(OldSecHdr[1].sh_size) / uint32(OldSecHdr[1].sh_entsize));
                  }
               }
               // Store auxiliary record
               NewSymbolTable.Push(&AuxSym, SIZE_SCOFF_SymTableEntry);               
               break;}

            case STT_COMMON:
            default:
               err.submit(2038, type); // Symbol type not supported
            }

            if (FoundSymTab == 1) {
               // Make translation table from old symbol index to new symbol index,
               // assuming there is only one symbol table.
               // Make sure all old symbols have an entry in the NewSymbolIndex table,
               // even if they are discarded.
               NewSymbolIndex.Push(NewSymI);
            }
         } // End OldSymI loop
      }
   } // End search for symbol table
   if (FoundSymTab == 0) err.submit(2034); // Symbol table not found
   if (FoundSymTab  > 1) err.submit(1032); // More than one symbol table found

   // Allocate space for SymbolsUsed table
   SymbolsUsed.SetNum(NewSymI+1);
   SymbolsUsed.SetZero();                  // Initialize
}


// HideUnusedSymbols(): Hide unused symbols if stripping debug info or exception info
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2COF<ELFSTRUCTURES>::HideUnusedSymbols() {

   if (cmd.DebugInfo != CMDL_DEBUG_STRIP && cmd.ExeptionInfo != CMDL_EXCEPTION_STRIP) {
      // No sections removed. Do nothing
      return;
   }

   // Pointer to new symbol table
   union {
      SCOFF_SymTableEntry * p; // Symtab entry pointer
      int8 * b;                // Used for increment
   } NewSymtab;
   NewSymtab.b = NewSymbolTable.Buf();
   int numaux = 0, isym;
   int NumberOfSymbols = NewSymbolTable.GetNumEntries();

   // Loop through new symbol table
   for (isym = 0; isym < NumberOfSymbols; isym += numaux+1, NewSymtab.b += SIZE_SCOFF_SymTableEntry*(numaux+1)) {

      // Number of auxiliary records belonging to same symbol
      numaux = NewSymtab.p->s.NumAuxSymbols;  if (numaux < 0) numaux = 0;

      if (NewSymtab.p->s.StorageClass == COFF_CLASS_EXTERNAL
      ||  NewSymtab.p->s.StorageClass == COFF_CLASS_WEAK_EXTERNAL) {
         if (NewSymtab.p->s.SectionNumber == COFF_SECTION_UNDEF) {
            // External symbol. Check if it is used
            if (!SymbolsUsed[isym]) {
               // Symbol is unused. Hide it to prevent linking errors
               NewSymtab.p->s.StorageClass = COFF_CLASS_NULL;
               NewSymtab.p->s.SectionNumber = COFF_SECTION_UNDEF;
               NewSymtab.p->s.Type = COFF_TYPE_NOT_FUNCTION;
               cmd.CountSymbolsHidden();
            }
         }
      }
   }
}

// MakeBinaryFile(): Convert subfunction to put all sections together
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2COF<ELFSTRUCTURES>::MakeBinaryFile() {

   // Insert string table size
   //NewStringTable.Get<uint32>(0) = NewStringTable.GetDataSize();
   // Some compilers fail with the double template here. Avoid the template:
   *(uint32*)(NewStringTable.Buf()) = NewStringTable.GetDataSize();

   // Update file header
   NewFileHeader.NumberOfSections = (uint16)NumSectionsNew;
   NewFileHeader.PSymbolTable = RawDataOffset + NewRawData.GetDataSize();
   NewFileHeader.NumberOfSymbols = NewSymbolTable.GetNumEntries();

   // Replace file header in new file with updated version
   memcpy(ToFile.Buf(), &NewFileHeader, sizeof(NewFileHeader));

   // Section headers have already been inserted.
   // Insert raw data in file
   ToFile.Push(NewRawData.Buf(), NewRawData.GetDataSize());

   // Insert symbol table
   ToFile.Push(NewSymbolTable.Buf(), NewSymbolTable.GetDataSize());

   // Insert string table
   ToFile.Push(NewStringTable.Buf(), NewStringTable.GetDataSize());
}


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