Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /****************************   cof2cof.cpp   *********************************
  2. * Author:        Agner Fog
  3. * Date created:  2006-07-28
  4. * Last modified: 2006-07-28
  5. * Project:       objconv
  6. * Module:        cof2cof.cpp
  7. * Description:
  8. * Module for changing symbol names in PE/COFF file
  9. *
  10. * Copyright 2006-2008 GNU General Public License http://www.gnu.org/licenses
  11. *****************************************************************************/
  12. #include "stdafx.h"
  13.  
  14.  
  15. CCOF2COF::CCOF2COF () {
  16.    // Constructor
  17. }
  18.  
  19. void CCOF2COF::Convert() {
  20.    // Do the conversion
  21.  
  22.    // Call the subfunctions
  23.    MakeSymbolTable();          // Symbol table and string tables
  24.    MakeBinaryFile();           // Putting sections together
  25.    *this << ToFile;            // Take over new file buffer
  26. }
  27.  
  28.  
  29. void CCOF2COF::MakeSymbolTable() {
  30.    // Convert subfunction: Make symbol table and string tables
  31.    int isym;                   // current symbol table entry
  32.    int numaux;                 // Number of auxiliary entries in source record
  33.    int symboltype = 0;         // Symbol type
  34.    int action = 0;             // Symbol change action
  35.    int isec;                   // Section number
  36.  
  37.    const char * name1;         // Old name of symbol
  38.    const char * name2;         // Changed name of symbol
  39.    const char * name3;         // New name to store
  40.  
  41.    // Pointer to old symbol table
  42.    union {
  43.       SCOFF_SymTableEntry * p; // Symtab entry pointer
  44.       int8 * b;                // Used for increment
  45.    } OldSymtab;
  46.  
  47.    // Initialize new string table. Make space for size
  48.    NewStringTable.Push(0, 4);
  49.  
  50.    // Loop through source symbol table
  51.    OldSymtab.p = SymbolTable;  // Pointer to source symbol table
  52.    for (isym = 0; isym < NumberOfSymbols; isym += numaux+1, OldSymtab.b += SIZE_SCOFF_SymTableEntry*(numaux+1)) {
  53.  
  54.       // Number of auxiliary records belonging to same symbol
  55.       numaux = OldSymtab.p->s.NumAuxSymbols;  if (numaux < 0) numaux = 0;
  56.  
  57.       // Get first aux record if numaux > 0
  58.       SCOFF_SymTableEntry * sa = (SCOFF_SymTableEntry *)(OldSymtab.b + SIZE_SCOFF_SymTableEntry);
  59.  
  60.       // Check symbol type
  61.       if (numaux && OldSymtab.p->s.StorageClass == COFF_CLASS_STATIC) {
  62.          // This is a section definition record
  63.          // aux record contains length and number of relocations. Ignore aux record
  64.          symboltype = SYMT_SECTION;
  65.          name1 = GetSymbolName(OldSymtab.p->s.Name);
  66.       }
  67.       else if (OldSymtab.p->s.StorageClass == COFF_CLASS_FILE) {
  68.          // This is a filename record
  69.          symboltype = SYMT_OTHER;
  70.          name1 = GetShortFileName(OldSymtab.p);
  71.          // or long file name ?!
  72.       }
  73.       else if (OldSymtab.p->s.Type == 0 && OldSymtab.p->s.StorageClass == COFF_CLASS_FUNCTION) {
  74.          // This is a .bf, .lf, or .ef record following a function record
  75.          // Contains line number information etc. Ignore this record
  76.          name1 = 0;
  77.       }
  78.       else {
  79.          // This is a symbol record
  80.          // Symbol name
  81.          name1 = GetSymbolName(OldSymtab.p->s.Name);
  82.          if (OldSymtab.p->s.StorageClass == COFF_CLASS_EXTERNAL) {
  83.             // This is a public or external symbol
  84.             if (OldSymtab.p->s.SectionNumber <= 0) {
  85.                // This is an external symbol
  86.                symboltype = SYMT_EXTERNAL;
  87.             }
  88.             else {
  89.                // This is a public symbol
  90.                symboltype = SYMT_PUBLIC;
  91.             }
  92.          }
  93.          else {
  94.             // This is a local symbol
  95.             symboltype = SYMT_LOCAL;
  96.          }
  97.       }
  98.       name3 = name1;
  99.       // Check if any change required for this symbol
  100.       action = cmd.SymbolChange(name1, &name2, symboltype);
  101.  
  102.       switch (action) {
  103.       case SYMA_NOCHANGE:
  104.          // No change
  105.          break;
  106.  
  107.       case SYMA_MAKE_WEAK:
  108.          // Make symbol weak
  109.          if (cmd.OutputType == FILETYPE_COFF) {
  110.             // PE/COFF format does not support weak publics. Use this only when converting to ELF
  111.             err.submit(2200);
  112.          }
  113.          // Make weak when converting to ELF
  114.          OldSymtab.p->s.StorageClass = COFF_CLASS_WEAK_EXTERNAL;
  115.          break;
  116.  
  117.       case SYMA_MAKE_LOCAL:
  118.          // Make public symbol local, make external symbol ignored
  119.          OldSymtab.p->s.StorageClass = COFF_CLASS_STATIC;
  120.          break;
  121.  
  122.       case SYMA_CHANGE_NAME:
  123.          // Change name of symbol
  124.          if (OldSymtab.p->s.StorageClass == COFF_CLASS_FILE) {
  125.             // File name is stored in aux records, not in symbol table
  126.             if ((uint32)strlen(name2) > (uint32)numaux * SIZE_SCOFF_SymTableEntry) {
  127.                // Name too long. I don't want to add more aux records
  128.                err.submit(2201, name2);
  129.             }
  130.             else {
  131.                // Insert new file name in aux records
  132.                memset(sa, 0, numaux * SIZE_SCOFF_SymTableEntry);
  133.                memcpy(sa, name2, strlen(name2));
  134.             }
  135.          }
  136.          else {
  137.             // Symbol name stored in normal way
  138.             name3 = name2;
  139.          }
  140.          break;
  141.  
  142.       case SYMA_ALIAS: {
  143.          // Make alias and keep old name
  144.          SCOFF_SymTableEntry AliasEntry = *OldSymtab.p;
  145.          AliasEntry.s.Type = 0;  // Make alias a label, not a function
  146.          AliasEntry.s.NumAuxSymbols = 0;  // No auxiliary .bf and .ef records
  147.          // Put new name into AliasEntry
  148.          memset(AliasEntry.s.Name, 0, 8);
  149.          if (strlen(name2) > 8) {
  150.             // Long name. use string table
  151.             // Store string table offset
  152.             ((uint32 *)(AliasEntry.s.Name))[1] = NewStringTable.GetDataSize();
  153.             // Put name into new string table
  154.             NewStringTable.PushString(name2);
  155.          }
  156.          else {
  157.            // Short name. Store in record
  158.             memcpy(AliasEntry.s.Name, name2, strlen(name2));
  159.          }
  160.          // Add new entry to extra symbol table
  161.          NewSymbolTable.Push(&AliasEntry, SIZE_SCOFF_SymTableEntry);
  162.          break;}
  163.  
  164.       default:
  165.          err.submit(9000); // unknown error
  166.       }
  167.  
  168.       if (name3 && OldSymtab.p->s.StorageClass != COFF_CLASS_FILE) {
  169.          // Store old or new name
  170.          if (strlen(name3) > 8) {
  171.             // Name is long. use string table
  172.             // Type-case Name field to string table entry
  173.             uint32 * LongNameStorage = (uint32 *)(OldSymtab.p->s.Name);
  174.             // Start with 0 to indicate long name
  175.             LongNameStorage[0] = 0;
  176.             // Index into new string table
  177.             LongNameStorage[1] = NewStringTable.GetDataSize();
  178.             // Put name into new string table
  179.             NewStringTable.PushString(name3);
  180.          }
  181.          else {
  182.             if (name3 != name1) {
  183.                // Store new name in Name field
  184.                memset(OldSymtab.p->s.Name, 0, 8);
  185.                memcpy(OldSymtab.p->s.Name, name3, strlen(name3));
  186.             }
  187.          }
  188.       }
  189.    }  // End symbol table loop
  190.  
  191.    // Loop through section headers to search for section names
  192.    uint32 SectionOffset = sizeof(SCOFF_FileHeader) + FileHeader->SizeOfOptionalHeader;
  193.    for (isec = 0; isec < NSections; isec++) {
  194.       SCOFF_SectionHeader * pSectHeader;
  195.       pSectHeader = &Get<SCOFF_SectionHeader>(SectionOffset);
  196.       SectionOffset += sizeof(SCOFF_SectionHeader);
  197.  
  198.       // Get section name
  199.       name1 = GetSectionName(pSectHeader->Name);
  200.  
  201.       // Check if change required
  202.       action = cmd.SymbolChange(name1, &name2, SYMT_SECTION);
  203.       if (action == SYMA_CHANGE_NAME) name1 = name2;
  204.  
  205.       // Store name (changed or unchanged)
  206.       memset(pSectHeader->Name, 0, 8);
  207.       if (strlen(name1) <= 8) {
  208.          // Short name. Store in section header
  209.          memcpy(pSectHeader->Name, name1, strlen(name1));
  210.       }
  211.       else {
  212.          // Long name. Store in string table
  213.          sprintf(pSectHeader->Name, "/%i", NewStringTable.GetDataSize());
  214.          //pSectHeader->Name[0] = '/';
  215.          //itoa(NewStringTable.GetDataSize(), pSectHeader->Name+1, 10);
  216.          NewStringTable.PushString(name1);
  217.       }
  218.    }
  219. }
  220.  
  221.  
  222. void CCOF2COF::MakeBinaryFile() {
  223.    // Convert subfunction: Combine everything into the new binary file
  224.    int i;
  225.  
  226.    // New file header = copy of old file header
  227.    SCOFF_FileHeader NewFileHeader = *FileHeader;
  228.  
  229.    ToFile.SetFileType(FILETYPE_COFF); // Set type of output file
  230.    ToFile.WordSize = WordSize;
  231.    ToFile.FileName = FileName;
  232.  
  233.    // Copy file header, section headers and sections to new file
  234.    ToFile.Push(Buf(), NewFileHeader.PSymbolTable);
  235.  
  236.    // Copy symbol table
  237.    ToFile.Push(SymbolTable, NumberOfSymbols * SIZE_SCOFF_SymTableEntry);
  238.  
  239.    // Additions to symbol table
  240.    int NumAddedSymbols = NewSymbolTable.GetNumEntries();
  241.    if (NumAddedSymbols) {
  242.       // Append to symbols table
  243.       ToFile.Push(NewSymbolTable.Buf(), NumAddedSymbols * SIZE_SCOFF_SymTableEntry);
  244.       // Update NumberOfSymbols in file header
  245.       NewFileHeader.NumberOfSymbols += NumAddedSymbols;
  246.    }
  247.  
  248.    // Insert new string table
  249.    uint32 NewStringTableSize = NewStringTable.GetDataSize();
  250.    // First 4 bytes = size
  251.    ToFile.Push(&NewStringTableSize, sizeof(uint32));
  252.    // Then the string table itself, except the first 4 bytes
  253.    if (NewStringTableSize > 4)
  254.       ToFile.Push(NewStringTable.Buf() + 4, NewStringTableSize - 4);
  255.  
  256.    // Find end of old and new string tables
  257.    uint32 EndOfOldStringTable = FileHeader->PSymbolTable
  258.       + NumberOfSymbols * SIZE_SCOFF_SymTableEntry + StringTableSize;
  259.  
  260.    uint32 EndOfNewStringTable = FileHeader->PSymbolTable
  261.       + (NumberOfSymbols + NumAddedSymbols) * SIZE_SCOFF_SymTableEntry + NewStringTableSize;
  262.  
  263.    // Check if there is anything after the string table
  264.    if (GetDataSize() > EndOfOldStringTable) {
  265.       // Old file has something after the string table
  266.  
  267.       if (EndOfNewStringTable < EndOfOldStringTable) {
  268.          // New symboltable + string table smaller than old
  269.          // Fill the space with zeroes so that the data that come after the string table
  270.          // will have the same address as before
  271.          ToFile.Push(0, EndOfOldStringTable - EndOfNewStringTable);
  272.          EndOfNewStringTable = EndOfOldStringTable;
  273.       }
  274.  
  275.       // Copy the data that come after the string table
  276.       ToFile.Push(Buf() + EndOfOldStringTable, GetDataSize() - EndOfOldStringTable);
  277.  
  278.       if (EndOfNewStringTable > EndOfOldStringTable) {
  279.          // New symboltable + string table bigger than old
  280.          // Find all references to the data that come after the string table and fix them
  281.          // Search all section headers
  282.          uint32 SectionOffset = sizeof(SCOFF_FileHeader) + NewFileHeader.SizeOfOptionalHeader;
  283.          for (i = 0; i < NSections; i++) {
  284.             SCOFF_SectionHeader * pSectHeader;
  285.             pSectHeader = &Get<SCOFF_SectionHeader>(SectionOffset);
  286.             SectionOffset += sizeof(SCOFF_SectionHeader);
  287.             if (pSectHeader->PRawData >= EndOfOldStringTable && pSectHeader->PRawData <= GetDataSize()) {
  288.                pSectHeader->PRawData += EndOfNewStringTable - EndOfOldStringTable;
  289.             }
  290.             if (pSectHeader->PRelocations >= EndOfOldStringTable && pSectHeader->PRawData <= GetDataSize()) {
  291.                pSectHeader->PRelocations += EndOfNewStringTable - EndOfOldStringTable;
  292.             }            if (pSectHeader->PLineNumbers >= EndOfOldStringTable && pSectHeader->PRawData <= GetDataSize()) {
  293.                pSectHeader->PLineNumbers += EndOfNewStringTable - EndOfOldStringTable;
  294.             }
  295.          }
  296.       }
  297.    }
  298.    // Update file header
  299.    memcpy(ToFile.Buf(), &NewFileHeader, sizeof(NewFileHeader));
  300.  
  301.    // Note: The checksum in the optional header may need to be updated.
  302.    // This is relevant for DLL's only. The checksum algorithm is undisclosed and
  303.    // must be calculated with IMAGHELP.DLL. You may add a calculation of the checksum
  304.    // here if you want the program to be able to change names in a Windows DLL,
  305.    // but the program will then only be able to compile under Windows.
  306. }
  307.