Trivial change to prepare for a real one
[deliverable/binutils-gdb.git] / binutils / objcopy.c
CommitLineData
c0367ba5 1/* objcopy.c -- copy object file from input to output, optionally massaging it.
f7b839f7 2 Copyright (C) 1991, 92, 93, 94 Free Software Foundation, Inc.
c0367ba5 3
46050fe4
ILT
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\f
c0367ba5
ILT
20#include "bfd.h"
21#include "sysdep.h"
22#include "bucomm.h"
23#include <getopt.h>
24
f7b839f7
DM
25static void setup_section ();
26static void copy_section ();
77ccab3c 27static void mark_symbols_used_in_relocations ();
c0367ba5 28
46050fe4 29#define nonfatal(s) {bfd_nonfatal(s); status = 1; return;}
c0367ba5 30
46050fe4
ILT
31static asymbol **isympp = NULL; /* Input symbols */
32static asymbol **osympp = NULL; /* Output symbols that survive stripping */
f7b839f7
DM
33
34/* If `copy_byte' >= 0, copy only that byte of every `interleave' bytes. */
35static int copy_byte = -1;
36static int interleave = 4;
37
46050fe4 38static boolean verbose; /* Print file and target names. */
f7b839f7 39static int status = 0; /* Exit status. */
c0367ba5
ILT
40
41enum strip_action
46050fe4
ILT
42 {
43 strip_undef,
44 strip_none, /* don't strip */
45 strip_debug, /* strip all debugger symbols */
46 strip_all /* strip all symbols */
47 };
c0367ba5
ILT
48
49/* Which symbols to remove. */
46050fe4 50static enum strip_action strip_symbols;
c0367ba5
ILT
51
52enum locals_action
46050fe4
ILT
53 {
54 locals_undef,
55 locals_start_L, /* discard locals starting with L */
56 locals_all /* discard all locals */
57 };
58
59/* Which local symbols to remove. Overrides strip_all. */
60static enum locals_action discard_locals;
61
62/* Options to handle if running as "strip". */
63
64static struct option strip_options[] =
c0367ba5 65{
46050fe4
ILT
66 {"discard-all", no_argument, 0, 'x'},
67 {"discard-locals", no_argument, 0, 'X'},
f7b839f7 68 {"format", required_argument, 0, 'F'}, /* Obsolete */
46050fe4 69 {"help", no_argument, 0, 'h'},
46050fe4 70 {"input-format", required_argument, 0, 'I'}, /* Obsolete */
f7b839f7 71 {"input-target", required_argument, 0, 'I'},
46050fe4 72 {"output-format", required_argument, 0, 'O'}, /* Obsolete */
f7b839f7
DM
73 {"output-target", required_argument, 0, 'O'},
74 {"strip-all", no_argument, 0, 's'},
75 {"strip-debug", no_argument, 0, 'S'},
46050fe4 76 {"target", required_argument, 0, 'F'},
46050fe4 77 {"verbose", no_argument, 0, 'v'},
f7b839f7 78 {"version", no_argument, 0, 'V'},
46050fe4 79 {0, no_argument, 0, 0}
c0367ba5
ILT
80};
81
46050fe4 82/* Options to handle if running as "objcopy". */
c0367ba5 83
46050fe4
ILT
84static struct option copy_options[] =
85{
f7b839f7 86 {"byte", required_argument, 0, 'b'},
46050fe4
ILT
87 {"discard-all", no_argument, 0, 'x'},
88 {"discard-locals", no_argument, 0, 'X'},
f7b839f7 89 {"format", required_argument, 0, 'F'}, /* Obsolete */
46050fe4 90 {"help", no_argument, 0, 'h'},
46050fe4 91 {"input-format", required_argument, 0, 'I'}, /* Obsolete */
f7b839f7
DM
92 {"input-target", required_argument, 0, 'I'},
93 {"interleave", required_argument, 0, 'i'},
46050fe4 94 {"output-format", required_argument, 0, 'O'}, /* Obsolete */
f7b839f7
DM
95 {"output-target", required_argument, 0, 'O'},
96 {"strip-all", no_argument, 0, 'S'},
97 {"strip-debug", no_argument, 0, 'g'},
46050fe4 98 {"target", required_argument, 0, 'F'},
46050fe4 99 {"verbose", no_argument, 0, 'v'},
f7b839f7 100 {"version", no_argument, 0, 'V'},
46050fe4 101 {0, no_argument, 0, 0}
c0367ba5
ILT
102};
103
104/* IMPORTS */
46050fe4
ILT
105extern char *program_name;
106extern char *program_version;
107
108/* This flag distinguishes between strip and objcopy:
109 1 means this is 'strip'; 0 means this is 'objcopy'.
110 -1 means if we should use argv[0] to decide. */
111extern int is_strip;
c0367ba5
ILT
112
113
46050fe4
ILT
114static void
115copy_usage (stream, status)
c0367ba5
ILT
116 FILE *stream;
117 int status;
118{
46050fe4 119 fprintf (stream, "\
f7b839f7
DM
120Usage: %s [-vVSgxX] [-I bfdname] [-O bfdname] [-F bfdname] [-b byte]\n\
121 [-i interleave] [--interleave=interleave] [--byte=byte]\n\
46050fe4
ILT
122 [--input-target=bfdname] [--output-target=bfdname] [--target=bfdname]\n\
123 [--strip-all] [--strip-debug] [--discard-all] [--discard-locals]\n\
f7b839f7
DM
124 [--verbose] [--version] [--help] in-file [out-file]\n",
125 program_name);
46050fe4 126 exit (status);
c0367ba5
ILT
127}
128
46050fe4
ILT
129static void
130strip_usage (stream, status)
c0367ba5
ILT
131 FILE *stream;
132 int status;
133{
46050fe4
ILT
134 fprintf (stream, "\
135Usage: %s [-vVsSgxX] [-I bfdname] [-O bfdname] [-F bfdname]\n\
136 [--input-target=bfdname] [--output-target=bfdname] [--target=bfdname]\n\
137 [--strip-all] [--strip-debug] [--discard-all] [--discard-locals]\n\
138 [--verbose] [--version] [--help] file...\n",
139 program_name);
140 exit (status);
c0367ba5
ILT
141}
142
143
46050fe4 144/* Return the name of a temporary file in the same directory as FILENAME. */
c0367ba5 145
46050fe4
ILT
146static char *
147make_tempname (filename)
148 char *filename;
c0367ba5 149{
46050fe4
ILT
150 static char template[] = "stXXXXXX";
151 char *tmpname;
152 char *slash = strrchr (filename, '/');
153
154 if (slash != (char *) NULL)
155 {
156 *slash = 0;
157 tmpname = xmalloc (strlen (filename) + sizeof (template) + 1);
158 strcpy (tmpname, filename);
159 strcat (tmpname, "/");
160 strcat (tmpname, template);
161 mktemp (tmpname);
162 *slash = '/';
163 }
164 else
165 {
166 tmpname = xmalloc (sizeof (template));
167 strcpy (tmpname, template);
168 mktemp (tmpname);
c0367ba5 169 }
46050fe4 170 return tmpname;
c0367ba5
ILT
171}
172
46050fe4 173/* Choose which symbol entries to copy; put the result in OSYMS.
c0367ba5 174 We don't copy in place, because that confuses the relocs.
46050fe4
ILT
175 Return the number of symbols to print. */
176
c0367ba5
ILT
177static unsigned int
178filter_symbols (abfd, osyms, isyms, symcount)
179 bfd *abfd;
180 asymbol **osyms, **isyms;
ae5d2ff5 181 long symcount;
c0367ba5
ILT
182{
183 register asymbol **from = isyms, **to = osyms;
ae5d2ff5 184 long src_count = 0, dst_count = 0;
c0367ba5 185
46050fe4
ILT
186 for (; src_count < symcount; src_count++)
187 {
188 asymbol *sym = from[src_count];
189 flagword flags = sym->flags;
190 int keep;
c0367ba5 191
46050fe4 192 if ((flags & BSF_GLOBAL) /* Keep if external. */
77ccab3c 193 || (flags & BSF_KEEP) /* Keep if used in a relocation. */
46050fe4
ILT
194 || bfd_get_section (sym) == &bfd_und_section
195 || bfd_is_com_section (bfd_get_section (sym)))
196 keep = 1;
197 else if ((flags & BSF_DEBUGGING) != 0) /* Debugging symbol. */
198 keep = strip_symbols != strip_debug;
199 else /* Local symbol. */
200 keep = discard_locals != locals_all
201 && (discard_locals != locals_start_L ||
77ccab3c 202 ! bfd_is_local_label (abfd, sym));
46050fe4
ILT
203 if (keep)
204 to[dst_count++] = sym;
c0367ba5 205 }
c0367ba5
ILT
206
207 return dst_count;
208}
209
f7b839f7
DM
210/* Keep only every `copy_byte'th byte in MEMHUNK, which is *SIZE bytes long.
211 Adjust *SIZE. */
212
213void
214filter_bytes (memhunk, size)
5d2f7e30 215 char *memhunk;
f7b839f7
DM
216 bfd_size_type *size;
217{
218 char *from = memhunk + copy_byte, *to = memhunk, *end = memhunk + *size;
219
220 for (; from < end; from += interleave)
221 *to++ = *from;
222 *size /= interleave;
223}
224
46050fe4
ILT
225/* Copy object file IBFD onto OBFD. */
226
c0367ba5 227static void
46050fe4
ILT
228copy_object (ibfd, obfd)
229 bfd *ibfd;
230 bfd *obfd;
c0367ba5 231{
ae5d2ff5 232 long symcount;
c0367ba5 233
46050fe4
ILT
234 if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
235 {
236 nonfatal (bfd_get_filename (obfd));
237 }
c0367ba5 238
46050fe4
ILT
239 if (verbose)
240 printf ("copy from %s(%s) to %s(%s)\n",
241 bfd_get_filename(ibfd), bfd_get_target(ibfd),
242 bfd_get_filename(obfd), bfd_get_target(obfd));
c0367ba5 243
46050fe4
ILT
244 if (!bfd_set_start_address (obfd, bfd_get_start_address (ibfd))
245 || !bfd_set_file_flags (obfd,
246 (bfd_get_file_flags (ibfd)
247 & bfd_applicable_file_flags (obfd))))
248 {
249 nonfatal (bfd_get_filename (ibfd));
250 }
c0367ba5 251
46050fe4
ILT
252 /* Copy architecture of input file to output file */
253 if (!bfd_set_arch_mach (obfd, bfd_get_arch (ibfd),
254 bfd_get_mach (ibfd)))
255 {
256 fprintf (stderr, "Output file cannot represent architecture %s\n",
257 bfd_printable_arch_mach (bfd_get_arch (ibfd),
258 bfd_get_mach (ibfd)));
259 }
260 if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
261 {
262 nonfatal (bfd_get_filename(ibfd));
263 }
c0367ba5 264
46050fe4
ILT
265 if (isympp)
266 free (isympp);
267 if (osympp != isympp)
268 free (osympp);
c0367ba5 269
77ccab3c
JL
270 /* Allow the BFD backend to copy any private data it understands
271 from the input BFD to the output BFD. */
272 if (!bfd_copy_private_bfd_data (ibfd, obfd))
273 {
274 fprintf (stderr, "%s: %s: error copying private BFD data: %s\n",
ae5d2ff5
ILT
275 program_name, bfd_get_filename (obfd),
276 bfd_errmsg (bfd_get_error ()));
77ccab3c
JL
277 status = 1;
278 return;
279 }
280
281 /* bfd mandates that all output sections be created and sizes set before
282 any output is done. Thus, we traverse all sections multiple times. */
283 bfd_map_over_sections (ibfd, setup_section, (void *) obfd);
284
285 /* Symbol filtering must happen after the output sections have
286 been created, but before their contents are set. */
46050fe4
ILT
287 if (strip_symbols == strip_all && discard_locals == locals_undef)
288 {
289 osympp = isympp = NULL;
290 symcount = 0;
c0367ba5 291 }
46050fe4
ILT
292 else
293 {
ae5d2ff5
ILT
294 long symsize;
295
296 symsize = bfd_get_symtab_upper_bound (ibfd);
297 if (symsize < 0)
298 {
299 nonfatal (bfd_get_filename (ibfd));
300 }
301
302 osympp = isympp = (asymbol **) xmalloc (symsize);
46050fe4 303 symcount = bfd_canonicalize_symtab (ibfd, isympp);
ae5d2ff5
ILT
304 if (symcount < 0)
305 {
306 nonfatal (bfd_get_filename (ibfd));
307 }
46050fe4
ILT
308
309 if (strip_symbols == strip_debug || discard_locals != locals_undef)
c0367ba5 310 {
77ccab3c
JL
311 /* Mark symbols used in output relocations so that they
312 are kept, even if they are local labels or static symbols.
313
314 Note we iterate over the input sections examining their
315 relocations since the relocations for the output sections
316 haven't been set yet. mark_symbols_used_in_relocations will
317 ignore input sections which have no corresponding output
318 section. */
319 bfd_map_over_sections (ibfd,
320 mark_symbols_used_in_relocations,
321 (void *)isympp);
46050fe4
ILT
322 osympp = (asymbol **) xmalloc (symcount * sizeof (asymbol *));
323 symcount = filter_symbols (ibfd, osympp, isympp, symcount);
c0367ba5 324 }
46050fe4
ILT
325 }
326
327 bfd_set_symtab (obfd, osympp, symcount);
c0367ba5 328
77ccab3c 329 /* This has to happen after the symbol table has been set. */
f7b839f7 330 bfd_map_over_sections (ibfd, copy_section, (void *) obfd);
c0367ba5 331}
46050fe4
ILT
332
333static char *
334cat (a, b, c)
335 char *a;
336 char *b;
337 char *c;
c0367ba5 338{
46050fe4
ILT
339 size_t size = strlen (a) + strlen (b) + strlen (c);
340 char *r = xmalloc (size + 1);
341
342 strcpy (r, a);
343 strcat (r, b);
344 strcat (r, c);
345 return r;
c0367ba5
ILT
346}
347
46050fe4
ILT
348/* Read each archive element in turn from IBFD, copy the
349 contents to temp file, and keep the temp file handle. */
350
351static void
352copy_archive (ibfd, obfd, output_target)
353 bfd *ibfd;
354 bfd *obfd;
355 char *output_target;
c0367ba5 356{
46050fe4
ILT
357 bfd **ptr = &obfd->archive_head;
358 bfd *this_element;
359 char *dir = cat ("./#", make_tempname (""), "cd");
360
361 /* Make a temp directory to hold the contents. */
362 mkdir (dir, 0777);
363 obfd->has_armap = ibfd->has_armap;
364
365 this_element = bfd_openr_next_archived_file (ibfd, NULL);
366 ibfd->archive_head = this_element;
367 while (this_element != (bfd *) NULL)
368 {
369 /* Create an output file for this member. */
370 char *output_name = cat (dir, "/", bfd_get_filename(this_element));
371 bfd *output_bfd = bfd_openw (output_name, output_target);
372
373 if (output_bfd == (bfd *) NULL)
374 {
375 nonfatal (output_name);
c0367ba5 376 }
46050fe4
ILT
377 if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
378 {
379 nonfatal (bfd_get_filename (obfd));
c0367ba5
ILT
380 }
381
46050fe4
ILT
382 if (bfd_check_format (this_element, bfd_object) == true)
383 {
384 copy_object (this_element, output_bfd);
385 }
c0367ba5 386
46050fe4
ILT
387 bfd_close (output_bfd);
388 /* Open the newly output file and attatch to our list. */
389 output_bfd = bfd_openr (output_name, output_target);
c0367ba5 390
46050fe4
ILT
391 /* Mark it for deletion. */
392 *ptr = output_bfd;
393 ptr = &output_bfd->next;
394 this_element->next = bfd_openr_next_archived_file (ibfd, this_element);
395 this_element = this_element->next;
c0367ba5 396 }
46050fe4 397 *ptr = (bfd *) NULL;
c0367ba5 398
46050fe4
ILT
399 if (!bfd_close (obfd))
400 {
401 nonfatal (bfd_get_filename (obfd));
c0367ba5 402 }
c0367ba5 403
46050fe4
ILT
404 /* Delete all the files that we opened.
405 Construct their names again, unfortunately, but
406 we're about to exit anyway. */
407 for (this_element = ibfd->archive_head;
408 this_element != (bfd *) NULL;
409 this_element = this_element->next)
410 {
411 unlink (cat (dir, "/", bfd_get_filename (this_element)));
412 }
413 rmdir (dir);
414 if (!bfd_close (ibfd))
415 {
416 nonfatal (bfd_get_filename (ibfd));
417 }
c0367ba5
ILT
418}
419
46050fe4
ILT
420/* The top-level control. */
421
422static void
423copy_file (input_filename, output_filename, input_target, output_target)
424 char *input_filename;
425 char *output_filename;
426 char *input_target;
427 char *output_target;
c0367ba5 428{
46050fe4 429 bfd *ibfd;
cef35d48 430 char **matching;
c0367ba5
ILT
431
432 /* To allow us to do "strip *" without dying on the first
433 non-object file, failures are nonfatal. */
434
46050fe4 435 ibfd = bfd_openr (input_filename, input_target);
c0367ba5
ILT
436 if (ibfd == NULL)
437 {
46050fe4 438 nonfatal (input_filename);
c0367ba5
ILT
439 }
440
cef35d48
DM
441 if (bfd_check_format (ibfd, bfd_archive))
442 {
443 bfd *obfd = bfd_openw (output_filename, output_target);
444 if (obfd == NULL)
445 {
446 nonfatal (output_filename);
447 }
448 copy_archive (ibfd, obfd, output_target);
449 }
450 else if (bfd_check_format_matches (ibfd, bfd_object, &matching))
46050fe4
ILT
451 {
452 bfd *obfd = bfd_openw (output_filename, output_target);
453 if (obfd == NULL)
454 {
455 nonfatal (output_filename);
456 }
c0367ba5 457
46050fe4 458 copy_object (ibfd, obfd);
c0367ba5 459
46050fe4
ILT
460 if (!bfd_close (obfd))
461 {
462 nonfatal (output_filename);
463 }
464
465 if (!bfd_close (ibfd))
466 {
467 nonfatal (input_filename);
468 }
469 }
cef35d48 470 else
46050fe4 471 {
cef35d48 472 bfd_nonfatal (input_filename);
c9563567 473 if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
46050fe4 474 {
cef35d48
DM
475 list_matching_formats (matching);
476 free (matching);
46050fe4 477 }
cef35d48 478 status = 1;
46050fe4
ILT
479 }
480}
481
482/* Create a section in OBFD with the same name and attributes
483 as ISECTION in IBFD. */
c0367ba5 484
c0367ba5 485static void
f7b839f7 486setup_section (ibfd, isection, obfd)
46050fe4
ILT
487 bfd *ibfd;
488 sec_ptr isection;
489 bfd *obfd;
c0367ba5 490{
46050fe4
ILT
491 sec_ptr osection;
492 char *err;
493
494 if ((bfd_get_section_flags (ibfd, isection) & SEC_DEBUGGING) != 0
495 && (strip_symbols == strip_debug
496 || strip_symbols == strip_all
497 || discard_locals == locals_all))
498 return;
499
77ccab3c 500 osection = bfd_make_section_anyway (obfd, bfd_section_name (ibfd, isection));
46050fe4
ILT
501 if (osection == NULL)
502 {
77ccab3c
JL
503 err = "making";
504 goto loser;
c0367ba5
ILT
505 }
506
46050fe4
ILT
507 if (!bfd_set_section_size (obfd,
508 osection,
509 bfd_section_size (ibfd, isection)))
510 {
511 err = "size";
512 goto loser;
c0367ba5
ILT
513 }
514
46050fe4
ILT
515 if (bfd_set_section_vma (obfd,
516 osection,
517 bfd_section_vma (ibfd, isection))
518 == false)
519 {
520 err = "vma";
521 goto loser;
522 }
c0367ba5 523
46050fe4
ILT
524 if (bfd_set_section_alignment (obfd,
525 osection,
526 bfd_section_alignment (ibfd, isection))
527 == false)
528 {
529 err = "alignment";
530 goto loser;
531 }
c0367ba5 532
46050fe4
ILT
533 if (!bfd_set_section_flags (obfd, osection,
534 bfd_get_section_flags (ibfd, isection)))
535 {
536 err = "flags";
537 goto loser;
c0367ba5
ILT
538 }
539
c9563567
JL
540 /* This used to be mangle_section; we do here to avoid using
541 bfd_get_section_by_name since some formats allow multiple
542 sections with the same name. */
543 isection->output_section = osection;
544 isection->output_offset = 0;
545
77ccab3c
JL
546 /* Allow the BFD backend to copy any private data it understands
547 from the input section to the output section. */
548 if (!bfd_copy_private_section_data (ibfd, isection, obfd, osection))
549 {
550 err = "private data";
551 goto loser;
552 }
553
46050fe4
ILT
554 /* All went well */
555 return;
c0367ba5
ILT
556
557loser:
46050fe4
ILT
558 fprintf (stderr, "%s: %s: section `%s': error in %s: %s\n",
559 program_name,
560 bfd_get_filename (ibfd), bfd_section_name (ibfd, isection),
c9563567 561 err, bfd_errmsg (bfd_get_error ()));
46050fe4
ILT
562 status = 1;
563}
564
565/* Copy the data of input section ISECTION of IBFD
566 to an output section with the same name in OBFD.
567 If stripping then don't copy any relocation info. */
568
c0367ba5 569static void
f7b839f7 570copy_section (ibfd, isection, obfd)
46050fe4
ILT
571 bfd *ibfd;
572 sec_ptr isection;
573 bfd *obfd;
c0367ba5 574{
46050fe4 575 arelent **relpp;
ae5d2ff5 576 long relcount;
46050fe4
ILT
577 sec_ptr osection;
578 bfd_size_type size;
579
580 if ((bfd_get_section_flags (ibfd, isection) & SEC_DEBUGGING) != 0
581 && (strip_symbols == strip_debug
582 || strip_symbols == strip_all
583 || discard_locals == locals_all))
584 {
585 return;
586 }
c0367ba5 587
77ccab3c 588 osection = isection->output_section;
46050fe4 589 size = bfd_get_section_size_before_reloc (isection);
c0367ba5 590
77ccab3c 591 if (size == 0 || osection == 0)
c0367ba5
ILT
592 return;
593
ae5d2ff5
ILT
594 if (strip_symbols == strip_all)
595 bfd_set_reloc (obfd, osection, (arelent **) NULL, 0);
46050fe4 596 else
c0367ba5 597 {
ae5d2ff5
ILT
598 long relsize;
599
600 relsize = bfd_get_reloc_upper_bound (ibfd, isection);
601 if (relsize < 0)
602 {
603 nonfatal (bfd_get_filename (ibfd));
604 }
605 if (relsize == 0)
606 bfd_set_reloc (obfd, osection, (arelent **) NULL, 0);
607 else
608 {
609 relpp = (arelent **) xmalloc (relsize);
610 relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, isympp);
611 if (relcount < 0)
612 {
613 nonfatal (bfd_get_filename (ibfd));
614 }
615 bfd_set_reloc (obfd, osection, relpp, relcount);
616 }
c0367ba5
ILT
617 }
618
619 isection->_cooked_size = isection->_raw_size;
46050fe4 620 isection->reloc_done = true;
c0367ba5 621
46050fe4 622 if (bfd_get_section_flags (ibfd, isection) & SEC_HAS_CONTENTS)
c0367ba5 623 {
46050fe4 624 PTR memhunk = (PTR) xmalloc ((unsigned) size);
c0367ba5 625
46050fe4
ILT
626 if (!bfd_get_section_contents (ibfd, isection, memhunk, (file_ptr) 0,
627 size))
628 {
629 nonfatal (bfd_get_filename (ibfd));
630 }
c0367ba5 631
f7b839f7
DM
632 if (copy_byte >= 0)
633 filter_bytes (memhunk, &size);
634
46050fe4
ILT
635 if (!bfd_set_section_contents (obfd, osection, memhunk, (file_ptr) 0,
636 size))
637 {
638 nonfatal (bfd_get_filename (obfd));
639 }
640 free (memhunk);
c0367ba5 641 }
46050fe4 642}
c0367ba5 643
77ccab3c
JL
644/* Mark all the symbols which will be used in output relocations with
645 the BSF_KEEP flag so that those symbols will not be stripped.
646
647 Ignore relocations which will not appear in the output file. */
648
649static void
650mark_symbols_used_in_relocations (ibfd, isection, symbols)
651 bfd *ibfd;
652 sec_ptr isection;
653 asymbol **symbols;
654{
ae5d2ff5 655 long relsize;
77ccab3c 656 arelent **relpp;
ae5d2ff5 657 long relcount, i;
77ccab3c
JL
658
659 /* Ignore an input section with no corresponding output section. */
660 if (isection->output_section == NULL)
661 return;
662
ae5d2ff5
ILT
663 relsize = bfd_get_reloc_upper_bound (ibfd, isection);
664 if (relsize < 0)
665 bfd_fatal (bfd_get_filename (ibfd));
666
667 relpp = (arelent **) xmalloc (relsize);
77ccab3c 668 relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, symbols);
ae5d2ff5
ILT
669 if (relcount < 0)
670 bfd_fatal (bfd_get_filename (ibfd));
77ccab3c
JL
671
672 /* Examine each symbol used in a relocation. If it's not one of the
673 special bfd section symbols, then mark it with BSF_KEEP. */
674 for (i = 0; i < relcount; i++)
675 {
676 if (*relpp[i]->sym_ptr_ptr != bfd_com_section.symbol
677 && *relpp[i]->sym_ptr_ptr != bfd_abs_section.symbol
678 && *relpp[i]->sym_ptr_ptr != bfd_und_section.symbol)
679 (*relpp[i]->sym_ptr_ptr)->flags |= BSF_KEEP;
680 }
681
682 if (relpp != NULL)
683 free (relpp);
684}
685
46050fe4
ILT
686/* The number of bytes to copy at once. */
687#define COPY_BUF 8192
688
689/* Copy file FROM to file TO, performing no translations.
690 Return 0 if ok, -1 if error. */
691
692static int
693simple_copy (from, to)
694 char *from, *to;
c0367ba5 695{
46050fe4
ILT
696 int fromfd, tofd, nread;
697 char buf[COPY_BUF];
698
699 fromfd = open (from, O_RDONLY);
700 if (fromfd < 0)
701 return -1;
702 tofd = open (to, O_WRONLY | O_CREAT | O_TRUNC);
703 if (tofd < 0)
704 {
705 close (fromfd);
706 return -1;
707 }
708 while ((nread = read (fromfd, buf, sizeof buf)) > 0)
709 {
710 if (write (tofd, buf, nread) != nread)
711 {
712 close (fromfd);
713 close (tofd);
714 return -1;
715 }
716 }
717 close (fromfd);
718 close (tofd);
719 if (nread < 0)
720 return -1;
721 return 0;
722}
c0367ba5 723
46050fe4
ILT
724#ifndef S_ISLNK
725#ifdef S_IFLNK
726#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
727#else
728#define S_ISLNK(m) 0
729#define lstat stat
730#endif
731#endif
732
733/* Rename FROM to TO, copying if TO is a link.
734 Assumes that TO already exists, because FROM is a temp file.
735 Return 0 if ok, -1 if error. */
736
737static int
738smart_rename (from, to)
739 char *from, *to;
740{
741 struct stat s;
742 int ret = 0;
c0367ba5 743
46050fe4
ILT
744 if (lstat (to, &s))
745 return -1;
c0367ba5 746
46050fe4
ILT
747 /* Use rename only if TO is not a symbolic link and has
748 only one hard link. */
749 if (!S_ISLNK (s.st_mode) && s.st_nlink == 1)
750 {
751 ret = rename (from, to);
752 if (ret == 0)
753 {
754 /* Try to preserve the permission bits and ownership of TO. */
755 chmod (to, s.st_mode & 07777);
756 chown (to, s.st_uid, s.st_gid);
757 }
758 }
759 else
760 {
761 ret = simple_copy (from, to);
762 if (ret == 0)
763 unlink (from);
764 }
765 return ret;
766}
767
768static int
769strip_main (argc, argv)
770 int argc;
771 char *argv[];
772{
773 char *input_target = NULL, *output_target = NULL;
774 boolean show_version = false;
775 int c, i;
776
777 while ((c = getopt_long (argc, argv, "I:O:F:sSgxXVv",
778 strip_options, (int *) 0)) != EOF)
779 {
780 switch (c)
781 {
782 case 'I':
783 input_target = optarg;
704bbd0d 784 break;
46050fe4
ILT
785 case 'O':
786 output_target = optarg;
787 break;
788 case 'F':
789 input_target = output_target = optarg;
790 break;
791 case 's':
c0367ba5 792 strip_symbols = strip_all;
46050fe4
ILT
793 break;
794 case 'S':
795 case 'g':
796 strip_symbols = strip_debug;
797 break;
798 case 'x':
799 discard_locals = locals_all;
800 break;
801 case 'X':
802 discard_locals = locals_start_L;
803 break;
804 case 'v':
805 verbose = true;
806 break;
807 case 'V':
808 show_version = true;
809 break;
810 case 0:
811 break; /* we've been given a long option */
812 case 'h':
813 strip_usage (stdout, 0);
814 default:
815 strip_usage (stderr, 1);
816 }
817 }
818
819 if (show_version)
820 {
821 printf ("GNU %s version %s\n", program_name, program_version);
822 exit (0);
823 }
c0367ba5 824
46050fe4
ILT
825 /* Default is to strip all symbols. */
826 if (strip_symbols == strip_undef && discard_locals == locals_undef)
827 strip_symbols = strip_all;
828
829 if (output_target == (char *) NULL)
830 output_target = input_target;
831
832 i = optind;
833 if (i == argc)
834 strip_usage (stderr, 1);
835
836 for (; i < argc; i++)
837 {
838 int hold_status = status;
c0367ba5 839
46050fe4
ILT
840 char *tmpname = make_tempname (argv[i]);
841 status = 0;
842 copy_file (argv[i], tmpname, input_target, output_target);
843 if (status == 0)
844 {
845 smart_rename (tmpname, argv[i]);
846 status = hold_status;
c0367ba5 847 }
46050fe4
ILT
848 else
849 unlink (tmpname);
850 free (tmpname);
851 }
852
853 return 0;
854}
855
856static int
857copy_main (argc, argv)
858 int argc;
859 char *argv[];
860{
861 char *input_filename, *output_filename;
862 char *input_target = NULL, *output_target = NULL;
863 boolean show_version = false;
864 int c;
865
f7b839f7 866 while ((c = getopt_long (argc, argv, "b:i:I:s:O:d:F:SgxXVv",
46050fe4
ILT
867 copy_options, (int *) 0)) != EOF)
868 {
869 switch (c)
870 {
f7b839f7
DM
871 case 'b':
872 copy_byte = atoi(optarg);
873 if (copy_byte < 0)
874 {
875 fprintf (stderr, "%s: byte number must be non-negative\n",
876 program_name);
877 exit (1);
878 }
879 break;
880 case 'i':
881 interleave = atoi(optarg);
882 if (interleave < 1)
883 {
884 fprintf(stderr, "%s: interleave must be positive\n",
885 program_name);
886 exit (1);
887 }
888 break;
c0367ba5 889 case 'I':
46050fe4 890 case 's': /* "source" - 'I' is preferred */
c0367ba5 891 input_target = optarg;
704bbd0d 892 break;
c0367ba5 893 case 'O':
46050fe4 894 case 'd': /* "destination" - 'O' is preferred */
c0367ba5
ILT
895 output_target = optarg;
896 break;
897 case 'F':
c0367ba5
ILT
898 input_target = output_target = optarg;
899 break;
c0367ba5
ILT
900 case 'S':
901 strip_symbols = strip_all;
902 break;
903 case 'g':
904 strip_symbols = strip_debug;
905 break;
906 case 'x':
907 discard_locals = locals_all;
908 break;
909 case 'X':
910 discard_locals = locals_start_L;
911 break;
912 case 'v':
913 verbose = true;
914 break;
915 case 'V':
916 show_version = true;
917 break;
46050fe4 918 case 0:
c0367ba5
ILT
919 break; /* we've been given a long option */
920 case 'h':
921 copy_usage (stdout, 0);
922 default:
923 copy_usage (stderr, 1);
46050fe4
ILT
924 }
925 }
926
927 if (show_version)
928 {
929 printf ("GNU %s version %s\n", program_name, program_version);
930 exit (0);
931 }
c0367ba5 932
f7b839f7
DM
933 if (copy_byte >= interleave)
934 {
935 fprintf (stderr, "%s: byte number must be less than interleave\n",
936 program_name);
937 exit (1);
938 }
939
46050fe4
ILT
940 if (optind == argc || optind + 2 < argc)
941 copy_usage (stderr, 1);
c0367ba5
ILT
942
943 input_filename = argv[optind];
944 if (optind + 1 < argc)
46050fe4 945 output_filename = argv[optind + 1];
c0367ba5
ILT
946
947 /* Default is to strip no symbols. */
948 if (strip_symbols == strip_undef && discard_locals == locals_undef)
46050fe4 949 strip_symbols = strip_none;
c0367ba5
ILT
950
951 if (output_target == (char *) NULL)
952 output_target = input_target;
953
46050fe4
ILT
954 /* If there is no destination file then create a temp and rename
955 the result into the input. */
956
957 if (output_filename == (char *) NULL)
958 {
959 char *tmpname = make_tempname (input_filename);
960 copy_file (input_filename, tmpname, input_target, output_target);
961 if (status == 0)
962 smart_rename (tmpname, input_filename);
963 else
964 unlink (tmpname);
965 }
966 else
967 {
968 copy_file (input_filename, output_filename, input_target, output_target);
969 }
970
c0367ba5
ILT
971 return 0;
972}
46050fe4
ILT
973
974int
975main (argc, argv)
976 int argc;
977 char *argv[];
978{
979 program_name = argv[0];
704bbd0d 980 xmalloc_set_program_name (program_name);
46050fe4
ILT
981 strip_symbols = strip_undef;
982 discard_locals = locals_undef;
983
984 bfd_init ();
985
986 if (is_strip < 0)
987 {
988 int i = strlen (program_name);
989 is_strip = (i >= 5 && strcmp (program_name + i - 5, "strip"));
990 }
991
992 if (is_strip)
993 strip_main (argc, argv);
994 else
995 copy_main (argc, argv);
996
997 return status;
998}
This page took 0.089961 seconds and 4 git commands to generate.