]> Git Repo - binutils.git/blob - binutils/objcopy.c
gcc -Wall lint:
[binutils.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 }
This page took 0.062462 seconds and 4 git commands to generate.