gcc -Wall lint:
[binutils-gdb.git] / binutils / objcopy.c
1 /* objcopy.c -- copy object file from input to output, optionally massaging it.
2 Copyright (C) 1991 Free Software Foundation, Inc.
3
4 This file is part of GNU Binutils.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20 #include "bfd.h"
21 #include "sysdep.h"
22 #include "bucomm.h"
23 #include <getopt.h>
24
25 asymbol **isympp = NULL; /* Input symbols */
26 asymbol **osympp = NULL; /* Output symbols that survive stripping */
27 char *input_target = NULL;
28 char *output_target = NULL;
29 char *input_filename = NULL;
30 char *output_filename = NULL;
31
32
33 static void setup_sections();
34 static void copy_sections();
35 static boolean verbose;
36
37 /* This flag distinguishes between strip and objcopy:
38 1 means this is 'strip'; 0 means this is 'objcopy'.
39 -1 means if we should use argv[0] to decide. */
40 extern int is_strip;
41
42 int show_version = 0;
43
44 enum strip_action
45 {
46 strip_undef,
47 strip_none, /* don't strip */
48 strip_debug, /* strip all debugger symbols */
49 strip_all /* strip all symbols */
50 };
51
52 /* Which symbols to remove. */
53 enum strip_action strip_symbols;
54
55 enum locals_action
56 {
57 locals_undef,
58 locals_start_L, /* discard locals starting with L */
59 locals_all /* discard all locals */
60 };
61
62 /* Which local symbols to remove. */
63 enum locals_action discard_locals;
64
65 /* Options to handle if running as "strip". */
66
67 struct option strip_options[] = {
68 {"strip-all", no_argument, 0, 's'},
69 {"strip-debug", no_argument, 0, 'S'},
70 {"discard-all", no_argument, 0, 'x'},
71 {"discard-locals", no_argument, 0, 'X'},
72 {"help", no_argument, 0, 'h'},
73 {"input-format", required_argument, 0, 'I'},
74 {"output-format", required_argument, 0, 'O'},
75 {"format", required_argument, 0, 'F'},
76 {"target", required_argument, 0, 'F'},
77
78 {"version", no_argument, 0, 'V'},
79 {"verbose", no_argument, 0, 'v'},
80 {0, no_argument, 0, 0}
81 };
82
83 /* Options to handle if running as "objcopy". */
84
85 struct option copy_options[] = {
86 {"strip-all", no_argument, 0, 'S'},
87 {"strip-debug", no_argument, 0, 'g'},
88 {"discard-all", no_argument, 0, 'x'},
89 {"discard-locals", no_argument, 0, 'X'},
90 {"help", no_argument, 0, 'h'},
91 {"input-format", required_argument, 0, 'I'},
92 {"output-format", required_argument, 0, 'O'},
93 {"format", required_argument, 0, 'F'},
94 {"target", required_argument, 0, 'F'},
95
96 {"version", no_argument, 0, 'V'},
97 {"verbose", no_argument, 0, 'v'},
98 {0, no_argument, 0, 0}
99 };
100
101 /* IMPORTS */
102 extern char *program_name;
103 extern char *program_version;
104
105
106 static
107 void
108 copy_usage(stream, status)
109 FILE *stream;
110 int status;
111 {
112 fprintf(stream, "\
113 Usage: %s [-vVSgxX] [-I format] [-O format] [-F format]\n\
114 [--format=format] [--target=format] [--input-format=format]\n\
115 [--output-format=format] [--strip-all] [--strip-debug]\n\
116 [--discard-all] [--discard-locals] [--verbose] [--version]\n\
117 [--help] in-file [out-file]\n", program_name);
118 exit(status);
119 }
120
121 static
122 void
123 strip_usage(stream, status)
124 FILE *stream;
125 int status;
126 {
127 fprintf(stream, "\
128 Usage: %s [-vVsSgxX] [-I format] [-O format] [-F format]\n\
129 [--format=format] [--target=format] [--input-format=format]\n\
130 [--output-format=format] [--strip-all] [--strip-debug] [--discard-all]\n\
131 [--discard-locals] [--verbose] [--version] [--help] file...\n",
132 program_name);
133 exit(status);
134 }
135
136
137 /* Create a temp file in the same directory as supplied */
138 static
139 char *
140 make_tempname(filename)
141 char *filename;
142 {
143 static char template[] = "stXXXXXX";
144 char *tmpname;
145 char * slash = strrchr( filename, '/' );
146 if (slash != (char *)NULL){
147 *slash = 0;
148 tmpname = xmalloc(strlen(filename) + sizeof(template) + 1 );
149 strcpy(tmpname, filename);
150 strcat(tmpname, "/" );
151 strcat(tmpname, template);
152 mktemp(tmpname );
153 *slash = '/';
154 } else {
155 tmpname = xmalloc(sizeof(template));
156 strcpy(tmpname, template);
157 mktemp(tmpname);
158 }
159 return tmpname;
160 }
161
162 /*
163 All the symbols have been read in and point to their owning input section.
164 They have been relocated to that they are all relative to the base of
165 their owning section. On the way out, all the symbols will be relocated to
166 their new location in the output file, through some complex sums.
167
168 */
169 static void
170 mangle_sections(ibfd, obfd)
171 bfd *ibfd;
172 bfd *obfd;
173 {
174 asection *current = ibfd->sections;
175 for (; current != NULL; current = current->next) {
176 current->output_section = bfd_get_section_by_name(obfd, current->name);
177 current->output_offset = 0;
178 }
179 }
180
181 /* Choose which symbol entries to copy; put the result in osyms.
182 We don't copy in place, because that confuses the relocs.
183 Return the number of symbols to be printed. */
184 static unsigned int
185 filter_symbols (abfd, osyms, isyms, symcount)
186 bfd *abfd;
187 asymbol **osyms, **isyms;
188 unsigned long symcount;
189 {
190 register asymbol **from = isyms, **to = osyms;
191 unsigned int dst_count = 0;
192 asymbol *sym;
193 char locals_prefix = bfd_get_symbol_leading_char(abfd) == '_' ? 'L' : '.';
194
195 unsigned int src_count = 0;
196 for (; src_count <symcount; src_count++) {
197 int keep = 0;
198
199 flagword flags = (from[src_count])->flags;
200 sym = from[src_count];
201 if ((flags & BSF_GLOBAL) /* Keep if external */
202 || (sym->section == &bfd_und_section)
203 || (bfd_is_com_section (sym->section)))
204 keep = 1;
205 else if ((flags & BSF_DEBUGGING) != 0) /* debugging symbol */
206 keep = strip_symbols != strip_debug;
207 else /* local symbol */
208 keep = (discard_locals != locals_all)
209 && !(discard_locals == locals_start_L &&
210 sym->name[0] == locals_prefix);
211
212
213 if (keep) {
214 to[dst_count++] = from[src_count];
215 }
216 }
217
218 return dst_count;
219 }
220
221 static void
222 copy_object(ibfd, obfd)
223 bfd *ibfd;
224 bfd *obfd;
225 {
226
227 unsigned int symcount;
228
229
230 if (!bfd_set_format(obfd, bfd_get_format(ibfd)))
231 bfd_fatal(output_filename);
232
233
234 if (verbose)
235 printf("copy from %s(%s) to %s(%s)\n",
236 ibfd->filename, ibfd->xvec->name,
237 obfd->filename, obfd->xvec->name);
238
239 if (! bfd_set_start_address (obfd, bfd_get_start_address (ibfd))
240 || ! bfd_set_file_flags (obfd,
241 (bfd_get_file_flags (ibfd)
242 & bfd_applicable_file_flags (obfd))))
243 bfd_fatal (bfd_get_filename (ibfd));
244
245 /* Copy architecture of input file to output file */
246 if (!bfd_set_arch_mach(obfd, bfd_get_arch(ibfd),
247 bfd_get_mach(ibfd))) {
248 fprintf(stderr, "Output file cannot represent architecture %s\n",
249 bfd_printable_arch_mach(bfd_get_arch(ibfd),
250 bfd_get_mach(ibfd)));
251 }
252 if (!bfd_set_format(obfd, bfd_get_format(ibfd)))
253 {
254 bfd_fatal(ibfd->filename);
255 }
256
257 if (isympp)
258 free (isympp);
259 if (osympp != isympp)
260 free (osympp);
261
262 if (strip_symbols == strip_all && discard_locals == locals_undef)
263 {
264 osympp = isympp = NULL;
265 symcount = 0;
266 }
267 else
268 {
269 osympp = isympp = (asymbol **) xmalloc(get_symtab_upper_bound(ibfd));
270 symcount = bfd_canonicalize_symtab(ibfd, isympp);
271
272 if (strip_symbols == strip_debug || discard_locals != locals_undef)
273 {
274 osympp = (asymbol **) xmalloc(symcount * sizeof(asymbol*));
275 symcount = filter_symbols (ibfd, osympp, isympp, symcount);
276 }
277 }
278
279 bfd_set_symtab(obfd, osympp, symcount);
280
281 /*
282 bfd mandates that all output sections be created and sizes set before
283 any output is done. Thus, we traverse all sections twice.
284 */
285 bfd_map_over_sections(ibfd, setup_sections, (void *) obfd);
286 bfd_map_over_sections(ibfd, copy_sections, (void *) obfd);
287 mangle_sections(ibfd, obfd);
288 }
289 static
290 char *
291 cat(a,b,c)
292 char *a;
293 char *b;
294 char *c;
295 {
296 int size = strlen(a) + strlen(b) + strlen(c);
297 char *r = xmalloc(size+1);
298 strcpy(r,a);
299 strcat(r,b);
300 strcat(r,c);
301 return r;
302 }
303
304 static void
305 copy_archive(ibfd, obfd)
306 bfd *ibfd;
307 bfd *obfd;
308 {
309 bfd **ptr = &obfd->archive_head;
310 bfd *this_element;
311 /* Read each archive element in turn from the input, copy the
312 contents to a temp file, and keep the temp file handle */
313 char *dir = cat("./#",make_tempname(""),"cd");
314
315 /* Make a temp directory to hold the contents */
316 mkdir(dir,0777);
317 obfd->has_armap = ibfd->has_armap;
318 this_element = bfd_openr_next_archived_file(ibfd, NULL);
319 ibfd->archive_head = this_element;
320 while (this_element != (bfd *)NULL) {
321
322 /* Create an output file for this member */
323 char *output_name = cat(dir, "/",this_element->filename);
324 bfd *output_bfd = bfd_openw(output_name, output_target);
325
326 if (!bfd_set_format(obfd, bfd_get_format(ibfd)))
327 bfd_fatal(output_filename);
328
329 if (output_bfd == (bfd *)NULL) {
330 bfd_fatal(output_name);
331 }
332 if (bfd_check_format(this_element, bfd_object) == true) {
333 copy_object(this_element, output_bfd);
334 }
335
336 bfd_close(output_bfd);
337 /* Now open the newly output file and attatch to our list */
338 output_bfd = bfd_openr(output_name, output_target);
339 /* Mark it for deletion */
340
341 *ptr = output_bfd;
342
343 ptr = &output_bfd->next;
344 this_element->next = bfd_openr_next_archived_file(ibfd, this_element);
345 this_element = this_element->next;
346
347 }
348 *ptr = (bfd *)NULL;
349
350 if (!bfd_close(obfd))
351 bfd_fatal(output_filename);
352
353 /* Now delete all the files that we opened.
354 Construct their names again, unfortunately, but so what;
355 we're about to exit anyway. */
356 for (this_element = ibfd->archive_head;
357 this_element != (bfd *)NULL;
358 this_element = this_element->next)
359 {
360 unlink(cat(dir,"/",this_element->filename));
361 }
362 rmdir(dir);
363 if (!bfd_close(ibfd))
364 bfd_fatal(input_filename);
365
366 }
367
368 static
369 void
370 copy_file(input_filename, output_filename)
371 char *input_filename;
372 char *output_filename;
373 {
374 bfd *ibfd;
375
376 /* To allow us to do "strip *" without dying on the first
377 non-object file, failures are nonfatal. */
378
379 ibfd = bfd_openr(input_filename, input_target);
380 if (ibfd == NULL)
381 {
382 bfd_perror(input_filename);
383 return;
384 }
385
386 if (bfd_check_format(ibfd, bfd_object)) {
387 bfd * obfd = bfd_openw(output_filename, output_target);
388 if (obfd == NULL)
389 {
390 bfd_perror(output_filename);
391 return;
392 }
393
394 copy_object(ibfd, obfd);
395
396 if (!bfd_close(obfd))
397 {
398 bfd_perror(output_filename);
399 return;
400 }
401
402 if (!bfd_close(ibfd))
403 {
404 bfd_perror(input_filename);
405 return;
406 }
407 }
408 else if (bfd_check_format(ibfd, bfd_archive)) {
409 bfd * obfd = bfd_openw(output_filename, output_target);
410 if (obfd == NULL)
411 {
412 bfd_perror(output_filename);
413 return;
414 }
415 copy_archive(ibfd, obfd);
416 }
417 else {
418 /* Get the right error message. */
419 (void) bfd_check_format (ibfd, bfd_object);
420 bfd_perror (input_filename);
421 }
422 }
423
424
425
426 /** Actually do the work */
427 static void
428 setup_sections(ibfd, isection, obfd)
429 bfd *ibfd;
430 sec_ptr isection;
431 bfd *obfd;
432 {
433 sec_ptr osection;
434 char *err;
435
436 osection = bfd_get_section_by_name(obfd, bfd_section_name(ibfd, isection));
437 if (osection == NULL) {
438 osection = bfd_make_section(obfd, bfd_section_name(ibfd, isection));
439 if (osection == NULL) {
440 err = "making";
441 goto loser;
442 }
443 }
444
445 if (!bfd_set_section_size(obfd,
446 osection,
447 bfd_section_size(ibfd, isection))) {
448 err = "size";
449 goto loser;
450 }
451
452 if (bfd_set_section_vma(obfd,
453 osection,
454 bfd_section_vma(ibfd, isection))
455 == false) {
456 err = "vma";
457 goto loser;
458 } /* on error */
459
460 if (bfd_set_section_alignment(obfd,
461 osection,
462 bfd_section_alignment(ibfd, isection))
463 == false) {
464 err = "alignment";
465 goto loser;
466 } /* on error */
467
468 if (!bfd_set_section_flags(obfd, osection,
469 bfd_get_section_flags(ibfd, isection))) {
470 err = "flags";
471 goto loser;
472 }
473
474 /* All went well */
475 return;
476
477 loser:
478 fprintf(stderr, "%s: file \"%s\", section \"%s\": error in %s: %s\n",
479 program_name,
480 bfd_get_filename(ibfd), bfd_section_name(ibfd, isection),
481 err, bfd_errmsg(bfd_error));
482 exit(1);
483 } /* setup_sections() */
484
485 /*
486 Copy all the section related data from an input section
487 to an output section
488
489 If stripping then don't copy any relocation info
490 */
491 static void
492 copy_sections(ibfd, isection, obfd)
493 bfd *ibfd;
494 sec_ptr isection;
495 bfd *obfd;
496 {
497
498 arelent **relpp;
499 int relcount;
500 sec_ptr osection;
501 bfd_size_type size;
502 osection = bfd_get_section_by_name(obfd,
503 bfd_section_name(ibfd, isection));
504
505 size = bfd_get_section_size_before_reloc(isection);
506
507 if (size == 0)
508 return;
509
510 if (strip_symbols == strip_all
511 || bfd_get_reloc_upper_bound(ibfd, isection) == 0)
512 {
513 bfd_set_reloc(obfd, osection, (arelent **)NULL, 0);
514 }
515 else
516 {
517 relpp = (arelent **) xmalloc(bfd_get_reloc_upper_bound(ibfd, isection));
518 relcount = bfd_canonicalize_reloc(ibfd, isection, relpp, isympp);
519 bfd_set_reloc(obfd, osection, relpp, relcount);
520 }
521
522 isection->_cooked_size = isection->_raw_size;
523 isection->reloc_done =true;
524
525
526 if (bfd_get_section_flags(ibfd, isection) & SEC_HAS_CONTENTS)
527 {
528 PTR memhunk = (PTR) xmalloc((unsigned)size);
529
530 if (!bfd_get_section_contents(ibfd, isection, memhunk, (file_ptr) 0, size))
531 bfd_fatal(bfd_get_filename(ibfd));
532
533 if (!bfd_set_section_contents(obfd, osection, memhunk, (file_ptr)0, size))
534 bfd_fatal(bfd_get_filename(obfd));
535 free(memhunk);
536 }
537
538
539 }
540 int
541 main(argc, argv)
542 int argc;
543 char *argv[];
544 {
545 int i;
546 int c; /* sez which option char */
547
548 program_name = argv[0];
549
550 strip_symbols = strip_undef; /* default is to strip everything. */
551 discard_locals = locals_undef;
552
553 bfd_init();
554
555 if (is_strip < 0) {
556 i = strlen (program_name);
557 is_strip = (i >= 5 && strcmp(program_name+i-5,"strip"));
558 }
559
560 if (is_strip) {
561
562 while ((c = getopt_long(argc, argv, "I:O:F:sSgxXVv",
563 strip_options, (int *) 0))
564 != EOF) {
565 switch (c) {
566 case 'I':
567 input_target = optarg;
568 case 'O':
569 output_target = optarg;
570 break;
571 case 'F':
572 input_target = output_target = optarg;
573 break;
574
575 case 's':
576 strip_symbols = strip_all;
577 break;
578 case 'S':
579 case 'g':
580 strip_symbols = strip_debug;
581 break;
582 case 'x':
583 discard_locals = locals_all;
584 break;
585 case 'X':
586 discard_locals = locals_start_L;
587 break;
588 case 'v':
589 verbose = true;
590 break;
591 case 'V':
592 show_version = true;
593 break;
594 case 0:
595 break; /* we've been given a long option */
596 case 'h':
597 strip_usage (stdout, 0);
598 default:
599 strip_usage (stderr, 1);
600 }
601 }
602
603 i = optind;
604
605 /* Default is to strip all symbols. */
606 if (strip_symbols == strip_undef && discard_locals == locals_undef)
607 strip_symbols = strip_all;
608
609 if (output_target == (char *) NULL)
610 output_target = input_target;
611
612 if (show_version) {
613 printf ("GNU %s version %s\n", program_name, program_version);
614 exit (0);
615 }
616 else if (i == argc)
617 strip_usage(stderr, 1);
618 for ( ; i < argc; i++) {
619 char *tmpname = make_tempname(argv[i]);
620 copy_file(argv[i], tmpname);
621 rename(tmpname, argv[i]);
622 }
623 return 0;
624 }
625
626 /* Invoked as "objcopy", not "strip" */
627
628 while ((c = getopt_long(argc, argv, "I:s:O:d:F:b:SgxXVv",
629 strip_options, (int *) 0))
630 != EOF) {
631 switch (c) {
632 case 'I':
633 case 's': /* "source" - 'I' is preferred */
634 input_target = optarg;
635 case 'O':
636 case 'd': /* "destination" - 'O' is preferred */
637 output_target = optarg;
638 break;
639 case 'F':
640 case 'b': /* "both" - 'F' is preferred */
641 input_target = output_target = optarg;
642 break;
643
644 case 'S':
645 strip_symbols = strip_all;
646 break;
647 case 'g':
648 strip_symbols = strip_debug;
649 break;
650 case 'x':
651 discard_locals = locals_all;
652 break;
653 case 'X':
654 discard_locals = locals_start_L;
655 break;
656 case 'v':
657 verbose = true;
658 break;
659 case 'V':
660 show_version = true;
661 break;
662 case 0:
663 break; /* we've been given a long option */
664 case 'h':
665 copy_usage (stdout, 0);
666 default:
667 copy_usage (stderr, 1);
668 }
669 }
670
671 if (show_version) {
672 printf ("GNU %s version %s\n", program_name, program_version);
673 exit (0);
674 }
675
676 if (optind == argc)
677 copy_usage(stderr, 1);
678
679 input_filename = argv[optind];
680 if (optind + 1 < argc)
681 output_filename = argv[optind+1];
682
683 /* Default is to strip no symbols. */
684 if (strip_symbols == strip_undef && discard_locals == locals_undef)
685 strip_symbols = strip_none;
686
687 if (input_filename == (char *) NULL)
688 copy_usage(stderr, 1);
689
690 if (output_target == (char *) NULL)
691 output_target = input_target;
692
693 /* If there is no destination file then create a temp and rename
694 the result into the input */
695
696 if (output_filename == (char *)NULL) {
697 char * tmpname = make_tempname(input_filename);
698 copy_file(input_filename, tmpname);
699 output_filename = input_filename;
700 rename(tmpname, input_filename);
701 }
702 else {
703 copy_file(input_filename, output_filename);
704 }
705 return 0;
706 }