objcopy.cpp

Go to the documentation of this file.
00001 /*
00002  * $Revision: 42181 $
00003  * $Date: 2013-03-26 15:04:45 -0500 (Tue, 26 Mar 2013) $
00004  */
00005 
00006 /* <copyright>
00007     Copyright (c) 2006-2013 Intel Corporation.  All Rights Reserved.
00008 
00009     Redistribution and use in source and binary forms, with or without
00010     modification, are permitted provided that the following conditions
00011     are met:
00012 
00013       * Redistributions of source code must retain the above copyright
00014         notice, this list of conditions and the following disclaimer.
00015       * Redistributions in binary form must reproduce the above copyright
00016         notice, this list of conditions and the following disclaimer in the
00017         documentation and/or other materials provided with the distribution.
00018       * Neither the name of Intel Corporation nor the names of its
00019         contributors may be used to endorse or promote products derived
00020         from this software without specific prior written permission.
00021 
00022     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00023     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00024     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00025     A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00026     HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00027     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00028     LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00029     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00030     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00031     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00032     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033 
00034 
00035 ------------------------------------------------------------------------
00036 
00037     Portions of this software are protected under the following patents:
00038         U.S. Patent 5,812,852
00039         U.S. Patent 6,792,599
00040         U.S. Patent 7,069,556
00041         U.S. Patent 7,328,433
00042         U.S. Patent 7,500,242
00043 
00044 </copyright> */
00045 
00046 #include <stdlib.h>
00047 #include <iostream>
00048 #include <strstream>
00049 #include <fstream>
00050 #include <string>
00051 #include <set>
00052 #include <map>
00053 #include <vector>
00054 #include <cstring>
00055 
00056 using namespace std;
00057 
00058 typedef std::string                      string_t;
00059 typedef std::vector< string_t >          strings_t;
00060 typedef std::map< string_t, string_t >   str_hash_t;
00061 typedef std::pair< string_t, string_t >  str_pair_t;
00062 #ifdef _WIN32
00063     typedef long long  int64_t;
00064 #endif
00065 
00066 string_t
00067 shift( strings_t & strs ) {
00068     string_t first = strs.front();
00069     strs.erase( strs.begin() );
00070     return first;
00071 } // shift
00072 
00073 string_t
00074 find(
00075     str_hash_t const & hash,
00076     string_t const &   key
00077 ) {
00078     string_t value;
00079     str_hash_t::const_iterator it = hash.find( key );
00080     if ( it != hash.end() ) {
00081         value = it->second;
00082     }; // if
00083     return value;
00084 } // find
00085 
00086 void die( string_t const & message ) {
00087     std::cerr << message << std::endl;
00088     exit( 1 );
00089 } // die
00090 
00091 void stop( string_t const & message ) {
00092     printf( "%s\n", message.c_str() );
00093     exit( 1 );
00094 }
00095 
00096 // An entry in the symbol table of a .obj file.
00097 struct symbol_t {
00098     long long        name;
00099     unsigned         value;
00100     unsigned  short  section_num;
00101     unsigned  short  type;
00102     char             storage_class;
00103     char             nAux;
00104 }; // struct symbol_t
00105 
00106 
00107 class _rstream_t : public std::istrstream {
00108 
00109     private:
00110 
00111         const char * buf;
00112 
00113     protected:
00114 
00115         _rstream_t( pair< const char *, streamsize > p )
00116             : istrstream( p.first, p.second ), buf( p.first )
00117         {
00118         }
00119 
00120         ~_rstream_t() {
00121             delete [] buf;
00122         }
00123 
00124 }; // class _rstream_t
00125 
00126 /* A stream encapuslating the content of a file or the content of a string, overriding the
00127    >> operator to read various integer types in binary form, as well as a symbol table
00128    entry.
00129 */
00130 class rstream_t : public _rstream_t {
00131 private:
00132 
00133     template< typename type_t >
00134     inline rstream_t & do_read( type_t & x ) {
00135     read( (char*) & x, sizeof( type_t ) );
00136     return * this;
00137     }
00138 
00139     static pair<const char*, streamsize> getBuf(const char *fileName) {
00140     ifstream raw(fileName,ios::binary | ios::in);
00141     if(!raw.is_open())
00142         stop("rstream.getBuf: Error opening file");
00143     raw.seekg(0,ios::end);
00144     streampos fileSize = raw.tellg();
00145     if(fileSize < 0)
00146         stop("rstream.getBuf: Error reading file");
00147     char *buf = new char[fileSize];
00148     raw.seekg(0,ios::beg);
00149     raw.read(buf, fileSize);
00150     return pair<const char*, streamsize>(buf,fileSize);
00151     }
00152 public:
00153     // construct from a string
00154     rstream_t( const char * buf, streamsize size ) :
00155         _rstream_t( pair< const char *, streamsize >( buf, size ) )
00156     {}
00157     /* construct from a file whole content is fully read once to initialize the content of
00158        this stream
00159     */
00160     rstream_t( string_t const & fileName )
00161         : _rstream_t( getBuf( fileName.c_str() ) )
00162     {
00163     }
00164 
00165     rstream_t & operator >>( int & x ) {
00166     return do_read(x);
00167     }
00168     rstream_t & operator >>(unsigned &x) {
00169     return do_read(x);
00170     }
00171     rstream_t & operator>>(short &x) {
00172     return do_read(x);
00173     }
00174     rstream_t & operator>>(unsigned short &x) {
00175     return do_read(x);
00176     }
00177     rstream_t & operator>>( symbol_t & e ) {
00178     read((char*)&e, 18);
00179     return *this;
00180     }
00181 }; // class rstream_t
00182 
00183 // string table in a .OBJ file
00184 class StringTable {
00185 private:
00186     map<string, unsigned> directory;
00187     size_t length;
00188     char *data;
00189 
00190     // make <directory> from <length> bytes in <data>
00191     void makeDirectory(void) {
00192     unsigned i = 4;
00193     while(i < length) {
00194         string s = string(data + i);
00195         directory.insert(make_pair(s, i));
00196         i += s.size() + 1;
00197     }
00198     }
00199     // initialize <length> and <data> with contents specified by the arguments
00200     void init(const char *_data) {
00201     unsigned _length = *(unsigned*)_data;
00202 
00203     if(_length < sizeof(unsigned) || _length != *(unsigned*)_data)
00204         stop("StringTable.init: Invalid symbol table");
00205     if(_data[_length - 1]) {
00206         // to prevent runaway strings, make sure the data ends with a zero
00207         data = new char[length = _length + 1];
00208         data[_length] = 0;
00209     } else {
00210         data = new char[length = _length];
00211     }
00212     *(unsigned*)data = length;
00213     memcpy( data + sizeof(unsigned), _data + sizeof(unsigned), length - sizeof(unsigned) );
00214     makeDirectory();
00215     }
00216 public:
00217     StringTable( rstream_t & f ) {
00218     /* Construct string table by reading from f.
00219      */
00220     streampos s;
00221     unsigned strSize;
00222     char *strData;
00223 
00224     s = f.tellg();
00225     f>>strSize;
00226     if(strSize < sizeof(unsigned))
00227         stop("StringTable: Invalid string table");
00228     strData = new char[strSize];
00229     *(unsigned*)strData = strSize;
00230     // read the raw data into <strData>
00231     f.read(strData + sizeof(unsigned), strSize - sizeof(unsigned));
00232     s = f.tellg() - s;
00233     if(s < strSize)
00234         stop("StringTable: Unexpected EOF");
00235     init(strData);
00236     delete[]strData;
00237     }
00238     StringTable(const set<string> &strings) {
00239     /* Construct string table from given strings.
00240      */
00241     char *p;
00242     set<string>::const_iterator it;
00243     size_t s;
00244 
00245     // count required size for data
00246     for(length = sizeof(unsigned), it = strings.begin(); it != strings.end(); ++it) {
00247         size_t l = (*it).size();
00248 
00249         if(l > (unsigned) 0xFFFFFFFF)
00250         stop("StringTable: String too long");
00251         if(l > 8) {
00252         length += l + 1;
00253         if(length > (unsigned) 0xFFFFFFFF)
00254             stop("StringTable: Symbol table too long");
00255         }
00256     }
00257     data = new char[length];
00258     *(unsigned*)data = length;
00259     // populate data and directory
00260     for(p = data + sizeof(unsigned), it = strings.begin(); it != strings.end(); ++it) {
00261         const string &str = *it;
00262         size_t l = str.size();
00263         if(l > 8) {
00264         directory.insert(make_pair(str, p - data));
00265         memcpy(p, str.c_str(), l);
00266         p[l] = 0;
00267         p += l + 1;
00268         }
00269     }
00270     }
00271     ~StringTable() {
00272     delete[] data;
00273     }
00274     /* Returns encoding for given string based on this string table.
00275        Error if string length is greater than 8 but string is not in
00276        the string table--returns 0.
00277     */
00278     int64_t encode(const string &str) {
00279     int64_t r;
00280 
00281     if(str.size() <= 8) {
00282         // encoded directly
00283         ((char*)&r)[7] = 0;
00284         strncpy((char*)&r, str.c_str(), 8);
00285         return r;
00286     } else {
00287         // represented as index into table
00288         map<string,unsigned>::const_iterator it = directory.find(str);
00289         if(it == directory.end())
00290         stop("StringTable::encode: String now found in string table");
00291         ((unsigned*)&r)[0] = 0;
00292         ((unsigned*)&r)[1] = (*it).second;
00293         return r;
00294     }
00295     }
00296     /* Returns string represented by x based on this string table.
00297        Error if x references an invalid position in the table--returns
00298        the empty string.
00299     */
00300     string decode(int64_t x) const {
00301     if(*(unsigned*)&x == 0) {
00302         // represented as index into table
00303         unsigned &p = ((unsigned*)&x)[1];
00304         if(p >= length)
00305         stop("StringTable::decode: Invalid string table lookup");
00306         return string(data + p);
00307     } else {
00308         // encoded directly
00309         char *p = (char*)&x;
00310         int i;
00311 
00312         for(i = 0; i < 8 && p[i]; ++i);
00313         return string(p, i);
00314     }
00315     }
00316     void write(ostream &os) {
00317     os.write(data, length);
00318     }
00319 };
00320 
00321 
00322 void
00323 obj_copy(
00324     string_t const &    src,    // Name of source file.
00325     string_t const &    dst,    // Name of destination file.
00326     str_hash_t const &  redefs  // List of redefinititions.
00327 ) {
00328 
00329     set< string > strings; // set of all occurring symbols, appropriately prefixed
00330     streampos fileSize;
00331     size_t strTabStart;
00332     unsigned symTabStart;
00333     unsigned symNEntries;
00334     int i;
00335 
00336 
00337     string const error_reading = "Error reading \"" + src + "\" file: ";
00338 
00339     rstream_t in( src );
00340 
00341     in.seekg( 0, ios::end );
00342     fileSize = in.tellg();
00343 
00344     in.seekg( 8 );
00345     in >> symTabStart >> symNEntries;
00346     strTabStart = symTabStart + 18 * size_t( symNEntries );
00347     in.seekg( strTabStart );
00348     if ( in.eof() ) {
00349         stop( error_reading + "Unexpected end of file" );
00350     }
00351     StringTable stringTableOld( in ); // Read original string table.
00352 
00353     if ( in.tellg() != fileSize ) {
00354         stop( error_reading + "Unexpected data after string table" );
00355     }
00356 
00357     // compute set of occurring strings with prefix added
00358     for ( i = 0; i < symNEntries; ++ i ) {
00359 
00360     symbol_t e;
00361 
00362     in.seekg( symTabStart + i * 18 );
00363     if ( in.eof() ) {
00364             stop("hideSymbols: Unexpected EOF");
00365         }
00366     in >> e;
00367     if ( in.fail() ) {
00368             stop("hideSymbols: File read error");
00369         }
00370     if ( e.nAux ) {
00371             i += e.nAux;
00372         }
00373     const string & s = stringTableOld.decode( e.name );
00374     // if symbol is extern and found in <hide>, prefix and insert into strings,
00375     // otherwise, just insert into strings without prefix
00376         string_t name = find( redefs, s );
00377     strings.insert( name != "" && e.storage_class == 2 ? name : s );
00378     }
00379 
00380     ofstream out( dst.c_str(), ios::trunc | ios::out | ios::binary );
00381     if ( ! out.is_open() ) {
00382         stop("hideSymbols: Error opening output file");
00383     }
00384 
00385     // make new string table from string set
00386     StringTable stringTableNew = StringTable( strings );
00387 
00388     // copy input file to output file up to just before the symbol table
00389     in.seekg( 0 );
00390     char * buf = new char[ symTabStart ];
00391     in.read( buf, symTabStart );
00392     out.write( buf, symTabStart );
00393     delete [] buf;
00394 
00395     // copy input symbol table to output symbol table with name translation
00396     for ( i = 0; i < symNEntries; ++ i ) {
00397     symbol_t e;
00398 
00399     in.seekg( symTabStart + i * 18 );
00400     if ( in.eof() ) {
00401             stop("hideSymbols: Unexpected EOF");
00402         }
00403     in >> e;
00404     if ( in.fail() ) {
00405             stop("hideSymbols: File read error");
00406         }
00407     const string & s = stringTableOld.decode( e.name );
00408     out.seekp( symTabStart + i * 18 );
00409         string_t name = find( redefs, s );
00410     e.name = stringTableNew.encode( ( e.storage_class == 2 && name != "" ) ? name : s );
00411     out.write( (char*) & e, 18 );
00412     if ( out.fail() ) {
00413             stop( "hideSymbols: File write error" );
00414         }
00415     if ( e.nAux ) {
00416         // copy auxiliary symbol table entries
00417         int nAux = e.nAux;
00418         for (int j = 1; j <= nAux; ++j ) {
00419         in >> e;
00420         out.seekp( symTabStart + ( i + j ) * 18 );
00421         out.write( (char*) & e, 18 );
00422         }
00423         i += nAux;
00424     }
00425     }
00426     // output string table
00427     stringTableNew.write( out );
00428 }
00429 
00430 
00431 void
00432 split( string_t const & str, char ch, string_t & head, string_t & tail ) {
00433     string_t::size_type pos = str.find( ch );
00434     if ( pos == string_t::npos ) {
00435         head = str;
00436         tail = "";
00437     } else {
00438         head = str.substr( 0, pos );
00439         tail = str.substr( pos + 1 );
00440     }; // if
00441 } // split
00442 
00443 
00444 void help() {
00445     std::cout
00446         << "NAME\n"
00447         << "    objcopy -- copy and translate object files\n"
00448         << "\n"
00449         << "SYNOPSIS\n"
00450         << "    objcopy options... source destination\n"
00451         << "\n"
00452         << "OPTIONS\n"
00453         << "    --help  Print this help and exit.\n"
00454         << "    --redefine-sym old=new\n"
00455         << "            Rename \"old\" symbol in source object file to \"new\" symbol in\n"
00456         << "            destination object file.\n"
00457         << "    --redefine-syms sym_file\n"
00458         << "            For each pair \"old new\" in sym_file rename \"old\" symbol in \n"
00459         << "            source object file to \"new\" symbol in destination object file.\n"
00460         << "\n"
00461         << "ARGUMENTS\n"
00462         << "    source  The name of source object file.\n"
00463         << "    destination\n"
00464         << "            The name of destination object file.\n"
00465         << "\n"
00466         << "DESCRIPTION\n"
00467         << "    This program implements a minor bit of Linux* OS's objcopy utility on Windows* OS.\n"
00468         << "    It can copy object files and edit its symbol table.\n"
00469         << "\n"
00470         << "EXAMPLES\n"
00471         << "    \n"
00472         << "        > objcopy --redefine-sym fastcpy=__xxx_fastcpy a.obj b.obj\n"
00473         << "\n";
00474 } // help
00475 
00476 
00477 int
00478 main( int argc, char const * argv[] ) {
00479 
00480     strings_t   args( argc - 1 );
00481     str_hash_t  redefs;
00482     strings_t   files;
00483 
00484     std::copy( argv + 1, argv + argc, args.begin() );
00485 
00486     while ( args.size() > 0 ) {
00487         string_t arg = shift( args );
00488         if ( arg.substr( 0, 2 ) == "--" ) {
00489             // An option.
00490             if ( 0  ) {
00491             } else if ( arg == "--help" ) {
00492                 help();
00493                 return 0;
00494             } else if ( arg == "--redefine-sym" ) {
00495                 if ( args.size() == 0 ) {
00496                     die( "\"" + arg + "\" option requires an argument" );
00497                 }; // if
00498                 // read list of symbol pairs "old new" from command line.
00499                 string_t redef = shift( args );
00500                 string_t old_sym;
00501                 string_t new_sym;
00502                 split( redef, '=', old_sym, new_sym );
00503                 if ( old_sym.length() == 0 || new_sym.length() == 0 ) {
00504                     die( "Illegal redefinition: \"" + redef + "\"; neither old symbol nor new symbol may be empty" );
00505                 }; // if
00506                 redefs.insert( str_pair_t( old_sym, new_sym ) );
00507             } else if ( arg == "--redefine-syms" ) {
00508                 if ( args.size() == 0 ) {
00509                     die( "\"" + arg + "\" option requires an argument" );
00510                 }; // if
00511                 // read list of symbol pairs "old new" from file.
00512                 string_t fname = shift( args );
00513                 string_t redef;
00514         ifstream ifs( fname.c_str() );
00515         while ( ifs.good() ) {
00516                     getline( ifs, redef );// get pair of old/new symbols separated by space
00517                     string_t old_sym;
00518                     string_t new_sym;
00519                     // AC: gcount() does not work here (always return 0), so comment it
00520                     //if ( ifs.gcount() ) { // skip empty lines
00521                     split( redef, ' ', old_sym, new_sym );
00522                     if ( old_sym.length() == 0 || new_sym.length() == 0 ) {
00523                         break;  // end of file reached (last empty line)
00524                         //die( "Illegal redefinition: \"" + redef + "\"; neither old symbol nor new symbol may be empty" );
00525                     }; // if
00526                     redefs.insert( str_pair_t( old_sym, new_sym ) );
00527                     //}
00528         }
00529             } else {
00530                 die( "Illegal option: \"" + arg + "\"" );
00531             }; // if
00532         } else {
00533             // Not an option, a file name.
00534             if ( files.size() >= 2 ) {
00535                 die( "Too many files specified; two files required (use --help option for help)" );
00536             }; // if
00537             files.push_back( arg );
00538         }; // if
00539     }; // while
00540     if ( files.size() < 2 ) {
00541         die( "Not enough files specified; two files required (use --help option for help)" );
00542     }; // if
00543 
00544     obj_copy( files[ 0 ], files[ 1 ], redefs );
00545 
00546     return 0;
00547 
00548 } // main
00549 
00550 
00551 // end of file //

Generated on 25 Aug 2013 for libomp_oss by  doxygen 1.6.1