Subversion Repositories Kolibri OS

Rev

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

  1. /****************************  elf2mac.cpp   *********************************
  2. * Author:        Agner Fog
  3. * Date created:  2007-01-10
  4. * Last modified: 2012-05-05
  5. * Project:       objconv
  6. * Module:        elf2mac.cpp
  7. * Description:
  8. * Module for converting ELF file to Mach-O file
  9. *
  10. * Copyright 2007-2012 GNU General Public License http://www.gnu.org/licenses
  11. *****************************************************************************/
  12.  
  13. #include "stdafx.h"
  14.  
  15. template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation,
  16.           class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
  17.    CELF2MAC<ELFSTRUCTURES,MACSTRUCTURES>::CELF2MAC() {
  18.    // Constructor
  19.       memset(this, 0, sizeof(*this));                   // Reset everything
  20. }
  21.  
  22. template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation,
  23.           class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
  24.    void CELF2MAC<ELFSTRUCTURES,MACSTRUCTURES>::Convert() {
  25.    // Do the conversion
  26.    // Some compilers require this-> for accessing members of template base class,
  27.    // according to the so-called two-phase lookup rule.
  28.  
  29.    // Call the subfunctions
  30.    ToFile.SetFileType(FILETYPE_MACHO_LE);             // Set type of new file
  31.    MakeFileHeader();                                  // Make file header
  32.    MakeSectionsIndex();                               // Make sections index translation table
  33.    FindUnusedSymbols();                               // Check if symbols used, remove unused symbols
  34.    MakeSymbolTable();                                 // Make symbol table and string tables
  35.    MakeSections();                                    // Make sections and relocation tables
  36.    MakeBinaryFile();                                  // Put sections together
  37.    *this << ToFile;                                   // Take over new file buffer
  38. }
  39.  
  40.  
  41. template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation,
  42.           class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
  43. void CELF2MAC<ELFSTRUCTURES,MACSTRUCTURES>::MakeFileHeader() {
  44.    // Convert subfunction: Make file header and load segment command
  45.    TMAC_header NewHeader;                             // new file header
  46.    NewHeader.magic      = (this->WordSize == 32) ? MAC_MAGIC_32 : MAC_MAGIC_64; // Mach magic number identifier
  47.    NewHeader.cputype    = (this->WordSize == 32) ? MAC_CPU_TYPE_I386 : MAC_CPU_TYPE_X86_64;
  48.    NewHeader.cpusubtype = MAC_CPU_SUBTYPE_I386_ALL;
  49.    NewHeader.filetype   = MAC_OBJECT;
  50.    NewHeader.ncmds      = 3;                          // Three commands = segment, symbol table, dynsymtab
  51.    NewHeader.sizeofcmds = 0;                          // Set this later
  52.    NewHeader.flags      = 0;                          // No flags needed
  53.  
  54.    // put file header in OutFile
  55.    ToFile.Push(&NewHeader, sizeof(NewHeader));
  56. }
  57.  
  58.  
  59. template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation,
  60.           class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
  61. void CELF2MAC<ELFSTRUCTURES,MACSTRUCTURES>::MakeSectionsIndex() {
  62.    // Make sections index translation table and section offset table.
  63.  
  64.    // We must make these tables before the sections, because they are needed for the
  65.    // symbol tables and relocation tables, and we must make the symbol tables before
  66.    // the relocation tables, and we must make the relocation tables together with the
  67.    // sections.
  68.    uint32 oldsec;                         // Section number in old file
  69.    uint32 newsec = 0;                     // Section number in new file
  70.    NewSectIndex. SetNum(this->NSections); // Allocate size for section index table
  71.    NewSectIndex. SetZero();               // Initialize
  72.    NewSectOffset.SetNum(this->NSections); // Allocate buffer for section offset table
  73.    NewSectOffset.SetZero();               // Initialize
  74.  
  75.    MInt NewVirtualAddress = 0;            // Virtual address of new section as specified in Mach-O file
  76.  
  77.    // First loop through old sections
  78.    for (oldsec = 0; oldsec < this->NSections; oldsec++) {
  79.       NewSectIndex[oldsec]  = 0;
  80.       NewSectOffset[oldsec] = 0;
  81.  
  82.       // Get section name
  83.       const char * sname = "";
  84.       uint32 namei = this->SectionHeaders[oldsec].sh_name;
  85.       if (namei >= this->SecStringTableLen) {
  86.          err.submit(2112);
  87.       }
  88.       else sname = this->SecStringTable + namei;
  89.  
  90.       if (cmd.DebugInfo == CMDL_DEBUG_STRIP) {
  91.          // Check for debug section names
  92.          if (strncmp(sname, ".note",    5) == 0
  93.          ||  strncmp(sname, ".comment", 8) == 0
  94.          ||  strncmp(sname, ".stab",    5) == 0
  95.          ||  strncmp(sname, ".debug",   6) == 0) {
  96.             // Remove this section
  97.             this->SectionHeaders[oldsec].sh_type = SHT_REMOVE_ME;
  98.             cmd.CountDebugRemoved();
  99.             continue;
  100.          }
  101.       }
  102.  
  103.       if (cmd.ExeptionInfo == CMDL_EXCEPTION_STRIP) {
  104.          // Check for exception section name
  105.          if (strncmp(sname, ".eh_frame", 9) == 0) {
  106.             // Remove this section
  107.             this->SectionHeaders[oldsec].sh_type = SHT_REMOVE_ME;
  108.             cmd.CountExceptionRemoved();
  109.             continue;
  110.          }
  111.       }
  112.  
  113.       // Search for program data sections only
  114.       if (this->SectionHeaders[oldsec].sh_type != SHT_PROGBITS
  115.       &&  this->SectionHeaders[oldsec].sh_type != SHT_NOBITS) {
  116.          // Has no data. Ignore
  117.          continue;
  118.       }
  119.  
  120.       if (this->SectionHeaders[oldsec].sh_size == 0) {
  121.          // Remove empty section
  122.          // The linker has a bug with empty sections
  123.          continue;
  124.       }
  125.  
  126.       // Section index translation table
  127.       NewSectIndex[oldsec] = newsec++;
  128.  
  129.       // Calculate virtual memory address of section. This address does not have
  130.       // much to do with the final address, but it is needed in relocation entries.
  131.  
  132.       // Alignment
  133.       int NewAlign = FloorLog2((uint32)this->SectionHeaders[oldsec].sh_addralign);
  134.       if (NewAlign > 12) NewAlign = 12;   // What is the limit for highest alignment?
  135.       int AlignBy = 1 << NewAlign;
  136.  
  137.       // Align memory address
  138.       NewVirtualAddress = (NewVirtualAddress + AlignBy - 1) & -(MInt)AlignBy;
  139.  
  140.       // Virtual memory address of new section
  141.       NewSectOffset[oldsec] = NewVirtualAddress;
  142.  
  143.       // Increment memory address
  144.       NewVirtualAddress += this->SectionHeaders[oldsec].sh_size;
  145.  
  146.       // Fix v. 2.14: Align end of memory address by 4
  147.       NewVirtualAddress = (NewVirtualAddress + 3) & MInt(-4);
  148.    }
  149.  
  150.    // Store number of sections in new file
  151.    NumSectionsNew = newsec;
  152.  
  153.    // Calculate file offset of first raw data
  154.    RawDataOffset = sizeof(TMAC_header)
  155.       + sizeof(TMAC_segment_command)
  156.       + NumSectionsNew * sizeof(TMAC_section)
  157.       + sizeof(MAC_symtab_command)
  158.       + sizeof(MAC_dysymtab_command);
  159.  
  160.    // Align end of memory address by 4
  161.    NewVirtualAddress = (NewVirtualAddress + 3) & MInt(-4);
  162.  
  163.    // Make segment command
  164.    TMAC_segment_command NewSegment;
  165.    memset(&NewSegment, 0, sizeof(NewSegment));
  166.    NewSegment.cmd      = (this->WordSize == 32) ? MAC_LC_SEGMENT : MAC_LC_SEGMENT_64;
  167.    NewSegment.cmdsize  = sizeof(TMAC_segment_command) + NumSectionsNew * sizeof(TMAC_section);
  168.    NewSegment.fileoff  = RawDataOffset;
  169.    NewSegment.nsects   = NumSectionsNew;
  170.    NewSegment.maxprot  = NewSegment.initprot = 7; // 1=read, 2=write, 4=execute
  171.    NewSegment.vmsize   = NewVirtualAddress;
  172.    NewSegment.filesize = 0;                       // Changed later
  173.  
  174.    // put segment command in OutFile
  175.    CommandOffset = ToFile.Push(&NewSegment, sizeof(NewSegment));
  176. }
  177.  
  178.  
  179. template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation,
  180.           class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
  181. void CELF2MAC<ELFSTRUCTURES,MACSTRUCTURES>::MakeSymbolTable() {
  182.    // Convert subfunction: Symbol table and string tables
  183.    uint32 oldsec;                  // Section number in old file
  184.    TELF_SectionHeader OldHeader;   // Old section header
  185.    int FoundSymTab = 0;            // Found symbol table
  186.    int8 * strtab;                  // Old symbol string table
  187.    int8 * symtab;                  // Old symbol table
  188.    uint32 symtabsize;              // Size of old symbol table
  189.    int8 * symtabend;               // End of old symbol table
  190.    uint32 entrysize;               // Size of each entry in old symbol table
  191.    TELF_Symbol OldSym;             // Old symbol table record
  192.    uint32 OldSymI;                 // Symbol index in old symbol table
  193.    const char * symname;           // Symbol name
  194.    int NewSection = 0;             // New section index
  195.    int NewType;                    // New symbol type
  196.    int NewDesc;                    // New symbol reference type
  197.    MInt Value;                     // Symbol value
  198.    uint32 Scope;                   // 0: Local, 1: Public, 2: External
  199.  
  200.    // Loop through old sections to find symbol table
  201.    for (oldsec = 0; oldsec < this->NSections; oldsec++) {
  202.  
  203.       // Search for program data sections only
  204.       if (this->SectionHeaders[oldsec].sh_type == SHT_SYMTAB
  205.       ||  this->SectionHeaders[oldsec].sh_type == SHT_DYNSYM) {
  206.          FoundSymTab++;
  207.  
  208.          // Copy symbol table header for convenience
  209.          OldHeader = this->SectionHeaders[oldsec];
  210.  
  211.          // Find associated string table
  212.          if (OldHeader.sh_link >= (uint32)(this->NSections)) {
  213.             err.submit(2035); OldHeader.sh_link = 0;
  214.          }
  215.          strtab = this->Buf() + (uint32)this->SectionHeaders[OldHeader.sh_link].sh_offset;
  216.  
  217.          // Find old symbol table
  218.          entrysize = (uint32)OldHeader.sh_entsize;
  219.          if (entrysize < sizeof(TELF_Symbol)) {err.submit(2033); entrysize = sizeof(TELF_Symbol);}
  220.  
  221.          symtab = this->Buf() + (uint32)OldHeader.sh_offset;
  222.          symtabsize = (uint32)OldHeader.sh_size;
  223.          symtabend = symtab + symtabsize;
  224.  
  225.          if (NewSymTab[0].GetNumEntries() == 0) {
  226.             // make empty symbol record for index 0
  227.             NewSymTab[0].AddSymbol(0, "", 0, 0, 0, 0);
  228.          }
  229.  
  230.          // Loop through old symbol table
  231.          for (OldSymI = 0; symtab < symtabend; symtab += entrysize, OldSymI++) {
  232.  
  233.             if (OldSymI == 0) continue; // First symbol entry in ELF file is unused
  234.  
  235.             // Copy 32 bit symbol table entry or convert 64 bit entry
  236.             OldSym = *(TELF_Symbol*)symtab;
  237.  
  238.             // Old symbol type
  239.             int type = OldSym.st_type;
  240.  
  241.             // Old symbol storage class = binding
  242.             int binding = OldSym.st_bind;
  243.  
  244.             // Get symbol name
  245.             if (OldSym.st_name < this->SymbolStringTableSize) {
  246.                symname = strtab + OldSym.st_name;
  247.             }
  248.             else {
  249.                err.submit(2112); // String table corrupt
  250.                continue;       // Ignore
  251.             }
  252.             if (symname == 0 || *symname == 0) {
  253.                // Symbol has no name. Give it a name
  254.                // Mac linker messes this up if the symbol doesn't have a unique name.
  255.                char tempbuf[80];
  256.                sprintf(tempbuf, "?unnamed%i", OldSymI);
  257.                int os = UnnamedSymbolsTable.PushString(tempbuf);
  258.                symname = UnnamedSymbolsTable.Buf() + os;
  259.             }
  260.            
  261.             NewType = NewDesc = 0; // New symbol type
  262.  
  263.             // Value = address
  264.             Value = OldSym.st_value;
  265.  
  266.             // Section
  267.             if (OldSym.st_shndx == SHN_UNDEF) {
  268.                NewSection = 0; // External
  269.             }
  270.             else if ((int16)(OldSym.st_shndx) == SHN_ABS) {
  271.                NewType |= MAC_N_ABS; // Absolute symbol
  272.                NewDesc |= MAC_N_NO_DEAD_STRIP;
  273.                NewSection = 0;
  274.             }
  275.             else if ((int16)(OldSym.st_shndx) == SHN_COMMON) {
  276.                NewType |= MAC_N_ABS; // Common symbol. Translate to abs and make warning
  277.                NewDesc |= MAC_N_NO_DEAD_STRIP;
  278.                NewSection = 0;
  279.                err.submit(1053, symname); // Warning. Common symbol
  280.             }            
  281.             else if (OldSym.st_shndx >= this->NSections) {
  282.                err.submit(2036, OldSym.st_shndx); // Special/unknown section index or out of range
  283.             }
  284.             else {
  285.                // Normal section index.
  286.                // Look up in section index translation table and add 1 because it is 1-based
  287.                NewSection = NewSectIndex[OldSym.st_shndx] + 1;
  288.                // Value must be absolute address. Add section address
  289.                Value += NewSectOffset[OldSym.st_shndx];
  290.             }
  291.  
  292.             // Convert binding/storage class
  293.             switch (binding) {
  294.             case STB_LOCAL:   // Local
  295.                Scope = S_LOCAL;
  296.                if (!(NewType & MAC_N_ABS)) NewType |= MAC_N_SECT;
  297.                break;
  298.  
  299.             case STB_GLOBAL:
  300.                if (NewSection || (NewType & MAC_N_ABS)) {
  301.                   // Public
  302.                   Scope = S_PUBLIC;
  303.                   NewType |= MAC_N_EXT;
  304.                   if (!(NewType & MAC_N_ABS)) NewType |= MAC_N_SECT;
  305.                }
  306.                else {
  307.                   // External
  308.                   Scope = S_EXTERNAL;
  309.                   NewType |= MAC_N_EXT;
  310.                }
  311.                NewDesc |= MAC_REF_FLAG_UNDEFINED_NON_LAZY;
  312.                break;
  313.  
  314.             case STB_WEAK:
  315.                if (NewSection) {
  316.                   // Weak public
  317.                   Scope = S_PUBLIC;
  318.                   NewType |= MAC_N_EXT | MAC_N_SECT;
  319.                   NewDesc |= MAC_N_WEAK_DEF;
  320.                   if (this->WordSize == 32) {
  321.                      err.submit(1051, symname);  // Weak public only allowed in coalesced section of MachO-32
  322.                   }
  323.                }
  324.                else {
  325.                   // Weak external
  326.                   Scope = S_EXTERNAL;
  327.                   NewType |= MAC_N_EXT;
  328.                   NewDesc |= MAC_N_WEAK_REF;
  329.                }
  330.                break;
  331.  
  332.             default:
  333.                Scope = S_LOCAL;
  334.                err.submit(2037, binding); // Other. Not supported
  335.             }
  336.  
  337.             // Make record depending on type
  338.             switch (type) {
  339.             case STT_OBJECT: case STT_NOTYPE:
  340.                // Data object
  341.                break;
  342.  
  343.             case STT_GNU_IFUNC:
  344.                err.submit(1063); // Warning: Gnu indirect function cannot be converted
  345.                // continue in next case:
  346.  
  347.             case STT_FUNC:
  348.                // Function
  349.                break;
  350.  
  351.             case STT_FILE:
  352.                // File name record. Ignore
  353.                continue;
  354.  
  355.             case STT_SECTION:
  356.                // Section name record. (Has no name)
  357.                break;
  358.  
  359.             case STT_COMMON:
  360.             default:
  361.                err.submit(2038, type); // Symbol type not supported
  362.                continue;
  363.             }
  364.  
  365.             // Discard unused symbols
  366.             if (Scope != S_PUBLIC && !OldSymbolUsed[OldSymI]) continue;
  367.  
  368.             // Store new symbol record in the appropriate table
  369.             if (Scope > 2) err.submit(9000);
  370.  
  371.             NewSymTab[Scope].AddSymbol(OldSymI, symname, NewType, NewDesc, NewSection, Value);
  372.  
  373.             // Store scope in OldSymbolScope
  374.             if (OldSymI < NumOldSymbols) {
  375.                OldSymbolScope[OldSymI] = Scope;
  376.             }
  377.          } // End OldSymI loop
  378.       }
  379.    } // End search for symbol table
  380.    if (FoundSymTab == 0) err.submit(2034); // Symbol table not found
  381.    if (FoundSymTab  > 1) err.submit(1032); // More than one symbol table found
  382. }
  383.  
  384.  
  385. template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation,
  386.           class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
  387. void CELF2MAC<ELFSTRUCTURES,MACSTRUCTURES>::Elf2MacRelocations(Elf32_Shdr & OldRelHeader, MAC_section_32 & NewHeader, uint32 NewRawDataOffset, uint32 oldsec) {
  388.    // Convert 32-bit relocations from ELF to MAC
  389.    // (This function has two template instances, only the 32-bit instance is used)
  390.  
  391.    Elf32_Rela OldRelocation;  // Old relocation table entry
  392.    MAC_scattered_relocation_info scat; // Scattered relocation entry
  393.    memset(&scat, 0, sizeof(scat));
  394.  
  395.    // Get pointer to old relocation table
  396.    int8 * reltab = this->Buf() + OldRelHeader.sh_offset;
  397.    int8 * reltabend = reltab + OldRelHeader.sh_size;
  398.  
  399.    // Get entry size
  400.    uint32 entrysize = (uint32)OldRelHeader.sh_entsize;
  401.    uint32 expectedentrysize = (OldRelHeader.sh_type == SHT_REL) ? sizeof(Elf32_Rel) : sizeof(Elf32_Rela);
  402.    if (entrysize < expectedentrysize) {err.submit(2033); entrysize = expectedentrysize;}
  403.  
  404.    // File pointer to relocations
  405.    NewHeader.reloff = NewRelocationTab.GetNumEntries()*sizeof(MAC_relocation_info);  // Offset to first relocation table added later
  406.  
  407.    // Loop through relocation table entries
  408.    for (; reltab < reltabend; reltab += entrysize) {
  409.  
  410.       // Copy relocation entry with or without addend
  411.       OldRelocation.r_addend = 0;
  412.       memcpy(&OldRelocation, reltab, entrysize);
  413.  
  414.       // Find inline addend
  415.       uint32 InlinePosition = (uint32)(NewRawDataOffset + OldRelocation.r_offset);
  416.  
  417.       // Check that address is valid
  418.       if (InlinePosition >= this->GetDataSize()) {
  419.          // Address is invalid
  420.          err.submit(2032);  break;
  421.       }
  422.  
  423.       // Pointer to inline addend
  424.       int32 * piaddend = (int32*)(NewRawData.Buf() + InlinePosition);
  425.  
  426.       // Add old addend if any
  427.       *piaddend += (int32)OldRelocation.r_addend;
  428.  
  429.       // Define relocation parameters
  430.       uint32  r_address = 0;      // section-relative offset to relocation source
  431.       uint32  r_symbolnum = 0;    // symbol index if r_extern == 1 or section ordinal if r_extern == 0
  432.       // uint32  r_value = 0;        // value of relocation target
  433.       // int     r_scattered = 0;    // use scattered relocation
  434.       int     r_pcrel = 0;        // self relative
  435.       int     r_length = 2;       // size of source: 0=byte, 1=2 bytes, 2=4 bytes, 3=8 bytes
  436.       int     r_extern = 0;       // public or external
  437.       int     r_type = 0;         // if not 0, machine specific relocation type
  438.       int     Scope = 0;          // Symbol scope: 0 = local, 1 = public, 2 = external
  439.  
  440.       // source offset
  441.       r_address = (uint32)OldRelocation.r_offset;
  442.  
  443.       // target scope
  444.       if (OldRelocation.r_sym < NumOldSymbols) {
  445.          Scope = OldSymbolScope[OldRelocation.r_sym];
  446.       }
  447.  
  448.       // Get r_extern: 0 = local target referenced by address,
  449.       //               1 = external symbol referenced by symbol table index
  450.       switch (Scope) {
  451.       case S_LOCAL:  // Local target must be referenced by address
  452.          r_extern = 0;  break;
  453.  
  454.       case S_PUBLIC:  // Public target is optionally referenced by index or by address
  455.          r_extern = 0;
  456.          // r_extern = 1; is not allowed!
  457.          break;
  458.  
  459.       case S_EXTERNAL:  // External target is always referenced by index
  460.          r_extern = 1;  break;
  461.       }
  462.  
  463.       // Get zero-based index into NewSymTab[Scope]
  464.       int newindex = NewSymTab[Scope].TranslateIndex(OldRelocation.r_sym);
  465.       if (newindex < 0) {
  466.          // Symbol not found or wrong type
  467.          err.submit(2031);
  468.          break;
  469.       }
  470.       if (r_extern) {
  471.          // r_symbolnum is zero based index into combined symbol tables.
  472.          // Add number of entries in preceding NewSymTab tables to index
  473.          // into NewSymTab[Scope]
  474.          r_symbolnum = newindex + NumSymbols[Scope];
  475.       }
  476.       else {
  477.          // r_extern = 0. r_symbolnum = target section
  478.          r_symbolnum = NewSymTab[Scope][newindex].n_sect;
  479.  
  480.          // Absolute address of target stored inline in source
  481.          *piaddend  += (uint32)NewSymTab[Scope][newindex].n_value;
  482.       }
  483.  
  484.       // Get relocation type and fix addend
  485.       switch(OldRelocation.r_type) {
  486.       case R_386_NONE:    // Ignored
  487.          continue;
  488.  
  489.       case R_386_IRELATIVE:
  490.          err.submit(1063); // Warning: Gnu indirect function cannot be converted
  491.          // continue in next case?:
  492.       case R_386_32:       // 32-bit absolute virtual address
  493.          r_type  = MAC32_RELOC_VANILLA;  
  494.          break;
  495.  
  496.       case R_386_PC32:   // 32-bit self-relative
  497.          r_type  = MAC32_RELOC_VANILLA;  
  498.          r_pcrel = 1;
  499.          // Mach-O 32 bit format requires that self-relative addresses must have
  500.          // self-relative values already before relocation. Therefore
  501.          // the source address is subtracted.
  502.          // (The PC reference point is the end of the source = start
  503.          // of source + 4, but ELF files have the same offset so no further
  504.          // correction is needed when converting from ELF file).
  505.  
  506.          // !! ToDo: Self-relative relocations plus offset to local symbol in a different section
  507.          // sometimes causes problems in Mac linker, perhaps because it fails to determine
  508.          // correctly which section the target is in. Use a relocation with a reference point
  509.          // instead. This probably occurs only in assembler-coded self-relative 32-bit code.
  510.          // (Use asmlib A_strtoupper and A_strcspn as test cases - they fail if dummy data
  511.          // at the end of .data section is removed)
  512.          *piaddend -= r_address + (uint32)NewHeader.addr;
  513.          break;
  514.  
  515.       case R_UNSUPPORTED_IMAGEREL:  // 32-bit image-relative
  516.          // This occurs only when converting from COFF (via ELF)
  517.          // Needs scattered relocation entry
  518.          scat.r_address   = r_address;
  519.          scat.r_length    = 2;
  520.          scat.r_pcrel     = 0;
  521.          scat.r_scattered = 1;
  522.          scat.r_type      = MAC32_RELOC_SECTDIFF;
  523.          scat.r_value     = r_symbolnum;
  524.          // Store first entry of scattered pair
  525.          NewRelocationTab.Push(&scat, sizeof(scat));
  526.          NewHeader.nreloc++;
  527.          // Make subtractor record for image base
  528.          scat.r_type      = MAC32_RELOC_PAIR;
  529.          scat.r_value     = GetImagebaseSymbol();
  530.          // Store second entry of scattered pair
  531.          NewRelocationTab.Push(&scat, sizeof(scat));
  532.          NewHeader.nreloc++;
  533.          continue;
  534.  
  535.       case R_386_GOT32: case R_386_GLOB_DAT: case R_386_GOTOFF: case R_386_GOTPC:
  536.          // Global offset table
  537.          err.submit(2042);     // cannot convert position-independent code
  538.          err.ClearError(2042); // report this error only once
  539.          r_type = 0;
  540.          break;
  541.  
  542.       case R_386_PLT32: case R_386_JMP_SLOT:
  543.          // procedure linkage table
  544.          err.submit(2043);     // cannot convert import table
  545.          err.ClearError(2043); // report this error only once
  546.          r_type = 0;
  547.          break;
  548.  
  549.       default:      // Unknown or unsupported relocation method
  550.          err.submit(2030, OldRelocation.r_type);
  551.          r_type = 0;  break;
  552.       }
  553.  
  554.       if (!r_pcrel) {
  555.          // Warn for position dependent code.
  556.          // This warning is currently turned off in error.cpp.
  557.          err.submit(1050, this->SymbolName(OldRelocation.r_sym));
  558.          // Write this error only once
  559.          err.ClearError(1050);
  560.       }
  561.  
  562.       // Make relocation entry
  563.       MAC_relocation_info rel;
  564.       memset(&rel, 0, sizeof(rel));
  565.  
  566.       // Make non-scattered relocation entry
  567.       rel.r_address   = r_address;
  568.       rel.r_symbolnum = r_symbolnum;
  569.       rel.r_pcrel     = r_pcrel;
  570.       rel.r_length    = r_length;
  571.       rel.r_extern    = r_extern;
  572.       rel.r_type      = r_type;
  573.  
  574.       // Store relocation entry
  575.       NewRelocationTab.Push(&rel, sizeof(rel));
  576.       NewHeader.nreloc++;
  577.  
  578.       // Remember that symbol is used
  579.       // if (SymbolsUsed && OldRelocation.r_type && NewRelocation.r_symbolnum < ?) {
  580.       // SymbolsUsed[NewRelocation.r_symbolnum]++;}
  581.  
  582.    } // End of relocations loop
  583. }
  584.  
  585. template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation,
  586.           class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
  587. void CELF2MAC<ELFSTRUCTURES,MACSTRUCTURES>::Elf2MacRelocations(Elf64_Shdr & OldRelHeader, MAC_section_64 & NewHeader, uint32 NewRawDataOffset, uint32 oldsec) {
  588.    // Convert 64-bit relocations from ELF to MAC
  589.    // (This function has two template instances, only the 64-bit instance is used)
  590.  
  591.    // Make relocation entry for dummy subtractor
  592.    MAC_relocation_info relsub;
  593.    memset(&relsub, 0, sizeof(relsub));
  594.  
  595.    Elf64_Rela OldRelocation;  // Old relocation table entry
  596.  
  597.    // Get pointer to old relocation table
  598.    int8 * reltab = this->Buf() + OldRelHeader.sh_offset;
  599.    int8 * reltabend = reltab + OldRelHeader.sh_size;
  600.  
  601.    // Get entry size
  602.    uint32 entrysize = (uint32)OldRelHeader.sh_entsize;
  603.    uint32 expectedentrysize = (OldRelHeader.sh_type == SHT_REL) ? sizeof(Elf64_Rel) : sizeof(Elf64_Rela);
  604.    if (entrysize < expectedentrysize) {err.submit(2033); entrysize = expectedentrysize;}
  605.  
  606.    // File pointer to relocations
  607.    NewHeader.reloff = NewRelocationTab.GetNumEntries()*sizeof(MAC_relocation_info);  // Offset to first relocation table added later
  608.  
  609.    // Loop through relocation table entries
  610.    for (; reltab < reltabend; reltab += entrysize) {
  611.  
  612.       // Copy relocation entry with or without addend
  613.       OldRelocation.r_addend = 0;
  614.       memcpy(&OldRelocation, reltab, entrysize);
  615.  
  616.       // Find inline addend
  617.       uint32 InlinePosition = (uint32)(NewRawDataOffset + OldRelocation.r_offset);
  618.  
  619.       // Check that address is valid
  620.       if (InlinePosition >= this->GetDataSize()) {
  621.          // Address is invalid
  622.          err.submit(2032);
  623.          break;
  624.       }
  625.  
  626.       // Pointer to inline addend
  627.       int32 * piaddend = (int32*)(NewRawData.Buf() + InlinePosition);
  628.  
  629.       // Add old addend if any
  630.       *piaddend += (uint32)OldRelocation.r_addend;
  631.  
  632.       // Define relocation parameters
  633.       uint32  r_address = 0;      // section-relative offset to relocation source
  634.       uint32  r_symbolnum = 0;    // symbol index if r_extern == 1 or section ordinal if r_extern == 0
  635.       // uint32  r_value = 0;        // value of relocation target
  636.       // int     r_scattered = 0;    // scattered relocations not used in 64 bit
  637.       int     r_pcrel = 0;        // self relative
  638.       int     r_length = 2;       // size of source: 0=byte, 1=2 bytes, 2=4 bytes, 3=8 bytes
  639.       int     r_extern = 0;       // public or external
  640.       int     r_type = 0;         // if not 0, machine specific relocation type
  641.       int     Scope = 0;          // Symbol scope: 0 = local, 1 = public, 2 = external
  642.  
  643.       // source offset
  644.       r_address = (uint32)OldRelocation.r_offset;
  645.  
  646.       // target scope
  647.       if (OldRelocation.r_sym < NumOldSymbols) {
  648.          Scope = OldSymbolScope[OldRelocation.r_sym];
  649.       }
  650.  
  651.       // Get r_extern: 0 = local target referenced by address,
  652.       //               1 = public or external symbol referenced by symbol table index
  653.       switch (Scope) {
  654.       case S_LOCAL:   // Local target
  655.          // r_extern = 0;  // Local target must be referenced by address
  656.          // Note: the description in reloc.h says that local targets are addressed
  657.          // relative to any preceding public target. If there is no preceding label
  658.          // then referenced by address in the segment. However, the Gnu compiler
  659.          // uses reference to a local symbol and sets r_extern = 1 to indicate that
  660.          // it refers to a symbol record, not to an address. I have chosen to use the
  661.          // latter method because it is simpler, though undocumented.
  662.          r_extern = 1;
  663.          break;
  664.  
  665.       case S_PUBLIC:  // Public target is optionally referenced by index or by address
  666.          r_extern = 1;
  667.          break;
  668.  
  669.       case S_EXTERNAL:  // External target is always referenced by index
  670.          r_extern = 1;  
  671.          break;
  672.       }
  673.  
  674.       // Get zero-based index into NewSymTab[Scope]
  675.       int newindex = NewSymTab[Scope].TranslateIndex(OldRelocation.r_sym);
  676.       if (newindex < 0) {
  677.          // Symbol not found or wrong type
  678.          err.submit(2031);
  679.          break;
  680.       }
  681.  
  682.       // r_symbolnum is zero based index into combined symbol tables.
  683.       // Add number of entries in preceding NewSymTab tables to index
  684.       // into NewSymTab[Scope]
  685.       r_symbolnum = newindex + NumSymbols[Scope];
  686.  
  687.       // Get relocation type and fix addend, 64 bit
  688.       switch(OldRelocation.r_type) {
  689.       case R_X86_64_NONE:    // Ignored
  690.          continue;
  691.  
  692.       case R_X86_64_64:      
  693.          // 64-bit absolute virtual address
  694.          r_type  = MAC64_RELOC_UNSIGNED;  r_length = 3;
  695.          break;
  696.  
  697.       case R_X86_64_IRELATIVE:
  698.          err.submit(1063); // Warning: Gnu indirect function cannot be converted
  699.          // continue in next case?:
  700.       case R_X86_64_32: case R_X86_64_32S: {
  701.          // 32-bit absolute virtual address
  702.          // Note: The linker doesn't accept a 32-bit absolute address
  703.          // Make address relative to the image base, and add the value of the image base to compensate
  704.          if (cmd.ImageBase == 0) {
  705.             // Default image base if not specified
  706.             cmd.ImageBase = 0x400000;
  707.          }
  708.  
  709.          // Make subtractor relocation entry for image base
  710.          relsub.r_address   = r_address;
  711.          relsub.r_symbolnum = GetImagebaseSymbol();
  712.          relsub.r_length    = 2;
  713.          relsub.r_extern    = 1;
  714.          relsub.r_type      = MAC64_RELOC_SUBTRACTOR;
  715.  
  716.          NewRelocationTab.Push(&relsub, sizeof(relsub));
  717.          NewHeader.nreloc++;
  718.          // Add image base to compensate for subtracted image base
  719.          *piaddend += cmd.ImageBase;
  720.          
  721.          // Now we can add the address we really want:
  722.          r_type  = MAC64_RELOC_UNSIGNED;  
  723.          r_length = 2;
  724.          
  725.          // Warn that image base must be set to the specified value
  726.          char ImageBaseHex[32];
  727.          sprintf(ImageBaseHex, "%X", cmd.ImageBase); // write value as hexadecimal
  728.          err.submit(1300, ImageBaseHex);  err.ClearError(1300);
  729.          break;}      
  730.  
  731.       case R_X86_64_PC32:   // 32-bit self-relative
  732.          r_type  = MAC64_RELOC_BRANCH;
  733.          // MAC64_RELOC_SIGNED does the same, but the linker complains if external symbol
  734.          r_length = 2;  
  735.          r_pcrel = 1;
  736.          // Difference between EIP-relative and self-relative relocation = size of address field
  737.          // Adjust inline addend for different relocation method:
  738.          *piaddend += 4;
  739.          break;
  740.  
  741.       case R_UNSUPPORTED_IMAGEREL:  // 32-bit image-relative
  742.          // This occurs only when converting from COFF (via ELF)
  743.          // Make subtractor relocation entry for image base
  744.          relsub.r_address   = r_address;
  745.          relsub.r_symbolnum = GetImagebaseSymbol();
  746.          relsub.r_length    = 2;
  747.          relsub.r_extern    = 1;
  748.          relsub.r_type      = MAC64_RELOC_SUBTRACTOR;
  749.  
  750.          NewRelocationTab.Push(&relsub, sizeof(relsub));
  751.          NewHeader.nreloc++;
  752.          
  753.          // Second record adds the target address
  754.          r_type  = MAC64_RELOC_UNSIGNED;  
  755.          r_length = 2;
  756.          break;
  757.  
  758.       case R_X86_64_GLOB_DAT: case R_X86_64_GOTPCREL:
  759.          // Create 64-bit GOT entry??
  760.          r_type  = MAC64_RELOC_GOT;  r_length = 2;
  761.          break;        
  762.  
  763.       case R_X86_64_GOT32:
  764.          // 32-bit GOT entry
  765.          err.submit(2042);     // cannot convert 32-bit GOT
  766.          err.ClearError(2042); // report this error only once
  767.          r_type = 0;
  768.          break;
  769.  
  770.       case R_X86_64_PLT32: case R_X86_64_JUMP_SLOT:
  771.          // procedure linkage table
  772.          err.submit(2043);     // cannot convert import table
  773.          err.ClearError(2043); // report this error only once
  774.          r_type = 0;
  775.          break;
  776.  
  777.       case R_X86_64_COPY: case R_X86_64_RELATIVE:
  778.       default:      // Unknown or unsupported relocation method
  779.          err.submit(2030, OldRelocation.r_type);
  780.          r_type = 0;  break;
  781.       }
  782.  
  783.       // Make relocation entry
  784.       MAC_relocation_info rel;
  785.       memset(&rel, 0, sizeof(rel));
  786.  
  787.       // Make non-scattered relocation entry
  788.       rel.r_address   = r_address;
  789.       rel.r_symbolnum = r_symbolnum;
  790.       rel.r_pcrel     = r_pcrel;
  791.       rel.r_length    = r_length;
  792.       rel.r_extern    = r_extern;
  793.       rel.r_type      = r_type;
  794.  
  795.       // Store relocation entry
  796.       NewRelocationTab.Push(&rel, sizeof(rel));
  797.       NewHeader.nreloc++;
  798.  
  799.       // Remember that symbol is used
  800.       // if (SymbolsUsed && OldRelocation.r_type && NewRelocation.r_symbolnum < ?) {
  801.       // SymbolsUsed[NewRelocation.r_symbolnum]++;}
  802.  
  803.    } // End of relocations loop
  804. }
  805.  
  806. template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation,
  807.           class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
  808. void CELF2MAC<ELFSTRUCTURES,MACSTRUCTURES>::MakeSections() {
  809.    // Convert subfunction: Make sections and relocation tables
  810.    uint32 oldsec;                  // Section number in old file
  811.    uint32 relsec;                  // Relocation section in old file
  812.    TMAC_section NewHeader;         // New section header
  813.    TELF_SectionHeader OldHeader;   // Old section header
  814.    TELF_SectionHeader OldRelHeader;// Old relocation section header
  815.    uint32 NewVirtualAddress = 0;   // Virtual address of new section
  816.    uint32 NewRawDataOffset = 0;    // Offset into NewRawData of section.
  817.    // NewRawDataOffset is different from NewVirtualAddress if alignment of sections in
  818.    // the object file is different from alignment of sections in memory
  819.  
  820.    // Count cumulative number of symbols in each scope
  821.    NumSymbols[0] = 0;
  822.    NumSymbols[1] = NumSymbols[0] + NewSymTab[0].GetNumEntries();
  823.    NumSymbols[2] = NumSymbols[1] + NewSymTab[1].GetNumEntries();
  824.    NumSymbols[3] = NumSymbols[2] + NewSymTab[2].GetNumEntries();
  825.    if (NumSymbols[3] >= 0x1000000) err.submit(2051); // Too many symbols, max = 2^24
  826.  
  827.    NewSectHeadOffset = ToFile.GetDataSize();
  828.  
  829.    // Second loop through old sections
  830.    for (oldsec = 0; oldsec < this->NSections; oldsec++) {
  831.  
  832.       // Copy old header for convenience
  833.       OldHeader = this->SectionHeaders[oldsec];
  834.  
  835.       if (OldHeader.sh_size == 0) {
  836.          // Remove empty section
  837.          // The linker has a bug with empty sections
  838.          continue;
  839.       }
  840.  
  841.       // Search for program data sections only
  842.       if (OldHeader.sh_type == SHT_PROGBITS || OldHeader.sh_type == SHT_NOBITS) {
  843.  
  844.          // Reset new section header
  845.          memset(&NewHeader, 0, sizeof(NewHeader));
  846.  
  847.          // Section name
  848.          const char * sname = "";
  849.          uint32 namei = OldHeader.sh_name;
  850.          if (namei >= this->SecStringTableLen) err.submit(2112);
  851.          else sname = this->SecStringTable + namei;
  852.  
  853.          // Translate section name and truncate to 16 characters
  854.          if (!stricmp(sname,".text") || !stricmp(sname,"_text")) {
  855.             strcpy(NewHeader.sectname, "__text");
  856.             strcpy(NewHeader.segname,  "__TEXT");
  857.          }
  858.          else if (!stricmp(sname,".data") || !stricmp(sname,"_data")) {
  859.             strcpy(NewHeader.sectname, "__data");
  860.             strcpy(NewHeader.segname,  "__DATA");
  861.          }
  862.          else if (!strnicmp(sname+1,"bss", 3)) {
  863.             strcpy(NewHeader.sectname, "__bss");
  864.             strcpy(NewHeader.segname,  "__DATA");
  865.          }
  866.          else if (!strnicmp(sname+1,"const", 5) || !strnicmp(sname+1,"rodata", 6)) {
  867.             strcpy(NewHeader.sectname, "__const");
  868.             strcpy(NewHeader.segname,  "__DATA");
  869.          }
  870.          else if (!strnicmp(sname, ELF_CONSTRUCTOR_NAME, 5)) {
  871.             // Constructors
  872.             strcpy(NewHeader.sectname, MAC_CONSTRUCTOR_NAME);
  873.             strcpy(NewHeader.segname,  "__DATA");
  874.             NewHeader.flags = MAC_S_MOD_INIT_FUNC_POINTERS;
  875.          }
  876.          else if (OldHeader.sh_flags & SHF_EXECINSTR) {
  877.             // Other code section
  878.             if (strlen(NewHeader.sectname) > 16) err.submit(1040, NewHeader.sectname); // Warning: name truncated
  879.             strncpy(NewHeader.sectname, sname, 16);
  880.             strcpy(NewHeader.segname,  "__TEXT");
  881.          }
  882.          else {
  883.             // Other data section. Truncate name to 16 characters
  884.             if (strlen(NewHeader.sectname) > 16) err.submit(1040, NewHeader.sectname); // Warning: name truncated
  885.             strncpy(NewHeader.sectname, sname, 16);
  886.             strcpy(NewHeader.segname,  "__DATA");
  887.          }
  888.          if (NewHeader.sectname[0] == '.') {
  889.             // Make sure name begins with '_'
  890.             NewHeader.sectname[0] = '_';
  891.          }
  892.  
  893.          // Raw data
  894.          NewHeader.size = OldHeader.sh_size;  // section size in file
  895.  
  896.          // File  to raw data for section
  897.          NewHeader.offset = NewRawData.GetDataSize() + RawDataOffset;
  898.  
  899.          if (OldHeader.sh_size && OldHeader.sh_type != SHT_NOBITS) { // Not for .bss segment
  900.             // Copy raw data
  901.             NewRawDataOffset = NewRawData.Push(this->Buf()+(uint32)OldHeader.sh_offset, (uint32)OldHeader.sh_size);
  902.             NewRawData.Align(4);
  903.          }
  904.  
  905.          // Section flags
  906.          if (OldHeader.sh_flags & SHF_EXECINSTR) {
  907.             NewHeader.flags |= MAC_S_ATTR_PURE_INSTRUCTIONS | MAC_S_ATTR_SOME_INSTRUCTIONS;
  908.          }
  909.          else if (OldHeader.sh_type == SHT_NOBITS) {
  910.             NewHeader.flags |= MAC_S_ZEROFILL;              // .bss segment
  911.          }
  912.  
  913.          // Alignment
  914.          NewHeader.align = FloorLog2((uint32)OldHeader.sh_addralign);
  915.          if (NewHeader.align > 12) NewHeader.align = 12;   // What is the limit for highest alignment?
  916.          int AlignBy = 1 << NewHeader.align;
  917.  
  918.          // Align memory address
  919.          NewVirtualAddress = (NewVirtualAddress + AlignBy - 1) & -AlignBy;
  920.  
  921.          // Virtual memory address of new section
  922.          NewHeader.addr = NewVirtualAddress;
  923.          NewVirtualAddress += (uint32)OldHeader.sh_size;
  924.  
  925.          // Find relocation table for this section by searching through all sections
  926.          for (relsec = 1; relsec < this->NSections; relsec++) {
  927.  
  928.             // Get section header
  929.             OldRelHeader = this->SectionHeaders[relsec];            
  930.            
  931.             // Check if this is a relocations section referring to oldsec
  932.             if ((OldRelHeader.sh_type == SHT_REL || OldRelHeader.sh_type == SHT_RELA) // if section is relocation
  933.             && OldRelHeader.sh_info == oldsec) { // and if section refers to current section
  934.                Elf2MacRelocations(OldRelHeader, NewHeader, NewRawDataOffset, oldsec);
  935.             }
  936.          } // End of search for relocation table
  937.  
  938.          // Align raw data for next section
  939.          NewRawData.Align(4);
  940.  
  941.          // Fix v. 2.14: adjust NewVirtualAddress to match above alignment
  942.          NewVirtualAddress = (NewVirtualAddress + 3) & MInt(-4);
  943.  
  944.          // Store section header in file
  945.          ToFile.Push(&NewHeader, sizeof(NewHeader));
  946.  
  947.       } // End of if section has program data
  948.  
  949.    } // End of loop through old sections
  950.  
  951. } // End of function MakeSections
  952.  
  953.  
  954. template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation,
  955.           class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
  956. void CELF2MAC<ELFSTRUCTURES,MACSTRUCTURES>::FindUnusedSymbols() {
  957.    // Check if symbols used, remove unused symbols
  958.  
  959.    // Allocate table OldSymbolScope and OldSymbolUsed
  960.    NumOldSymbols = this->SymbolTableEntries;
  961.    if (NumOldSymbols > 0 && NumOldSymbols < 0x1000000) {
  962.       OldSymbolScope.SetNum(NumOldSymbols);
  963.       OldSymbolScope.SetZero();
  964.       OldSymbolUsed.SetNum(NumOldSymbols);
  965.       OldSymbolUsed.SetZero();
  966.    }
  967.  
  968.    // Loop through section headers
  969.    for (uint32 sc = 0; sc < this->NSections; sc++) {
  970.       uint32 entrysize = uint32(this->SectionHeaders[sc].sh_entsize);
  971.       // printf("\n%2i Name: %-18s ", sc, SecStringTable + sheader.sh_name);
  972.  
  973.       if ((this->SectionHeaders[sc].sh_type==SHT_REL || this->SectionHeaders[sc].sh_type==SHT_RELA)) {
  974.          // Relocation list
  975.          int8 * reltab = this->Buf() + uint32(this->SectionHeaders[sc].sh_offset);
  976.          int8 * reltabend = reltab + uint32(this->SectionHeaders[sc].sh_size);
  977.          uint32 expectedentrysize = this->SectionHeaders[sc].sh_type == SHT_RELA ?
  978.             sizeof(TELF_Relocation) :              // Elf32_Rela, Elf64_Rela
  979.             sizeof(TELF_Relocation) - this->WordSize/8;  // Elf32_Rel,  Elf64_Rel
  980.          if (entrysize < expectedentrysize) {err.submit(2033); entrysize = expectedentrysize;}
  981.  
  982.          // Loop through entries
  983.          for (; reltab < reltabend; reltab += entrysize) {
  984.             int isymbol = ((TELF_Relocation*)reltab)->r_sym;
  985.             // printf("\n>SymbolUsed: %i, Name: %s",isymbol,SymbolName(isymbol));
  986.             // Remember symbol used
  987.             OldSymbolUsed[isymbol]++;
  988.          }
  989.       }
  990.    }
  991. }
  992.  
  993. template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation,
  994.           class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
  995. void CELF2MAC<ELFSTRUCTURES,MACSTRUCTURES>::MakeBinaryFile() {
  996.    // Convert subfunction: Putting sections together
  997.    // File header, segment command and section headers have been inserted.
  998.    int i;
  999.  
  1000.    // Update segment header for segment size in file
  1001.    ((TMAC_segment_command*)(ToFile.Buf()+CommandOffset))->filesize = NewRawData.GetDataSize();
  1002.  
  1003.    // Make symbol table command
  1004.    MAC_symtab_command symtab;
  1005.    memset(&symtab, 0, sizeof(symtab));
  1006.    symtab.cmd = MAC_LC_SYMTAB;
  1007.    symtab.cmdsize = sizeof(symtab);
  1008.    // symoff, nsyms, stroff, strsize inserted later
  1009.    // Store symtab command
  1010.    NewSymtabOffset = ToFile.Push(&symtab, sizeof(symtab));
  1011.  
  1012.    // Make MAC_dysymtab_command command
  1013.    MAC_dysymtab_command dysymtab;
  1014.    memset(&dysymtab, 0, sizeof(dysymtab));
  1015.    dysymtab.cmd        = MAC_LC_DYSYMTAB;
  1016.    dysymtab.cmdsize    = sizeof(dysymtab);
  1017.    dysymtab.ilocalsym  = 0;                            // index to local symbols
  1018.    dysymtab.nlocalsym  = NewSymTab[0].GetNumEntries(); // number of local symbols
  1019.    dysymtab.iextdefsym = dysymtab.nlocalsym;           // index to externally defined symbols
  1020.    dysymtab.nextdefsym = NewSymTab[1].GetNumEntries(); // number of externally defined symbols
  1021.    dysymtab.iundefsym  = dysymtab.iextdefsym + dysymtab.nextdefsym;     // index to public symbols
  1022.    dysymtab.nundefsym  = NewSymTab[2].GetNumEntries(); // number of public symbols
  1023.    // Store MAC_dysymtab_command command
  1024.    ToFile.Push(&dysymtab, sizeof(dysymtab));
  1025.  
  1026.    // Store section data
  1027.    uint32 Current = ToFile.Push(NewRawData.Buf(), NewRawData.GetDataSize());
  1028.    if (Current != RawDataOffset) err.submit(9000);
  1029.  
  1030.    ToFile.Align(4);
  1031.  
  1032.    // Store relocation tables
  1033.    uint32 Reltabs = ToFile.Push(NewRelocationTab.Buf(), NewRelocationTab.GetDataSize());
  1034.  
  1035.    // Initialize new string table. First string is empty
  1036.    NewStringTable.Push(0, 1);
  1037.  
  1038.    // Store symbol tables and make string table
  1039.    // Tables are not sorted alphabetically yet. This will be done subsequently
  1040.    // by CMAC2MAC
  1041.    uint32 Symtabs = ToFile.GetDataSize();
  1042.    uint32 NumSyms = 0;
  1043.    for (i = 0; i < 3; i++) {
  1044.       NumSyms += NewSymTab[i].GetNumEntries();
  1045.       NewSymTab[i].StoreList(&ToFile, &NewStringTable);
  1046.    }
  1047.  
  1048.    // Store string table
  1049.    uint32 StringTab = ToFile.Push(NewStringTable.Buf(), NewStringTable.GetDataSize());
  1050.  
  1051.    // Set missing values in file header
  1052.    ((TMAC_header*)ToFile.Buf())->sizeofcmds = RawDataOffset - sizeof(TMAC_header);
  1053.  
  1054.    // Adjust relocation offsets in section headers
  1055.    TMAC_section* sectp = (TMAC_section*)(ToFile.Buf() + NewSectHeadOffset);
  1056.    for (i = 0; i < NumSectionsNew; i++, sectp++) {
  1057.       sectp->reloff += Reltabs;
  1058.    }
  1059.  
  1060.    // Set missing symoff, nsyms, stroff, strsize in symtab command
  1061.    MAC_symtab_command * symtabp = (MAC_symtab_command*)(ToFile.Buf() + NewSymtabOffset);
  1062.    symtabp->symoff  = Symtabs;
  1063.    symtabp->nsyms   = NumSyms;
  1064.    symtabp->stroff  = StringTab;
  1065.    symtabp->strsize = NewStringTable.GetDataSize();
  1066. }
  1067.  
  1068. template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation,
  1069.           class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
  1070. int CELF2MAC<ELFSTRUCTURES,MACSTRUCTURES>::GetImagebaseSymbol() {
  1071.    // Get symbol table index of __mh_execute_header = image base
  1072.    // Create this symbol table entry if it doesn't exist
  1073.  
  1074.    const char * ImageBaseName = "__mh_execute_header";
  1075.    static int ImagebaseSymbol = -1;
  1076.  
  1077.    if (ImagebaseSymbol >= 0) {
  1078.       // Found previously
  1079.       return ImagebaseSymbol;
  1080.    }
  1081.    // Search for name among external symbols
  1082.    int index2 = NewSymTab[2].Search(ImageBaseName);
  1083.    if (index2 >= 0) {
  1084.       // found
  1085.       ImagebaseSymbol = index2 + NumSymbols[2];
  1086.       return ImagebaseSymbol;
  1087.    }
  1088.    // Not found. Create symbol
  1089.    NewSymTab[2].AddSymbol(NumOldSymbols, ImageBaseName, MAC_N_EXT, 0, 0, 0);
  1090.    ImagebaseSymbol = NewSymTab[2].TranslateIndex(NumOldSymbols) + NumSymbols[2];
  1091.    NumSymbols[3]++;
  1092.    return ImagebaseSymbol;
  1093. }
  1094.  
  1095.  
  1096. // Make template instances for 32 and 64 bits
  1097. template class CELF2MAC<ELF32STRUCTURES,MAC32STRUCTURES>;
  1098. template class CELF2MAC<ELF64STRUCTURES,MAC64STRUCTURES>;
  1099.