Subversion Repositories Kolibri OS

Rev

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

  1. /****************************  cmdline.cpp  **********************************
  2. * Author:        Agner Fog
  3. * Date created:  2006-07-25
  4. * Last modified: 2018-01-29
  5. * Project:       objconv
  6. * Module:        cmdline.cpp
  7. * Description:
  8. * This module is for interpretation of command line options
  9. * Also contains symbol change function
  10. *
  11. * Copyright 2006-2018 GNU General Public License http://www.gnu.org/licenses
  12. *****************************************************************************/
  13.  
  14. #include "stdafx.h"
  15.  
  16. // List of recognized output file type options
  17. static SIntTxt TypeOptionNames[] = {
  18.     {CMDL_OUTPUT_ELF,   "elf"},
  19.     {CMDL_OUTPUT_PE,    "pe"},
  20.     {CMDL_OUTPUT_PE,    "coff"},
  21.     {CMDL_OUTPUT_PE,    "cof"},
  22.     {CMDL_OUTPUT_PE,    "win"},
  23.     {CMDL_OUTPUT_OMF,   "omf"},
  24.     {CMDL_OUTPUT_MACHO, "mac"},
  25.     {CMDL_OUTPUT_MACHO, "macho"},
  26.     {CMDL_OUTPUT_MACHO, "mach-o"},
  27.     {CMDL_OUTPUT_MACHO, "mach"},
  28.     {CMDL_OUTPUT_MASM,  "asm"},
  29.     {CMDL_OUTPUT_MASM,  "masm"},
  30.     {CMDL_OUTPUT_MASM,  "tasm"},
  31.     {CMDL_OUTPUT_MASM,  "nasm"},
  32.     {CMDL_OUTPUT_MASM,  "yasm"},
  33.     {CMDL_OUTPUT_MASM,  "gasm"},
  34.     {CMDL_OUTPUT_MASM,  "gas"}
  35. };
  36.  
  37. // List of subtype names
  38. static SIntTxt SubtypeNames[] = {
  39.     {SUBTYPE_MASM,  "asm"},
  40.     {SUBTYPE_MASM,  "masm"},
  41.     {SUBTYPE_MASM,  "tasm"},
  42.     {SUBTYPE_YASM,  "nasm"},
  43.     {SUBTYPE_YASM,  "yasm"},
  44.     {SUBTYPE_GASM,  "gasm"},
  45.     {SUBTYPE_GASM,  "gas"}
  46. };
  47.  
  48. // List of standard names that are always translated
  49. const uint32 MaxType = FILETYPE_MACHO_LE;
  50.  
  51. // Standard names in 32-bit mode
  52. const char * StandardNames32[][MaxType+1] = {
  53.     //  0,    COFF,          OMF,           ELF,                MACHO
  54.     {0,"___ImageBase","___ImageBase","__executable_start","__mh_execute_header"}
  55. };
  56.  
  57. // Standard names in 64-bit mode
  58. // COFF removes an underscore in 32-bit. There is no 64-bit OMF
  59. const char * StandardNames64[][MaxType+1] = {
  60.     //  0,    COFF,       OMF,         ELF,                MACHO
  61.     {0,"__ImageBase",  "",    "__executable_start","__mh_execute_header"}
  62. };
  63.  
  64. const int NumStandardNames = sizeof(StandardNames32) / sizeof(StandardNames32[0]);
  65.  
  66.  
  67. // Command line interpreter
  68. CCommandLineInterpreter cmd;                  // Instantiate command line interpreter
  69.  
  70. CCommandLineInterpreter::CCommandLineInterpreter() {
  71.     // Default constructor
  72.     memset(this, 0, sizeof(*this));            // Set all to zero
  73.     Verbose        = CMDL_VERBOSE_YES;         // How much diagnostics to print on screen
  74.     DumpOptions    = DUMP_NONE;                // Dump options
  75.     DebugInfo      = CMDL_DEBUG_DEFAULT;       // Strip or convert debug info
  76.     ExeptionInfo   = CMDL_EXCEPTION_DEFAULT;   // Strip or preserve exception handling info
  77.     SegmentDot     = CMDL_SECTIONDOT_NOCHANGE; // Change underscore/dot in beginning of segment names
  78.     Underscore     = CMDL_UNDERSCORE_NOCHANGE; // Add/remove underscores in symbol names
  79.     LibraryOptions = CMDL_LIBRARY_DEFAULT;     // Library options
  80. }
  81.  
  82.  
  83. CCommandLineInterpreter::~CCommandLineInterpreter() { // Destructor
  84. }
  85.  
  86.  
  87. void CCommandLineInterpreter::ReadCommandLine(int argc, char * argv[]) {
  88.  
  89.     // Read command line
  90.     for (int i = 1; i < argc; i++) {
  91.         ReadCommandItem(argv[i]);
  92.     }
  93.     if (ShowHelp || (InputFile == 0 && OutputFile == 0) /* || !OutputType */) {
  94.         // No useful command found. Print help
  95.         Help();  ShowHelp = 1;
  96.         return;
  97.     }
  98.     // Check file options
  99.     FileOptions = CMDL_FILE_INPUT;
  100.     if (LibraryOptions == CMDL_LIBRARY_ADDMEMBER) {
  101.         // Adding object files to library. Library may not exist
  102.         FileOptions = CMDL_FILE_IN_IF_EXISTS;
  103.     }
  104.     if (DumpOptions || ((LibraryOptions & CMDL_LIBRARY_EXTRACTMEM) && !(LibraryOptions & CMDL_LIBRARY_ADDMEMBER))) {
  105.         // Dumping or extracting. Output file not used
  106.         if (OutputFile) err.submit(1103); // Output file name ignored
  107.         OutputFile = 0;
  108.     }
  109.     else {
  110.         // Output file required
  111.         FileOptions |= CMDL_FILE_OUTPUT;
  112.     }
  113.     if ((LibraryOptions & CMDL_LIBRARY_ADDMEMBER) && !(LibraryOptions & CMDL_LIBRARY_CONVERT)) {
  114.         // Adding library members only. Output file may have same name as input file
  115.         FileOptions |= CMDL_FILE_IN_OUT_SAME;
  116.     }
  117.     // Check output type
  118.     if (!OutputType) {
  119.         // Output type not defined yet
  120.         if (LibraryOptions & (CMDL_LIBRARY_CONVERT | CMDL_LIBRARY_ADDMEMBER)) {
  121.             OutputType = FILETYPE_LIBRARY;
  122.         }
  123.     }
  124. }
  125.  
  126.  
  127. void CCommandLineInterpreter::ReadCommandItem(char * string) {
  128.     // Read one option from command line
  129.     // Skip leading whitespace
  130.     while (*string != 0 && *string <= ' ') string++;
  131.     if (*string == 0) return;  // Empty string
  132.  
  133.     // Look for option prefix and response file prefix
  134.     const char OptionPrefix1 = '-';  // Option must begin with '-'
  135. #if defined (_WIN32) || defined (__WINDOWS__)
  136.     const char OptionPrefix2 = '/';  // '/' allowed instead of '-' in Windows only
  137. #else
  138.     const char OptionPrefix2 = '-';
  139. #endif
  140.     const char ResponseFilePrefix = '@';  // Response file name prefixed by '@'
  141.     if (*string == OptionPrefix1 || *string == OptionPrefix2) {
  142.         // Option prefix found. This is a command line option
  143.         InterpretCommandOption(string+1);
  144.     }
  145.     else if (*string == ResponseFilePrefix) {
  146.         // Response file prefix found. Read more options from response file
  147.         ReadCommandFile(string+1);
  148.     }
  149.     else {
  150.         // No prefix found. This is an input or output file name
  151.         InterpretFileName(string);
  152.     }
  153.  
  154.     int loc, last = SymbolList.GetNumEntries() - 1;
  155.     if (last > 0) {
  156.         // relocate last entry (binary insertion sort):
  157.         SSymbolChange * List = (SSymbolChange *)SymbolList.Buf();
  158.         SSymbolChange key = List[last];
  159.         SymbolBinSearch(key.Name1, last, &loc);
  160.         memmove(List + loc + 1, List + loc, (last - loc) * sizeof(SSymbolChange));
  161.         List[loc] = key;
  162.     }
  163. }
  164.  
  165.  
  166. void CCommandLineInterpreter::ReadCommandFile(char * filename) {
  167.     // Read commands from file
  168.     if (*filename <= ' ') {
  169.         err.submit(1001); return;    // Warning: empty filename
  170.     }
  171.  
  172.     // Check if too many response file buffers (possibly because file includes itself)
  173.     if (++NumBuffers > MAX_COMMAND_FILES) {err.submit(2107); return;}
  174.  
  175.     // Allocate buffer for response files.
  176.     if (ResponseFiles.GetNumEntries() == 0) {
  177.         ResponseFiles.SetNum(MAX_COMMAND_FILES);
  178.         ResponseFiles.SetZero();
  179.     }
  180.  
  181.     // Read response file into new buffer
  182.     ResponseFiles[NumBuffers-1].FileName = filename;
  183.     ResponseFiles[NumBuffers-1].Read();
  184.  
  185.     // Get buffer with file contents
  186.     char * buffer = ResponseFiles[NumBuffers-1].Buf();
  187.     char * ItemBegin, * ItemEnd;  // Mark begin and end of token in buffer
  188.  
  189.     // Check if buffer is allocated
  190.     if (buffer) {
  191.  
  192.         // Parse contents of response file for tokens
  193.         while (*buffer) {
  194.  
  195.             // Skip whitespace
  196.             while (*buffer != 0 && uint8(*buffer) <= uint8(' ')) buffer++;
  197.             if (*buffer == 0) break; // End of buffer found
  198.             ItemBegin = buffer;
  199.  
  200.             // Find end of token
  201.             ItemEnd = buffer+1;
  202.             while (uint8(*ItemEnd) > uint8(' ')) ItemEnd++;
  203.             if (*ItemEnd == 0) {
  204.                 buffer = ItemEnd;
  205.             }
  206.             else {
  207.                 buffer = ItemEnd + 1;
  208.                 *ItemEnd = 0;    // Mark end of token
  209.             }
  210.             // Found token.
  211.             // Check if it is a comment beginning with '#' or '//'
  212.             if (ItemBegin[0] == '#' || (ItemBegin[0] == '/' && ItemBegin[1] == '/' )) {
  213.                 // This is a comment. Skip to end of line
  214.                 ItemEnd = buffer;
  215.                 while (*ItemEnd != 0 && *ItemEnd != '\n') {
  216.                     ItemEnd++;
  217.                 }
  218.                 if (*ItemEnd == 0) {
  219.                     buffer = ItemEnd;
  220.                 }
  221.                 else {
  222.                     buffer = ItemEnd + 1;
  223.                 }
  224.                 continue;
  225.             }
  226.             // Not a comment. Interpret token
  227.             ReadCommandItem(ItemBegin);
  228.         }
  229.     }
  230. }
  231.  
  232.  
  233. void CCommandLineInterpreter::InterpretFileName(char * string) {
  234.     // Interpret input or output filename from command line
  235.  
  236.     switch (libmode) {
  237.     case 1:            // First filename after -lib = inputfile and outputfile
  238.         InputFile = string;
  239.         libmode = 2;
  240.         return;
  241.  
  242.     case 2:            // Second or later filename after -lib = object file to add to library
  243.         AddObjectToLibrary(string, string);
  244.         return;
  245.     }
  246.     // libmode = 0: Ordinary input or output file
  247.  
  248.     if (!InputFile) {
  249.         // Input file not specified yet
  250.         InputFile = string;
  251.     }
  252.     else if (!OutputFile) {
  253.         // Output file not specified yet
  254.         OutputFile = string;
  255.     }
  256.     else {
  257.         // Both input and output files already specified
  258.         err.submit(2001);
  259.     }
  260. }
  261.  
  262.  
  263. void CCommandLineInterpreter::InterpretCommandOption(char * string) {
  264.     // Interpret one option from command line
  265.     if (*string <= ' ') {
  266.         err.submit(1001); return;    // Warning: empty option
  267.     }
  268.  
  269.     // Detect option type
  270.     switch(string[0]) {
  271.     case 'f': case 'F':   // output file format
  272.         if (string[1] == 'd') {
  273.             // -fd == deprecated dump option
  274.             InterpretDumpOption(string+2);  break;
  275.         }
  276.         InterpretOutputTypeOption(string+1);  break;
  277.  
  278.     case 'v': case 'V':   // verbose/silent
  279.         InterpretVerboseOption(string+1);  break;
  280.  
  281.     case 'd': case 'D':   // dump option
  282.         InterpretDumpOption(string+1);  break;
  283.         // Debug info option
  284.         //InterpretDebugInfoOption(string+1);  break;
  285.  
  286.     case 'x': case 'X':   // Exception handler info option
  287.         InterpretExceptionInfoOption(string+1);  break;
  288.  
  289.     case 'h': case 'H': case '?':  // Help
  290.         ShowHelp = 1;  break;
  291.  
  292.     case 'e': case 'E':   // Error option
  293.     case 'w': case 'W':   // Warning option
  294.         InterpretErrorOption(string);  break;
  295.  
  296.     case 'n': case 'N':   // Symbol name change option
  297.     case 'a': case 'A':   // Symbol name alias option
  298.         InterpretSymbolNameChangeOption(string);  break;
  299.  
  300.     case 'i': case 'I':   // Imagebase
  301.         if ((string[1] | 0x20) == 'm') {
  302.             InterpretImagebaseOption(string);
  303.         }
  304.         break;
  305.  
  306.     case 'l': case 'L':   // Library option
  307.         InterpretLibraryOption(string);  break;
  308.  
  309.     case 'c':  // Count instruction codes supported
  310.         // This is an easter egg: You can only get it if you know it's there
  311.         if (strncmp(string,"countinstructions", 17) == 0) {
  312.             CDisassembler::CountInstructions();
  313.             exit(0);
  314.         }
  315.  
  316.     default:    // Unknown option
  317.         err.submit(1002, string);
  318.     }
  319. }
  320.  
  321.  
  322. void CCommandLineInterpreter::InterpretLibraryOption(char * string) {
  323.     // Interpret options for manipulating library/archive files
  324.  
  325.     // Check for -lib command
  326.     if (stricmp(string, "lib") == 0) {  // Found -lib command
  327.         if (InputFile) {
  328.             libmode = 2;                  // Input file already specified. Remaining file names are object files to add
  329.         }
  330.         else {
  331.             libmode = 1;                  // The rest of the command line must be interpreted as library name and object file names
  332.         }
  333.         return;
  334.     }
  335.  
  336.     SSymbolChange sym = {0,0,0,0};      // Symbol change record
  337.     int i;                              // Loop counter
  338.  
  339.     // Check for member name and optional new name in this command
  340.     char * name1 = 0, * name2 = 0, separator;
  341.     if ((string[2] == ':' || string[2] == '|') && string[3]) {
  342.         // name1 found
  343.         separator = string[2];
  344.         name1 = string+3;
  345.         // Search for second separator or end
  346.         name2 = name1 + 1;
  347.         while (name2[0] != 0) {
  348.             if (name2[0] == separator) {
  349.                 *name2 = 0;  // Mark end of name1
  350.                 if (name2[1]) {
  351.                     // name2 found
  352.                     name2++;     // Name2 starts here
  353.                     break;
  354.                 }
  355.             }
  356.             name2++;
  357.         }
  358.         if (name2 == 0 || name2[0] == 0 || name2[0] == separator) {
  359.             // name 2 is blank
  360.             //name2 = name1;
  361.             name2 = 0;
  362.         }
  363.         else {
  364.             // Check if name2 ends with separator
  365.             for (i = 0; i < (int)strlen(name2); i++) {
  366.                 if (name2[i] == separator) name2[i] = 0;
  367.             }
  368.         }
  369.     }
  370.     // Check for duplicate name
  371.     if (SymbolIsInList(name1)) {
  372.         // This symbol is already in list
  373.         err.submit(2017, name1);
  374.         return;
  375.     }
  376.  
  377.     sym.Name1 = name1;     // Store names in symbol change record
  378.     sym.Name2 = name2;    
  379.  
  380.     switch (string[1]) {
  381.     case 'a': case 'A':      // Add input file to library
  382.         if (name1) {
  383.             AddObjectToLibrary(name1, name2);
  384.         }
  385.         else err.submit(2004, string);
  386.         break;
  387.  
  388.     case 'x': case 'X':      // Extract member(s) from library
  389.         if (name1) {
  390.             // Extract specified member
  391.             cmd.LibraryOptions = CMDL_LIBRARY_EXTRACTMEM;
  392.             sym.Action  = SYMA_EXTRACT_MEMBER;
  393.             SymbolList.Push(&sym, sizeof(sym));
  394.         }
  395.         else {
  396.             // Extract all members
  397.             cmd.LibraryOptions = CMDL_LIBRARY_EXTRACTALL;
  398.         }
  399.         break;
  400.  
  401.     case 'd': case 'D':  // Delete member from library
  402.         if (name1) {
  403.             // Delete specified member
  404.             cmd.LibraryOptions = CMDL_LIBRARY_CONVERT;
  405.             sym.Action  = SYMA_DELETE_MEMBER;
  406.             SymbolList.Push(&sym, sizeof(sym));
  407.         }
  408.         else err.submit(2004, string);
  409.         break;
  410.  
  411.     case 's': case 'S':  // Use short member names for compatibility
  412.         cmd.LibrarySubtype = LIBTYPE_SHORTNAMES;
  413.         break;
  414.  
  415.     default:
  416.         err.submit(2004, string);  // Unknown option
  417.     }
  418. }
  419.  
  420.  
  421. void CCommandLineInterpreter::AddObjectToLibrary(char * filename, char * membername) {
  422.     // Add object file to library
  423.     if (!filename || !*filename) {          
  424.         err.submit(2004, filename-1);  return;     // Empty string
  425.     }
  426.  
  427.     if (!membername || !*membername) membername = filename;
  428.  
  429.     SSymbolChange Sym = {0,0,0,0};                // Symbol change record
  430.  
  431.     Sym.Name2 = filename;                         // Object file name
  432.  
  433.     if (!MemberNamesAllocated) {
  434.         // Allocate space for truncated member names
  435.         const int SafetySpace = 1024;
  436.  
  437.         // Get size of response files
  438.         if (ResponseFiles.GetNumEntries()) {
  439.             MemberNamesAllocated = ResponseFiles[0].GetDataSize() + ResponseFiles[1].GetDataSize();
  440.         }
  441.         // Allocate this size + SafetySpace
  442.         MemberNames.SetSize(MemberNamesAllocated + SafetySpace);
  443.  
  444.         // Remember allocated buffer size
  445.         MemberNamesAllocated = MemberNames.GetBufferSize();
  446.     }
  447.  
  448.     // Truncate name and store it in MemberNames
  449.     //uint32 Name1Offset = MemberNames.PushString(CLibrary::TruncateMemberName(membername));
  450.     uint32 Name1Offset = MemberNames.PushString(membername);  
  451.     Sym.Name1 = (char*)(MemberNames.Buf() + Name1Offset);
  452.     CLibrary::StripMemberName(Sym.Name1);
  453.  
  454.     // Note: Sym.Name1 points to allocated memory in violation of good programming practice.
  455.     // Check that it is not reallocated:
  456.     if (MemberNames.GetBufferSize() != MemberNamesAllocated) {
  457.         err.submit(2506); // Cannot reallocate MemberNames because we have pointers to in in SymbolList
  458.         return;
  459.     }
  460.  
  461.     // Check for duplicate name
  462.     if (SymbolIsInList(Sym.Name1)) {
  463.         // This symbol is already in list
  464.         err.submit(2017, Sym.Name1);
  465.         return;
  466.     }
  467.  
  468.     // Store options
  469.     cmd.LibraryOptions |= CMDL_LIBRARY_ADDMEMBER;
  470.     Sym.Action  = SYMA_ADD_MEMBER;
  471.  
  472.     // Store SYMA_ADD_MEMBER record in symbol list
  473.     SymbolList.Push(&Sym, sizeof(Sym));
  474. }
  475.  
  476.  
  477. void CCommandLineInterpreter::InterpretOutputTypeOption(char * string) {
  478.     // Interpret output file format option from command line
  479.  
  480.     int opt;
  481.     for (opt = 0; opt < TableSize(TypeOptionNames); opt++) {
  482.         int len = (int)strlen(TypeOptionNames[opt].b);
  483.         if (strncmp(string, TypeOptionNames[opt].b, len) == 0) {
  484.             // Match found
  485.             if (OutputType)  err.submit(2003, string);  // More than one output type specified
  486.             if (DumpOptions) err.submit(2007);          // Both dump and convert specified
  487.  
  488.             // Save desired output type
  489.             OutputType = TypeOptionNames[opt].a;
  490.  
  491.             // Check if name is followed by a word size
  492.             int wordsize = 0;
  493.             if (string[len]) wordsize = atoi(string+len);
  494.             switch (wordsize) {
  495.             case 0:  // No word size specified
  496.                 break;
  497.  
  498.             case 32: case 64:  // Valid word size
  499.                 DesiredWordSize = wordsize;
  500.                 break;
  501.  
  502.             default:  // Illegal word size
  503.                 err.submit(2002, wordsize);
  504.             }
  505.             break;   // Finished searching
  506.         }
  507.     }
  508.  
  509.     // Check if found
  510.     if (opt >= TableSize(TypeOptionNames)) err.submit(2004, string-1);
  511.  
  512.     if (OutputType == CMDL_OUTPUT_MASM) {
  513.         // Get subtype
  514.         for (opt = 0; opt < TableSize(SubtypeNames); opt++) {
  515.             int len = (int)strlen(SubtypeNames[opt].b);
  516.             if (strncmp(string, SubtypeNames[opt].b, len) == 0) {
  517.                 // Match found
  518.                 SubType = SubtypeNames[opt].a;  break;
  519.             }
  520.         }
  521.     }
  522. }
  523.  
  524.  
  525. void CCommandLineInterpreter::InterpretVerboseOption(char * string) {
  526.     // Interpret silent/verbose option from command line
  527.     Verbose = atoi(string);
  528. }
  529.  
  530.  
  531. void CCommandLineInterpreter::InterpretDumpOption(char * string) {
  532.     // Interpret dump option from command line
  533.     if (OutputType || DumpOptions) err.submit(2007);          // Both dump and convert specified
  534.  
  535.     char * s1 = string;
  536.     while (*s1) {
  537.         switch (*(s1++)) {
  538.         case 'f': case 'F':  // dump file header
  539.             DumpOptions |= DUMP_FILEHDR;  break;
  540.         case 'h': case 'H':  // dump section headers
  541.             DumpOptions |= DUMP_SECTHDR;  break;
  542.         case 's': case 'S':  // dump symbol table
  543.             DumpOptions |= DUMP_SYMTAB;  break;
  544.         case 'r': case 'R':  // dump relocations
  545.             DumpOptions |= DUMP_RELTAB;  break;
  546.         case 'n': case 'N':  // dump string table
  547.             DumpOptions |= DUMP_STRINGTB;  break;
  548.         case 'c': case 'C':  // dump comment records (currently only for OMF)
  549.             DumpOptions |= DUMP_COMMENT;  break;        
  550.         default:
  551.             err.submit(2004, string-1);  // Unknown option
  552.         }
  553.     }
  554.     if (DumpOptions == 0) DumpOptions = DUMP_FILEHDR;
  555.     OutputType = CMDL_OUTPUT_DUMP;
  556.     if (OutputType && OutputType != CMDL_OUTPUT_DUMP) err.submit(2007); // Both dump and convert specified
  557.     OutputType = CMDL_OUTPUT_DUMP;
  558. }
  559.  
  560.  
  561. void CCommandLineInterpreter::InterpretDebugInfoOption(char * string) {
  562.     // Interpret debug info option from command line
  563.     if (strlen(string) > 1) err.submit(2004, string-1);  // Unknown option
  564.     switch (*string) {
  565.     case 's': case 'S': case 'r': case 'R':  // Strip (remove)
  566.         DebugInfo = CMDL_DEBUG_STRIP;  break;
  567.     case 'p': case 'P':                      // Preserve
  568.         DebugInfo = CMDL_DEBUG_PRESERVE;  break;
  569.     case 'l': case 'L':                      // (Not supported)
  570.         DebugInfo = CMDL_DEBUG_LINNUM;  break;
  571.     case 'c': case 'C':                      // (Not supported)
  572.         DebugInfo = CMDL_DEBUG_SYMBOLS;  break;
  573.     default:
  574.         err.submit(2004, string-1);  // Unknown option
  575.     }
  576. }
  577.  
  578.  
  579. void CCommandLineInterpreter::InterpretExceptionInfoOption(char * string) {
  580.     // Interpret exception handler info option from command line
  581.     if (strlen(string) > 1) err.submit(2004, string-1);  // Unknown option
  582.     switch (*string) {
  583.     case 's': case 'S': case 'r': case 'R':  // Strip (remove)
  584.         ExeptionInfo = CMDL_EXCEPTION_STRIP;  break;
  585.     case 'p': case 'P':                      // Preserve
  586.         ExeptionInfo = CMDL_EXCEPTION_PRESERVE;  break;
  587.     default:
  588.         err.submit(2004, string-1);  // Unknown option
  589.     }
  590. }
  591.  
  592.  
  593. void CCommandLineInterpreter::InterpretErrorOption(char * string) {
  594.     // Interpret warning/error option from command line
  595.     if (strlen(string) < 3) {
  596.         err.submit(2004, string); return; // Unknown option
  597.     }
  598.     int newstatus;   // New status for this error number
  599.  
  600.     switch (string[1]) {
  601.     case 'd': case 'D':  // Disable
  602.         newstatus = 0;  break;
  603.  
  604.     case 'w': case 'W':  // Treat as warning
  605.         newstatus = 1;  break;
  606.  
  607.     case 'e': case 'E':  // Treat as error
  608.         newstatus = 2;  break;
  609.  
  610.     default:
  611.         err.submit(2004, string);  // Unknown option
  612.         return;
  613.     }
  614.     if (string[2] == 'x' || string[2] == 'X') {
  615.         // Apply new status to all non-fatal messages
  616.         for (SErrorText * ep = ErrorTexts; ep->Status < 9; ep++) {
  617.             ep->Status = newstatus;  // Change status of all errors
  618.         }
  619.     }
  620.     else {
  621.         int ErrNum = atoi(string+2);
  622.         if (ErrNum == 0 && string[2] != '0') {
  623.             err.submit(2004, string);  return; // Unknown option
  624.         }
  625.         // Search for this error number
  626.         SErrorText * ep = err.FindError(ErrNum);
  627.         if (ep->Status & 0x100) {
  628.             // Error number not found
  629.             err.submit(1003, ErrNum);  return; // Unknown error number
  630.         }
  631.         // Change status of this error
  632.         ep->Status = newstatus;
  633.     }
  634. }
  635.  
  636. void CCommandLineInterpreter::InterpretSymbolNameChangeOption(char * string) {
  637.     // Interpret various options for changing symbol names
  638.     SSymbolChange sym = {0,0,0,0};   // Symbol change record
  639.     string[0] |= 0x20;  // change first letter to lower case
  640.  
  641.     // Check for symbol names in this command
  642.     char * name1 = 0, * name2 = 0;
  643.     if (string[2] == ':' && string[3]) {
  644.         // name1 found
  645.         name1 = string+3;
  646.         // Search for second ':' or end
  647.         name2 = name1 + 1;
  648.         while (name2[0] != 0) {
  649.             if (name2[0] == ':') {
  650.                 *name2 = 0;  // Mark end of name1
  651.                 if (name2[1]) {
  652.                     // name2 found
  653.                     name2++;     // Name2 starts here
  654.                     break;
  655.                 }
  656.             }
  657.             name2++;
  658.         }
  659.         if (name2 && name2[0]) {
  660.             // name2 found. check if it ends with ':'
  661.             for (uint32 i = 0; i < (uint32)strlen(name2); i++) {
  662.                 if (name2[i] == ':') name2[i] = 0;
  663.             }
  664.         }
  665.         if (name2[0] == 0) name2 = 0;
  666.     }
  667.     // Check for duplicate name
  668.     if (name1 && SymbolIsInList(name1)) {
  669.         // This symbol is already in list
  670.         err.submit(2015, name1);
  671.         return;
  672.     }
  673.  
  674.     switch (string[1]) {
  675.     case 'u': case 'U':  // underscore option
  676.         switch (string[2]) {
  677.         case 0:
  678.             Underscore = CMDL_UNDERSCORE_CHANGE;
  679.             if (string[0] == 'a') Underscore |= CMDL_KEEP_ALIAS;
  680.             break;
  681.         case '+': case 'a': case 'A':
  682.             Underscore = CMDL_UNDERSCORE_ADD;
  683.             if (string[0] == 'a') Underscore |= CMDL_KEEP_ALIAS;
  684.             break;
  685.         case '-': case 'r': case 'R':
  686.             Underscore = CMDL_UNDERSCORE_REMOVE;
  687.             if (string[0] == 'a') Underscore |= CMDL_KEEP_ALIAS;
  688.             break;
  689.         default:
  690.             err.submit(2004, string);  // Unknown option
  691.         }
  692.         break;
  693.  
  694.     case 'd': case 'D':  // section name dot option
  695.         SegmentDot = CMDL_SECTIONDOT_CHANGE;
  696.         break;
  697.  
  698.     case 'r': case 'R':  // name replace option
  699.         if (name1 == 0 || name2 == 0 || *name1 == 0 || *name2 == 0) {
  700.             err.submit(2008, string); return;
  701.         }
  702.         sym.Name1 = name1;
  703.         sym.Name2 = name2;
  704.         sym.Action  = SYMA_CHANGE_NAME;
  705.         if (string[0] == 'a') sym.Action |= SYMA_ALIAS;
  706.         SymbolList.Push(&sym, sizeof(sym));  SymbolChangeEntries++;
  707.         break;
  708.  
  709.     case 'p': case 'P':  // prefix replace option
  710.         if (name1 == 0 || *name1 == 0) {
  711.             err.submit(2008, string); return;
  712.         }
  713.         if (name2 == 0) name2 = (char*)"";
  714.         sym.Name1 = name1;
  715.         sym.Name2 = name2;
  716.         sym.Action  = SYMA_CHANGE_PREFIX;
  717.         if (string[0] == 'a') sym.Action |= SYMA_ALIAS;
  718.         PrefixSuffixList.Push(&sym, sizeof(sym));  SymbolChangeEntries++;
  719.         break;
  720.  
  721.     case 's': case 'S':  // suffix replace option
  722.         if (name1 == 0 || *name1 == 0) {
  723.             err.submit(2008, string); return;
  724.         }
  725.         if (name2 == 0) name2 = (char*)"";
  726.         sym.Name1 = name1;
  727.         sym.Name2 = name2;
  728.         sym.Action  = SYMA_CHANGE_SUFFIX;
  729.         if (string[0] == 'a') sym.Action |= SYMA_ALIAS;
  730.         PrefixSuffixList.Push(&sym, sizeof(sym));  SymbolChangeEntries++;
  731.         break;
  732.  
  733.     case 'w': case 'W':  // Weaken symbol
  734.         if (name1 == 0 || *name1 == 0 || name2) {
  735.             err.submit(2009, string); return;
  736.         }
  737.         sym.Name1 = name1;
  738.         sym.Action  = SYMA_MAKE_WEAK;
  739.         SymbolList.Push(&sym, sizeof(sym));  SymbolChangeEntries++;
  740.         break;
  741.  
  742.     case 'l': case 'L':  // Make symbol local or hidden
  743.         if (name1 == 0 || *name1 == 0 || name2) {
  744.             err.submit(2009, string); return;
  745.         }
  746.         sym.Name1 = name1;
  747.         sym.Action  = SYMA_MAKE_LOCAL;
  748.         SymbolList.Push(&sym, sizeof(sym));  SymbolChangeEntries++;
  749.         break;
  750.  
  751.     default:
  752.         err.submit(2004, string);  // Unknown option
  753.     }
  754. }
  755.  
  756. void CCommandLineInterpreter::InterpretImagebaseOption(char * string) {
  757.     // Interpret image base option
  758.     char * p = strchr(string, '=');
  759.     if ((strnicmp(string, "imagebase", 9) && strnicmp(string, "image_base", 10)) || !p) {
  760.         // Unknown option
  761.         err.submit(1002, string);
  762.         return;
  763.     }
  764.     if (ImageBase) err.submit(2330); // Imagebase specified more than once
  765.  
  766.     p++;  // point to number following '='
  767.     // Loop through string to interpret hexadecimal number
  768.     while (*p) {
  769.         char letter = *p | 0x20; // lower case letter
  770.         if (*p >= '0' && *p <= '9') {
  771.             // 0 - 9 hexadecimal digit
  772.             ImageBase = (ImageBase << 4) + *p - '0';
  773.         }
  774.         else if (letter >= 'a' && letter <= 'f') {
  775.             // A - F hexadecimal digit
  776.             ImageBase = (ImageBase << 4) + letter - 'a' + 10;
  777.         }
  778.         else if (letter == 'h') {
  779.             // Hexadecimal number may end with 'H'
  780.             break;
  781.         }
  782.         else if (letter == 'x' || letter == ' ') {
  783.             // Hexadecimal number may begin with 0x
  784.             if (ImageBase) {
  785.                 // 'x' preceded by number other than 0
  786.                 err.submit(1002, string); break;
  787.             }
  788.         }
  789.         else {
  790.             // Any other character not allowed
  791.             err.submit(1002, string); break;
  792.         }
  793.         // next character
  794.         p++;
  795.     }
  796.     if (ImageBase & 0xFFF) {
  797.         // Must be divisible by page size
  798.         err.submit(2331, string);
  799.     }
  800.     if ((int32)ImageBase <= 0) {
  801.         // Cannot be zero or > 2^31
  802.         err.submit(2332, string);
  803.     }
  804. }
  805.  
  806.  
  807. SSymbolChange const * CCommandLineInterpreter::GetMemberToAdd() {
  808.     // Get names of object files to add to library
  809.     // replaced will be set to 1 if a member with the same name is replaced
  810.  
  811.     // Search through SymbolList, continuing from last CurrentSymbol
  812.     while (CurrentSymbol < SymbolList.GetDataSize()) {
  813.         // Get pointer to current symbol record
  814.         SSymbolChange * Sym = (SSymbolChange *)(SymbolList.Buf() + CurrentSymbol);
  815.         // Increment pointer
  816.         CurrentSymbol += sizeof(SSymbolChange);
  817.         // Check record type
  818.         if (Sym->Action == SYMA_ADD_MEMBER) {
  819.             // Name found
  820.             return Sym;
  821.         }
  822.     }
  823.     // No more names found
  824.     return 0;
  825. }
  826.  
  827.  
  828. void CCommandLineInterpreter::CheckExtractSuccess() {
  829.     // Check if library members to extract were found
  830.  
  831.     // Search through SymbolList for extract records
  832.     for (uint32 i = 0; i < SymbolList.GetDataSize(); i += sizeof(SSymbolChange)) {
  833.         SSymbolChange * Sym = (SSymbolChange *)(SymbolList.Buf() + i);
  834.         if (Sym->Action == SYMA_EXTRACT_MEMBER && Sym->Done == 0) {
  835.             // Member has not been extracted
  836.             err.submit(1104, Sym->Name1);
  837.         }
  838.     }
  839. }
  840.  
  841.  
  842. void CCommandLineInterpreter::CheckSymbolModifySuccess() {
  843.     // Check if symbols to modify were found
  844.  
  845.     // Search through SymbolList for symbol change records
  846.     for (uint32 i = 0; i < SymbolList.GetDataSize(); i += sizeof(SSymbolChange)) {
  847.         SSymbolChange * Sym = (SSymbolChange *)(SymbolList.Buf() + i);
  848.         if (Sym->Action >= SYMA_MAKE_WEAK && Sym->Action < SYMA_ADD_MEMBER && Sym->Done == 0) {
  849.             // Member has not been extracted
  850.             err.submit(1106, Sym->Name1);
  851.         }
  852.         if (Sym->Action == SYMA_DELETE_MEMBER && Sym->Done == 0) {
  853.             // Member has not been extracted
  854.             err.submit(1105, Sym->Name1);
  855.         }
  856.     }
  857. }
  858.  
  859.  
  860. int CCommandLineInterpreter::SymbolIsInList(char const * name) {
  861.     // Check if name is already in symbol list
  862.     int unused;
  863.     return SymbolBinSearch(name, SymbolList.GetNumEntries(), &unused);
  864. }
  865.  
  866.  
  867. int CCommandLineInterpreter::SymbolBinSearch(char const * name, int nsym, int * location) {
  868.     SSymbolChange * List = (SSymbolChange *)SymbolList.Buf();
  869.     int lo = 0, hi = nsym - 1;
  870.     while (lo <= hi) {
  871.         int mid = (lo + hi) >> 1;
  872.         int comp = strcmp(name, List[mid].Name1);
  873.         if (!comp) {
  874.             *location = mid;
  875.             return 1;
  876.         } else if (comp < 0) {
  877.             hi = mid - 1;
  878.         } else {
  879.             lo = mid + 1;
  880.         }
  881.     }
  882.     *location = lo;
  883.     return 0;
  884. }
  885.  
  886.  
  887. int CCommandLineInterpreter::SymbolChange(char const * oldname, char const ** newname, int symtype) {
  888.     // Check if symbol has to be changed
  889.     int action = 0, i, isym;
  890.     int nsym = SymbolList.GetNumEntries();
  891.     int n_prefix_suffix = PrefixSuffixList.GetNumEntries();
  892.     if (oldname == 0) return SYMA_NOCHANGE;
  893.     if (newname) *newname = 0;
  894.  
  895.     // Convert standard names if type conversion
  896.     if (cmd.InputType != cmd.OutputType
  897.         && uint32(cmd.InputType) <= MaxType && uint32(cmd.OutputType) <= MaxType) {
  898.             if (DesiredWordSize == 32) {
  899.                 // Look for standard names to translate, 32-bit
  900.                 for (i = 0; i < NumStandardNames; i++) {
  901.                     if (strcmp(oldname, StandardNames32[i][cmd.InputType]) == 0) {
  902.                         // Match found
  903.                         *newname = StandardNames32[i][cmd.OutputType];
  904.                         CountSymbolNameChanges++;
  905.                         return SYMA_CHANGE_NAME; // Change name of symbol
  906.                     }
  907.                 }
  908.             }
  909.             else {
  910.                 // Look for standard names to translate, 64-bit
  911.                 for (i = 0; i < NumStandardNames; i++) {
  912.                     if (strcmp(oldname, StandardNames64[i][cmd.InputType]) == 0) {
  913.                         // Match found
  914.                         *newname = StandardNames64[i][cmd.OutputType];
  915.                         CountSymbolNameChanges++;
  916.                         return SYMA_CHANGE_NAME; // Change name of symbol
  917.                     }
  918.                 }
  919.             }
  920.     }
  921.  
  922.     // See if there are other conversions to do
  923.     if (Underscore == 0 && SegmentDot == 0 && nsym == 0 && n_prefix_suffix == 0) return SYMA_NOCHANGE;  // Nothing to do
  924.     if (oldname == 0 || *oldname == 0) return SYMA_NOCHANGE;                    // No name
  925.  
  926.     static char NameBuffer[MAXSYMBOLLENGTH];
  927.  
  928.     // search for name in list of names specified by user on command line
  929.     SSymbolChange * psym;
  930.     int found = SymbolBinSearch(oldname, nsym, &isym);
  931.     if (found) {
  932.         psym = (SSymbolChange *)SymbolList.Buf() + isym;
  933.     } else {
  934.         // Search prefix/suffix match
  935.         psym = (SSymbolChange *)PrefixSuffixList.Buf();
  936.         for (isym = 0; isym < n_prefix_suffix; isym++, psym++) {
  937.             int n1len = (int)strlen(psym->Name1); // Length of string to search for
  938.             int onlen = (int)strlen(oldname);     // Length of string to match
  939.             if ((psym->Action&~SYMA_ALIAS) == SYMA_CHANGE_PREFIX && strncmp(oldname, psym->Name1, n1len)==0) break; // matching prefix found
  940.             if ((psym->Action&~SYMA_ALIAS) == SYMA_CHANGE_SUFFIX && strcmp(oldname+onlen-n1len, psym->Name1)==0) break; // matching suffix found
  941.         }
  942.         found = isym < n_prefix_suffix;
  943.     }
  944.  
  945.     if (found) {
  946.         // A matching name was found.
  947.         action = psym->Action;
  948.         // Whatever action is specified here is overriding any general option
  949.         // Statistics counting
  950.         switch (action & ~SYMA_ALIAS) {
  951.  
  952.         case SYMA_MAKE_WEAK: // Make public symbol weak
  953.             if (symtype == SYMT_PUBLIC) {
  954.                 CountSymbolsWeakened++;  psym->Done++;
  955.             }
  956.             else { // only public symbols can be weakened
  957.                 err.submit(1020, oldname); // cannot make weak
  958.                 action = SYMA_NOCHANGE;
  959.             }
  960.             break;
  961.  
  962.         case SYMA_MAKE_LOCAL: // Hide public or external symbol
  963.             if (symtype == SYMT_PUBLIC || symtype == SYMT_EXTERNAL) {
  964.                 CountSymbolsMadeLocal++;  psym->Done++;
  965.                 if (symtype == SYMT_EXTERNAL) err.submit(1023, oldname);
  966.             }
  967.             else { // only public and external symbols can be made local
  968.                 err.submit(1021, oldname); // cannot make local
  969.                 action = SYMA_NOCHANGE;
  970.             }
  971.             break;
  972.  
  973.         case SYMA_CHANGE_NAME: // Change name of symbol or segment or library member
  974.             CountSymbolNameChanges++;  psym->Done++;  
  975.             *newname = psym->Name2;
  976.             break;
  977.  
  978.         case SYMA_CHANGE_PREFIX: // Change beginning of symbol name
  979.             if (symtype == SYMT_PUBLIC || symtype == SYMT_EXTERNAL || symtype == SYMT_LOCAL || symtype == SYMT_SECTION) {
  980.                 if (strlen(oldname) - strlen(psym->Name1) + strlen(psym->Name2) >= MAXSYMBOLLENGTH) {
  981.                     err.submit(2202, oldname);  // Name too long
  982.                     action = SYMA_NOCHANGE;  break;
  983.                 }
  984.                 strcpy(NameBuffer, psym->Name2);
  985.                 strcpy(NameBuffer + strlen(psym->Name2), oldname + strlen(psym->Name1));
  986.                 action = SYMA_CHANGE_NAME;
  987.                 *newname = NameBuffer;
  988.                 CountSymbolNameChanges++;  psym->Done++;
  989.             }
  990.             else { // only symbols and segments can change prefix
  991.                 err.submit(1024, oldname);
  992.                 action = SYMA_NOCHANGE;
  993.             }
  994.             break;
  995.  
  996.         case SYMA_CHANGE_SUFFIX: // Change end of symbol name
  997.             if (symtype == SYMT_PUBLIC || symtype == SYMT_EXTERNAL || symtype == SYMT_LOCAL || symtype == SYMT_SECTION) {
  998.                 if (strlen(oldname) - strlen(psym->Name1) + strlen(psym->Name2) >= MAXSYMBOLLENGTH) {
  999.                     err.submit(2202, oldname);  // Name too long
  1000.                     action = SYMA_NOCHANGE;  break;
  1001.                 }
  1002.                 strcpy(NameBuffer, oldname);
  1003.                 strcpy(NameBuffer + strlen(oldname) - strlen(psym->Name1), psym->Name2);
  1004.                 action = SYMA_CHANGE_NAME;
  1005.                 *newname = NameBuffer;
  1006.                 CountSymbolNameChanges++;  psym->Done++;
  1007.             }
  1008.             else { // only symbols and segments can change prefix
  1009.                 err.submit(1024, oldname);
  1010.                 action = SYMA_NOCHANGE;
  1011.             }
  1012.             break;
  1013.  
  1014.         case SYMA_EXTRACT_MEMBER:
  1015.             *newname = psym->Name2;
  1016.             // continue in next case
  1017.         case SYMA_DELETE_MEMBER: case SYMA_ADD_MEMBER:
  1018.             if (symtype == SYMT_LIBRARYMEMBER) {
  1019.                 // Change to library member
  1020.                 psym->Done++;
  1021.             }
  1022.             else {
  1023.                 // Ignore action for symbols that have the same name as a library member
  1024.                 action = SYMA_NOCHANGE;
  1025.             }
  1026.         }
  1027.  
  1028.         if (action && (psym->Action & SYMA_ALIAS)) {
  1029.             // Keep old name as alias
  1030.             if (symtype == SYMT_PUBLIC) {
  1031.                 CountSymbolNameAliases++;  psym->Done++;
  1032.                 action = SYMA_ALIAS;
  1033.             }
  1034.             else { // only public symbols can have aliases
  1035.                 CountSymbolNameChanges--;
  1036.                 err.submit(1022, oldname); // cannot make alias
  1037.                 action = SYMA_NOCHANGE;
  1038.             }
  1039.         }
  1040.  
  1041.         // Action to take
  1042.         return action;
  1043.     }
  1044.  
  1045.     // Not found in list. Check for section options
  1046.     if (symtype == SYMT_SECTION) {
  1047.         if (!strncmp(oldname, ".rela", 5)) {
  1048.             // ELF relocation section must have same name change as mother section
  1049.             const char * name2;
  1050.             int action2 = SymbolChange(oldname+5, &name2, symtype);
  1051.             if (action2 == SYMA_CHANGE_NAME && strlen(name2) + 6 < MAXSYMBOLLENGTH) {
  1052.                 sprintf(NameBuffer, ".rela%s", name2);
  1053.                 *newname = NameBuffer;
  1054.                 return action2;
  1055.             }
  1056.         }
  1057.         if (!strncmp(oldname, ".rel", 4)) {
  1058.             // ELF relocation section must have same name change as mother section
  1059.             const char * name2;
  1060.             int action2 = SymbolChange(oldname+4, &name2, symtype);
  1061.             if (action2 == SYMA_CHANGE_NAME && strlen(name2) + 5 < MAXSYMBOLLENGTH) {
  1062.                 sprintf(NameBuffer, ".rel%s", name2);
  1063.                 *newname = NameBuffer;
  1064.                 return action2;
  1065.             }
  1066.         }
  1067.         if (SegmentDot) {
  1068.             // Change section name
  1069.  
  1070.             if (SegmentDot == CMDL_SECTIONDOT_U2DOT && oldname[0] == '_') {
  1071.                 // replace '_' by '.'
  1072.                 strncpy(NameBuffer, oldname, MAXSYMBOLLENGTH-1);
  1073.                 NameBuffer[MAXSYMBOLLENGTH-1] = 0;  // Terminate string
  1074.                 NameBuffer[0] = '.';
  1075.                 *newname = NameBuffer;
  1076.                 CountSectionDotConversions++;
  1077.                 return SYMA_CHANGE_NAME;
  1078.             }
  1079.             if (SegmentDot == CMDL_SECTIONDOT_DOT2U && oldname[0] == '.') {
  1080.                 // replace '.' by '_'
  1081.                 // Note: Microsoft and Intel compilers have . on standard names
  1082.                 // and _ on nonstandard names in COFF files
  1083.                 // Borland requires _ on all segment names in OMF files
  1084.                 /*
  1085.                 // Standard section names that should not be changed
  1086.                 static char const * StandardSectionNames[] = {
  1087.                 ".text", ".data", ".bss", ".comment", ".lib"
  1088.                 };
  1089.                 for (uint32 i = 0; i < sizeof(StandardSectionNames)/sizeof(StandardSectionNames[0]); i++) {
  1090.                 if (stricmp(oldname,StandardSectionNames[i]) == 0) {
  1091.                 // Standard name. Don't change
  1092.                 return SYMA_NOCHANGE;
  1093.                 }
  1094.                 }*/
  1095.                 strncpy(NameBuffer, oldname, MAXSYMBOLLENGTH-1);
  1096.                 NameBuffer[MAXSYMBOLLENGTH-1] = 0;  // Terminate string
  1097.                 NameBuffer[0] = '_';
  1098.                 *newname = NameBuffer;
  1099.                 CountSectionDotConversions++;
  1100.                 return SYMA_CHANGE_NAME;
  1101.             }
  1102.         }
  1103.     }
  1104.  
  1105.     // Check for underscore options
  1106.     if ((Underscore & 0x0F) == CMDL_UNDERSCORE_REMOVE && oldname[0] == '_') {
  1107.         // Remove underscore
  1108.         if ((Underscore & CMDL_KEEP_ALIAS) && symtype == SYMT_PUBLIC) {
  1109.             // Alias only applicable to public symbols
  1110.             // Make alias without underscore
  1111.             *newname = oldname + 1;
  1112.             CountUnderscoreConversions++;  CountSymbolNameAliases++;
  1113.             return SYMA_ALIAS;
  1114.         }
  1115.         // Change name applicable to public and external symbols
  1116.         if (symtype == SYMT_PUBLIC || symtype == SYMT_EXTERNAL) {
  1117.             // Make new name without underscore
  1118.             *newname = oldname + 1;
  1119.             CountUnderscoreConversions++;
  1120.             return SYMA_CHANGE_NAME;
  1121.         }
  1122.     }
  1123.     if ((Underscore & 0x0F) == CMDL_UNDERSCORE_ADD) {
  1124.         // Add underscore even if it already has one
  1125.         if ((Underscore & CMDL_KEEP_ALIAS) && symtype == SYMT_PUBLIC) {
  1126.             // Alias only applicable to public symbols
  1127.             // Make alias with underscore
  1128.             strncpy(NameBuffer+1, oldname, MAXSYMBOLLENGTH-2);
  1129.             NameBuffer[MAXSYMBOLLENGTH-1] = 0;  // Terminate string
  1130.             NameBuffer[0] = '_';
  1131.             *newname = NameBuffer;
  1132.             CountUnderscoreConversions++;  CountSymbolNameAliases++;
  1133.             return SYMA_ALIAS;
  1134.         }
  1135.         // Change name applicable to public and external symbols
  1136.         if (symtype == SYMT_PUBLIC || symtype == SYMT_EXTERNAL) {
  1137.             // Make new name with underscore
  1138.             strncpy(NameBuffer+1, oldname, MAXSYMBOLLENGTH-2);
  1139.             NameBuffer[MAXSYMBOLLENGTH-1] = 0;  // Terminate string
  1140.             NameBuffer[0] = '_';
  1141.             *newname = NameBuffer;
  1142.             CountUnderscoreConversions++;
  1143.             return SYMA_CHANGE_NAME;
  1144.         }
  1145.     }
  1146.     return SYMA_NOCHANGE;
  1147. }
  1148.  
  1149.  
  1150. int CCommandLineInterpreter::SymbolChangesRequested() {
  1151.     // Any kind of symbol change requested on command line
  1152.     return (Underscore != 0)
  1153.         | (SegmentDot != 0) << 1
  1154.         | (SymbolChangeEntries != 0) << 2;
  1155. }
  1156.  
  1157.  
  1158. void CCommandLineInterpreter::CountDebugRemoved() {
  1159.     // Count debug sections removed
  1160.     CountDebugSectionsRemoved++;
  1161. }
  1162.  
  1163.  
  1164. void CCommandLineInterpreter::CountExceptionRemoved() {
  1165.     // Count exception handler sections removed
  1166.     CountExceptionSectionsRemoved++;
  1167. }
  1168.  
  1169.  
  1170. void CCommandLineInterpreter::CountSymbolsHidden() {
  1171.     // Count unused external references hidden
  1172.     CountUnusedSymbolsHidden++;
  1173. }
  1174.  
  1175.  
  1176. void CCommandLineInterpreter::ReportStatistics() {
  1177.     // Report statistics about name changes etc.
  1178.     if (DebugInfo == CMDL_DEBUG_STRIP || ExeptionInfo == CMDL_EXCEPTION_STRIP
  1179.         || Underscore || SegmentDot || SymbolList.GetNumEntries()) {
  1180.             printf ("\n");
  1181.     }
  1182.     if (DebugInfo == CMDL_DEBUG_STRIP) {
  1183.         printf ("\n%3i Debug sections removed", CountDebugSectionsRemoved);
  1184.     }
  1185.     if (ExeptionInfo == CMDL_EXCEPTION_STRIP) {
  1186.         printf ("\n%3i Exception sections removed", CountExceptionSectionsRemoved);
  1187.     }
  1188.     if ((DebugInfo == CMDL_DEBUG_STRIP || ExeptionInfo == CMDL_EXCEPTION_STRIP)
  1189.         && CountUnusedSymbolsHidden) {
  1190.             printf ("\n%3i Unused external symbol references hidden", CountUnusedSymbolsHidden);
  1191.     }
  1192.  
  1193.     if (Underscore || SegmentDot || SymbolList.GetNumEntries()) {
  1194.         if (CountUnderscoreConversions || Underscore) {
  1195.             printf ("\n%3i Changes in leading underscores on symbol names", CountUnderscoreConversions);
  1196.         }
  1197.         if (CountSectionDotConversions || SegmentDot) {
  1198.             printf ("\n%3i Changes in leading characters on section names", CountSectionDotConversions);
  1199.         }
  1200.         if (CountSymbolNameChanges) {
  1201.             printf ("\n%3i Symbol names changed", CountSymbolNameChanges);
  1202.         }
  1203.         if (CountSymbolNameAliases) {
  1204.             printf ("\n%3i Public symbol names aliased", CountSymbolNameAliases);
  1205.         }
  1206.         if (CountSymbolsWeakened) {
  1207.             printf ("\n%3i Public symbol names made weak", CountSymbolsWeakened);
  1208.         }
  1209.         if (CountSymbolsMadeLocal) {
  1210.             printf ("\n%3i Public or external symbol names made local", CountSymbolsMadeLocal);
  1211.         }
  1212.         if (SymbolChangeEntries && !CountSymbolNameChanges && !CountSymbolNameAliases && !CountSymbolsWeakened && !CountSymbolsMadeLocal) {
  1213.             printf ("\n    No symbols to change were found");
  1214.         }
  1215.     }
  1216. }
  1217.  
  1218.  
  1219. void CCommandLineInterpreter::Help() {
  1220.     // Print help message
  1221.     printf("\nObject file converter version %.2f for x86 and x86-64 platforms.", OBJCONV_VERSION);
  1222.     printf("\nCopyright (c) 2018 by Agner Fog. Gnu General Public License.");
  1223.     printf("\n\nUsage: objconv options inputfile [outputfile]");
  1224.     printf("\n\nOptions:");
  1225.     printf("\n-fXXX[SS]  Output file format XXX, word size SS. Supported formats:");
  1226.     printf("\n           PE, COFF, ELF, OMF, MACHO\n");
  1227.     printf("\n-fasm      Disassemble file (-fmasm, -fnasm, -fyasm, -fgasm)\n");
  1228.     printf("\n-dXXX      Dump file contents to console.");
  1229.     printf("\n           Values of XXX (can be combined):");
  1230.     printf("\n           f: File header, h: section Headers, s: Symbol table,");
  1231.     printf("\n           r: Relocation table, n: string table.\n");
  1232.  
  1233.     printf("\n-nu        change symbol Name Underscores to the default for the target format.");
  1234.     printf("\n-nu-       remove Underscores from symbol Names.");
  1235.     printf("\n-nu+       add Underscores to symbol Names.");
  1236.     printf("\n-nd        replace Dot/underscore in section names.");
  1237.     printf("\n-nr:N1:N2  Replace symbol Name N1 with N2.");
  1238.     printf("\n-np:N1:N2  Replace symbol Prefix N1 with N2.");
  1239.     printf("\n-ns:N1:N2  Replace symbol Suffix N1 with N2.");
  1240.     printf("\n-ar:N1:N2  make Alias N2 for existing public name N1.");
  1241.     printf("\n-ap:N1:N2  Replace symbol Prefix and keep old name as alias.");
  1242.     printf("\n-as:N1:N2  Replace symbol Suffix and keep old name as alias.");
  1243.     printf("\n-nw:N1     make public symbol Name N1 Weak (ELF and MAC64 only).");
  1244.     printf("\n-nl:N1     make public symbol Name N1 Local (invisible).\n");
  1245.     //printf("\n-ds        Strip Debug info.");    // default if input and output are different formats
  1246.     //printf("\n-dp        Preserve Debug info, even if it is incompatible.");
  1247.     printf("\n-xs        Strip exception handling info and other incompatible info.");  // default if input and output are different formats. Hides unused symbols
  1248.     printf("\n-xp        Preserve exception handling info and other incompatible info.\n");
  1249.  
  1250.     printf("\n-lx        eXtract all members from Library.");
  1251.     printf("\n-lx:N1:N2  eXtract member N1 from Library to file N2.");
  1252.     printf("\n-ld:N1     Delete member N1 from Library.");
  1253.     printf("\n-la:N1:N2  Add object file N1 to Library as member N2.");
  1254.     printf("\n           Alternative: -lib LIBRARYNAME OBJECTFILENAMES.\n");
  1255.  
  1256.     printf("\n-vN        Verbose options. Values of N:");
  1257.     printf("\n           0: Silent, 1: Print file names and types, 2: Tell about conversions.");
  1258.  
  1259.     printf("\n-wdNNN     Disable Warning NNN.");
  1260.     printf("\n-weNNN     treat Warning NNN as Error. -wex: treat all warnings as errors.");
  1261.     printf("\n-edNNN     Disable Error number NNN.");
  1262.     printf("\n-ewNNN     treat Error number NNN as Warning.\n");
  1263.  
  1264.     printf("\n-h         Print this help screen.\n");
  1265.  
  1266.     printf("\n@RFILE     Read additional options from response file RFILE.\n");
  1267.     printf("\n\nExample:");
  1268.     printf("\nobjconv -felf32 -nu filename.obj filename.o\n\n");
  1269. }
  1270.