Subversion Repositories Kolibri OS

Rev

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

  1. /****************************    mac2mac.cpp    *****************************
  2. * Author:        Agner Fog
  3. * Date created:  2008-05-25
  4. * Last modified: 2008-05-25
  5. * Project:       objconv
  6. * Module:        mac2mac.cpp
  7. * Description:
  8. * Module for changing symbol names in Mach-O file
  9. *
  10. * Copyright 2008 GNU General Public License http://www.gnu.org/licenses
  11. *****************************************************************************/
  12. #include "stdafx.h"
  13. // All functions in this module are templated to make two versions: 32 and 64 bits.
  14. // See instantiations at the end of this file.
  15.  
  16.  
  17. // Constructor
  18. template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
  19. CMAC2MAC<MACSTRUCTURES>::CMAC2MAC() {
  20.    // Initialize everything
  21.    memset(this, 0, sizeof(*this));
  22. }
  23.  
  24.  
  25. // Convert()
  26. template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
  27. void CMAC2MAC<MACSTRUCTURES>::Convert() {
  28.    MakeSymbolTable();                  // Remake symbol tables and string tables
  29.    MakeBinaryFile();                   // Put everyting together into ToFile
  30.    ChangeSegments();                   // Modify section names and relocation table symbol indices
  31.    *this << ToFile;                    // Take over new file buffer
  32. }
  33.  
  34.  
  35. // MakeSymbolTable()
  36. template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
  37. void CMAC2MAC<MACSTRUCTURES>::MakeSymbolTable() {
  38.    // Remake symbol tables and string table
  39.    int OldScope = 0;                   // Old scope of symbol. 0=local, 1=public, 2=external
  40.    int NewScope;                       // New scope of symbol. 0=local, 1=public, 2=external
  41.    uint32 symi;                        // Old index of symbol
  42.    const char * Name1;                 // Old symbol name
  43.    const char * Name2;                 // New symbol name
  44.    int action;                         // Action to take on symbol
  45.    int SymType;                        // Symbol type
  46.    int SymDesc;                        // Symbol descriptor
  47.    uint8 Section;                      // Symbol section
  48.  
  49.    // pointer to symbol table
  50.    TMAC_nlist * symp = (TMAC_nlist*)(this->Buf() + this->SymTabOffset);
  51.  
  52.    // pointer to string table
  53.    char * strtab = (char*)(this->Buf() + this->StringTabOffset);
  54.  
  55.    // loop through symbol table
  56.    for (symi = 0; symi < this->SymTabNumber; symi++, symp++) {
  57.  
  58.       // Check indices for first symbol of each scope category
  59.       if (symi == this->iextdefsym && this->nextdefsym) OldScope = 1;
  60.       if (symi == this->iundefsym  && this->nundefsym)  OldScope = 2;
  61.       NewScope = OldScope;
  62.  
  63.       if (symp->n_strx >= this->StringTabSize) {
  64.          // Index out of range
  65.          err.submit(2112); continue;
  66.       }
  67.  
  68.       // Get symbol name
  69.       Name1 = strtab + symp->n_strx;
  70.  
  71.       // Get type, descriptor and section
  72.       SymType = symp->n_type;          // Symbol type
  73.       SymDesc = symp->n_desc;          // Symbol descriptor
  74.       Section = symp->n_sect;          // Symbol section
  75.  
  76.       // Check if any change required for this symbol
  77.       action = cmd.SymbolChange(Name1, &Name2, SYMT_LOCAL + OldScope);
  78.  
  79.       switch (action) {
  80.       case SYMA_NOCHANGE:
  81.          // No change
  82.          break;
  83.  
  84.       case SYMA_MAKE_WEAK:
  85.          // Make symbol weak
  86.          if (cmd.OutputType == FILETYPE_COFF) {
  87.             // PE/COFF format does not support weak publics
  88.             err.submit(2200);
  89.          }
  90.          // Make weak
  91.          if (OldScope == 1) {
  92.             SymDesc |= MAC_N_WEAK_DEF;   // Weak public. Allowed only in coalesced (communal) section
  93.          }
  94.          else if (OldScope == 2) {
  95.             SymDesc |= MAC_N_WEAK_REF;   // Weak external
  96.          }
  97.          else {
  98.             err.submit(1020, Name1);     // Local symbol
  99.          }
  100.          break;
  101.  
  102.       case SYMA_MAKE_LOCAL:
  103.          // Make public symbol local, make external symbol ignored
  104.          if (OldScope == 1) {
  105.             NewScope = 0;  // Public changed to local
  106.             SymType &= ~MAC_N_EXT;
  107.          }
  108.          else if (OldScope == 2) {
  109.             Section = MAC_NO_SECT;  // External symbol. Set to 0
  110.             SymDesc = 0;
  111.             SymType = MAC_N_UNDF;
  112.          }
  113.          else err.submit(1021, Name1);
  114.          break;
  115.  
  116.       case SYMA_CHANGE_NAME:
  117.          // Change name of symbol
  118.          Name1 = Name2;  Name2 = 0;
  119.          break;
  120.  
  121.       case SYMA_ALIAS:
  122.          // Make alias and keep old name
  123.          if (OldScope != 1) {
  124.             err.submit(1022, Name1); break;
  125.          }
  126.          // Make alias
  127.          NewSymbols[1].AddSymbol(-1, Name2, SymType, SymDesc, Section, symp->n_value);
  128.          break;
  129.  
  130.       default:
  131.          err.submit(9000); // unknown error
  132.       }
  133.  
  134.       // Store symbol, possibly modified
  135.       NewSymbols[NewScope].AddSymbol(symi, Name1, SymType, SymDesc, Section, symp->n_value);
  136.    }
  137.  
  138.    // Put everything into symbol table and string table
  139.    if (this->SymTabNumber) {
  140.       NewStringTable.SetDataSize(1); // First record must indicate empty string (see nlist.n_un in Mach-O File Format Reference)
  141.    }
  142.    for (NewScope = 0; NewScope < 3; NewScope++) {
  143.       NewSymbols[NewScope].SortList();  // Sort each list alphabetically
  144.       NewSymbols[NewScope].StoreList(&NewSymbolTable, &NewStringTable);
  145.    }
  146.  
  147.    // Indices to local, public and external symbols
  148.    NewIlocalsym = 0;                                // index to local symbols
  149.    NewNlocalsym = NewSymbols[0].GetNumEntries(); // number of local symbols
  150.    NewIextdefsym = NewNlocalsym;                        // index to public symbols
  151.    NewNextdefsym = NewSymbols[1].GetNumEntries();// number of public symbols
  152.    NewIundefsym = NewNlocalsym + NewNextdefsym;  // index to external symbols
  153.    NewNundefsym = NewSymbols[2].GetNumEntries(); // number of external symbols
  154.  
  155.    // Calculate difference in size of new tables versus old tables
  156.    // (this calculation is moved to MakeBinaryFile)
  157.    // SizeDifference = NewSymbolTable.GetDataSize + NewStringTable.GetDataSize()
  158.    // - this->SymTabNumber * sizeof(TMAC_nlist) - this->StringTabSize;
  159. }
  160.  
  161. template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
  162. int CMAC2MAC<MACSTRUCTURES>::NewSymbolIndex(int32 OldIndex) {
  163.    // Convert subfunction: Translate old to new symbol index
  164.    int NewIndex;
  165.    int Scope;
  166.    // Search for symbol in all scopes
  167.    for (Scope = 0; Scope < 3; Scope++) {
  168.       NewIndex = NewSymbols[Scope].TranslateIndex(OldIndex);
  169.       if (NewIndex >= 0) {
  170.          // OldIndex found. Add offset into appropriate table
  171.          if (Scope == 1) NewIndex += NewIextdefsym;
  172.          else if (Scope == 2) NewIndex += NewIundefsym;
  173.          return NewIndex;
  174.       }
  175.    }
  176.    //err.submit(2031);
  177.    return -1;
  178. }
  179.  
  180.  
  181. template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
  182. uint32 CMAC2MAC<MACSTRUCTURES>::NewFileOffset(uint32 OldOffset) {
  183.    // Convert subfunction: Translate old to new file offset
  184.    if (OldOffset <= NewSymtabOffset) {
  185.       // Before symbol table. No change
  186.       return OldOffset;
  187.    }
  188.    if (OldOffset >= OldTablesEnd) {
  189.       // After string table. Add size difference
  190.       return OldOffset + SizeDifference;
  191.    }
  192.    // Between symbol table and string table.
  193.    // The possibility of something between these two tables has not been accounted for
  194.    err.submit(2052);
  195.    return 0;
  196. }
  197.  
  198.  
  199. // MakeBinaryFile()
  200. template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
  201. void CMAC2MAC<MACSTRUCTURES>::MakeBinaryFile() {
  202.    uint32 OldSymtabEnd;                // End of old symbol table
  203.    uint32 OldStringtabEnd;             // End of old string table
  204.    const int WordSize = sizeof(MInt) * 8;  // Word size, 32 or 64 bits
  205.  
  206.    // Offset to symbol table and string table
  207.    NewSymtabOffset = this->SymTabOffset;
  208.    if (this->StringTabOffset && this->StringTabOffset < NewSymtabOffset) NewSymtabOffset = this->StringTabOffset;
  209.    if (NewSymtabOffset == 0) NewSymtabOffset = this->GetDataSize();
  210.  
  211.    // Copy all headers and all data until TablesOffset
  212.    ToFile.Push(this->Buf(), NewSymtabOffset);
  213.    ToFile.Align(WordSize/8);
  214.    NewSymtabOffset = ToFile.GetDataSize();
  215.  
  216.    // Copy new symbol table
  217.    ToFile.Push(NewSymbolTable.Buf(), NewSymbolTable.GetDataSize());
  218.  
  219.    // Copy new string table
  220.    NewStringtabOffset = ToFile.GetDataSize();
  221.    ToFile.Push(NewStringTable.Buf(), NewStringTable.GetDataSize());
  222.    ToFile.Align(2);
  223.    NewStringtabEnd = ToFile.GetDataSize();
  224.  
  225.    // Find end of old tables
  226.    OldSymtabEnd = this->SymTabOffset + this->SymTabNumber * sizeof(TMAC_nlist);
  227.    OldStringtabEnd = this->StringTabOffset + this->StringTabSize;
  228.    OldTablesEnd = OldStringtabEnd;
  229.    if (OldSymtabEnd > OldTablesEnd) OldTablesEnd = OldSymtabEnd;
  230.    if (OldTablesEnd == 0) OldTablesEnd = this->GetDataSize();
  231.  
  232.    // Size difference between new and old tables
  233.    SizeDifference = NewStringtabEnd - OldTablesEnd;
  234.  
  235.    // Is there anything in the old file after these tables?
  236.    if (OldTablesEnd && this->GetDataSize() > OldTablesEnd) {
  237.       // There is something after these tables. Copy it
  238.       ToFile.Push(this->Buf() + OldTablesEnd, this->GetDataSize() - OldTablesEnd);
  239.    }
  240. }
  241.  
  242.  
  243. // ChangeSegments()
  244. template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
  245. void CMAC2MAC<MACSTRUCTURES>::ChangeSegments() {
  246.    // Convert subfunction: Change section names if needed and adjust all relocation tables
  247.  
  248.    uint32 FileOffset;                  // Current offset into file
  249.    uint32 lcmd;                        // Load command
  250.    uint32 cmdsize = 0;                 // Command size
  251.    uint32 icmd;                        // Loop counter
  252.    int action;                         // Name change action
  253.    char * Name1;                       // Old name
  254.    const char * Name2;                 // New name
  255.  
  256.    FileOffset = sizeof(TMAC_header);
  257.    // Loop through file commands
  258.    for (icmd = 1; icmd <= this->FileHeader.ncmds; icmd++, FileOffset += cmdsize) {
  259.       lcmd    = ((MAC_load_command*)(ToFile.Buf() + FileOffset)) -> cmd;
  260.       cmdsize = ((MAC_load_command*)(ToFile.Buf() + FileOffset)) -> cmdsize;
  261.  
  262.       // Interpret specific command type
  263.       switch(lcmd) {
  264.       case MAC_LC_SEGMENT: { // 32-bit segment
  265.          MAC_segment_command_32 * sh = (MAC_segment_command_32*)(ToFile.Buf() + FileOffset);
  266.          Name1 = sh->segname;
  267.          // Check if any change required for this symbol
  268.          action = cmd.SymbolChange(Name1, &Name2, SYMT_SECTION);
  269.          if (action == SYMA_CHANGE_NAME) {
  270.             // Change segment name
  271.             if (strlen(Name2) > 16) err.submit(1040);
  272.             strncpy(Name1, Name2, 16);
  273.          }
  274.          // Change section names and relocations in all sections under this segment
  275.          ChangeSections(FileOffset + sizeof(MAC_segment_command_32), sh->nsects);
  276.          break;}
  277.  
  278.       case MAC_LC_SEGMENT_64: { // 64-bit segment
  279.          MAC_segment_command_64 * sh = (MAC_segment_command_64*)(ToFile.Buf() + FileOffset);
  280.          Name1 = sh->segname;
  281.          // Check if any change required for this symbol
  282.          action = cmd.SymbolChange(Name1, &Name2, SYMT_SECTION);
  283.          if (action == SYMA_CHANGE_NAME) {
  284.             // Change segment name
  285.             if (strlen(Name2) > 16) err.submit(1040);
  286.             strncpy(Name1, Name2, 16);
  287.          }
  288.          // Change section names and relocations in all sections under this segment
  289.          ChangeSections(FileOffset + sizeof(MAC_segment_command_64), sh->nsects);
  290.          break;}
  291.  
  292.       case MAC_LC_SYMTAB: { // Symbol table header
  293.          MAC_symtab_command * sh = (MAC_symtab_command*)(ToFile.Buf() + FileOffset);
  294.          // Change table addresses
  295.          sh->symoff = NewSymtabOffset;
  296.          sh->nsyms = NewSymbolTable.GetDataSize() / sizeof(TMAC_nlist);
  297.          sh->stroff = NewStringtabOffset;
  298.          sh->strsize = NewStringtabEnd - NewStringtabOffset;
  299.          break;}
  300.  
  301.       case MAC_LC_DYSYMTAB: { // dynamic link-edit symbol table
  302.          MAC_dysymtab_command * sh = (MAC_dysymtab_command*)(ToFile.Buf() + FileOffset);
  303.          // Change indices to symbol tables
  304.          sh->ilocalsym = NewIlocalsym;
  305.          sh->nlocalsym = NewNlocalsym;
  306.          sh->iextdefsym = NewIextdefsym;
  307.          sh->nextdefsym = NewNextdefsym;
  308.          sh->iundefsym = NewIundefsym;            
  309.          sh->nundefsym = NewNundefsym;
  310.  
  311.          // Change table addresses
  312.          sh->tocoff = NewFileOffset(sh->tocoff);
  313.          sh->modtaboff = NewFileOffset(sh->modtaboff);
  314.          sh->extrefsymoff = NewFileOffset(sh->extrefsymoff);
  315.          sh->indirectsymoff = NewFileOffset(sh->indirectsymoff);
  316.          sh->extreloff = NewFileOffset(sh->extreloff);
  317.          sh->locreloff = NewFileOffset(sh->locreloff);
  318.  
  319.          if (sh->nindirectsyms) {
  320.             // Change symbol indices in import table
  321.             ChangeImportTable(sh->indirectsymoff, sh->nindirectsyms);
  322.          }
  323.          break;}
  324.       }
  325.    }
  326. }
  327.  
  328.  
  329. template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
  330. void CMAC2MAC<MACSTRUCTURES>::ChangeSections(uint32 HeaderOffset, uint32 Num) {
  331.    // Convert subfunction: Change section names and relocation records if needed
  332.    int action;                         // Name change action
  333.    char * Name1;                       // Old name
  334.    const char * Name2;                 // New name
  335.    uint32 isec1;                       // Section index
  336.    TMAC_section * secp;                // Pointer to section header
  337.    uint32 irel;                        // Relocation index
  338.    MAC_relocation_info * relp;         // Pointer to relocation record
  339.  
  340.    // Loop through section headers
  341.    for (isec1 = 0; isec1 < Num; isec1++) {
  342.       // Find section header
  343.       secp = (TMAC_section*)(ToFile.Buf() + HeaderOffset + isec1*sizeof(TMAC_section));
  344.  
  345.       // Segment name
  346.       Name1 = secp->segname;
  347.       action = cmd.SymbolChange(Name1, &Name2, SYMT_SECTION);
  348.       if (action == SYMA_CHANGE_NAME) {
  349.          // Change segment name
  350.          if (strlen(Name2) > 16) err.submit(1040);
  351.          strncpy(Name1, Name2, 16);
  352.       }
  353.  
  354.       // Section name
  355.       Name1 = secp->sectname;
  356.       action = cmd.SymbolChange(Name1, &Name2, SYMT_SECTION);
  357.       if (action == SYMA_CHANGE_NAME) {
  358.          // Change section name
  359.          if (strlen(Name2) > 16) err.submit(1040);
  360.          strncpy(Name1, Name2, 16);
  361.       }
  362.  
  363.       // Update file offset
  364.       secp->offset = NewFileOffset(secp->offset);
  365.  
  366.       if (secp->nreloc) {
  367.          // This section has relocations
  368.          // Update relocations offset
  369.          secp->reloff = NewFileOffset(secp->reloff);
  370.  
  371.          // Pointer to relocation records
  372.          relp = (MAC_relocation_info*)(ToFile.Buf() + secp->reloff);
  373.  
  374.          // Loop through relocations, if any
  375.          for (irel = 0; irel < secp->nreloc; irel++, relp++) {
  376.             // Only non-scattered r_extern relocations have symbol index
  377.             if (!(relp->r_address & R_SCATTERED) && relp->r_extern) {
  378.                // Update symbol index
  379.                relp->r_symbolnum = NewSymbolIndex(relp->r_symbolnum);
  380.             }
  381.          }
  382.       }
  383.    }
  384. }
  385.  
  386.  
  387. template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
  388. void CMAC2MAC<MACSTRUCTURES>::ChangeImportTable(uint32 FileOffset, uint32 Num) {
  389.    // Convert subfunction: Change symbol indices in import table if needed
  390.    uint32 i;                           // Index
  391.    uint32 * p;                         // pointer to current entry
  392.  
  393.    // Find first entry
  394.    p = (uint32*)(ToFile.Buf() + FileOffset);
  395.  
  396.    // Loop through table
  397.    for (i = 0;  i < Num; i++, p++) {
  398.       // Translate symbol index
  399.       *p = NewSymbolIndex(*p);
  400.    }
  401. }
  402.  
  403.  
  404. // Make template instances for 32 and 64 bits
  405. template class CMAC2MAC<MAC32STRUCTURES>;
  406. template class CMAC2MAC<MAC64STRUCTURES>;
  407.