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