/**************************** main.cpp ********************************** * Author: Agner Fog * Date created: 2006-07-26 * Last modified: 2011-10-28 * Project: objconv * Module: main.cpp * Description: * Objconv is a portable C++ program for converting object file formats. * Compile for console mode on any platform. * * Module main contains the program entry * * Copyright 2006-2011 GNU General Public License http://www.gnu.org/licenses *****************************************************************************/ #include "stdafx.h" // Texts of option feedback. Adding or removing leading underscores on symbols SIntTxt UnderscoreOptionNames[] = { {CMDL_UNDERSCORE_NOCHANGE, "Not adding or removing underscores for this filetype"}, {CMDL_UNDERSCORE_REMOVE, "Removing leading underscores from symbol names"}, {CMDL_UNDERSCORE_ADD, "Adding leading underscores to symbol names"}, {CMDL_UNDERSCORE_REMOVE|CMDL_KEEP_ALIAS, "Removing leading underscores from symbol names. Keeping old name as alias"}, {CMDL_UNDERSCORE_ADD|CMDL_KEEP_ALIAS, "Adding leading underscores to symbol names. Keeping old name as alias"} }; // Texts of option feedback. Changing leading dot or underscore on section names SIntTxt SectionDotOptionNames[] = { {CMDL_SECTIONDOT_NOCHANGE, "Not changing leading character on section names for this filetype"}, {CMDL_SECTIONDOT_U2DOT, "Changing leading underscores on section names to dot"}, {CMDL_SECTIONDOT_DOT2U, "Changing leading dot on nonstandard section names to underscore"} }; // Check that integer type definitions are correct. // Will generate an error message if the compiler makes the integer types // with wrong size. static void CheckIntegerTypes() { if ( sizeof(uint8) != 1 || sizeof(int16) != 2 || sizeof(int32) != 4 || sizeof(int64) != 8) { err.submit(9001); // Make error message if type definitions are wrong } } // Check that we are running on a machine with little-endian memory organization static void CheckEndianness() { static uint8 bytes[4] = {1, 2, 3, 4}; if (*(uint32*)bytes != 0x04030201) { // Big endian err.submit(9002); } } // Function to convert powers of 2 to index int FloorLog2(uint32 x) { int i = -1; do { x >>= 1; i++; } while (x); return i; } const char * timestring(uint32 t) { // Convert 32 bit time stamp to string // Fix the problem that time_t may be 32 bit or 64 bit union { time_t t; uint32 t32; } utime; utime.t = 0; utime.t32 = t; const char * string = ctime(&utime.t); if (string == 0) string = "?"; return string; } // Main. Program starts here int main(int argc, char * argv[]) { CheckIntegerTypes(); // Check that compiler has the right integer sizes CheckEndianness(); // Check that machine is little-endian #ifdef _DEBUG // For debugging only. Remove this if (argc == 1) { char * dummyarg[] = {"", "@resp.txt"}; // Read command line from file resp.txt argc = 2; argv = dummyarg;} #endif cmd.ReadCommandLine(argc, argv); // Read command line parameters if (cmd.ShowHelp) return 0; // Help screen has been printed. Do nothing else CMain maincvt; // This object takes care of all conversions etc. maincvt.Go(); // Do everything the command line says if (cmd.Verbose) printf("\n"); // End with newline return err.GetWorstError(); // Return with error code } // Class CMainConverter is used for control of the conversion process CMain::CMain() : CFileBuffer() { } void CMain::Go() { // Do whatever the command line parameters say FileName = cmd.InputFile; // Get input file name from command line // Ignore nonexisting filename when building library int IgnoreError = (cmd.FileOptions & CMDL_FILE_IN_IF_EXISTS) && !cmd.OutputFile; Read(IgnoreError); // Read input file GetFileType(); // Determine file type cmd.InputType = FileType; // Save input file type in cmd for access from other modules if (cmd.OutputType == 0) { // desired type not specified cmd.OutputType = FileType; } if (err.Number()) return; // Return if error CheckOutputFileName(); // Construct output file name with default extension if (err.Number()) return; if ((FileType & (FILETYPE_LIBRARY | FILETYPE_OMFLIBRARY)) || (cmd.LibraryOptions & CMDL_LIBRARY_ADDMEMBER)) { // Input file is a library or we are building a library CLibrary lib; // Library handler object *this >> lib; // Transfer my file buffer to lib lib.Go(); // Do conversion or dump *this << lib; // Get file buffer back } else { // Input file is an object file CConverter conv; // Make converter object *this >> conv; // Transfer my file buffer to conv conv.Go(); // Do conversion or dump *this << conv; // Get file buffer back } if ((cmd.FileOptions & CMDL_FILE_OUTPUT) && OutputFileName) { // There is an output file to write cmd.CheckSymbolModifySuccess(); // Check if symbols to modify were found if (err.Number()) return; // Return if error FileName = OutputFileName; // Output file name Write(); // Write output file if (cmd.Verbose) cmd.ReportStatistics(); // Report statistics } } CConverter::CConverter() { // Constructor } void CConverter::DumpCOF() { // Dump COFF file CCOFF cof; // Make object for interpreting COFF file *this >> cof; // Give it my buffer cof.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error cof.Dump(cmd.DumpOptions); // Dump file *this << cof; // Take back my buffer } void CConverter::DumpELF() { // Dump ELF file if (WordSize == 32) { // Make object for interpreting 32 bit ELF file CELF elf; *this >> elf; // Give it my buffer elf.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error elf.Dump(cmd.DumpOptions); // Dump file *this << elf; // Take back my buffer } else { // Make object for interpreting 32 bit ELF file CELF elf; *this >> elf; // Give it my buffer elf.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error elf.Dump(cmd.DumpOptions); // Dump file *this << elf; // Take back my buffer } } void CConverter::DumpMACHO() { // Dump Mach-O file if (WordSize == 32) { // Make object for interpreting 32 bit Mach-O file CMACHO macho; *this >> macho; // Give it my buffer macho.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error macho.Dump(cmd.DumpOptions); // Dump file *this << macho; // Take back my buffer } else { // Make object for interpreting 64 bit Mach-O file CMACHO macho; *this >> macho; // Give it my buffer macho.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error macho.Dump(cmd.DumpOptions); // Dump file *this << macho; // Take back my buffer } } void CConverter::ParseMACUnivBin() { // Dump Mac universal binary CMACUNIV macuniv; // Make object for interpreting Mac universal binary file *this >> macuniv; // Give it my buffer macuniv.Go(cmd.DumpOptions); // Dump file components *this << macuniv; // Take back my buffer } void CConverter::DumpOMF() { // Dump OMF file COMF omf; // Make object for interpreting OMF file *this >> omf; // Give it my buffer omf.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error omf.Dump(cmd.DumpOptions); // Dump file *this << omf; // Take back my buffer } void CConverter::COF2ELF() { // Convert COFF to ELF file if (WordSize == 32) { // Make instance of converter, 32 bit template CCOF2ELF conv; // Make object for conversion *this >> conv; // Give it my buffer conv.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error conv.Convert(); // Convert *this << conv; // Take back converted buffer } else { // Make instance of converter, 64 bit template CCOF2ELF conv; // Make object for conversion *this >> conv; // Give it my buffer conv.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error conv.Convert(); // Convert *this << conv; // Take back converted buffer } } void CConverter::COF2OMF() { // Convert COFF to OMF file CCOF2OMF conv; // Make object for conversion *this >> conv; // Give it my buffer conv.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error conv.Convert(); // Convert *this << conv; // Take back converted buffer } void CConverter::OMF2COF() { // Convert OMF to COFF file COMF2COF conv; // Make object for conversion *this >> conv; // Give it my buffer conv.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error conv.Convert(); // Convert *this << conv; // Take back converted buffer } void CConverter::ELF2COF() { // Convert ELF to COFF file if (WordSize == 32) { // Make instance of converter, 32 bit template CELF2COF conv; *this >> conv; // Give it my buffer conv.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error conv.Convert(); // Convert *this << conv; // Take back converted buffer } else { // Make instance of converter, 64 bit template CELF2COF conv; *this >> conv; // Give it my buffer conv.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error conv.Convert(); // Convert *this << conv; // Take back converted buffer } } void CConverter::ELF2MAC() { // Convert ELF to Mach-O file if (WordSize == 32) { // Make instance of converter, 32 bit template CELF2MAC conv; *this >> conv; // Give it my buffer conv.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error conv.Convert(); // Convert *this << conv; // Take back converted buffer } else { // Make instance of converter, 64 bit template CELF2MAC conv; *this >> conv; // Give it my buffer conv.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error conv.Convert(); // Convert *this << conv; // Take back converted buffer } } void CConverter::MAC2ELF() { // Convert Mach-O file to ELF file if (WordSize == 32) { // Make instance of converter, 32 bit template CMAC2ELF conv; *this >> conv; // Give it my buffer conv.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error conv.Convert(); // Convert *this << conv; // Take back converted buffer } else { // Make instance of converter, 64 bit template CMAC2ELF conv; *this >> conv; // Give it my buffer conv.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error conv.Convert(); // Convert *this << conv; // Take back converted buffer } } void CConverter::COF2ASM() { // Disassemble COFF file CCOF2ASM conv; // Make object for conversion *this >> conv; // Give it my buffer conv.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error conv.Convert(); // Convert *this << conv; // Take back converted buffer } void CConverter::ELF2ASM() { // Disassemble ELF file if (WordSize == 32) { // Make instance of converter, 32 bit template CELF2ASM conv; *this >> conv; // Give it my buffer conv.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error conv.Convert(); // Convert *this << conv; // Take back converted buffer } else { // Make instance of converter, 64 bit template CELF2ASM conv; *this >> conv; // Give it my buffer conv.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error conv.Convert(); // Convert *this << conv; // Take back converted buffer } } void CConverter::MAC2ASM() { // Disassemble Mach-O file if (WordSize == 32) { // Make instance of converter, 32 bit template CMAC2ASM conv; *this >> conv; // Give it my buffer conv.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error conv.Convert(); // Convert *this << conv; // Take back converted buffer } else { // Make instance of converter, 64 bit template CMAC2ASM conv; *this >> conv; // Give it my buffer conv.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error conv.Convert(); // Convert *this << conv; // Take back converted buffer } } void CConverter::OMF2ASM() { // Disassemble OMF file COMF2ASM conv; // Make object for conversion *this >> conv; // Give it my buffer conv.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error conv.Convert(); // Convert *this << conv; // Take back converted buffer } void CConverter::COF2COF() { // Make changes in COFF file CCOF2COF conv; // Make instance of converter *this >> conv; // Give it my buffer conv.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error conv.Convert(); // Convert *this << conv; // Take back converted buffer } void CConverter::ELF2ELF() { // Make changes in ELF file if (WordSize == 32) { // Make instance of converter, 32 bit template CELF2ELF conv; *this >> conv; // Give it my buffer conv.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error conv.Convert(); // Convert *this << conv; // Take back converted buffer } else { // Make instance of converter, 64 bit template CELF2ELF conv; *this >> conv; // Give it my buffer conv.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error conv.Convert(); // Convert *this << conv; // Take back converted buffer } } void CConverter::MAC2MAC() { // Make changes in Mach-O file if (WordSize == 32) { // Make instance of converter, 32 bit template CMAC2MAC conv; *this >> conv; // Give it my buffer conv.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error conv.Convert(); // Convert *this << conv; // Take back converted buffer } else { // Make instance of converter, 64 bit template CMAC2MAC conv; *this >> conv; // Give it my buffer conv.ParseFile(); // Parse file buffer if (err.Number()) return; // Return if error conv.Convert(); // Convert *this << conv; // Take back converted buffer } } void CConverter::Go() { // Convert or dump file, depending on command line parameters GetFileType(); // Determine file type cmd.InputType = FileType; // Save input file type in cmd for access from other modules if (err.Number()) return; // Return if error if (cmd.OutputType == CMDL_OUTPUT_DUMP) { // File dump requested if (cmd.Verbose > 0) { // Tell what we are doing: printf("\nDump of file: %s, type: %s%i", FileName, GetFileFormatName(FileType), WordSize); } switch(FileType) { case FILETYPE_ELF: DumpELF(); break; case FILETYPE_COFF: DumpCOF(); break; case FILETYPE_MACHO_LE: DumpMACHO(); break; case FILETYPE_OMF: DumpOMF(); break; case FILETYPE_MAC_UNIVBIN: ParseMACUnivBin(); break; default: err.submit(2010, GetFileFormatName(FileType)); // Dump of this file type not supported } printf("\n"); // New line } else { // File conversion requested if (cmd.DesiredWordSize == 0) cmd.DesiredWordSize = WordSize; if (WordSize && WordSize != cmd.DesiredWordSize) { err.submit(2012, WordSize, cmd.DesiredWordSize); // Cannot convert word size return; } if (Executable && cmd.OutputType != CMDL_OUTPUT_MASM) { // Attempt to convert executable file err.submit(2022); } if (err.Number()) return; // Return if error if (cmd.Verbose > (uint32)(cmd.LibraryOptions != 0)) { // Tell what we are doing: printf("\nInput file: %s, output file: %s", FileName, OutputFileName); if (FileType != cmd.OutputType) { printf("\nConverting from %s%2i to %s%2i", GetFileFormatName(FileType), WordSize, GetFileFormatName(cmd.OutputType), WordSize); } else { printf("\nModifying %s%2i file", GetFileFormatName(FileType), WordSize); } } // Check underscore options if (cmd.Underscore && cmd.OutputType != 0) { if (cmd.Underscore == CMDL_UNDERSCORE_CHANGE) { // Find underscore option for desired conversion if (WordSize == 32) { // In 32-bit, all formats except ELF have underscores if (FileType == FILETYPE_ELF && cmd.OutputType != FILETYPE_ELF) { // Converting from ELF32. Add underscores cmd.Underscore = CMDL_UNDERSCORE_ADD; } else if (FileType != FILETYPE_ELF && cmd.OutputType == FILETYPE_ELF) { // Converting to ELF32. Remove underscores cmd.Underscore = CMDL_UNDERSCORE_REMOVE; } else { // Anything else 32-bit. No change cmd.Underscore = CMDL_UNDERSCORE_NOCHANGE; } } else { // In 64-bit, only Mach-O has underscores if (FileType == FILETYPE_MACHO_LE && cmd.OutputType != FILETYPE_MACHO_LE) { // Converting from MachO-64. Remove underscores cmd.Underscore = CMDL_UNDERSCORE_REMOVE; } else if (FileType != FILETYPE_MACHO_LE && cmd.OutputType == FILETYPE_MACHO_LE) { // Converting to MachO-64. Add underscores cmd.Underscore = CMDL_UNDERSCORE_ADD; } else { // Anything else 64-bit. No change cmd.Underscore = CMDL_UNDERSCORE_NOCHANGE; } } } if (cmd.Verbose > (uint32)(cmd.LibraryOptions != 0)) { // Tell which option is chosen printf("\n%s", Lookup(UnderscoreOptionNames, cmd.Underscore)); } } // Check sectionname options if (cmd.SegmentDot && cmd.OutputType != 0) { if (cmd.SegmentDot == CMDL_SECTIONDOT_CHANGE) { if (cmd.OutputType == FILETYPE_COFF || cmd.OutputType == FILETYPE_MACHO_LE || cmd.OutputType == FILETYPE_OMF) { // Change leading '.' to '_' in nonstandard section names cmd.SegmentDot = CMDL_SECTIONDOT_DOT2U; } else if (cmd.OutputType == FILETYPE_ELF) { // Change leading '_' to '.' in nonstandard section names cmd.SegmentDot = CMDL_SECTIONDOT_U2DOT; } else { cmd.SegmentDot = CMDL_SECTIONDOT_NOCHANGE; } } if (cmd.Verbose > (uint32)(cmd.LibraryOptions != 0)) { // Tell which option is chosen printf("\n%s", Lookup(SectionDotOptionNames, cmd.SegmentDot)); } } // Check debug info options if (cmd.DebugInfo == CMDL_DEBUG_DEFAULT) { cmd.DebugInfo = (FileType != cmd.OutputType) ? CMDL_DEBUG_STRIP : CMDL_DEBUG_PRESERVE; } // Check exception handler info options if (cmd.ExeptionInfo == CMDL_EXCEPTION_DEFAULT) { cmd.ExeptionInfo = (FileType != cmd.OutputType) ? CMDL_EXCEPTION_STRIP : CMDL_EXCEPTION_PRESERVE; } // Choose conversion switch (FileType) { // Conversion from ELF case FILETYPE_ELF: switch (cmd.OutputType) { case FILETYPE_COFF: // Conversion from ELF to COFF ELF2ELF(); // Make symbol changes in ELF file if (err.Number()) return; // Return if error ELF2COF(); // Convert to COFF break; case FILETYPE_MACHO_LE: // Conversion from ELF to Mach-O ELF2MAC(); // Convert to Mach-O if (err.Number()) return; // Return if error MAC2MAC(); // Make symbol changes in Mach-O file, sort symbol tables alphabetically break; case FILETYPE_OMF: // Conversion from ELF to OMF ELF2ELF(); // Make symbol changes in ELF file if (err.Number()) return; // Return if error ELF2COF(); // Convert to COFF first if (err.Number()) return; // Return if error COF2OMF(); // Then convert to OMF break; case FILETYPE_ELF: // Make changes in ELF file if (cmd.SymbolChangesRequested()) { ELF2ELF(); // Make symbol changes in ELF file } else if (!cmd.LibraryOptions) { err.submit(1006); // Warning: nothing to do } break; case CMDL_OUTPUT_MASM: // Disassemble ELF file ELF2ASM(); // Disassemble break; default: // Conversion not supported err.submit(2013, GetFileFormatName(FileType), GetFileFormatName(cmd.OutputType)); } break; // Conversion from COFF case FILETYPE_COFF: switch (cmd.OutputType) { case FILETYPE_COFF: // No conversion. Modify file if (cmd.DebugInfo == CMDL_DEBUG_STRIP || cmd.ExeptionInfo == CMDL_EXCEPTION_STRIP) { COF2ELF(); // Convert to ELF and back again to strip debug and exception info if (err.Number()) return; // Return if error ELF2COF(); err.submit(1008); // Warning: Converting to ELF and back again } if (cmd.SymbolChangesRequested()) { COF2COF(); // Make symbol name changes in COFF file } else if (cmd.DebugInfo != CMDL_DEBUG_STRIP && cmd.ExeptionInfo != CMDL_EXCEPTION_STRIP && !cmd.LibraryOptions) { err.submit(1006); // Warning: nothing to do } break; case FILETYPE_ELF: COF2COF(); // Make symbol changes in COFF file if (err.Number()) return; // Return if error COF2ELF(); // Convert to ELF break; case FILETYPE_OMF: COF2COF(); // Make symbol changes in COFF file if (err.Number()) return; // Return if error COF2OMF(); // Convert to OMF break; case FILETYPE_MACHO_LE: COF2ELF(); // Convert from COFF to ELF if (err.Number()) return; // Return if error ELF2MAC(); // Then convert from ELF to Mach-O if (err.Number()) return; // Return if error MAC2MAC(); // Make symbol changes in Mach-O file and sort symbol table break; case CMDL_OUTPUT_MASM: // Disassemble COFF file COF2ASM(); // Disassemble break; default: // Conversion not supported err.submit(2013, GetFileFormatName(FileType), GetFileFormatName(cmd.OutputType)); } break; // Conversion from OMF case FILETYPE_OMF: switch (cmd.OutputType) { case FILETYPE_OMF: // No conversion. Modify file if (cmd.SymbolChangesRequested() || cmd.DebugInfo == CMDL_DEBUG_STRIP || cmd.ExeptionInfo == CMDL_EXCEPTION_STRIP) { OMF2COF(); // Convert to COFF and back again to do requested changes if (err.Number()) return; // Return if error COF2COF(); // Make symbol changes in COFF file if (err.Number()) return; // Return if error COF2OMF(); err.submit(1009); // Warning: Converting to COFF and back again } break; case FILETYPE_COFF: OMF2COF(); // Convert to COFF if (err.Number()) return; // Return if error COF2COF(); // Make symbol changes in COFF file break; case FILETYPE_ELF: OMF2COF(); // Convert to COFF if (err.Number()) return; // Return if error COF2COF(); // Make symbol changes in COFF file if (err.Number()) return; // Return if error COF2ELF(); // Convert to ELF break; case FILETYPE_MACHO_LE: OMF2COF(); // Convert to COFF if (err.Number()) return; // Return if error COF2ELF(); // Convert from COFF to ELF if (err.Number()) return; // Return if error ELF2MAC(); // Then convert from ELF to Mach-O if (err.Number()) return; // Return if error MAC2MAC(); // Make symbol changes in Mach-O file and sort symbol table break; case CMDL_OUTPUT_MASM: // Disassemble OMF file OMF2ASM(); // Disassemble break; default: // Conversion not supported err.submit(2013, GetFileFormatName(FileType), GetFileFormatName(cmd.OutputType)); } break; // Conversions from Mach-O case FILETYPE_MACHO_LE: switch (cmd.OutputType) { case FILETYPE_ELF: MAC2ELF(); // Convert to ELF if (err.Number()) return; // Return if error ELF2ELF(); // Make symbol changes in ELF file break; case FILETYPE_COFF: MAC2ELF(); // Convert to ELF if (err.Number()) return; // Return if error ELF2ELF(); // Make symbol changes in ELF file if (err.Number()) return; // Return if error ELF2COF(); // Convert to COFF break; case FILETYPE_OMF: MAC2ELF(); // Convert to ELF if (err.Number()) return; // Return if error ELF2ELF(); // Make symbol changes in ELF file if (err.Number()) return; // Return if error ELF2COF(); // Convert to COFF if (err.Number()) return; // Return if error COF2OMF(); // Convert to OMF break; case FILETYPE_MACHO_LE: MAC2MAC(); // Make symbol changes in mACH-o file break; case CMDL_OUTPUT_MASM: // Disassemble Mach-O file MAC2ASM(); // Disassemble break; default: // Conversion not supported err.submit(2013, GetFileFormatName(FileType), GetFileFormatName(cmd.OutputType)); } break; case FILETYPE_MAC_UNIVBIN: ParseMACUnivBin(); break; // Conversion from other types default: err.submit(2006, FileName, GetFileFormatName(FileType)); // Conversion of this file type not supported } } }