blob: afd18b02bc46263d97e3846a61427bc02daa3f2a [file] [log] [blame]
Jim Cownie5e8470a2013-09-27 10:38:44 +00001/*
2 * $Revision: 42181 $
3 * $Date: 2013-03-26 15:04:45 -0500 (Tue, 26 Mar 2013) $
4 */
5
6
7//===----------------------------------------------------------------------===//
8//
9// The LLVM Compiler Infrastructure
10//
11// This file is dual licensed under the MIT and the University of Illinois Open
12// Source Licenses. See LICENSE.txt for details.
13//
14//===----------------------------------------------------------------------===//
15
16
17#include <stdlib.h>
18#include <iostream>
19#include <strstream>
20#include <fstream>
21#include <string>
22#include <set>
23#include <map>
24#include <vector>
25#include <cstring>
26
27using namespace std;
28
29typedef std::string string_t;
30typedef std::vector< string_t > strings_t;
31typedef std::map< string_t, string_t > str_hash_t;
32typedef std::pair< string_t, string_t > str_pair_t;
33#ifdef _WIN32
34 typedef long long int64_t;
35#endif
36
37string_t
38shift( strings_t & strs ) {
39 string_t first = strs.front();
40 strs.erase( strs.begin() );
41 return first;
42} // shift
43
44string_t
45find(
46 str_hash_t const & hash,
47 string_t const & key
48) {
49 string_t value;
50 str_hash_t::const_iterator it = hash.find( key );
51 if ( it != hash.end() ) {
52 value = it->second;
53 }; // if
54 return value;
55} // find
56
57void die( string_t const & message ) {
58 std::cerr << message << std::endl;
59 exit( 1 );
60} // die
61
62void stop( string_t const & message ) {
63 printf( "%s\n", message.c_str() );
64 exit( 1 );
65}
66
67// An entry in the symbol table of a .obj file.
68struct symbol_t {
69 long long name;
70 unsigned value;
71 unsigned short section_num;
72 unsigned short type;
73 char storage_class;
74 char nAux;
75}; // struct symbol_t
76
77
78class _rstream_t : public std::istrstream {
79
80 private:
81
82 const char * buf;
83
84 protected:
85
86 _rstream_t( pair< const char *, streamsize > p )
87 : istrstream( p.first, p.second ), buf( p.first )
88 {
89 }
90
91 ~_rstream_t() {
92 delete [] buf;
93 }
94
95}; // class _rstream_t
96
97/* A stream encapuslating the content of a file or the content of a string, overriding the
98 >> operator to read various integer types in binary form, as well as a symbol table
99 entry.
100*/
101class rstream_t : public _rstream_t {
102private:
103
104 template< typename type_t >
105 inline rstream_t & do_read( type_t & x ) {
106 read( (char*) & x, sizeof( type_t ) );
107 return * this;
108 }
109
110 static pair<const char*, streamsize> getBuf(const char *fileName) {
111 ifstream raw(fileName,ios::binary | ios::in);
112 if(!raw.is_open())
113 stop("rstream.getBuf: Error opening file");
114 raw.seekg(0,ios::end);
115 streampos fileSize = raw.tellg();
116 if(fileSize < 0)
117 stop("rstream.getBuf: Error reading file");
118 char *buf = new char[fileSize];
119 raw.seekg(0,ios::beg);
120 raw.read(buf, fileSize);
121 return pair<const char*, streamsize>(buf,fileSize);
122 }
123public:
124 // construct from a string
125 rstream_t( const char * buf, streamsize size ) :
126 _rstream_t( pair< const char *, streamsize >( buf, size ) )
127 {}
128 /* construct from a file whole content is fully read once to initialize the content of
129 this stream
130 */
131 rstream_t( string_t const & fileName )
132 : _rstream_t( getBuf( fileName.c_str() ) )
133 {
134 }
135
136 rstream_t & operator >>( int & x ) {
137 return do_read(x);
138 }
139 rstream_t & operator >>(unsigned &x) {
140 return do_read(x);
141 }
142 rstream_t & operator>>(short &x) {
143 return do_read(x);
144 }
145 rstream_t & operator>>(unsigned short &x) {
146 return do_read(x);
147 }
148 rstream_t & operator>>( symbol_t & e ) {
149 read((char*)&e, 18);
150 return *this;
151 }
152}; // class rstream_t
153
154// string table in a .OBJ file
155class StringTable {
156private:
157 map<string, unsigned> directory;
158 size_t length;
159 char *data;
160
161 // make <directory> from <length> bytes in <data>
162 void makeDirectory(void) {
163 unsigned i = 4;
164 while(i < length) {
165 string s = string(data + i);
166 directory.insert(make_pair(s, i));
167 i += s.size() + 1;
168 }
169 }
170 // initialize <length> and <data> with contents specified by the arguments
171 void init(const char *_data) {
172 unsigned _length = *(unsigned*)_data;
173
174 if(_length < sizeof(unsigned) || _length != *(unsigned*)_data)
175 stop("StringTable.init: Invalid symbol table");
176 if(_data[_length - 1]) {
177 // to prevent runaway strings, make sure the data ends with a zero
178 data = new char[length = _length + 1];
179 data[_length] = 0;
180 } else {
181 data = new char[length = _length];
182 }
183 *(unsigned*)data = length;
184 memcpy( data + sizeof(unsigned), _data + sizeof(unsigned), length - sizeof(unsigned) );
185 makeDirectory();
186 }
187public:
188 StringTable( rstream_t & f ) {
189 /* Construct string table by reading from f.
190 */
191 streampos s;
192 unsigned strSize;
193 char *strData;
194
195 s = f.tellg();
196 f>>strSize;
197 if(strSize < sizeof(unsigned))
198 stop("StringTable: Invalid string table");
199 strData = new char[strSize];
200 *(unsigned*)strData = strSize;
201 // read the raw data into <strData>
202 f.read(strData + sizeof(unsigned), strSize - sizeof(unsigned));
203 s = f.tellg() - s;
204 if(s < strSize)
205 stop("StringTable: Unexpected EOF");
206 init(strData);
207 delete[]strData;
208 }
209 StringTable(const set<string> &strings) {
210 /* Construct string table from given strings.
211 */
212 char *p;
213 set<string>::const_iterator it;
214 size_t s;
215
216 // count required size for data
217 for(length = sizeof(unsigned), it = strings.begin(); it != strings.end(); ++it) {
218 size_t l = (*it).size();
219
220 if(l > (unsigned) 0xFFFFFFFF)
221 stop("StringTable: String too long");
222 if(l > 8) {
223 length += l + 1;
224 if(length > (unsigned) 0xFFFFFFFF)
225 stop("StringTable: Symbol table too long");
226 }
227 }
228 data = new char[length];
229 *(unsigned*)data = length;
230 // populate data and directory
231 for(p = data + sizeof(unsigned), it = strings.begin(); it != strings.end(); ++it) {
232 const string &str = *it;
233 size_t l = str.size();
234 if(l > 8) {
235 directory.insert(make_pair(str, p - data));
236 memcpy(p, str.c_str(), l);
237 p[l] = 0;
238 p += l + 1;
239 }
240 }
241 }
242 ~StringTable() {
243 delete[] data;
244 }
245 /* Returns encoding for given string based on this string table.
246 Error if string length is greater than 8 but string is not in
247 the string table--returns 0.
248 */
249 int64_t encode(const string &str) {
250 int64_t r;
251
252 if(str.size() <= 8) {
253 // encoded directly
254 ((char*)&r)[7] = 0;
255 strncpy((char*)&r, str.c_str(), 8);
256 return r;
257 } else {
258 // represented as index into table
259 map<string,unsigned>::const_iterator it = directory.find(str);
260 if(it == directory.end())
261 stop("StringTable::encode: String now found in string table");
262 ((unsigned*)&r)[0] = 0;
263 ((unsigned*)&r)[1] = (*it).second;
264 return r;
265 }
266 }
267 /* Returns string represented by x based on this string table.
268 Error if x references an invalid position in the table--returns
269 the empty string.
270 */
271 string decode(int64_t x) const {
272 if(*(unsigned*)&x == 0) {
273 // represented as index into table
274 unsigned &p = ((unsigned*)&x)[1];
275 if(p >= length)
276 stop("StringTable::decode: Invalid string table lookup");
277 return string(data + p);
278 } else {
279 // encoded directly
280 char *p = (char*)&x;
281 int i;
282
283 for(i = 0; i < 8 && p[i]; ++i);
284 return string(p, i);
285 }
286 }
287 void write(ostream &os) {
288 os.write(data, length);
289 }
290};
291
292
293void
294obj_copy(
295 string_t const & src, // Name of source file.
296 string_t const & dst, // Name of destination file.
297 str_hash_t const & redefs // List of redefinititions.
298) {
299
300 set< string > strings; // set of all occurring symbols, appropriately prefixed
301 streampos fileSize;
302 size_t strTabStart;
303 unsigned symTabStart;
304 unsigned symNEntries;
305 int i;
306
307
308 string const error_reading = "Error reading \"" + src + "\" file: ";
309
310 rstream_t in( src );
311
312 in.seekg( 0, ios::end );
313 fileSize = in.tellg();
314
315 in.seekg( 8 );
316 in >> symTabStart >> symNEntries;
317 strTabStart = symTabStart + 18 * size_t( symNEntries );
318 in.seekg( strTabStart );
319 if ( in.eof() ) {
320 stop( error_reading + "Unexpected end of file" );
321 }
322 StringTable stringTableOld( in ); // Read original string table.
323
324 if ( in.tellg() != fileSize ) {
325 stop( error_reading + "Unexpected data after string table" );
326 }
327
328 // compute set of occurring strings with prefix added
329 for ( i = 0; i < symNEntries; ++ i ) {
330
331 symbol_t e;
332
333 in.seekg( symTabStart + i * 18 );
334 if ( in.eof() ) {
335 stop("hideSymbols: Unexpected EOF");
336 }
337 in >> e;
338 if ( in.fail() ) {
339 stop("hideSymbols: File read error");
340 }
341 if ( e.nAux ) {
342 i += e.nAux;
343 }
344 const string & s = stringTableOld.decode( e.name );
345 // if symbol is extern and found in <hide>, prefix and insert into strings,
346 // otherwise, just insert into strings without prefix
347 string_t name = find( redefs, s );
348 strings.insert( name != "" && e.storage_class == 2 ? name : s );
349 }
350
351 ofstream out( dst.c_str(), ios::trunc | ios::out | ios::binary );
352 if ( ! out.is_open() ) {
353 stop("hideSymbols: Error opening output file");
354 }
355
356 // make new string table from string set
357 StringTable stringTableNew = StringTable( strings );
358
359 // copy input file to output file up to just before the symbol table
360 in.seekg( 0 );
361 char * buf = new char[ symTabStart ];
362 in.read( buf, symTabStart );
363 out.write( buf, symTabStart );
364 delete [] buf;
365
366 // copy input symbol table to output symbol table with name translation
367 for ( i = 0; i < symNEntries; ++ i ) {
368 symbol_t e;
369
370 in.seekg( symTabStart + i * 18 );
371 if ( in.eof() ) {
372 stop("hideSymbols: Unexpected EOF");
373 }
374 in >> e;
375 if ( in.fail() ) {
376 stop("hideSymbols: File read error");
377 }
378 const string & s = stringTableOld.decode( e.name );
379 out.seekp( symTabStart + i * 18 );
380 string_t name = find( redefs, s );
381 e.name = stringTableNew.encode( ( e.storage_class == 2 && name != "" ) ? name : s );
382 out.write( (char*) & e, 18 );
383 if ( out.fail() ) {
384 stop( "hideSymbols: File write error" );
385 }
386 if ( e.nAux ) {
387 // copy auxiliary symbol table entries
388 int nAux = e.nAux;
389 for (int j = 1; j <= nAux; ++j ) {
390 in >> e;
391 out.seekp( symTabStart + ( i + j ) * 18 );
392 out.write( (char*) & e, 18 );
393 }
394 i += nAux;
395 }
396 }
397 // output string table
398 stringTableNew.write( out );
399}
400
401
402void
403split( string_t const & str, char ch, string_t & head, string_t & tail ) {
404 string_t::size_type pos = str.find( ch );
405 if ( pos == string_t::npos ) {
406 head = str;
407 tail = "";
408 } else {
409 head = str.substr( 0, pos );
410 tail = str.substr( pos + 1 );
411 }; // if
412} // split
413
414
415void help() {
416 std::cout
417 << "NAME\n"
418 << " objcopy -- copy and translate object files\n"
419 << "\n"
420 << "SYNOPSIS\n"
421 << " objcopy options... source destination\n"
422 << "\n"
423 << "OPTIONS\n"
424 << " --help Print this help and exit.\n"
425 << " --redefine-sym old=new\n"
426 << " Rename \"old\" symbol in source object file to \"new\" symbol in\n"
427 << " destination object file.\n"
428 << " --redefine-syms sym_file\n"
429 << " For each pair \"old new\" in sym_file rename \"old\" symbol in \n"
430 << " source object file to \"new\" symbol in destination object file.\n"
431 << "\n"
432 << "ARGUMENTS\n"
433 << " source The name of source object file.\n"
434 << " destination\n"
435 << " The name of destination object file.\n"
436 << "\n"
437 << "DESCRIPTION\n"
438 << " This program implements a minor bit of Linux* OS's objcopy utility on Windows* OS.\n"
439 << " It can copy object files and edit its symbol table.\n"
440 << "\n"
441 << "EXAMPLES\n"
442 << " \n"
443 << " > objcopy --redefine-sym fastcpy=__xxx_fastcpy a.obj b.obj\n"
444 << "\n";
445} // help
446
447
448int
449main( int argc, char const * argv[] ) {
450
451 strings_t args( argc - 1 );
452 str_hash_t redefs;
453 strings_t files;
454
455 std::copy( argv + 1, argv + argc, args.begin() );
456
457 while ( args.size() > 0 ) {
458 string_t arg = shift( args );
459 if ( arg.substr( 0, 2 ) == "--" ) {
460 // An option.
461 if ( 0 ) {
462 } else if ( arg == "--help" ) {
463 help();
464 return 0;
465 } else if ( arg == "--redefine-sym" ) {
466 if ( args.size() == 0 ) {
467 die( "\"" + arg + "\" option requires an argument" );
468 }; // if
469 // read list of symbol pairs "old new" from command line.
470 string_t redef = shift( args );
471 string_t old_sym;
472 string_t new_sym;
473 split( redef, '=', old_sym, new_sym );
474 if ( old_sym.length() == 0 || new_sym.length() == 0 ) {
475 die( "Illegal redefinition: \"" + redef + "\"; neither old symbol nor new symbol may be empty" );
476 }; // if
477 redefs.insert( str_pair_t( old_sym, new_sym ) );
478 } else if ( arg == "--redefine-syms" ) {
479 if ( args.size() == 0 ) {
480 die( "\"" + arg + "\" option requires an argument" );
481 }; // if
482 // read list of symbol pairs "old new" from file.
483 string_t fname = shift( args );
484 string_t redef;
485 ifstream ifs( fname.c_str() );
486 while ( ifs.good() ) {
487 getline( ifs, redef );// get pair of old/new symbols separated by space
488 string_t old_sym;
489 string_t new_sym;
490 // AC: gcount() does not work here (always return 0), so comment it
491 //if ( ifs.gcount() ) { // skip empty lines
492 split( redef, ' ', old_sym, new_sym );
493 if ( old_sym.length() == 0 || new_sym.length() == 0 ) {
494 break; // end of file reached (last empty line)
495 //die( "Illegal redefinition: \"" + redef + "\"; neither old symbol nor new symbol may be empty" );
496 }; // if
497 redefs.insert( str_pair_t( old_sym, new_sym ) );
498 //}
499 }
500 } else {
501 die( "Illegal option: \"" + arg + "\"" );
502 }; // if
503 } else {
504 // Not an option, a file name.
505 if ( files.size() >= 2 ) {
506 die( "Too many files specified; two files required (use --help option for help)" );
507 }; // if
508 files.push_back( arg );
509 }; // if
510 }; // while
511 if ( files.size() < 2 ) {
512 die( "Not enough files specified; two files required (use --help option for help)" );
513 }; // if
514
515 obj_copy( files[ 0 ], files[ 1 ], redefs );
516
517 return 0;
518
519} // main
520
521
522// end of file //