1 /* copy.c -- copy object file from input to output, optionally massaging it.
2 Copyright (C) 1991 Free Software Foundation, Inc.
4 This file is part of GNU Binutils.
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.
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.
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. */
26 char *input_target
= NULL
;
27 char *output_target
= NULL
;
28 char *input_filename
= NULL
;
29 char *output_filename
= NULL
;
32 static void setup_sections();
33 static void copy_sections();
34 static boolean verbose
;
36 /* This flag distinguishes between strip and copy:
37 1 means this is 'strip'; 0 means this is 'copy'.
38 -1 means if we should use argv[0] to decide. */
46 strip_none
, /* don't strip */
47 strip_debug
, /* strip all debugger symbols */
48 strip_all
/* strip all symbols */
51 /* Which symbols to remove. */
52 enum strip_action strip_symbols
;
57 locals_start_L
, /* discard locals starting with L */
58 locals_all
/* discard all locals */
61 /* Which local symbols to remove. */
62 enum locals_action discard_locals
;
64 /* Options to handle if running as "strip". */
66 struct option strip_options
[] = {
67 {"strip-all", no_argument
, 0, 's'},
68 {"strip-debug", no_argument
, 0, 'S'},
69 {"discard-all", no_argument
, 0, 'x'},
70 {"discard-locals", no_argument
, 0, 'X'},
71 {"input-format", required_argument
, 0, 'I'},
72 {"output-format", required_argument
, 0, 'O'},
73 {"format", required_argument
, 0, 'F'},
74 {"target", required_argument
, 0, 'F'},
76 {"version", no_argument
, 0, 'V'},
77 {"verbose", no_argument
, 0, 'v'},
78 {0, no_argument
, 0, 0}
81 /* Options to handle if running as "copy". */
83 struct option copy_options
[] = {
84 {"strip-all", no_argument
, 0, 'S'},
85 {"strip-debug", no_argument
, 0, 'g'},
86 {"discard-all", no_argument
, 0, 'x'},
87 {"discard-locals", no_argument
, 0, 'X'},
88 {"input-format", required_argument
, 0, 'I'},
89 {"output-format", required_argument
, 0, 'O'},
90 {"format", required_argument
, 0, 'F'},
91 {"target", required_argument
, 0, 'F'},
93 {"version", no_argument
, 0, 'V'},
94 {"verbose", no_argument
, 0, 'v'},
95 {0, no_argument
, 0, 0}
99 extern char *program_name
;
100 extern char *program_version
;
107 fprintf(stderr
, "copy %s\n\
108 Usage: %s [-vVSgxX] [-I format] [-O format] [-F format]\n\
109 [--format=format] [--target=format] [--input-format=format]\n\
110 [--output-format=format] [--strip-all] [--strip-debug]\n\
111 [--discard-all] [--discard-locals] [--verbose] [--version]\n\
113 program_version
, program_name
);
121 fprintf(stderr
, "strip %s\n\
122 Usage: %s [-vVsSgxX] [-I format] [-O format] [-F format]\n\
123 [--format=format] [--target=format] [--input-format=format]\n\
124 [--output-format=format] [--strip-all] [--strip-debug]\n\
125 [--discard-all] [--discard-locals] [--verbose] [--version] file...\n",
126 program_version
, program_name
);
131 /* Create a temp file in the same directory as supplied */
134 make_tempname(filename
)
137 static char template[] = "stXXXXXX";
139 char * slash
= strrchr( filename
, '/' );
140 if (slash
!= (char *)NULL
){
142 tmpname
= xmalloc(strlen(filename
) + sizeof(template) + 1 );
143 strcpy(tmpname
, filename
);
144 strcat(tmpname
, "/" );
145 strcat(tmpname
, template);
149 tmpname
= xmalloc(sizeof(template));
150 strcpy(tmpname
, template);
157 All the symbols have been read in and point to their owning input section.
158 They have been relocated to that they are all relative to the base of
159 their owning section. On the way out, all the symbols will be relocated to
160 their new location in the output file, through some complex sums.
164 mangle_sections(ibfd
, obfd
)
168 asection
*current
= ibfd
->sections
;
169 for (; current
!= NULL
; current
= current
->next
) {
170 current
->output_section
= bfd_get_section_by_name(obfd
, current
->name
);
171 current
->output_offset
= 0;
175 /* Choose which symbol entries to copy;
176 compact them downward to get rid of the rest.
177 Return the number of symbols to be printed. */
179 filter_symbols (abfd
, syms
, symcount
)
182 unsigned long symcount
;
184 asymbol
**from
, **to
;
185 unsigned int dst_count
= 0;
187 char locals_prefix
= bfd_get_symbol_leading_char(abfd
) == '_' ? 'L' : '.';
189 unsigned int src_count
;
190 for (from
= to
= syms
, src_count
= 0; src_count
<symcount
; src_count
++) {
193 flagword flags
= (from
[src_count
])->flags
;
194 sym
= from
[src_count
];
195 if ((flags
& BSF_GLOBAL
) /* Keep if external */
196 || (sym
->section
== &bfd_und_section
)
197 || (bfd_is_com_section (sym
->section
)))
199 else if ((flags
& BSF_DEBUGGING
) != 0) /* debugging symbol */
200 keep
= strip_symbols
!= strip_debug
;
201 else /* local symbol */
202 keep
= (discard_locals
!= locals_all
)
203 && !(discard_locals
== locals_start_L
&&
204 sym
->name
[0] == locals_prefix
);
208 to
[dst_count
++] = from
[src_count
];
217 copy_object(ibfd
, obfd
)
222 unsigned int symcount
;
225 if (!bfd_set_format(obfd
, bfd_get_format(ibfd
)))
226 bfd_fatal(output_filename
);
230 printf("copy from %s(%s) to %s(%s)\n",
231 ibfd
->filename
, ibfd
->xvec
->name
,
232 obfd
->filename
, obfd
->xvec
->name
);
234 if ((bfd_set_start_address(obfd
, bfd_get_start_address(ibfd
)) == false)
236 (bfd_set_file_flags(obfd
, (bfd_get_file_flags(ibfd
) &
237 (HAS_LINENO
| HAS_DEBUG
|
238 HAS_RELOC
| HAS_SYMS
| D_PAGED
|
239 HAS_LOCALS
))) == false)) {
240 bfd_fatal(bfd_get_filename(ibfd
));
243 /* Copy architecture of input file to output file */
244 if (!bfd_set_arch_mach(obfd
, bfd_get_arch(ibfd
),
245 bfd_get_mach(ibfd
))) {
246 fprintf(stderr
, "Output file cannot represent architecture %s\n",
247 bfd_printable_arch_mach(bfd_get_arch(ibfd
),
248 bfd_get_mach(ibfd
)));
250 if (!bfd_set_format(obfd
, bfd_get_format(ibfd
)))
252 bfd_fatal(ibfd
->filename
);
255 sympp
= (asymbol
**) xmalloc(get_symtab_upper_bound(ibfd
));
256 symcount
= bfd_canonicalize_symtab(ibfd
, sympp
);
258 if (strip_symbols
== strip_debug
|| discard_locals
!= locals_undef
)
259 symcount
= filter_symbols (ibfd
, sympp
, symcount
);
262 bfd_set_symtab(obfd
, sympp
,
263 strip_symbols
== strip_all
? 0 : symcount
);
266 bfd mandates that all output sections be created and sizes set before
267 any output is done. Thus, we traverse all sections twice.
269 bfd_map_over_sections(ibfd
, setup_sections
, (void *) obfd
);
270 bfd_map_over_sections(ibfd
, copy_sections
, (void *) obfd
);
271 mangle_sections(ibfd
, obfd
);
280 int size
= strlen(a
) + strlen(b
) + strlen(c
);
281 char *r
= xmalloc(size
+1);
289 copy_archive(ibfd
, obfd
)
293 bfd
**ptr
= &obfd
->archive_head
;
295 /* Read each archive element in turn from the input, copy the
296 contents to a temp file, and keep the temp file handle */
297 char *dir
= cat("./#",make_tempname(""),"cd");
299 /* Make a temp directory to hold the contents */
301 obfd
->has_armap
= ibfd
->has_armap
;
302 this_element
= bfd_openr_next_archived_file(ibfd
, NULL
);
303 ibfd
->archive_head
= this_element
;
304 while (this_element
!= (bfd
*)NULL
) {
306 /* Create an output file for this member */
307 char *output_name
= cat(dir
, "/",this_element
->filename
);
308 bfd
*output_bfd
= bfd_openw(output_name
, output_target
);
310 if (!bfd_set_format(obfd
, bfd_get_format(ibfd
)))
311 bfd_fatal(output_filename
);
313 if (output_bfd
== (bfd
*)NULL
) {
314 bfd_fatal(output_name
);
316 if (bfd_check_format(this_element
, bfd_object
) == true) {
317 copy_object(this_element
, output_bfd
);
320 bfd_close(output_bfd
);
321 /* Now open the newly output file and attatch to our list */
322 output_bfd
= bfd_openr(output_name
, output_target
);
323 /* Mark it for deletion */
327 ptr
= &output_bfd
->next
;
328 this_element
->next
= bfd_openr_next_archived_file(ibfd
, this_element
);
329 this_element
= this_element
->next
;
334 if (!bfd_close(obfd
))
335 bfd_fatal(output_filename
);
337 /* Now delete all the files that we opened.
338 Construct their names again, unfortunately, but so what;
339 we're about to exit anyway. */
340 for (this_element
= ibfd
->archive_head
;
341 this_element
!= (bfd
*)NULL
;
342 this_element
= this_element
->next
)
344 unlink(cat(dir
,"/",this_element
->filename
));
347 if (!bfd_close(ibfd
))
348 bfd_fatal(input_filename
);
354 copy_file(input_filename
, output_filename
)
355 char *input_filename
;
356 char *output_filename
;
360 ibfd
= bfd_openr(input_filename
, input_target
);
362 bfd_fatal(input_filename
);
364 if (bfd_check_format(ibfd
, bfd_object
)) {
365 bfd
* obfd
= bfd_openw(output_filename
, output_target
);
367 bfd_fatal(output_filename
);
369 copy_object(ibfd
, obfd
);
371 if (ibfd
->flags
& EXEC_P
)
372 obfd
->flags
|= EXEC_P
;
373 if (!bfd_close(obfd
))
374 bfd_fatal(output_filename
);
376 if (!bfd_close(ibfd
))
377 bfd_fatal(input_filename
);
379 else if (bfd_check_format(ibfd
, bfd_archive
)) {
380 bfd
* obfd
= bfd_openw(output_filename
, output_target
);
382 bfd_fatal(output_filename
);
383 copy_archive(ibfd
, obfd
);
389 /** Actually do the work */
391 setup_sections(ibfd
, isection
, obfd
)
399 osection
= bfd_get_section_by_name(obfd
, bfd_section_name(ibfd
, isection
));
400 if (osection
== NULL
) {
401 osection
= bfd_make_section(obfd
, bfd_section_name(ibfd
, isection
));
402 if (osection
== NULL
) {
408 if (!bfd_set_section_size(obfd
,
410 bfd_section_size(ibfd
, isection
))) {
415 if (bfd_set_section_vma(obfd
,
417 bfd_section_vma(ibfd
, isection
))
423 if (bfd_set_section_alignment(obfd
,
425 bfd_section_alignment(ibfd
, isection
))
431 if (!bfd_set_section_flags(obfd
, osection
,
432 bfd_get_section_flags(ibfd
, isection
))) {
441 fprintf(stderr
, "%s: file \"%s\", section \"%s\": error in %s: %s\n",
443 bfd_get_filename(ibfd
), bfd_section_name(ibfd
, isection
),
444 err
, bfd_errmsg(bfd_error
));
446 } /* setup_sections() */
449 Copy all the section related data from an input section
452 If stripping then don't copy any relocation info
455 copy_sections(ibfd
, isection
, obfd
)
465 osection
= bfd_get_section_by_name(obfd
,
466 bfd_section_name(ibfd
, isection
));
468 size
= bfd_get_section_size_before_reloc(isection
);
473 if (strip_symbols
== strip_all
474 || bfd_get_reloc_upper_bound(ibfd
, isection
) == 0)
476 bfd_set_reloc(obfd
, osection
, (arelent
**)NULL
, 0);
480 relpp
= (arelent
**) xmalloc(bfd_get_reloc_upper_bound(ibfd
, isection
));
481 relcount
= bfd_canonicalize_reloc(ibfd
, isection
, relpp
, sympp
);
482 bfd_set_reloc(obfd
, osection
, relpp
, relcount
);
485 isection
->_cooked_size
= isection
->_raw_size
;
486 isection
->reloc_done
=true;
489 if (bfd_get_section_flags(ibfd
, isection
) & SEC_HAS_CONTENTS
)
491 PTR memhunk
= (PTR
) xmalloc((unsigned)size
);
493 if (!bfd_get_section_contents(ibfd
, isection
, memhunk
, (file_ptr
) 0, size
))
494 bfd_fatal(bfd_get_filename(ibfd
));
496 if (!bfd_set_section_contents(obfd
, osection
, memhunk
, (file_ptr
)0, size
))
497 bfd_fatal(bfd_get_filename(obfd
));
509 int c
; /* sez which option char */
511 program_name
= argv
[0];
513 strip_symbols
= strip_undef
; /* default is to strip everything. */
514 discard_locals
= locals_undef
;
519 i
= strlen (program_name
);
520 is_strip
= (i
>= 5 && strcmp(program_name
+i
-5,"strip"));
525 while ((c
= getopt_long(argc
, argv
, "I:O:F:sSgxXVv",
526 strip_options
, (int *) 0))
530 input_target
= optarg
;
532 output_target
= optarg
;
535 input_target
= output_target
= optarg
;
539 strip_symbols
= strip_all
;
543 strip_symbols
= strip_debug
;
546 discard_locals
= locals_all
;
549 discard_locals
= locals_start_L
;
559 break; /* we've been given a long option */
567 /* Default is to strip all symbols. */
568 if (strip_symbols
== strip_undef
&& discard_locals
== locals_undef
)
569 strip_symbols
= strip_all
;
571 if (output_target
== (char *) NULL
)
572 output_target
= input_target
;
575 printf ("%s version %s\n", program_name
, program_version
);
578 for ( ; i
< argc
; i
++) {
579 char *tmpname
= make_tempname(argv
[i
]);
580 copy_file(argv
[i
], tmpname
);
581 rename(tmpname
, argv
[i
]);
586 /* Invoked as "copy", not "strip" */
588 while ((c
= getopt_long(argc
, argv
, "I:s:O:d:F:b:SgxXVv",
589 strip_options
, (int *) 0))
593 case 's': /* "source" - 'I' is preferred */
594 input_target
= optarg
;
596 case 'd': /* "destination" - 'O' is preferred */
597 output_target
= optarg
;
600 case 'b': /* "both" - 'F' is preferred */
601 input_target
= output_target
= optarg
;
605 strip_symbols
= strip_all
;
608 strip_symbols
= strip_debug
;
611 discard_locals
= locals_all
;
614 discard_locals
= locals_start_L
;
624 break; /* we've been given a long option */
631 printf ("%s version %s\n", program_name
, program_version
);
639 input_filename
= argv
[optind
];
640 if (optind
+ 1 < argc
)
641 output_filename
= argv
[optind
+1];
643 /* Default is to strip no symbols. */
644 if (strip_symbols
== strip_undef
&& discard_locals
== locals_undef
)
645 strip_symbols
= strip_none
;
647 if (input_filename
== (char *) NULL
)
650 if (output_target
== (char *) NULL
)
651 output_target
= input_target
;
653 /* If there is no destination file then create a temp and rename
654 the result into the input */
656 if (output_filename
== (char *)NULL
) {
657 char * tmpname
= make_tempname(input_filename
);
658 copy_file(input_filename
, tmpname
);
659 output_filename
= input_filename
;
660 rename(tmpname
, input_filename
);
663 copy_file(input_filename
, output_filename
);