00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
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 }
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 };
00083 return value;
00084 }
00085
00086 void die( string_t const & message ) {
00087 std::cerr << message << std::endl;
00088 exit( 1 );
00089 }
00090
00091 void stop( string_t const & message ) {
00092 printf( "%s\n", message.c_str() );
00093 exit( 1 );
00094 }
00095
00096
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 };
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 };
00125
00126
00127
00128
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
00154 rstream_t( const char * buf, streamsize size ) :
00155 _rstream_t( pair< const char *, streamsize >( buf, size ) )
00156 {}
00157
00158
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 };
00182
00183
00184 class StringTable {
00185 private:
00186 map<string, unsigned> directory;
00187 size_t length;
00188 char *data;
00189
00190
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
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
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
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
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
00240
00241 char *p;
00242 set<string>::const_iterator it;
00243 size_t s;
00244
00245
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
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
00275
00276
00277
00278 int64_t encode(const string &str) {
00279 int64_t r;
00280
00281 if(str.size() <= 8) {
00282
00283 ((char*)&r)[7] = 0;
00284 strncpy((char*)&r, str.c_str(), 8);
00285 return r;
00286 } else {
00287
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
00297
00298
00299
00300 string decode(int64_t x) const {
00301 if(*(unsigned*)&x == 0) {
00302
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
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,
00325 string_t const & dst,
00326 str_hash_t const & redefs
00327 ) {
00328
00329 set< string > strings;
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 );
00352
00353 if ( in.tellg() != fileSize ) {
00354 stop( error_reading + "Unexpected data after string table" );
00355 }
00356
00357
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
00375
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
00386 StringTable stringTableNew = StringTable( strings );
00387
00388
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
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
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
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 };
00441 }
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 }
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
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 };
00498
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 };
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 };
00511
00512 string_t fname = shift( args );
00513 string_t redef;
00514 ifstream ifs( fname.c_str() );
00515 while ( ifs.good() ) {
00516 getline( ifs, redef );
00517 string_t old_sym;
00518 string_t new_sym;
00519
00520
00521 split( redef, ' ', old_sym, new_sym );
00522 if ( old_sym.length() == 0 || new_sym.length() == 0 ) {
00523 break;
00524
00525 };
00526 redefs.insert( str_pair_t( old_sym, new_sym ) );
00527
00528 }
00529 } else {
00530 die( "Illegal option: \"" + arg + "\"" );
00531 };
00532 } else {
00533
00534 if ( files.size() >= 2 ) {
00535 die( "Too many files specified; two files required (use --help option for help)" );
00536 };
00537 files.push_back( arg );
00538 };
00539 };
00540 if ( files.size() < 2 ) {
00541 die( "Not enough files specified; two files required (use --help option for help)" );
00542 };
00543
00544 obj_copy( files[ 0 ], files[ 1 ], redefs );
00545
00546 return 0;
00547
00548 }
00549
00550
00551