133965Sjdp/* objcopy.c -- copy object file from input to output, optionally massaging it.
278828Sobrien   Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
3218822Sdim   2001, 2002, 2003, 2004, 2005, 2006, 2007
438889Sjdp   Free Software Foundation, Inc.
533965Sjdp
633965Sjdp   This file is part of GNU Binutils.
733965Sjdp
833965Sjdp   This program is free software; you can redistribute it and/or modify
933965Sjdp   it under the terms of the GNU General Public License as published by
1033965Sjdp   the Free Software Foundation; either version 2 of the License, or
1133965Sjdp   (at your option) any later version.
1233965Sjdp
1333965Sjdp   This program is distributed in the hope that it will be useful,
1433965Sjdp   but WITHOUT ANY WARRANTY; without even the implied warranty of
1533965Sjdp   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1633965Sjdp   GNU General Public License for more details.
1733965Sjdp
1833965Sjdp   You should have received a copy of the GNU General Public License
1933965Sjdp   along with this program; if not, write to the Free Software
20218822Sdim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
21218822Sdim   02110-1301, USA.  */
2233965Sjdp
23218822Sdim#include "sysdep.h"
2433965Sjdp#include "bfd.h"
2533965Sjdp#include "progress.h"
2633965Sjdp#include "getopt.h"
2733965Sjdp#include "libiberty.h"
28218822Sdim#include "bucomm.h"
2933965Sjdp#include "budbg.h"
3061843Sobrien#include "filenames.h"
31130561Sobrien#include "fnmatch.h"
32130561Sobrien#include "elf-bfd.h"
3333965Sjdp#include <sys/stat.h>
34218822Sdim#include "libbfd.h"
3533965Sjdp
3638889Sjdp/* A list of symbols to explicitly strip out, or to keep.  A linked
3738889Sjdp   list is good enough for a small number from the command line, but
3838889Sjdp   this will slow things down a lot if many symbols are being
39104834Sobrien   deleted.  */
4038889Sjdp
4138889Sjdpstruct symlist
4238889Sjdp{
4338889Sjdp  const char *name;
4438889Sjdp  struct symlist *next;
4538889Sjdp};
4638889Sjdp
4760484Sobrien/* A list to support redefine_sym.  */
4860484Sobrienstruct redefine_node
4960484Sobrien{
5060484Sobrien  char *source;
5160484Sobrien  char *target;
5260484Sobrien  struct redefine_node *next;
5360484Sobrien};
5460484Sobrien
5589857Sobrientypedef struct section_rename
5689857Sobrien{
5789857Sobrien  const char *            old_name;
5889857Sobrien  const char *            new_name;
5989857Sobrien  flagword                flags;
6089857Sobrien  struct section_rename * next;
6189857Sobrien}
6289857Sobriensection_rename;
6389857Sobrien
6489857Sobrien/* List of sections to be renamed.  */
65130561Sobrienstatic section_rename *section_rename_list;
6689857Sobrien
6760484Sobrien#define RETURN_NONFATAL(s) {bfd_nonfatal (s); status = 1; return;}
6833965Sjdp
69130561Sobrienstatic asymbol **isympp = NULL;	/* Input symbols.  */
70130561Sobrienstatic asymbol **osympp = NULL;	/* Output symbols that survive stripping.  */
7133965Sjdp
7233965Sjdp/* If `copy_byte' >= 0, copy only that byte of every `interleave' bytes.  */
7333965Sjdpstatic int copy_byte = -1;
7433965Sjdpstatic int interleave = 4;
7533965Sjdp
76130561Sobrienstatic bfd_boolean verbose;		/* Print file and target names.  */
77130561Sobrienstatic bfd_boolean preserve_dates;	/* Preserve input file timestamp.  */
7833965Sjdpstatic int status = 0;		/* Exit status.  */
7933965Sjdp
8033965Sjdpenum strip_action
8133965Sjdp  {
8260484Sobrien    STRIP_UNDEF,
83130561Sobrien    STRIP_NONE,			/* Don't strip.  */
84130561Sobrien    STRIP_DEBUG,		/* Strip all debugger symbols.  */
85130561Sobrien    STRIP_UNNEEDED,		/* Strip unnecessary symbols.  */
86130561Sobrien    STRIP_NONDEBUG,		/* Strip everything but debug info.  */
87130561Sobrien    STRIP_ALL			/* Strip all symbols.  */
8833965Sjdp  };
8933965Sjdp
90104834Sobrien/* Which symbols to remove.  */
9133965Sjdpstatic enum strip_action strip_symbols;
9233965Sjdp
9333965Sjdpenum locals_action
9433965Sjdp  {
9560484Sobrien    LOCALS_UNDEF,
96130561Sobrien    LOCALS_START_L,		/* Discard locals starting with L.  */
97130561Sobrien    LOCALS_ALL			/* Discard all locals.  */
9833965Sjdp  };
9933965Sjdp
10060484Sobrien/* Which local symbols to remove.  Overrides STRIP_ALL.  */
10133965Sjdpstatic enum locals_action discard_locals;
10233965Sjdp
10360484Sobrien/* What kind of change to perform.  */
10460484Sobrienenum change_action
10560484Sobrien{
10660484Sobrien  CHANGE_IGNORE,
10760484Sobrien  CHANGE_MODIFY,
10860484Sobrien  CHANGE_SET
10960484Sobrien};
11060484Sobrien
11133965Sjdp/* Structure used to hold lists of sections and actions to take.  */
11233965Sjdpstruct section_list
11333965Sjdp{
114130561Sobrien  struct section_list * next;	   /* Next section to change.  */
115130561Sobrien  const char *		name;	   /* Section name.  */
116130561Sobrien  bfd_boolean		used;	   /* Whether this entry was used.  */
117130561Sobrien  bfd_boolean		remove;	   /* Whether to remove this section.  */
118130561Sobrien  bfd_boolean		copy;	   /* Whether to copy this section.  */
119130561Sobrien  enum change_action	change_vma;/* Whether to change or set VMA.  */
120130561Sobrien  bfd_vma		vma_val;   /* Amount to change by or set to.  */
121130561Sobrien  enum change_action	change_lma;/* Whether to change or set LMA.  */
122130561Sobrien  bfd_vma		lma_val;   /* Amount to change by or set to.  */
123130561Sobrien  bfd_boolean		set_flags; /* Whether to set the section flags.	 */
124130561Sobrien  flagword		flags;	   /* What to set the section flags to.	 */
12533965Sjdp};
12633965Sjdp
12760484Sobrienstatic struct section_list *change_sections;
12889857Sobrien
129130561Sobrien/* TRUE if some sections are to be removed.  */
130130561Sobrienstatic bfd_boolean sections_removed;
13189857Sobrien
132130561Sobrien/* TRUE if only some sections are to be copied.  */
133130561Sobrienstatic bfd_boolean sections_copied;
13433965Sjdp
13560484Sobrien/* Changes to the start address.  */
13660484Sobrienstatic bfd_vma change_start = 0;
137130561Sobrienstatic bfd_boolean set_start_set = FALSE;
13833965Sjdpstatic bfd_vma set_start;
13933965Sjdp
14060484Sobrien/* Changes to section addresses.  */
14160484Sobrienstatic bfd_vma change_section_address = 0;
14233965Sjdp
14333965Sjdp/* Filling gaps between sections.  */
144130561Sobrienstatic bfd_boolean gap_fill_set = FALSE;
14533965Sjdpstatic bfd_byte gap_fill = 0;
14633965Sjdp
14733965Sjdp/* Pad to a given address.  */
148130561Sobrienstatic bfd_boolean pad_to_set = FALSE;
14933965Sjdpstatic bfd_vma pad_to;
15033965Sjdp
151218822Sdim/* Use alternative machine code?  */
152218822Sdimstatic unsigned long use_alt_mach_code = 0;
15389857Sobrien
154130561Sobrien/* Output BFD flags user wants to set or clear */
155130561Sobrienstatic flagword bfd_flags_to_set;
156130561Sobrienstatic flagword bfd_flags_to_clear;
157130561Sobrien
15833965Sjdp/* List of sections to add.  */
15933965Sjdpstruct section_add
16033965Sjdp{
16133965Sjdp  /* Next section to add.  */
16233965Sjdp  struct section_add *next;
16333965Sjdp  /* Name of section to add.  */
16433965Sjdp  const char *name;
16533965Sjdp  /* Name of file holding section contents.  */
16633965Sjdp  const char *filename;
16733965Sjdp  /* Size of file.  */
16833965Sjdp  size_t size;
16933965Sjdp  /* Contents of file.  */
17033965Sjdp  bfd_byte *contents;
17133965Sjdp  /* BFD section, after it has been added.  */
17233965Sjdp  asection *section;
17333965Sjdp};
17433965Sjdp
17589857Sobrien/* List of sections to add to the output BFD.  */
17633965Sjdpstatic struct section_add *add_sections;
17733965Sjdp
178130561Sobrien/* If non-NULL the argument to --add-gnu-debuglink.
179130561Sobrien   This should be the filename to store in the .gnu_debuglink section.  */
180130561Sobrienstatic const char * gnu_debuglink_filename = NULL;
181130561Sobrien
18233965Sjdp/* Whether to convert debugging information.  */
183130561Sobrienstatic bfd_boolean convert_debugging = FALSE;
18433965Sjdp
18533965Sjdp/* Whether to change the leading character in symbol names.  */
186130561Sobrienstatic bfd_boolean change_leading_char = FALSE;
18733965Sjdp
18833965Sjdp/* Whether to remove the leading character from global symbol names.  */
189130561Sobrienstatic bfd_boolean remove_leading_char = FALSE;
19033965Sjdp
191130561Sobrien/* Whether to permit wildcard in symbol comparison.  */
192130561Sobrienstatic bfd_boolean wildcard = FALSE;
193130561Sobrien
194218822Sdim/* True if --localize-hidden is in effect.  */
195218822Sdimstatic bfd_boolean localize_hidden = FALSE;
196218822Sdim
19778828Sobrien/* List of symbols to strip, keep, localize, keep-global, weaken,
19878828Sobrien   or redefine.  */
19938889Sjdpstatic struct symlist *strip_specific_list = NULL;
200218822Sdimstatic struct symlist *strip_unneeded_list = NULL;
20138889Sjdpstatic struct symlist *keep_specific_list = NULL;
20238889Sjdpstatic struct symlist *localize_specific_list = NULL;
203218822Sdimstatic struct symlist *globalize_specific_list = NULL;
20478828Sobrienstatic struct symlist *keepglobal_specific_list = NULL;
20538889Sjdpstatic struct symlist *weaken_specific_list = NULL;
20660484Sobrienstatic struct redefine_node *redefine_sym_list = NULL;
20738889Sjdp
208130561Sobrien/* If this is TRUE, we weaken global symbols (set BSF_WEAK).  */
209130561Sobrienstatic bfd_boolean weaken = FALSE;
21038889Sjdp
211218822Sdim/* If this is TRUE, we retain BSF_FILE symbols.  */
212218822Sdimstatic bfd_boolean keep_file_symbols = FALSE;
213218822Sdim
214130561Sobrien/* Prefix symbols/sections.  */
215130561Sobrienstatic char *prefix_symbols_string = 0;
216130561Sobrienstatic char *prefix_sections_string = 0;
217130561Sobrienstatic char *prefix_alloc_sections_string = 0;
218130561Sobrien
219218822Sdim/* True if --extract-symbol was passed on the command line.  */
220218822Sdimstatic bfd_boolean extract_symbol = FALSE;
221218822Sdim
222218822Sdim/* If `reverse_bytes' is nonzero, then reverse the order of every chunk
223218822Sdim   of <reverse_bytes> bytes within each output section.  */
224218822Sdimstatic int reverse_bytes = 0;
225218822Sdim
226218822Sdim
22733965Sjdp/* 150 isn't special; it's just an arbitrary non-ASCII char value.  */
228130561Sobrienenum command_line_switch
229130561Sobrien  {
230130561Sobrien    OPTION_ADD_SECTION=150,
231130561Sobrien    OPTION_CHANGE_ADDRESSES,
232130561Sobrien    OPTION_CHANGE_LEADING_CHAR,
233130561Sobrien    OPTION_CHANGE_START,
234130561Sobrien    OPTION_CHANGE_SECTION_ADDRESS,
235130561Sobrien    OPTION_CHANGE_SECTION_LMA,
236130561Sobrien    OPTION_CHANGE_SECTION_VMA,
237130561Sobrien    OPTION_CHANGE_WARNINGS,
238130561Sobrien    OPTION_DEBUGGING,
239130561Sobrien    OPTION_GAP_FILL,
240130561Sobrien    OPTION_NO_CHANGE_WARNINGS,
241130561Sobrien    OPTION_PAD_TO,
242130561Sobrien    OPTION_REMOVE_LEADING_CHAR,
243130561Sobrien    OPTION_SET_SECTION_FLAGS,
244130561Sobrien    OPTION_SET_START,
245130561Sobrien    OPTION_STRIP_UNNEEDED,
246130561Sobrien    OPTION_WEAKEN,
247130561Sobrien    OPTION_REDEFINE_SYM,
248130561Sobrien    OPTION_REDEFINE_SYMS,
249130561Sobrien    OPTION_SREC_LEN,
250130561Sobrien    OPTION_SREC_FORCES3,
251130561Sobrien    OPTION_STRIP_SYMBOLS,
252218822Sdim    OPTION_STRIP_UNNEEDED_SYMBOL,
253218822Sdim    OPTION_STRIP_UNNEEDED_SYMBOLS,
254130561Sobrien    OPTION_KEEP_SYMBOLS,
255218822Sdim    OPTION_LOCALIZE_HIDDEN,
256130561Sobrien    OPTION_LOCALIZE_SYMBOLS,
257218822Sdim    OPTION_GLOBALIZE_SYMBOL,
258218822Sdim    OPTION_GLOBALIZE_SYMBOLS,
259130561Sobrien    OPTION_KEEPGLOBAL_SYMBOLS,
260130561Sobrien    OPTION_WEAKEN_SYMBOLS,
261130561Sobrien    OPTION_RENAME_SECTION,
262130561Sobrien    OPTION_ALT_MACH_CODE,
263130561Sobrien    OPTION_PREFIX_SYMBOLS,
264130561Sobrien    OPTION_PREFIX_SECTIONS,
265130561Sobrien    OPTION_PREFIX_ALLOC_SECTIONS,
266130561Sobrien    OPTION_FORMATS_INFO,
267130561Sobrien    OPTION_ADD_GNU_DEBUGLINK,
268130561Sobrien    OPTION_ONLY_KEEP_DEBUG,
269218822Sdim    OPTION_KEEP_FILE_SYMBOLS,
270130561Sobrien    OPTION_READONLY_TEXT,
271130561Sobrien    OPTION_WRITABLE_TEXT,
272130561Sobrien    OPTION_PURE,
273218822Sdim    OPTION_IMPURE,
274218822Sdim    OPTION_EXTRACT_SYMBOL,
275218822Sdim    OPTION_REVERSE_BYTES
276130561Sobrien  };
27733965Sjdp
27833965Sjdp/* Options to handle if running as "strip".  */
27933965Sjdp
28033965Sjdpstatic struct option strip_options[] =
28133965Sjdp{
28233965Sjdp  {"discard-all", no_argument, 0, 'x'},
28333965Sjdp  {"discard-locals", no_argument, 0, 'X'},
28433965Sjdp  {"format", required_argument, 0, 'F'}, /* Obsolete */
28533965Sjdp  {"help", no_argument, 0, 'h'},
286130561Sobrien  {"info", no_argument, 0, OPTION_FORMATS_INFO},
28733965Sjdp  {"input-format", required_argument, 0, 'I'}, /* Obsolete */
28833965Sjdp  {"input-target", required_argument, 0, 'I'},
289218822Sdim  {"keep-file-symbols", no_argument, 0, OPTION_KEEP_FILE_SYMBOLS},
29033965Sjdp  {"keep-symbol", required_argument, 0, 'K'},
291130561Sobrien  {"only-keep-debug", no_argument, 0, OPTION_ONLY_KEEP_DEBUG},
29233965Sjdp  {"output-format", required_argument, 0, 'O'},	/* Obsolete */
29333965Sjdp  {"output-target", required_argument, 0, 'O'},
29480016Sobrien  {"output-file", required_argument, 0, 'o'},
29533965Sjdp  {"preserve-dates", no_argument, 0, 'p'},
29633965Sjdp  {"remove-section", required_argument, 0, 'R'},
29733965Sjdp  {"strip-all", no_argument, 0, 's'},
29833965Sjdp  {"strip-debug", no_argument, 0, 'S'},
29933965Sjdp  {"strip-unneeded", no_argument, 0, OPTION_STRIP_UNNEEDED},
30033965Sjdp  {"strip-symbol", required_argument, 0, 'N'},
30133965Sjdp  {"target", required_argument, 0, 'F'},
30233965Sjdp  {"verbose", no_argument, 0, 'v'},
30333965Sjdp  {"version", no_argument, 0, 'V'},
304130561Sobrien  {"wildcard", no_argument, 0, 'w'},
30533965Sjdp  {0, no_argument, 0, 0}
30633965Sjdp};
30733965Sjdp
30833965Sjdp/* Options to handle if running as "objcopy".  */
30933965Sjdp
31033965Sjdpstatic struct option copy_options[] =
31133965Sjdp{
312130561Sobrien  {"add-gnu-debuglink", required_argument, 0, OPTION_ADD_GNU_DEBUGLINK},
31333965Sjdp  {"add-section", required_argument, 0, OPTION_ADD_SECTION},
31460484Sobrien  {"adjust-start", required_argument, 0, OPTION_CHANGE_START},
31560484Sobrien  {"adjust-vma", required_argument, 0, OPTION_CHANGE_ADDRESSES},
31660484Sobrien  {"adjust-section-vma", required_argument, 0, OPTION_CHANGE_SECTION_ADDRESS},
31760484Sobrien  {"adjust-warnings", no_argument, 0, OPTION_CHANGE_WARNINGS},
318130561Sobrien  {"alt-machine-code", required_argument, 0, OPTION_ALT_MACH_CODE},
31989857Sobrien  {"binary-architecture", required_argument, 0, 'B'},
32033965Sjdp  {"byte", required_argument, 0, 'b'},
32160484Sobrien  {"change-addresses", required_argument, 0, OPTION_CHANGE_ADDRESSES},
32233965Sjdp  {"change-leading-char", no_argument, 0, OPTION_CHANGE_LEADING_CHAR},
32360484Sobrien  {"change-section-address", required_argument, 0, OPTION_CHANGE_SECTION_ADDRESS},
32460484Sobrien  {"change-section-lma", required_argument, 0, OPTION_CHANGE_SECTION_LMA},
32560484Sobrien  {"change-section-vma", required_argument, 0, OPTION_CHANGE_SECTION_VMA},
32660484Sobrien  {"change-start", required_argument, 0, OPTION_CHANGE_START},
32760484Sobrien  {"change-warnings", no_argument, 0, OPTION_CHANGE_WARNINGS},
32833965Sjdp  {"debugging", no_argument, 0, OPTION_DEBUGGING},
32933965Sjdp  {"discard-all", no_argument, 0, 'x'},
33033965Sjdp  {"discard-locals", no_argument, 0, 'X'},
331218822Sdim  {"extract-symbol", no_argument, 0, OPTION_EXTRACT_SYMBOL},
33233965Sjdp  {"format", required_argument, 0, 'F'}, /* Obsolete */
33333965Sjdp  {"gap-fill", required_argument, 0, OPTION_GAP_FILL},
334218822Sdim  {"globalize-symbol", required_argument, 0, OPTION_GLOBALIZE_SYMBOL},
335218822Sdim  {"globalize-symbols", required_argument, 0, OPTION_GLOBALIZE_SYMBOLS},
33633965Sjdp  {"help", no_argument, 0, 'h'},
337130561Sobrien  {"impure", no_argument, 0, OPTION_IMPURE},
338130561Sobrien  {"info", no_argument, 0, OPTION_FORMATS_INFO},
33933965Sjdp  {"input-format", required_argument, 0, 'I'}, /* Obsolete */
34033965Sjdp  {"input-target", required_argument, 0, 'I'},
34133965Sjdp  {"interleave", required_argument, 0, 'i'},
342218822Sdim  {"keep-file-symbols", no_argument, 0, OPTION_KEEP_FILE_SYMBOLS},
343130561Sobrien  {"keep-global-symbol", required_argument, 0, 'G'},
344130561Sobrien  {"keep-global-symbols", required_argument, 0, OPTION_KEEPGLOBAL_SYMBOLS},
34533965Sjdp  {"keep-symbol", required_argument, 0, 'K'},
346130561Sobrien  {"keep-symbols", required_argument, 0, OPTION_KEEP_SYMBOLS},
347218822Sdim  {"localize-hidden", no_argument, 0, OPTION_LOCALIZE_HIDDEN},
348130561Sobrien  {"localize-symbol", required_argument, 0, 'L'},
349130561Sobrien  {"localize-symbols", required_argument, 0, OPTION_LOCALIZE_SYMBOLS},
35060484Sobrien  {"no-adjust-warnings", no_argument, 0, OPTION_NO_CHANGE_WARNINGS},
35160484Sobrien  {"no-change-warnings", no_argument, 0, OPTION_NO_CHANGE_WARNINGS},
352130561Sobrien  {"only-keep-debug", no_argument, 0, OPTION_ONLY_KEEP_DEBUG},
353130561Sobrien  {"only-section", required_argument, 0, 'j'},
35433965Sjdp  {"output-format", required_argument, 0, 'O'},	/* Obsolete */
35533965Sjdp  {"output-target", required_argument, 0, 'O'},
35633965Sjdp  {"pad-to", required_argument, 0, OPTION_PAD_TO},
357130561Sobrien  {"prefix-symbols", required_argument, 0, OPTION_PREFIX_SYMBOLS},
358130561Sobrien  {"prefix-sections", required_argument, 0, OPTION_PREFIX_SECTIONS},
359130561Sobrien  {"prefix-alloc-sections", required_argument, 0, OPTION_PREFIX_ALLOC_SECTIONS},
36033965Sjdp  {"preserve-dates", no_argument, 0, 'p'},
361130561Sobrien  {"pure", no_argument, 0, OPTION_PURE},
362130561Sobrien  {"readonly-text", no_argument, 0, OPTION_READONLY_TEXT},
363130561Sobrien  {"redefine-sym", required_argument, 0, OPTION_REDEFINE_SYM},
364130561Sobrien  {"redefine-syms", required_argument, 0, OPTION_REDEFINE_SYMS},
36533965Sjdp  {"remove-leading-char", no_argument, 0, OPTION_REMOVE_LEADING_CHAR},
36633965Sjdp  {"remove-section", required_argument, 0, 'R'},
36789857Sobrien  {"rename-section", required_argument, 0, OPTION_RENAME_SECTION},
368218822Sdim  {"reverse-bytes", required_argument, 0, OPTION_REVERSE_BYTES},
36933965Sjdp  {"set-section-flags", required_argument, 0, OPTION_SET_SECTION_FLAGS},
37033965Sjdp  {"set-start", required_argument, 0, OPTION_SET_START},
371130561Sobrien  {"srec-len", required_argument, 0, OPTION_SREC_LEN},
372130561Sobrien  {"srec-forceS3", no_argument, 0, OPTION_SREC_FORCES3},
37333965Sjdp  {"strip-all", no_argument, 0, 'S'},
37433965Sjdp  {"strip-debug", no_argument, 0, 'g'},
37533965Sjdp  {"strip-unneeded", no_argument, 0, OPTION_STRIP_UNNEEDED},
376218822Sdim  {"strip-unneeded-symbol", required_argument, 0, OPTION_STRIP_UNNEEDED_SYMBOL},
377218822Sdim  {"strip-unneeded-symbols", required_argument, 0, OPTION_STRIP_UNNEEDED_SYMBOLS},
37833965Sjdp  {"strip-symbol", required_argument, 0, 'N'},
379130561Sobrien  {"strip-symbols", required_argument, 0, OPTION_STRIP_SYMBOLS},
38033965Sjdp  {"target", required_argument, 0, 'F'},
38133965Sjdp  {"verbose", no_argument, 0, 'v'},
38233965Sjdp  {"version", no_argument, 0, 'V'},
38333965Sjdp  {"weaken", no_argument, 0, OPTION_WEAKEN},
38438889Sjdp  {"weaken-symbol", required_argument, 0, 'W'},
38578828Sobrien  {"weaken-symbols", required_argument, 0, OPTION_WEAKEN_SYMBOLS},
386130561Sobrien  {"wildcard", no_argument, 0, 'w'},
387130561Sobrien  {"writable-text", no_argument, 0, OPTION_WRITABLE_TEXT},
38833965Sjdp  {0, no_argument, 0, 0}
38933965Sjdp};
39033965Sjdp
39133965Sjdp/* IMPORTS */
39233965Sjdpextern char *program_name;
39333965Sjdp
39433965Sjdp/* This flag distinguishes between strip and objcopy:
39533965Sjdp   1 means this is 'strip'; 0 means this is 'objcopy'.
396104834Sobrien   -1 means if we should use argv[0] to decide.  */
39733965Sjdpextern int is_strip;
39833965Sjdp
39977298Sobrien/* The maximum length of an S record.  This variable is declared in srec.c
40077298Sobrien   and can be modified by the --srec-len parameter.  */
40177298Sobrienextern unsigned int Chunk;
40233965Sjdp
40377298Sobrien/* Restrict the generation of Srecords to type S3 only.
40477298Sobrien   This variable is declare in bfd/srec.c and can be toggled
40577298Sobrien   on by the --srec-forceS3 command line switch.  */
406130561Sobrienextern bfd_boolean S3Forced;
40777298Sobrien
408130561Sobrien/* Defined in bfd/binary.c.  Used to set architecture and machine of input
409130561Sobrien   binary files.  */
410130561Sobrienextern enum bfd_architecture  bfd_external_binary_architecture;
411130561Sobrienextern unsigned long          bfd_external_machine;
41289857Sobrien
413130561Sobrien/* Forward declarations.  */
414130561Sobrienstatic void setup_section (bfd *, asection *, void *);
415218822Sdimstatic void setup_bfd_headers (bfd *, bfd *);
416130561Sobrienstatic void copy_section (bfd *, asection *, void *);
417130561Sobrienstatic void get_sections (bfd *, asection *, void *);
418130561Sobrienstatic int compare_section_lma (const void *, const void *);
419130561Sobrienstatic void mark_symbols_used_in_relocations (bfd *, asection *, void *);
420130561Sobrienstatic bfd_boolean write_debugging_info (bfd *, void *, long *, asymbol ***);
421130561Sobrienstatic const char *lookup_sym_redefinition (const char *);
42289857Sobrien
42333965Sjdpstatic void
424130561Sobriencopy_usage (FILE *stream, int exit_status)
42533965Sjdp{
42689857Sobrien  fprintf (stream, _("Usage: %s [option(s)] in-file [out-file]\n"), program_name);
42789857Sobrien  fprintf (stream, _(" Copies a binary file, possibly transforming it in the process\n"));
42889857Sobrien  fprintf (stream, _(" The options are:\n"));
42960484Sobrien  fprintf (stream, _("\
43060484Sobrien  -I --input-target <bfdname>      Assume input file is in format <bfdname>\n\
43160484Sobrien  -O --output-target <bfdname>     Create an output file in format <bfdname>\n\
43289857Sobrien  -B --binary-architecture <arch>  Set arch of output file, when input is binary\n\
43360484Sobrien  -F --target <bfdname>            Set both input and output format to <bfdname>\n\
43460484Sobrien     --debugging                   Convert debugging information, if possible\n\
43560484Sobrien  -p --preserve-dates              Copy modified/access timestamps to the output\n\
43660484Sobrien  -j --only-section <name>         Only copy section <name> into the output\n\
437130561Sobrien     --add-gnu-debuglink=<file>    Add section .gnu_debuglink linking to <file>\n\
43860484Sobrien  -R --remove-section <name>       Remove section <name> from the output\n\
43960484Sobrien  -S --strip-all                   Remove all symbol and relocation information\n\
440130561Sobrien  -g --strip-debug                 Remove all debugging symbols & sections\n\
44160484Sobrien     --strip-unneeded              Remove all symbols not needed by relocations\n\
44260484Sobrien  -N --strip-symbol <name>         Do not copy symbol <name>\n\
443218822Sdim     --strip-unneeded-symbol <name>\n\
444218822Sdim                                   Do not copy symbol <name> unless needed by\n\
445218822Sdim                                     relocations\n\
446130561Sobrien     --only-keep-debug             Strip everything but the debug information\n\
447218822Sdim     --extract-symbol              Remove section contents but keep symbols\n\
448218822Sdim  -K --keep-symbol <name>          Do not strip symbol <name>\n\
449218822Sdim     --keep-file-symbols           Do not strip file symbol(s)\n\
450218822Sdim     --localize-hidden             Turn all ELF hidden symbols into locals\n\
45160484Sobrien  -L --localize-symbol <name>      Force symbol <name> to be marked as a local\n\
452218822Sdim     --globalize-symbol <name>     Force symbol <name> to be marked as a global\n\
45378828Sobrien  -G --keep-global-symbol <name>   Localize all symbols except <name>\n\
45460484Sobrien  -W --weaken-symbol <name>        Force symbol <name> to be marked as a weak\n\
45560484Sobrien     --weaken                      Force all global symbols to be marked as weak\n\
456218822Sdim  -w --wildcard                    Permit wildcard in symbol comparison\n\
45760484Sobrien  -x --discard-all                 Remove all non-global symbols\n\
45860484Sobrien  -X --discard-locals              Remove any compiler-generated symbols\n\
45960484Sobrien  -i --interleave <number>         Only copy one out of every <number> bytes\n\
46060484Sobrien  -b --byte <num>                  Select byte <num> in every interleaved block\n\
46160484Sobrien     --gap-fill <val>              Fill gaps between sections with <val>\n\
46260484Sobrien     --pad-to <addr>               Pad the last section up to address <addr>\n\
46360484Sobrien     --set-start <addr>            Set the start address to <addr>\n\
46460484Sobrien    {--change-start|--adjust-start} <incr>\n\
46560484Sobrien                                   Add <incr> to the start address\n\
46660484Sobrien    {--change-addresses|--adjust-vma} <incr>\n\
46760484Sobrien                                   Add <incr> to LMA, VMA and start addresses\n\
46860484Sobrien    {--change-section-address|--adjust-section-vma} <name>{=|+|-}<val>\n\
46960484Sobrien                                   Change LMA and VMA of section <name> by <val>\n\
47060484Sobrien     --change-section-lma <name>{=|+|-}<val>\n\
47160484Sobrien                                   Change the LMA of section <name> by <val>\n\
47260484Sobrien     --change-section-vma <name>{=|+|-}<val>\n\
47360484Sobrien                                   Change the VMA of section <name> by <val>\n\
47460484Sobrien    {--[no-]change-warnings|--[no-]adjust-warnings}\n\
47560484Sobrien                                   Warn if a named section does not exist\n\
47660484Sobrien     --set-section-flags <name>=<flags>\n\
47760484Sobrien                                   Set section <name>'s properties to <flags>\n\
47860484Sobrien     --add-section <name>=<file>   Add section <name> found in <file> to output\n\
47989857Sobrien     --rename-section <old>=<new>[,<flags>] Rename section <old> to <new>\n\
48060484Sobrien     --change-leading-char         Force output format's leading character style\n\
48160484Sobrien     --remove-leading-char         Remove leading character from global symbols\n\
482218822Sdim     --reverse-bytes=<num>         Reverse <num> bytes at a time, in output sections with content\n\
48360484Sobrien     --redefine-sym <old>=<new>    Redefine symbol name <old> to <new>\n\
484130561Sobrien     --redefine-syms <file>        --redefine-sym for all symbol pairs \n\
485130561Sobrien                                     listed in <file>\n\
48677298Sobrien     --srec-len <number>           Restrict the length of generated Srecords\n\
48777298Sobrien     --srec-forceS3                Restrict the type of generated Srecords to S3\n\
48878828Sobrien     --strip-symbols <file>        -N for all symbols listed in <file>\n\
489218822Sdim     --strip-unneeded-symbols <file>\n\
490218822Sdim                                   --strip-unneeded-symbol for all symbols listed\n\
491218822Sdim                                     in <file>\n\
49278828Sobrien     --keep-symbols <file>         -K for all symbols listed in <file>\n\
49378828Sobrien     --localize-symbols <file>     -L for all symbols listed in <file>\n\
494218822Sdim     --globalize-symbols <file>    --globalize-symbol for all in <file>\n\
49578828Sobrien     --keep-global-symbols <file>  -G for all symbols listed in <file>\n\
49678828Sobrien     --weaken-symbols <file>       -W for all symbols listed in <file>\n\
497218822Sdim     --alt-machine-code <index>    Use the target's <index>'th alternative machine\n\
498130561Sobrien     --writable-text               Mark the output text as writable\n\
499130561Sobrien     --readonly-text               Make the output text write protected\n\
500130561Sobrien     --pure                        Mark the output file as demand paged\n\
501130561Sobrien     --impure                      Mark the output file as impure\n\
502130561Sobrien     --prefix-symbols <prefix>     Add <prefix> to start of every symbol name\n\
503130561Sobrien     --prefix-sections <prefix>    Add <prefix> to start of every section name\n\
504130561Sobrien     --prefix-alloc-sections <prefix>\n\
505130561Sobrien                                   Add <prefix> to start of every allocatable\n\
506130561Sobrien                                     section name\n\
50760484Sobrien  -v --verbose                     List all object files modified\n\
508218822Sdim  @<file>                          Read options from <file>\n\
50960484Sobrien  -V --version                     Display this program's version number\n\
51060484Sobrien  -h --help                        Display this output\n\
511130561Sobrien     --info                        List object formats & architectures supported\n\
51260484Sobrien"));
51333965Sjdp  list_supported_targets (program_name, stream);
514218822Sdim  if (REPORT_BUGS_TO[0] && exit_status == 0)
51560484Sobrien    fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
51633965Sjdp  exit (exit_status);
51733965Sjdp}
51833965Sjdp
51933965Sjdpstatic void
520130561Sobrienstrip_usage (FILE *stream, int exit_status)
52133965Sjdp{
52289857Sobrien  fprintf (stream, _("Usage: %s <option(s)> in-file(s)\n"), program_name);
52389857Sobrien  fprintf (stream, _(" Removes symbols and sections from files\n"));
52489857Sobrien  fprintf (stream, _(" The options are:\n"));
52560484Sobrien  fprintf (stream, _("\
52689857Sobrien  -I --input-target=<bfdname>      Assume input file is in format <bfdname>\n\
52789857Sobrien  -O --output-target=<bfdname>     Create an output file in format <bfdname>\n\
52889857Sobrien  -F --target=<bfdname>            Set both input and output format to <bfdname>\n\
52960484Sobrien  -p --preserve-dates              Copy modified/access timestamps to the output\n\
53089857Sobrien  -R --remove-section=<name>       Remove section <name> from the output\n\
53160484Sobrien  -s --strip-all                   Remove all symbol and relocation information\n\
532130561Sobrien  -g -S -d --strip-debug           Remove all debugging symbols & sections\n\
53360484Sobrien     --strip-unneeded              Remove all symbols not needed by relocations\n\
534130561Sobrien     --only-keep-debug             Strip everything but the debug information\n\
53589857Sobrien  -N --strip-symbol=<name>         Do not copy symbol <name>\n\
536218822Sdim  -K --keep-symbol=<name>          Do not strip symbol <name>\n\
537218822Sdim     --keep-file-symbols           Do not strip file symbol(s)\n\
538218822Sdim  -w --wildcard                    Permit wildcard in symbol comparison\n\
53960484Sobrien  -x --discard-all                 Remove all non-global symbols\n\
54060484Sobrien  -X --discard-locals              Remove any compiler-generated symbols\n\
54160484Sobrien  -v --verbose                     List all object files modified\n\
54260484Sobrien  -V --version                     Display this program's version number\n\
54360484Sobrien  -h --help                        Display this output\n\
544130561Sobrien     --info                        List object formats & architectures supported\n\
54560484Sobrien  -o <file>                        Place stripped output into <file>\n\
54660484Sobrien"));
54760484Sobrien
54833965Sjdp  list_supported_targets (program_name, stream);
549218822Sdim  if (REPORT_BUGS_TO[0] && exit_status == 0)
55060484Sobrien    fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
55133965Sjdp  exit (exit_status);
55233965Sjdp}
55333965Sjdp
55433965Sjdp/* Parse section flags into a flagword, with a fatal error if the
55533965Sjdp   string can't be parsed.  */
55633965Sjdp
55733965Sjdpstatic flagword
558130561Sobrienparse_flags (const char *s)
55933965Sjdp{
56033965Sjdp  flagword ret;
56133965Sjdp  const char *snext;
56233965Sjdp  int len;
56333965Sjdp
56433965Sjdp  ret = SEC_NO_FLAGS;
56533965Sjdp
56633965Sjdp  do
56733965Sjdp    {
56833965Sjdp      snext = strchr (s, ',');
56933965Sjdp      if (snext == NULL)
57033965Sjdp	len = strlen (s);
57133965Sjdp      else
57233965Sjdp	{
57333965Sjdp	  len = snext - s;
57433965Sjdp	  ++snext;
57533965Sjdp	}
57633965Sjdp
57738889Sjdp      if (0) ;
57838889Sjdp#define PARSE_FLAG(fname,fval) \
57938889Sjdp  else if (strncasecmp (fname, s, len) == 0) ret |= fval
58033965Sjdp      PARSE_FLAG ("alloc", SEC_ALLOC);
58133965Sjdp      PARSE_FLAG ("load", SEC_LOAD);
58260484Sobrien      PARSE_FLAG ("noload", SEC_NEVER_LOAD);
58333965Sjdp      PARSE_FLAG ("readonly", SEC_READONLY);
58460484Sobrien      PARSE_FLAG ("debug", SEC_DEBUGGING);
58533965Sjdp      PARSE_FLAG ("code", SEC_CODE);
58633965Sjdp      PARSE_FLAG ("data", SEC_DATA);
58733965Sjdp      PARSE_FLAG ("rom", SEC_ROM);
588218822Sdim      PARSE_FLAG ("share", SEC_COFF_SHARED);
58938889Sjdp      PARSE_FLAG ("contents", SEC_HAS_CONTENTS);
59033965Sjdp#undef PARSE_FLAG
59138889Sjdp      else
59238889Sjdp	{
59338889Sjdp	  char *copy;
59433965Sjdp
59538889Sjdp	  copy = xmalloc (len + 1);
59638889Sjdp	  strncpy (copy, s, len);
59738889Sjdp	  copy[len] = '\0';
59860484Sobrien	  non_fatal (_("unrecognized section flag `%s'"), copy);
59960484Sobrien	  fatal (_("supported flags: %s"),
60060484Sobrien		 "alloc, load, noload, readonly, debug, code, data, rom, share, contents");
60138889Sjdp	}
60238889Sjdp
60333965Sjdp      s = snext;
60433965Sjdp    }
60533965Sjdp  while (s != NULL);
60633965Sjdp
60733965Sjdp  return ret;
60833965Sjdp}
60933965Sjdp
61060484Sobrien/* Find and optionally add an entry in the change_sections list.  */
61133965Sjdp
61233965Sjdpstatic struct section_list *
613130561Sobrienfind_section_list (const char *name, bfd_boolean add)
61433965Sjdp{
615130561Sobrien  struct section_list *p;
61633965Sjdp
61760484Sobrien  for (p = change_sections; p != NULL; p = p->next)
61833965Sjdp    if (strcmp (p->name, name) == 0)
61933965Sjdp      return p;
62033965Sjdp
62133965Sjdp  if (! add)
62233965Sjdp    return NULL;
62333965Sjdp
624130561Sobrien  p = xmalloc (sizeof (struct section_list));
62533965Sjdp  p->name = name;
626130561Sobrien  p->used = FALSE;
627130561Sobrien  p->remove = FALSE;
628130561Sobrien  p->copy = FALSE;
62960484Sobrien  p->change_vma = CHANGE_IGNORE;
63060484Sobrien  p->change_lma = CHANGE_IGNORE;
63160484Sobrien  p->vma_val = 0;
63260484Sobrien  p->lma_val = 0;
633130561Sobrien  p->set_flags = FALSE;
63433965Sjdp  p->flags = 0;
63533965Sjdp
63660484Sobrien  p->next = change_sections;
63760484Sobrien  change_sections = p;
63833965Sjdp
63933965Sjdp  return p;
64033965Sjdp}
64133965Sjdp
64233965Sjdp/* Add a symbol to strip_specific_list.  */
64333965Sjdp
64460484Sobrienstatic void
645130561Sobrienadd_specific_symbol (const char *name, struct symlist **list)
64633965Sjdp{
64733965Sjdp  struct symlist *tmp_list;
64833965Sjdp
649130561Sobrien  tmp_list = xmalloc (sizeof (struct symlist));
65033965Sjdp  tmp_list->name = name;
65138889Sjdp  tmp_list->next = *list;
65238889Sjdp  *list = tmp_list;
65333965Sjdp}
65433965Sjdp
655104834Sobrien/* Add symbols listed in `filename' to strip_specific_list.  */
65678828Sobrien
65778828Sobrien#define IS_WHITESPACE(c)      ((c) == ' ' || (c) == '\t')
65878828Sobrien#define IS_LINE_TERMINATOR(c) ((c) == '\n' || (c) == '\r' || (c) == '\0')
65978828Sobrien
66078828Sobrienstatic void
661130561Sobrienadd_specific_symbols (const char *filename, struct symlist **list)
66278828Sobrien{
663130561Sobrien  off_t  size;
66478828Sobrien  FILE * f;
66578828Sobrien  char * line;
66678828Sobrien  char * buffer;
66778828Sobrien  unsigned int line_count;
668104834Sobrien
669130561Sobrien  size = get_file_size (filename);
670130561Sobrien  if (size == 0)
671218822Sdim    {
672218822Sdim      status = 1;
673218822Sdim      return;
674218822Sdim    }
67578828Sobrien
676130561Sobrien  buffer = xmalloc (size + 2);
67778828Sobrien  f = fopen (filename, FOPEN_RT);
67878828Sobrien  if (f == NULL)
679130561Sobrien    fatal (_("cannot open '%s': %s"), filename, strerror (errno));
68078828Sobrien
681130561Sobrien  if (fread (buffer, 1, size, f) == 0 || ferror (f))
68278828Sobrien    fatal (_("%s: fread failed"), filename);
68378828Sobrien
68478828Sobrien  fclose (f);
685130561Sobrien  buffer [size] = '\n';
686130561Sobrien  buffer [size + 1] = '\0';
68778828Sobrien
68878828Sobrien  line_count = 1;
689104834Sobrien
69078828Sobrien  for (line = buffer; * line != '\0'; line ++)
69178828Sobrien    {
69278828Sobrien      char * eol;
69378828Sobrien      char * name;
69478828Sobrien      char * name_end;
695130561Sobrien      int finished = FALSE;
69678828Sobrien
69778828Sobrien      for (eol = line;; eol ++)
69878828Sobrien	{
69978828Sobrien	  switch (* eol)
70078828Sobrien	    {
70178828Sobrien	    case '\n':
70278828Sobrien	      * eol = '\0';
70378828Sobrien	      /* Cope with \n\r.  */
70478828Sobrien	      if (eol[1] == '\r')
70578828Sobrien		++ eol;
706130561Sobrien	      finished = TRUE;
70778828Sobrien	      break;
708104834Sobrien
70978828Sobrien	    case '\r':
71078828Sobrien	      * eol = '\0';
71178828Sobrien	      /* Cope with \r\n.  */
71278828Sobrien	      if (eol[1] == '\n')
71378828Sobrien		++ eol;
714130561Sobrien	      finished = TRUE;
71578828Sobrien	      break;
716104834Sobrien
71778828Sobrien	    case 0:
718130561Sobrien	      finished = TRUE;
71978828Sobrien	      break;
720104834Sobrien
72178828Sobrien	    case '#':
72278828Sobrien	      /* Line comment, Terminate the line here, in case a
72378828Sobrien		 name is present and then allow the rest of the
72478828Sobrien		 loop to find the real end of the line.  */
72578828Sobrien	      * eol = '\0';
72678828Sobrien	      break;
727104834Sobrien
72878828Sobrien	    default:
72978828Sobrien	      break;
73078828Sobrien	    }
73178828Sobrien
73278828Sobrien	  if (finished)
73378828Sobrien	    break;
73478828Sobrien	}
73578828Sobrien
73678828Sobrien      /* A name may now exist somewhere between 'line' and 'eol'.
73778828Sobrien	 Strip off leading whitespace and trailing whitespace,
73878828Sobrien	 then add it to the list.  */
73978828Sobrien      for (name = line; IS_WHITESPACE (* name); name ++)
74078828Sobrien	;
74178828Sobrien      for (name_end = name;
74278828Sobrien	   (! IS_WHITESPACE (* name_end))
74378828Sobrien	   && (! IS_LINE_TERMINATOR (* name_end));
744104834Sobrien	   name_end ++)
745104834Sobrien	;
74678828Sobrien
74778828Sobrien      if (! IS_LINE_TERMINATOR (* name_end))
74878828Sobrien	{
74978828Sobrien	  char * extra;
75078828Sobrien
75178828Sobrien	  for (extra = name_end + 1; IS_WHITESPACE (* extra); extra ++)
75278828Sobrien	    ;
75378828Sobrien
75478828Sobrien	  if (! IS_LINE_TERMINATOR (* extra))
755218822Sdim	    non_fatal (_("%s:%d: Ignoring rubbish found on this line"),
756218822Sdim		       filename, line_count);
75778828Sobrien	}
758104834Sobrien
75978828Sobrien      * name_end = '\0';
76078828Sobrien
76178828Sobrien      if (name_end > name)
76278828Sobrien	add_specific_symbol (name, list);
76378828Sobrien
76478828Sobrien      /* Advance line pointer to end of line.  The 'eol ++' in the for
76578828Sobrien	 loop above will then advance us to the start of the next line.  */
76678828Sobrien      line = eol;
76778828Sobrien      line_count ++;
76878828Sobrien    }
76978828Sobrien}
77078828Sobrien
77133965Sjdp/* See whether a symbol should be stripped or kept based on
77233965Sjdp   strip_specific_list and keep_symbols.  */
77333965Sjdp
774130561Sobrienstatic bfd_boolean
775130561Sobrienis_specified_symbol (const char *name, struct symlist *list)
77633965Sjdp{
77733965Sjdp  struct symlist *tmp_list;
77833965Sjdp
779130561Sobrien  if (wildcard)
780130561Sobrien    {
781130561Sobrien      for (tmp_list = list; tmp_list; tmp_list = tmp_list->next)
782130561Sobrien	if (*(tmp_list->name) != '!')
783130561Sobrien	  {
784130561Sobrien	    if (!fnmatch (tmp_list->name, name, 0))
785130561Sobrien	      return TRUE;
786130561Sobrien	  }
787130561Sobrien	else
788130561Sobrien	  {
789130561Sobrien	    if (fnmatch (tmp_list->name + 1, name, 0))
790130561Sobrien	      return TRUE;
791130561Sobrien	  }
792130561Sobrien    }
793130561Sobrien  else
794130561Sobrien    {
795130561Sobrien      for (tmp_list = list; tmp_list; tmp_list = tmp_list->next)
796130561Sobrien	if (strcmp (name, tmp_list->name) == 0)
797130561Sobrien	  return TRUE;
798130561Sobrien    }
79989857Sobrien
800130561Sobrien  return FALSE;
80133965Sjdp}
80233965Sjdp
803218822Sdim/* Return a pointer to the symbol used as a signature for GROUP.  */
804218822Sdim
805218822Sdimstatic asymbol *
806218822Sdimgroup_signature (asection *group)
807218822Sdim{
808218822Sdim  bfd *abfd = group->owner;
809218822Sdim  Elf_Internal_Shdr *ghdr;
810218822Sdim
811218822Sdim  if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
812218822Sdim    return NULL;
813218822Sdim
814218822Sdim  ghdr = &elf_section_data (group)->this_hdr;
815218822Sdim  if (ghdr->sh_link < elf_numsections (abfd))
816218822Sdim    {
817218822Sdim      const struct elf_backend_data *bed = get_elf_backend_data (abfd);
818218822Sdim      Elf_Internal_Shdr *symhdr = elf_elfsections (abfd) [ghdr->sh_link];
819218822Sdim
820218822Sdim      if (symhdr->sh_type == SHT_SYMTAB
821218822Sdim	  && ghdr->sh_info < symhdr->sh_size / bed->s->sizeof_sym)
822218822Sdim	return isympp[ghdr->sh_info - 1];
823218822Sdim    }
824218822Sdim  return NULL;
825218822Sdim}
826218822Sdim
82733965Sjdp/* See if a section is being removed.  */
82833965Sjdp
829130561Sobrienstatic bfd_boolean
830130561Sobrienis_strip_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
83133965Sjdp{
832130561Sobrien  if (sections_removed || sections_copied)
833130561Sobrien    {
834130561Sobrien      struct section_list *p;
83533965Sjdp
836130561Sobrien      p = find_section_list (bfd_get_section_name (abfd, sec), FALSE);
837130561Sobrien
838130561Sobrien      if (sections_removed && p != NULL && p->remove)
839130561Sobrien	return TRUE;
840130561Sobrien      if (sections_copied && (p == NULL || ! p->copy))
841130561Sobrien	return TRUE;
842130561Sobrien    }
843130561Sobrien
844130561Sobrien  if ((bfd_get_section_flags (abfd, sec) & SEC_DEBUGGING) != 0)
845130561Sobrien    {
846130561Sobrien      if (strip_symbols == STRIP_DEBUG
84760484Sobrien	  || strip_symbols == STRIP_UNNEEDED
84860484Sobrien	  || strip_symbols == STRIP_ALL
84960484Sobrien	  || discard_locals == LOCALS_ALL
850130561Sobrien	  || convert_debugging)
851130561Sobrien	return TRUE;
85233965Sjdp
853130561Sobrien      if (strip_symbols == STRIP_NONDEBUG)
854130561Sobrien	return FALSE;
855130561Sobrien    }
85660484Sobrien
857218822Sdim  if ((bfd_get_section_flags (abfd, sec) & SEC_GROUP) != 0)
858218822Sdim    {
859218822Sdim      asymbol *gsym;
860218822Sdim      const char *gname;
861218822Sdim
862218822Sdim      /* PR binutils/3166
863218822Sdim	 Group sections look like debugging sections but they are not.
864218822Sdim	 (They have a non-zero size but they are not ALLOCated).  */
865218822Sdim      if (strip_symbols == STRIP_NONDEBUG)
866218822Sdim	return TRUE;
867218822Sdim
868218822Sdim      /* PR binutils/3181
869218822Sdim	 If we are going to strip the group signature symbol, then
870218822Sdim	 strip the group section too.  */
871218822Sdim      gsym = group_signature (sec);
872218822Sdim      if (gsym != NULL)
873218822Sdim	gname = gsym->name;
874218822Sdim      else
875218822Sdim	gname = sec->name;
876218822Sdim      if ((strip_symbols == STRIP_ALL
877218822Sdim	   && !is_specified_symbol (gname, keep_specific_list))
878218822Sdim	  || is_specified_symbol (gname, strip_specific_list))
879218822Sdim	return TRUE;
880218822Sdim    }
881218822Sdim
882130561Sobrien  return FALSE;
88333965Sjdp}
88433965Sjdp
885218822Sdim/* Return true if SYM is a hidden symbol.  */
886218822Sdim
887218822Sdimstatic bfd_boolean
888218822Sdimis_hidden_symbol (asymbol *sym)
889218822Sdim{
890218822Sdim  elf_symbol_type *elf_sym;
891218822Sdim
892218822Sdim  elf_sym = elf_symbol_from (sym->the_bfd, sym);
893218822Sdim  if (elf_sym != NULL)
894218822Sdim    switch (ELF_ST_VISIBILITY (elf_sym->internal_elf_sym.st_other))
895218822Sdim      {
896218822Sdim      case STV_HIDDEN:
897218822Sdim      case STV_INTERNAL:
898218822Sdim	return TRUE;
899218822Sdim      }
900218822Sdim  return FALSE;
901218822Sdim}
902218822Sdim
90333965Sjdp/* Choose which symbol entries to copy; put the result in OSYMS.
90433965Sjdp   We don't copy in place, because that confuses the relocs.
90533965Sjdp   Return the number of symbols to print.  */
90633965Sjdp
90733965Sjdpstatic unsigned int
908130561Sobrienfilter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms,
909130561Sobrien		asymbol **isyms, long symcount)
91033965Sjdp{
911130561Sobrien  asymbol **from = isyms, **to = osyms;
91233965Sjdp  long src_count = 0, dst_count = 0;
913218822Sdim  int relocatable = (abfd->flags & (EXEC_P | DYNAMIC)) == 0;
91433965Sjdp
91533965Sjdp  for (; src_count < symcount; src_count++)
91633965Sjdp    {
91733965Sjdp      asymbol *sym = from[src_count];
91833965Sjdp      flagword flags = sym->flags;
919130561Sobrien      char *name = (char *) bfd_asymbol_name (sym);
920218822Sdim      bfd_boolean keep;
921218822Sdim      bfd_boolean used_in_reloc = FALSE;
922130561Sobrien      bfd_boolean undefined;
923130561Sobrien      bfd_boolean rem_leading_char;
924130561Sobrien      bfd_boolean add_leading_char;
92533965Sjdp
926130561Sobrien      undefined = bfd_is_und_section (bfd_get_section (sym));
927130561Sobrien
92860484Sobrien      if (redefine_sym_list)
92960484Sobrien	{
930130561Sobrien	  char *old_name, *new_name;
93160484Sobrien
932130561Sobrien	  old_name = (char *) bfd_asymbol_name (sym);
933130561Sobrien	  new_name = (char *) lookup_sym_redefinition (old_name);
934130561Sobrien	  bfd_asymbol_name (sym) = new_name;
935130561Sobrien	  name = new_name;
93660484Sobrien	}
93760484Sobrien
938130561Sobrien      /* Check if we will remove the current leading character.  */
939130561Sobrien      rem_leading_char =
940130561Sobrien	(name[0] == bfd_get_symbol_leading_char (abfd))
941130561Sobrien	&& (change_leading_char
942130561Sobrien	    || (remove_leading_char
943130561Sobrien		&& ((flags & (BSF_GLOBAL | BSF_WEAK)) != 0
944130561Sobrien		    || undefined
945130561Sobrien		    || bfd_is_com_section (bfd_get_section (sym)))));
94633965Sjdp
947130561Sobrien      /* Check if we will add a new leading character.  */
948130561Sobrien      add_leading_char =
949130561Sobrien	change_leading_char
950130561Sobrien	&& (bfd_get_symbol_leading_char (obfd) != '\0')
951130561Sobrien	&& (bfd_get_symbol_leading_char (abfd) == '\0'
952130561Sobrien	    || (name[0] == bfd_get_symbol_leading_char (abfd)));
95333965Sjdp
954130561Sobrien      /* Short circuit for change_leading_char if we can do it in-place.  */
955130561Sobrien      if (rem_leading_char && add_leading_char && !prefix_symbols_string)
956130561Sobrien        {
957130561Sobrien	  name[0] = bfd_get_symbol_leading_char (obfd);
958130561Sobrien	  bfd_asymbol_name (sym) = name;
959130561Sobrien	  rem_leading_char = FALSE;
960130561Sobrien	  add_leading_char = FALSE;
961130561Sobrien        }
96289857Sobrien
963130561Sobrien      /* Remove leading char.  */
964130561Sobrien      if (rem_leading_char)
965130561Sobrien	bfd_asymbol_name (sym) = ++name;
96633965Sjdp
967130561Sobrien      /* Add new leading char and/or prefix.  */
968130561Sobrien      if (add_leading_char || prefix_symbols_string)
969130561Sobrien        {
970130561Sobrien          char *n, *ptr;
971130561Sobrien
972130561Sobrien          ptr = n = xmalloc (1 + strlen (prefix_symbols_string)
973130561Sobrien			     + strlen (name) + 1);
974130561Sobrien          if (add_leading_char)
975130561Sobrien	    *ptr++ = bfd_get_symbol_leading_char (obfd);
976130561Sobrien
977130561Sobrien          if (prefix_symbols_string)
978130561Sobrien            {
979130561Sobrien              strcpy (ptr, prefix_symbols_string);
980130561Sobrien              ptr += strlen (prefix_symbols_string);
981130561Sobrien           }
982130561Sobrien
983130561Sobrien          strcpy (ptr, name);
984130561Sobrien          bfd_asymbol_name (sym) = n;
985130561Sobrien          name = n;
986130561Sobrien	}
987130561Sobrien
98860484Sobrien      if (strip_symbols == STRIP_ALL)
989218822Sdim	keep = FALSE;
99060484Sobrien      else if ((flags & BSF_KEEP) != 0		/* Used in relocation.  */
99160484Sobrien	       || ((flags & BSF_SECTION_SYM) != 0
99260484Sobrien		   && ((*bfd_get_section (sym)->symbol_ptr_ptr)->flags
99360484Sobrien		       & BSF_KEEP) != 0))
994218822Sdim	{
995218822Sdim	  keep = TRUE;
996218822Sdim	  used_in_reloc = TRUE;
997218822Sdim	}
998104834Sobrien      else if (relocatable			/* Relocatable file.  */
99977298Sobrien	       && (flags & (BSF_GLOBAL | BSF_WEAK)) != 0)
1000218822Sdim	keep = TRUE;
100178828Sobrien      else if (bfd_decode_symclass (sym) == 'I')
100278828Sobrien	/* Global symbols in $idata sections need to be retained
1003130561Sobrien	   even if relocatable is FALSE.  External users of the
100478828Sobrien	   library containing the $idata section may reference these
100578828Sobrien	   symbols.  */
1006218822Sdim	keep = TRUE;
100733965Sjdp      else if ((flags & BSF_GLOBAL) != 0	/* Global symbol.  */
100833965Sjdp	       || (flags & BSF_WEAK) != 0
100989857Sobrien	       || undefined
101033965Sjdp	       || bfd_is_com_section (bfd_get_section (sym)))
101160484Sobrien	keep = strip_symbols != STRIP_UNNEEDED;
101233965Sjdp      else if ((flags & BSF_DEBUGGING) != 0)	/* Debugging symbol.  */
101360484Sobrien	keep = (strip_symbols != STRIP_DEBUG
101460484Sobrien		&& strip_symbols != STRIP_UNNEEDED
101533965Sjdp		&& ! convert_debugging);
1016218822Sdim      else if (bfd_coff_get_comdat_section (abfd, bfd_get_section (sym)))
101780016Sobrien	/* COMDAT sections store special information in local
101880016Sobrien	   symbols, so we cannot risk stripping any of them.  */
1019218822Sdim	keep = TRUE;
102033965Sjdp      else			/* Local symbol.  */
102160484Sobrien	keep = (strip_symbols != STRIP_UNNEEDED
102260484Sobrien		&& (discard_locals != LOCALS_ALL
102360484Sobrien		    && (discard_locals != LOCALS_START_L
102433965Sjdp			|| ! bfd_is_local_label (abfd, sym))));
102533965Sjdp
102638889Sjdp      if (keep && is_specified_symbol (name, strip_specific_list))
1027218822Sdim	{
1028218822Sdim	  /* There are multiple ways to set 'keep' above, but if it
1029218822Sdim	     was the relocatable symbol case, then that's an error.  */
1030218822Sdim	  if (used_in_reloc)
1031218822Sdim	    {
1032218822Sdim	      non_fatal (_("not stripping symbol `%s' because it is named in a relocation"), name);
1033218822Sdim	      status = 1;
1034218822Sdim	    }
1035218822Sdim	  else
1036218822Sdim	    keep = FALSE;
1037218822Sdim	}
1038218822Sdim
1039218822Sdim      if (keep
1040218822Sdim	  && !(flags & BSF_KEEP)
1041218822Sdim	  && is_specified_symbol (name, strip_unneeded_list))
1042218822Sdim	keep = FALSE;
1043218822Sdim
1044218822Sdim      if (!keep
1045218822Sdim	  && ((keep_file_symbols && (flags & BSF_FILE))
1046218822Sdim	      || is_specified_symbol (name, keep_specific_list)))
1047218822Sdim	keep = TRUE;
1048218822Sdim
104933965Sjdp      if (keep && is_strip_section (abfd, bfd_get_section (sym)))
1050218822Sdim	keep = FALSE;
105133965Sjdp
1052218822Sdim      if (keep)
105333965Sjdp	{
1054218822Sdim	  if ((flags & BSF_GLOBAL) != 0
1055218822Sdim	      && (weaken || is_specified_symbol (name, weaken_specific_list)))
1056218822Sdim	    {
1057218822Sdim	      sym->flags &= ~ BSF_GLOBAL;
1058218822Sdim	      sym->flags |= BSF_WEAK;
1059218822Sdim	    }
1060218822Sdim
1061218822Sdim	  if (!undefined
1062218822Sdim	      && (flags & (BSF_GLOBAL | BSF_WEAK))
1063218822Sdim	      && (is_specified_symbol (name, localize_specific_list)
1064218822Sdim		  || (keepglobal_specific_list != NULL
1065218822Sdim		      && ! is_specified_symbol (name, keepglobal_specific_list))
1066218822Sdim		  || (localize_hidden && is_hidden_symbol (sym))))
1067218822Sdim	    {
1068218822Sdim	      sym->flags &= ~ (BSF_GLOBAL | BSF_WEAK);
1069218822Sdim	      sym->flags |= BSF_LOCAL;
1070218822Sdim	    }
1071218822Sdim
1072218822Sdim	  if (!undefined
1073218822Sdim	      && (flags & BSF_LOCAL)
1074218822Sdim	      && is_specified_symbol (name, globalize_specific_list))
1075218822Sdim	    {
1076218822Sdim	      sym->flags &= ~ BSF_LOCAL;
1077218822Sdim	      sym->flags |= BSF_GLOBAL;
1078218822Sdim	    }
1079218822Sdim
1080218822Sdim	  to[dst_count++] = sym;
108133965Sjdp	}
108233965Sjdp    }
108333965Sjdp
108433965Sjdp  to[dst_count] = NULL;
108533965Sjdp
108633965Sjdp  return dst_count;
108733965Sjdp}
108833965Sjdp
108989857Sobrien/* Find the redefined name of symbol SOURCE.  */
109089857Sobrien
109160484Sobrienstatic const char *
1092130561Sobrienlookup_sym_redefinition (const char *source)
109360484Sobrien{
109460484Sobrien  struct redefine_node *list;
109560484Sobrien
109689857Sobrien  for (list = redefine_sym_list; list != NULL; list = list->next)
109789857Sobrien    if (strcmp (source, list->source) == 0)
109889857Sobrien      return list->target;
109960484Sobrien
110089857Sobrien  return source;
110160484Sobrien}
110260484Sobrien
110389857Sobrien/* Add a node to a symbol redefine list.  */
110460484Sobrien
110560484Sobrienstatic void
1106130561Sobrienredefine_list_append (const char *cause, const char *source, const char *target)
110760484Sobrien{
110860484Sobrien  struct redefine_node **p;
110960484Sobrien  struct redefine_node *list;
111060484Sobrien  struct redefine_node *new_node;
111160484Sobrien
111260484Sobrien  for (p = &redefine_sym_list; (list = *p) != NULL; p = &list->next)
111360484Sobrien    {
111460484Sobrien      if (strcmp (source, list->source) == 0)
111589857Sobrien	fatal (_("%s: Multiple redefinition of symbol \"%s\""),
1116130561Sobrien	       cause, source);
111760484Sobrien
111860484Sobrien      if (strcmp (target, list->target) == 0)
111989857Sobrien	fatal (_("%s: Symbol \"%s\" is target of more than one redefinition"),
1120130561Sobrien	       cause, target);
112160484Sobrien    }
112260484Sobrien
1123130561Sobrien  new_node = xmalloc (sizeof (struct redefine_node));
112460484Sobrien
112560484Sobrien  new_node->source = strdup (source);
112660484Sobrien  new_node->target = strdup (target);
112760484Sobrien  new_node->next = NULL;
112860484Sobrien
112960484Sobrien  *p = new_node;
113060484Sobrien}
113160484Sobrien
1132130561Sobrien/* Handle the --redefine-syms option.  Read lines containing "old new"
1133130561Sobrien   from the file, and add them to the symbol redefine list.  */
113433965Sjdp
113533965Sjdpstatic void
1136130561Sobrienadd_redefine_syms_file (const char *filename)
113733965Sjdp{
1138130561Sobrien  FILE *file;
1139130561Sobrien  char *buf;
1140130561Sobrien  size_t bufsize;
1141130561Sobrien  size_t len;
1142130561Sobrien  size_t outsym_off;
1143130561Sobrien  int c, lineno;
114433965Sjdp
1145130561Sobrien  file = fopen (filename, "r");
1146130561Sobrien  if (file == NULL)
1147130561Sobrien    fatal (_("couldn't open symbol redefinition file %s (error: %s)"),
1148130561Sobrien	   filename, strerror (errno));
114989857Sobrien
1150130561Sobrien  bufsize = 100;
1151130561Sobrien  buf = xmalloc (bufsize);
1152130561Sobrien
1153130561Sobrien  lineno = 1;
1154130561Sobrien  c = getc (file);
1155130561Sobrien  len = 0;
1156130561Sobrien  outsym_off = 0;
1157130561Sobrien  while (c != EOF)
1158130561Sobrien    {
1159130561Sobrien      /* Collect the input symbol name.  */
1160130561Sobrien      while (! IS_WHITESPACE (c) && ! IS_LINE_TERMINATOR (c) && c != EOF)
1161130561Sobrien	{
1162130561Sobrien	  if (c == '#')
1163130561Sobrien	    goto comment;
1164130561Sobrien	  buf[len++] = c;
1165130561Sobrien	  if (len >= bufsize)
1166130561Sobrien	    {
1167130561Sobrien	      bufsize *= 2;
1168130561Sobrien	      buf = xrealloc (buf, bufsize);
1169130561Sobrien	    }
1170130561Sobrien	  c = getc (file);
1171130561Sobrien	}
1172130561Sobrien      buf[len++] = '\0';
1173130561Sobrien      if (c == EOF)
1174130561Sobrien	break;
1175130561Sobrien
1176130561Sobrien      /* Eat white space between the symbol names.  */
1177130561Sobrien      while (IS_WHITESPACE (c))
1178130561Sobrien	c = getc (file);
1179130561Sobrien      if (c == '#' || IS_LINE_TERMINATOR (c))
1180130561Sobrien	goto comment;
1181130561Sobrien      if (c == EOF)
1182130561Sobrien	break;
1183130561Sobrien
1184130561Sobrien      /* Collect the output symbol name.  */
1185130561Sobrien      outsym_off = len;
1186130561Sobrien      while (! IS_WHITESPACE (c) && ! IS_LINE_TERMINATOR (c) && c != EOF)
1187130561Sobrien	{
1188130561Sobrien	  if (c == '#')
1189130561Sobrien	    goto comment;
1190130561Sobrien	  buf[len++] = c;
1191130561Sobrien	  if (len >= bufsize)
1192130561Sobrien	    {
1193130561Sobrien	      bufsize *= 2;
1194130561Sobrien	      buf = xrealloc (buf, bufsize);
1195130561Sobrien	    }
1196130561Sobrien	  c = getc (file);
1197130561Sobrien	}
1198130561Sobrien      buf[len++] = '\0';
1199130561Sobrien      if (c == EOF)
1200130561Sobrien	break;
1201130561Sobrien
1202130561Sobrien      /* Eat white space at end of line.  */
1203130561Sobrien      while (! IS_LINE_TERMINATOR(c) && c != EOF && IS_WHITESPACE (c))
1204130561Sobrien	c = getc (file);
1205130561Sobrien      if (c == '#')
1206130561Sobrien	goto comment;
1207130561Sobrien      /* Handle \r\n.  */
1208130561Sobrien      if ((c == '\r' && (c = getc (file)) == '\n')
1209130561Sobrien	  || c == '\n' || c == EOF)
1210130561Sobrien	{
1211130561Sobrien end_of_line:
1212130561Sobrien	  /* Append the redefinition to the list.  */
1213130561Sobrien	  if (buf[0] != '\0')
1214130561Sobrien	    redefine_list_append (filename, &buf[0], &buf[outsym_off]);
1215130561Sobrien
1216218822Sdim	  lineno++;
1217130561Sobrien	  len = 0;
1218130561Sobrien	  outsym_off = 0;
1219130561Sobrien	  if (c == EOF)
1220130561Sobrien	    break;
1221130561Sobrien	  c = getc (file);
1222130561Sobrien	  continue;
1223130561Sobrien	}
1224130561Sobrien      else
1225218822Sdim	fatal (_("%s:%d: garbage found at end of line"), filename, lineno);
1226130561Sobrien comment:
1227130561Sobrien      if (len != 0 && (outsym_off == 0 || outsym_off == len))
1228218822Sdim	fatal (_("%s:%d: missing new symbol name"), filename, lineno);
1229130561Sobrien      buf[len++] = '\0';
1230130561Sobrien
1231130561Sobrien      /* Eat the rest of the line and finish it.  */
1232130561Sobrien      while (c != '\n' && c != EOF)
1233130561Sobrien	c = getc (file);
1234130561Sobrien      goto end_of_line;
1235130561Sobrien    }
1236130561Sobrien
1237130561Sobrien  if (len != 0)
1238218822Sdim    fatal (_("%s:%d: premature end of file"), filename, lineno);
1239130561Sobrien
1240130561Sobrien  free (buf);
124133965Sjdp}
124233965Sjdp
1243218822Sdim/* Copy unkown object file IBFD onto OBFD.
1244218822Sdim   Returns TRUE upon success, FALSE otherwise.  */
1245218822Sdim
1246218822Sdimstatic bfd_boolean
1247218822Sdimcopy_unknown_object (bfd *ibfd, bfd *obfd)
1248218822Sdim{
1249218822Sdim  char *cbuf;
1250218822Sdim  int tocopy;
1251218822Sdim  long ncopied;
1252218822Sdim  long size;
1253218822Sdim  struct stat buf;
1254218822Sdim
1255218822Sdim  if (bfd_stat_arch_elt (ibfd, &buf) != 0)
1256218822Sdim    {
1257218822Sdim      bfd_nonfatal (bfd_get_archive_filename (ibfd));
1258218822Sdim      return FALSE;
1259218822Sdim    }
1260218822Sdim
1261218822Sdim  size = buf.st_size;
1262218822Sdim  if (size < 0)
1263218822Sdim    {
1264218822Sdim      non_fatal (_("stat returns negative size for `%s'"),
1265218822Sdim		 bfd_get_archive_filename (ibfd));
1266218822Sdim      return FALSE;
1267218822Sdim    }
1268218822Sdim
1269218822Sdim  if (bfd_seek (ibfd, (file_ptr) 0, SEEK_SET) != 0)
1270218822Sdim    {
1271218822Sdim      bfd_nonfatal (bfd_get_archive_filename (ibfd));
1272218822Sdim      return FALSE;
1273218822Sdim    }
1274218822Sdim
1275218822Sdim  if (verbose)
1276218822Sdim    printf (_("copy from `%s' [unknown] to `%s' [unknown]\n"),
1277218822Sdim	    bfd_get_archive_filename (ibfd), bfd_get_filename (obfd));
1278218822Sdim
1279218822Sdim  cbuf = xmalloc (BUFSIZE);
1280218822Sdim  ncopied = 0;
1281218822Sdim  while (ncopied < size)
1282218822Sdim    {
1283218822Sdim      tocopy = size - ncopied;
1284218822Sdim      if (tocopy > BUFSIZE)
1285218822Sdim	tocopy = BUFSIZE;
1286218822Sdim
1287218822Sdim      if (bfd_bread (cbuf, (bfd_size_type) tocopy, ibfd)
1288218822Sdim	  != (bfd_size_type) tocopy)
1289218822Sdim	{
1290218822Sdim	  bfd_nonfatal (bfd_get_archive_filename (ibfd));
1291218822Sdim	  free (cbuf);
1292218822Sdim	  return FALSE;
1293218822Sdim	}
1294218822Sdim
1295218822Sdim      if (bfd_bwrite (cbuf, (bfd_size_type) tocopy, obfd)
1296218822Sdim	  != (bfd_size_type) tocopy)
1297218822Sdim	{
1298218822Sdim	  bfd_nonfatal (bfd_get_filename (obfd));
1299218822Sdim	  free (cbuf);
1300218822Sdim	  return FALSE;
1301218822Sdim	}
1302218822Sdim
1303218822Sdim      ncopied += tocopy;
1304218822Sdim    }
1305218822Sdim
1306218822Sdim  chmod (bfd_get_filename (obfd), buf.st_mode);
1307218822Sdim  free (cbuf);
1308218822Sdim  return TRUE;
1309218822Sdim}
1310218822Sdim
1311130561Sobrien/* Copy object file IBFD onto OBFD.
1312130561Sobrien   Returns TRUE upon success, FALSE otherwise.  */
131333965Sjdp
1314130561Sobrienstatic bfd_boolean
1315130561Sobriencopy_object (bfd *ibfd, bfd *obfd)
131633965Sjdp{
131733965Sjdp  bfd_vma start;
131833965Sjdp  long symcount;
131933965Sjdp  asection **osections = NULL;
1320130561Sobrien  asection *gnu_debuglink_section = NULL;
132133965Sjdp  bfd_size_type *gaps = NULL;
132233965Sjdp  bfd_size_type max_gap = 0;
132360484Sobrien  long symsize;
1324130561Sobrien  void *dhandle;
1325130561Sobrien  enum bfd_architecture iarch;
1326130561Sobrien  unsigned int imach;
132733965Sjdp
132877298Sobrien  if (ibfd->xvec->byteorder != obfd->xvec->byteorder
132977298Sobrien      && ibfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN
133077298Sobrien      && obfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN)
1331130561Sobrien    fatal (_("Unable to change endianness of input file(s)"));
1332130561Sobrien
1333130561Sobrien  if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
133477298Sobrien    {
1335130561Sobrien      bfd_nonfatal (bfd_get_filename (obfd));
1336130561Sobrien      return FALSE;
133777298Sobrien    }
133860484Sobrien
133933965Sjdp  if (verbose)
1340218822Sdim    printf (_("copy from `%s' [%s] to `%s' [%s]\n"),
1341218822Sdim	    bfd_get_archive_filename (ibfd), bfd_get_target (ibfd),
134260484Sobrien	    bfd_get_filename (obfd), bfd_get_target (obfd));
134333965Sjdp
1344218822Sdim  if (extract_symbol)
1345218822Sdim    start = 0;
134633965Sjdp  else
1347218822Sdim    {
1348218822Sdim      if (set_start_set)
1349218822Sdim	start = set_start;
1350218822Sdim      else
1351218822Sdim	start = bfd_get_start_address (ibfd);
1352218822Sdim      start += change_start;
1353218822Sdim    }
135433965Sjdp
1355104834Sobrien  /* Neither the start address nor the flags
1356104834Sobrien     need to be set for a core file.  */
135789857Sobrien  if (bfd_get_format (obfd) != bfd_core)
135889857Sobrien    {
1359130561Sobrien      flagword flags;
1360130561Sobrien
1361130561Sobrien      flags = bfd_get_file_flags (ibfd);
1362130561Sobrien      flags |= bfd_flags_to_set;
1363130561Sobrien      flags &= ~bfd_flags_to_clear;
1364130561Sobrien      flags &= bfd_applicable_file_flags (obfd);
1365130561Sobrien
136689857Sobrien      if (!bfd_set_start_address (obfd, start)
1367130561Sobrien	  || !bfd_set_file_flags (obfd, flags))
1368130561Sobrien	{
1369218822Sdim	  bfd_nonfatal (bfd_get_archive_filename (ibfd));
1370130561Sobrien	  return FALSE;
1371130561Sobrien	}
137289857Sobrien    }
137333965Sjdp
137489857Sobrien  /* Copy architecture of input file to output file.  */
1375130561Sobrien  iarch = bfd_get_arch (ibfd);
1376130561Sobrien  imach = bfd_get_mach (ibfd);
1377130561Sobrien  if (!bfd_set_arch_mach (obfd, iarch, imach)
1378130561Sobrien      && (ibfd->target_defaulted
1379130561Sobrien	  || bfd_get_arch (ibfd) != bfd_get_arch (obfd)))
1380130561Sobrien    {
1381130561Sobrien      if (bfd_get_arch (ibfd) == bfd_arch_unknown)
1382218822Sdim	non_fatal (_("Unable to recognise the format of the input file `%s'"),
1383218822Sdim		   bfd_get_archive_filename (ibfd));
1384130561Sobrien      else
1385218822Sdim	non_fatal (_("Warning: Output file cannot represent architecture `%s'"),
1386218822Sdim		   bfd_printable_arch_mach (bfd_get_arch (ibfd),
1387218822Sdim					    bfd_get_mach (ibfd)));
1388218822Sdim      return FALSE;
1389130561Sobrien    }
139060484Sobrien
139133965Sjdp  if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
1392130561Sobrien    {
1393218822Sdim      bfd_nonfatal (bfd_get_archive_filename (ibfd));
1394130561Sobrien      return FALSE;
1395130561Sobrien    }
139633965Sjdp
139733965Sjdp  if (isympp)
139833965Sjdp    free (isympp);
139960484Sobrien
140033965Sjdp  if (osympp != isympp)
140133965Sjdp    free (osympp);
140233965Sjdp
1403218822Sdim  isympp = NULL;
1404218822Sdim  osympp = NULL;
1405218822Sdim
1406218822Sdim  symsize = bfd_get_symtab_upper_bound (ibfd);
1407218822Sdim  if (symsize < 0)
1408218822Sdim    {
1409218822Sdim      bfd_nonfatal (bfd_get_archive_filename (ibfd));
1410218822Sdim      return FALSE;
1411218822Sdim    }
1412218822Sdim
1413218822Sdim  osympp = isympp = xmalloc (symsize);
1414218822Sdim  symcount = bfd_canonicalize_symtab (ibfd, isympp);
1415218822Sdim  if (symcount < 0)
1416218822Sdim    {
1417218822Sdim      bfd_nonfatal (bfd_get_filename (ibfd));
1418218822Sdim      return FALSE;
1419218822Sdim    }
1420218822Sdim
142160484Sobrien  /* BFD mandates that all output sections be created and sizes set before
142233965Sjdp     any output is done.  Thus, we traverse all sections multiple times.  */
1423130561Sobrien  bfd_map_over_sections (ibfd, setup_section, obfd);
142433965Sjdp
1425218822Sdim  setup_bfd_headers (ibfd, obfd);
1426218822Sdim
142733965Sjdp  if (add_sections != NULL)
142833965Sjdp    {
142933965Sjdp      struct section_add *padd;
143033965Sjdp      struct section_list *pset;
143133965Sjdp
143233965Sjdp      for (padd = add_sections; padd != NULL; padd = padd->next)
143333965Sjdp	{
1434130561Sobrien	  flagword flags;
1435130561Sobrien
1436130561Sobrien	  pset = find_section_list (padd->name, FALSE);
1437130561Sobrien	  if (pset != NULL)
1438130561Sobrien	    pset->used = TRUE;
143933965Sjdp
1440218822Sdim	  flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DATA;
1441130561Sobrien	  if (pset != NULL && pset->set_flags)
1442130561Sobrien	    flags = pset->flags | SEC_HAS_CONTENTS;
1443218822Sdim
1444218822Sdim	  /* bfd_make_section_with_flags() does not return very helpful
1445218822Sdim	     error codes, so check for the most likely user error first.  */
1446218822Sdim	  if (bfd_get_section_by_name (obfd, padd->name))
1447218822Sdim	    {
1448218822Sdim	      non_fatal (_("can't add section '%s' - it already exists!"), padd->name);
1449218822Sdim	      return FALSE;
1450218822Sdim	    }
1451130561Sobrien	  else
1452218822Sdim	    {
1453218822Sdim	      padd->section = bfd_make_section_with_flags (obfd, padd->name, flags);
1454218822Sdim	      if (padd->section == NULL)
1455218822Sdim		{
1456218822Sdim		  non_fatal (_("can't create section `%s': %s"),
1457218822Sdim			     padd->name, bfd_errmsg (bfd_get_error ()));
1458218822Sdim		  return FALSE;
1459218822Sdim		}
1460218822Sdim	    }
146133965Sjdp
1462218822Sdim	  if (! bfd_set_section_size (obfd, padd->section, padd->size))
1463130561Sobrien	    {
1464130561Sobrien	      bfd_nonfatal (bfd_get_filename (obfd));
1465130561Sobrien	      return FALSE;
1466130561Sobrien	    }
146760484Sobrien
1468130561Sobrien	  if (pset != NULL)
1469130561Sobrien	    {
1470130561Sobrien	      if (pset->change_vma != CHANGE_IGNORE)
1471130561Sobrien		if (! bfd_set_section_vma (obfd, padd->section,
1472130561Sobrien					   pset->vma_val))
1473130561Sobrien		  {
1474130561Sobrien		    bfd_nonfatal (bfd_get_filename (obfd));
1475130561Sobrien		    return FALSE;
1476130561Sobrien		  }
147733965Sjdp
1478130561Sobrien	      if (pset->change_lma != CHANGE_IGNORE)
147933965Sjdp		{
1480130561Sobrien		  padd->section->lma = pset->lma_val;
148160484Sobrien
1482130561Sobrien		  if (! bfd_set_section_alignment
1483130561Sobrien		      (obfd, padd->section,
1484130561Sobrien		       bfd_section_alignment (obfd, padd->section)))
148560484Sobrien		    {
1486130561Sobrien		      bfd_nonfatal (bfd_get_filename (obfd));
1487130561Sobrien		      return FALSE;
148860484Sobrien		    }
148933965Sjdp		}
149033965Sjdp	    }
149133965Sjdp	}
149233965Sjdp    }
149333965Sjdp
1494130561Sobrien  if (gnu_debuglink_filename != NULL)
1495130561Sobrien    {
1496130561Sobrien      gnu_debuglink_section = bfd_create_gnu_debuglink_section
1497130561Sobrien	(obfd, gnu_debuglink_filename);
1498130561Sobrien
1499130561Sobrien      if (gnu_debuglink_section == NULL)
1500130561Sobrien	{
1501130561Sobrien	  bfd_nonfatal (gnu_debuglink_filename);
1502130561Sobrien	  return FALSE;
1503130561Sobrien	}
1504130561Sobrien
1505218822Sdim      /* Special processing for PE format files.  We
1506218822Sdim	 have no way to distinguish PE from COFF here.  */
1507218822Sdim      if (bfd_get_flavour (obfd) == bfd_target_coff_flavour)
1508218822Sdim	{
1509218822Sdim	  bfd_vma debuglink_vma;
1510218822Sdim	  asection * highest_section;
1511218822Sdim	  asection * sec;
1512218822Sdim
1513218822Sdim	  /* The PE spec requires that all sections be adjacent and sorted
1514218822Sdim	     in ascending order of VMA.  It also specifies that debug
1515218822Sdim	     sections should be last.  This is despite the fact that debug
1516218822Sdim	     sections are not loaded into memory and so in theory have no
1517218822Sdim	     use for a VMA.
1518218822Sdim
1519218822Sdim	     This means that the debuglink section must be given a non-zero
1520218822Sdim	     VMA which makes it contiguous with other debug sections.  So
1521218822Sdim	     walk the current section list, find the section with the
1522218822Sdim	     highest VMA and start the debuglink section after that one.  */
1523218822Sdim	  for (sec = obfd->sections, highest_section = NULL;
1524218822Sdim	       sec != NULL;
1525218822Sdim	       sec = sec->next)
1526218822Sdim	    if (sec->vma > 0
1527218822Sdim		&& (highest_section == NULL
1528218822Sdim		    || sec->vma > highest_section->vma))
1529218822Sdim	      highest_section = sec;
1530218822Sdim
1531218822Sdim	  if (highest_section)
1532218822Sdim	    debuglink_vma = BFD_ALIGN (highest_section->vma
1533218822Sdim				       + highest_section->size,
1534218822Sdim				       /* FIXME: We ought to be using
1535218822Sdim					  COFF_PAGE_SIZE here or maybe
1536218822Sdim					  bfd_get_section_alignment() (if it
1537218822Sdim					  was set) but since this is for PE
1538218822Sdim					  and we know the required alignment
1539218822Sdim					  it is easier just to hard code it.  */
1540218822Sdim				       0x1000);
1541218822Sdim	  else
1542218822Sdim	    /* Umm, not sure what to do in this case.  */
1543218822Sdim	    debuglink_vma = 0x1000;
1544218822Sdim
1545222204Sbenl	  (void) bfd_set_section_vma (obfd, gnu_debuglink_section,
1546222204Sbenl				      debuglink_vma);
1547218822Sdim	}
1548130561Sobrien    }
1549130561Sobrien
1550218822Sdim  if (bfd_count_sections (obfd) != 0
1551218822Sdim      && (gap_fill_set || pad_to_set))
155233965Sjdp    {
155333965Sjdp      asection **set;
155433965Sjdp      unsigned int c, i;
155533965Sjdp
155633965Sjdp      /* We must fill in gaps between the sections and/or we must pad
155733965Sjdp	 the last section to a specified address.  We do this by
155833965Sjdp	 grabbing a list of the sections, sorting them by VMA, and
155933965Sjdp	 increasing the section sizes as required to fill the gaps.
156033965Sjdp	 We write out the gap contents below.  */
156133965Sjdp
156233965Sjdp      c = bfd_count_sections (obfd);
1563130561Sobrien      osections = xmalloc (c * sizeof (asection *));
156433965Sjdp      set = osections;
1565130561Sobrien      bfd_map_over_sections (obfd, get_sections, &set);
156633965Sjdp
156738889Sjdp      qsort (osections, c, sizeof (asection *), compare_section_lma);
156833965Sjdp
1569130561Sobrien      gaps = xmalloc (c * sizeof (bfd_size_type));
157033965Sjdp      memset (gaps, 0, c * sizeof (bfd_size_type));
157133965Sjdp
157233965Sjdp      if (gap_fill_set)
157333965Sjdp	{
157433965Sjdp	  for (i = 0; i < c - 1; i++)
157533965Sjdp	    {
157633965Sjdp	      flagword flags;
157733965Sjdp	      bfd_size_type size;
157833965Sjdp	      bfd_vma gap_start, gap_stop;
157933965Sjdp
158033965Sjdp	      flags = bfd_get_section_flags (obfd, osections[i]);
158133965Sjdp	      if ((flags & SEC_HAS_CONTENTS) == 0
158233965Sjdp		  || (flags & SEC_LOAD) == 0)
158333965Sjdp		continue;
158433965Sjdp
158533965Sjdp	      size = bfd_section_size (obfd, osections[i]);
158638889Sjdp	      gap_start = bfd_section_lma (obfd, osections[i]) + size;
158738889Sjdp	      gap_stop = bfd_section_lma (obfd, osections[i + 1]);
158833965Sjdp	      if (gap_start < gap_stop)
158933965Sjdp		{
159033965Sjdp		  if (! bfd_set_section_size (obfd, osections[i],
159133965Sjdp					      size + (gap_stop - gap_start)))
159233965Sjdp		    {
159360484Sobrien		      non_fatal (_("Can't fill gap after %s: %s"),
1594104834Sobrien				 bfd_get_section_name (obfd, osections[i]),
1595104834Sobrien				 bfd_errmsg (bfd_get_error ()));
159633965Sjdp		      status = 1;
159733965Sjdp		      break;
159833965Sjdp		    }
159933965Sjdp		  gaps[i] = gap_stop - gap_start;
160033965Sjdp		  if (max_gap < gap_stop - gap_start)
160133965Sjdp		    max_gap = gap_stop - gap_start;
160233965Sjdp		}
160333965Sjdp	    }
160433965Sjdp	}
160533965Sjdp
160633965Sjdp      if (pad_to_set)
160733965Sjdp	{
160838889Sjdp	  bfd_vma lma;
160933965Sjdp	  bfd_size_type size;
161033965Sjdp
161138889Sjdp	  lma = bfd_section_lma (obfd, osections[c - 1]);
161233965Sjdp	  size = bfd_section_size (obfd, osections[c - 1]);
161338889Sjdp	  if (lma + size < pad_to)
161433965Sjdp	    {
161533965Sjdp	      if (! bfd_set_section_size (obfd, osections[c - 1],
161638889Sjdp					  pad_to - lma))
161733965Sjdp		{
161860484Sobrien		  non_fatal (_("Can't add padding to %s: %s"),
1619104834Sobrien			     bfd_get_section_name (obfd, osections[c - 1]),
1620104834Sobrien			     bfd_errmsg (bfd_get_error ()));
162133965Sjdp		  status = 1;
162233965Sjdp		}
162333965Sjdp	      else
162433965Sjdp		{
162538889Sjdp		  gaps[c - 1] = pad_to - (lma + size);
162638889Sjdp		  if (max_gap < pad_to - (lma + size))
162738889Sjdp		    max_gap = pad_to - (lma + size);
162833965Sjdp		}
162933965Sjdp	    }
163038889Sjdp	}
163133965Sjdp    }
163233965Sjdp
163389857Sobrien  /* Symbol filtering must happen after the output sections
163489857Sobrien     have been created, but before their contents are set.  */
163560484Sobrien  dhandle = NULL;
163660484Sobrien  if (convert_debugging)
163760484Sobrien    dhandle = read_debugging_info (ibfd, isympp, symcount);
163833965Sjdp
163960484Sobrien  if (strip_symbols == STRIP_DEBUG
164060484Sobrien      || strip_symbols == STRIP_ALL
164160484Sobrien      || strip_symbols == STRIP_UNNEEDED
1642130561Sobrien      || strip_symbols == STRIP_NONDEBUG
164360484Sobrien      || discard_locals != LOCALS_UNDEF
1644218822Sdim      || localize_hidden
164560484Sobrien      || strip_specific_list != NULL
164660484Sobrien      || keep_specific_list != NULL
164760484Sobrien      || localize_specific_list != NULL
1648218822Sdim      || globalize_specific_list != NULL
164978828Sobrien      || keepglobal_specific_list != NULL
165060484Sobrien      || weaken_specific_list != NULL
1651130561Sobrien      || prefix_symbols_string
165260484Sobrien      || sections_removed
165360484Sobrien      || sections_copied
165460484Sobrien      || convert_debugging
165560484Sobrien      || change_leading_char
165660484Sobrien      || remove_leading_char
165760484Sobrien      || redefine_sym_list
165860484Sobrien      || weaken)
165960484Sobrien    {
166060484Sobrien      /* Mark symbols used in output relocations so that they
166160484Sobrien	 are kept, even if they are local labels or static symbols.
166233965Sjdp
166360484Sobrien	 Note we iterate over the input sections examining their
166460484Sobrien	 relocations since the relocations for the output sections
166560484Sobrien	 haven't been set yet.  mark_symbols_used_in_relocations will
166660484Sobrien	 ignore input sections which have no corresponding output
166760484Sobrien	 section.  */
166860484Sobrien      if (strip_symbols != STRIP_ALL)
166960484Sobrien	bfd_map_over_sections (ibfd,
167060484Sobrien			       mark_symbols_used_in_relocations,
1671130561Sobrien			       isympp);
1672130561Sobrien      osympp = xmalloc ((symcount + 1) * sizeof (asymbol *));
167360484Sobrien      symcount = filter_symbols (ibfd, obfd, osympp, isympp, symcount);
167460484Sobrien    }
167533965Sjdp
167660484Sobrien  if (convert_debugging && dhandle != NULL)
167760484Sobrien    {
167860484Sobrien      if (! write_debugging_info (obfd, dhandle, &symcount, &osympp))
167933965Sjdp	{
168060484Sobrien	  status = 1;
1681130561Sobrien	  return FALSE;
168233965Sjdp	}
168333965Sjdp    }
168433965Sjdp
168533965Sjdp  bfd_set_symtab (obfd, osympp, symcount);
168633965Sjdp
168733965Sjdp  /* This has to happen after the symbol table has been set.  */
1688130561Sobrien  bfd_map_over_sections (ibfd, copy_section, obfd);
168933965Sjdp
169033965Sjdp  if (add_sections != NULL)
169133965Sjdp    {
169233965Sjdp      struct section_add *padd;
169333965Sjdp
169433965Sjdp      for (padd = add_sections; padd != NULL; padd = padd->next)
169533965Sjdp	{
1696130561Sobrien	  if (! bfd_set_section_contents (obfd, padd->section, padd->contents,
1697130561Sobrien					  0, padd->size))
1698130561Sobrien	    {
1699130561Sobrien	      bfd_nonfatal (bfd_get_filename (obfd));
1700130561Sobrien	      return FALSE;
1701130561Sobrien	    }
170233965Sjdp	}
170333965Sjdp    }
170433965Sjdp
1705130561Sobrien  if (gnu_debuglink_filename != NULL)
1706130561Sobrien    {
1707130561Sobrien      if (! bfd_fill_in_gnu_debuglink_section
1708130561Sobrien	  (obfd, gnu_debuglink_section, gnu_debuglink_filename))
1709130561Sobrien	{
1710130561Sobrien	  bfd_nonfatal (gnu_debuglink_filename);
1711130561Sobrien	  return FALSE;
1712130561Sobrien	}
1713130561Sobrien    }
1714130561Sobrien
171533965Sjdp  if (gap_fill_set || pad_to_set)
171633965Sjdp    {
171733965Sjdp      bfd_byte *buf;
171833965Sjdp      int c, i;
171933965Sjdp
172033965Sjdp      /* Fill in the gaps.  */
172133965Sjdp      if (max_gap > 8192)
172233965Sjdp	max_gap = 8192;
1723130561Sobrien      buf = xmalloc (max_gap);
1724130561Sobrien      memset (buf, gap_fill, max_gap);
172533965Sjdp
172633965Sjdp      c = bfd_count_sections (obfd);
172733965Sjdp      for (i = 0; i < c; i++)
172833965Sjdp	{
172933965Sjdp	  if (gaps[i] != 0)
173033965Sjdp	    {
173133965Sjdp	      bfd_size_type left;
173233965Sjdp	      file_ptr off;
173333965Sjdp
173433965Sjdp	      left = gaps[i];
173533965Sjdp	      off = bfd_section_size (obfd, osections[i]) - left;
173689857Sobrien
173733965Sjdp	      while (left > 0)
173833965Sjdp		{
173933965Sjdp		  bfd_size_type now;
174033965Sjdp
174133965Sjdp		  if (left > 8192)
174233965Sjdp		    now = 8192;
174333965Sjdp		  else
174433965Sjdp		    now = left;
174560484Sobrien
174633965Sjdp		  if (! bfd_set_section_contents (obfd, osections[i], buf,
174733965Sjdp						  off, now))
1748130561Sobrien		    {
1749130561Sobrien		      bfd_nonfatal (bfd_get_filename (obfd));
1750130561Sobrien		      return FALSE;
1751130561Sobrien		    }
175260484Sobrien
175333965Sjdp		  left -= now;
175433965Sjdp		  off += now;
175533965Sjdp		}
175633965Sjdp	    }
175733965Sjdp	}
175833965Sjdp    }
175933965Sjdp
1760218822Sdim  /* Do not copy backend data if --extract-symbol is passed; anything
1761218822Sdim     that needs to look at the section contents will fail.  */
1762218822Sdim  if (extract_symbol)
1763218822Sdim    return TRUE;
1764218822Sdim
176533965Sjdp  /* Allow the BFD backend to copy any private data it understands
176633965Sjdp     from the input BFD to the output BFD.  This is done last to
176733965Sjdp     permit the routine to look at the filtered symbol table, which is
176833965Sjdp     important for the ECOFF code at least.  */
1769218822Sdim  if (! bfd_copy_private_bfd_data (ibfd, obfd))
177033965Sjdp    {
177160484Sobrien      non_fatal (_("%s: error copying private BFD data: %s"),
177260484Sobrien		 bfd_get_filename (obfd),
177360484Sobrien		 bfd_errmsg (bfd_get_error ()));
1774130561Sobrien      return FALSE;
177533965Sjdp    }
177689857Sobrien
177789857Sobrien  /* Switch to the alternate machine code.  We have to do this at the
177889857Sobrien     very end, because we only initialize the header when we create
177989857Sobrien     the first section.  */
1780218822Sdim  if (use_alt_mach_code != 0)
1781218822Sdim    {
1782218822Sdim      if (! bfd_alt_mach_code (obfd, use_alt_mach_code))
1783218822Sdim	{
1784218822Sdim	  non_fatal (_("this target does not support %lu alternative machine codes"),
1785218822Sdim		     use_alt_mach_code);
1786218822Sdim	  if (bfd_get_flavour (obfd) == bfd_target_elf_flavour)
1787218822Sdim	    {
1788218822Sdim	      non_fatal (_("treating that number as an absolute e_machine value instead"));
1789218822Sdim	      elf_elfheader (obfd)->e_machine = use_alt_mach_code;
1790218822Sdim	    }
1791218822Sdim	  else
1792218822Sdim	    non_fatal (_("ignoring the alternative value"));
1793218822Sdim	}
1794218822Sdim    }
1795130561Sobrien
1796130561Sobrien  return TRUE;
179733965Sjdp}
179833965Sjdp
179933965Sjdp/* Read each archive element in turn from IBFD, copy the
1800218822Sdim   contents to temp file, and keep the temp file handle.
1801218822Sdim   If 'force_output_target' is TRUE then make sure that
1802218822Sdim   all elements in the new archive are of the type
1803218822Sdim   'output_target'.  */
180433965Sjdp
180533965Sjdpstatic void
1806218822Sdimcopy_archive (bfd *ibfd, bfd *obfd, const char *output_target,
1807218822Sdim	      bfd_boolean force_output_target)
180833965Sjdp{
180933965Sjdp  struct name_list
181033965Sjdp    {
181133965Sjdp      struct name_list *next;
181291041Sobrien      const char *name;
181333965Sjdp      bfd *obfd;
181433965Sjdp    } *list, *l;
181533965Sjdp  bfd **ptr = &obfd->archive_head;
181633965Sjdp  bfd *this_element;
1817218822Sdim  char * dir;
181833965Sjdp
181933965Sjdp  /* Make a temp directory to hold the contents.  */
1820218822Sdim  dir = make_tempdir (bfd_get_filename (obfd));
1821218822Sdim  if (dir == NULL)
1822218822Sdim      fatal (_("cannot create tempdir for archive copying (error: %s)"),
1823218822Sdim	   strerror (errno));
1824130561Sobrien
182533965Sjdp  obfd->has_armap = ibfd->has_armap;
182633965Sjdp
182733965Sjdp  list = NULL;
182833965Sjdp
182933965Sjdp  this_element = bfd_openr_next_archived_file (ibfd, NULL);
183089857Sobrien
183189857Sobrien  if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
183289857Sobrien    RETURN_NONFATAL (bfd_get_filename (obfd));
183389857Sobrien
1834130561Sobrien  while (!status && this_element != NULL)
183533965Sjdp    {
183691041Sobrien      char *output_name;
183791041Sobrien      bfd *output_bfd;
183833965Sjdp      bfd *last_element;
183960484Sobrien      struct stat buf;
184060484Sobrien      int stat_status = 0;
1841130561Sobrien      bfd_boolean delete = TRUE;
184233965Sjdp
184391041Sobrien      /* Create an output file for this member.  */
184491041Sobrien      output_name = concat (dir, "/",
184591041Sobrien			    bfd_get_filename (this_element), (char *) 0);
184691041Sobrien
184791041Sobrien      /* If the file already exists, make another temp dir.  */
184891041Sobrien      if (stat (output_name, &buf) >= 0)
184991041Sobrien	{
1850218822Sdim	  output_name = make_tempdir (output_name);
1851218822Sdim	  if (output_name == NULL)
1852218822Sdim	    fatal (_("cannot create tempdir for archive copying (error: %s)"),
1853218822Sdim		   strerror (errno));
1854130561Sobrien
1855130561Sobrien	  l = xmalloc (sizeof (struct name_list));
185691041Sobrien	  l->name = output_name;
185791041Sobrien	  l->next = list;
185891041Sobrien	  l->obfd = NULL;
185991041Sobrien	  list = l;
186091041Sobrien	  output_name = concat (output_name, "/",
186191041Sobrien				bfd_get_filename (this_element), (char *) 0);
186291041Sobrien	}
186391041Sobrien
186460484Sobrien      if (preserve_dates)
186560484Sobrien	{
186660484Sobrien	  stat_status = bfd_stat_arch_elt (this_element, &buf);
186789857Sobrien
186860484Sobrien	  if (stat_status != 0)
186960484Sobrien	    non_fatal (_("internal stat error on %s"),
187060484Sobrien		       bfd_get_filename (this_element));
187160484Sobrien	}
187260484Sobrien
1873130561Sobrien      l = xmalloc (sizeof (struct name_list));
187433965Sjdp      l->name = output_name;
187533965Sjdp      l->next = list;
1876218822Sdim      l->obfd = NULL;
187733965Sjdp      list = l;
187833965Sjdp
1879130561Sobrien      if (bfd_check_format (this_element, bfd_object))
1880218822Sdim	{
1881218822Sdim	  /* PR binutils/3110: Cope with archives
1882218822Sdim	     containing multiple target types.  */
1883218822Sdim	  if (force_output_target)
1884218822Sdim	    output_bfd = bfd_openw (output_name, output_target);
1885218822Sdim	  else
1886218822Sdim	    output_bfd = bfd_openw (output_name, bfd_get_target (this_element));
188760484Sobrien
1888218822Sdim	  if (output_bfd == NULL)
1889218822Sdim	    RETURN_NONFATAL (output_name);
1890218822Sdim
1891218822Sdim	  delete = ! copy_object (this_element, output_bfd);
1892218822Sdim
1893218822Sdim	  if (! delete
1894218822Sdim	      || bfd_get_arch (this_element) != bfd_arch_unknown)
1895218822Sdim	    {
1896218822Sdim	      if (!bfd_close (output_bfd))
1897218822Sdim		{
1898218822Sdim		  bfd_nonfatal (bfd_get_filename (output_bfd));
1899218822Sdim		  /* Error in new object file. Don't change archive.  */
1900218822Sdim		  status = 1;
1901218822Sdim		}
1902218822Sdim	    }
1903218822Sdim	  else
1904218822Sdim	    goto copy_unknown_element;
1905218822Sdim	}
1906218822Sdim      else
190733965Sjdp	{
1908218822Sdim	  non_fatal (_("Unable to recognise the format of the input file `%s'"),
1909218822Sdim		     bfd_get_archive_filename (this_element));
1910218822Sdim
1911218822Sdim	  output_bfd = bfd_openw (output_name, output_target);
1912218822Sdimcopy_unknown_element:
1913218822Sdim	  delete = !copy_unknown_object (this_element, output_bfd);
1914218822Sdim	  if (!bfd_close_all_done (output_bfd))
1915218822Sdim	    {
1916218822Sdim	      bfd_nonfatal (bfd_get_filename (output_bfd));
1917218822Sdim	      /* Error in new object file. Don't change archive.  */
1918218822Sdim	      status = 1;
1919218822Sdim	    }
192033965Sjdp	}
192133965Sjdp
1922130561Sobrien      if (delete)
1923130561Sobrien	{
1924130561Sobrien	  unlink (output_name);
1925130561Sobrien	  status = 1;
1926130561Sobrien	}
1927130561Sobrien      else
1928130561Sobrien	{
1929130561Sobrien	  if (preserve_dates && stat_status == 0)
1930130561Sobrien	    set_times (output_name, &buf);
193133965Sjdp
1932130561Sobrien	  /* Open the newly output file and attach to our list.  */
1933130561Sobrien	  output_bfd = bfd_openr (output_name, output_target);
193433965Sjdp
1935130561Sobrien	  l->obfd = output_bfd;
193633965Sjdp
1937130561Sobrien	  *ptr = output_bfd;
1938218822Sdim	  ptr = &output_bfd->archive_next;
193933965Sjdp
1940130561Sobrien	  last_element = this_element;
194133965Sjdp
1942130561Sobrien	  this_element = bfd_openr_next_archived_file (ibfd, last_element);
194333965Sjdp
1944130561Sobrien	  bfd_close (last_element);
1945130561Sobrien	}
194633965Sjdp    }
1947130561Sobrien  *ptr = NULL;
194833965Sjdp
194933965Sjdp  if (!bfd_close (obfd))
195060484Sobrien    RETURN_NONFATAL (bfd_get_filename (obfd));
195133965Sjdp
195233965Sjdp  if (!bfd_close (ibfd))
195360484Sobrien    RETURN_NONFATAL (bfd_get_filename (ibfd));
195433965Sjdp
195533965Sjdp  /* Delete all the files that we opened.  */
195633965Sjdp  for (l = list; l != NULL; l = l->next)
195733965Sjdp    {
195891041Sobrien      if (l->obfd == NULL)
195991041Sobrien	rmdir (l->name);
196091041Sobrien      else
196191041Sobrien	{
196291041Sobrien	  bfd_close (l->obfd);
196391041Sobrien	  unlink (l->name);
196491041Sobrien	}
196533965Sjdp    }
196633965Sjdp  rmdir (dir);
196733965Sjdp}
196833965Sjdp
196933965Sjdp/* The top-level control.  */
197033965Sjdp
197133965Sjdpstatic void
1972130561Sobriencopy_file (const char *input_filename, const char *output_filename,
1973130561Sobrien	   const char *input_target,   const char *output_target)
197433965Sjdp{
197533965Sjdp  bfd *ibfd;
1976130561Sobrien  char **obj_matching;
1977130561Sobrien  char **core_matching;
197833965Sjdp
1979130561Sobrien  if (get_file_size (input_filename) < 1)
1980130561Sobrien    {
1981130561Sobrien      status = 1;
1982130561Sobrien      return;
1983130561Sobrien    }
1984130561Sobrien
198533965Sjdp  /* To allow us to do "strip *" without dying on the first
198633965Sjdp     non-object file, failures are nonfatal.  */
198733965Sjdp  ibfd = bfd_openr (input_filename, input_target);
198833965Sjdp  if (ibfd == NULL)
198960484Sobrien    RETURN_NONFATAL (input_filename);
199033965Sjdp
199133965Sjdp  if (bfd_check_format (ibfd, bfd_archive))
199233965Sjdp    {
1993218822Sdim      bfd_boolean force_output_target;
199433965Sjdp      bfd *obfd;
199533965Sjdp
199633965Sjdp      /* bfd_get_target does not return the correct value until
199733965Sjdp         bfd_check_format succeeds.  */
199833965Sjdp      if (output_target == NULL)
1999218822Sdim	{
2000218822Sdim	  output_target = bfd_get_target (ibfd);
2001218822Sdim	  force_output_target = FALSE;
2002218822Sdim	}
2003218822Sdim      else
2004218822Sdim	force_output_target = TRUE;
200533965Sjdp
200633965Sjdp      obfd = bfd_openw (output_filename, output_target);
200733965Sjdp      if (obfd == NULL)
200860484Sobrien	RETURN_NONFATAL (output_filename);
200960484Sobrien
2010218822Sdim      copy_archive (ibfd, obfd, output_target, force_output_target);
201133965Sjdp    }
2012130561Sobrien  else if (bfd_check_format_matches (ibfd, bfd_object, &obj_matching))
201333965Sjdp    {
201433965Sjdp      bfd *obfd;
2015130561Sobrien    do_copy:
201633965Sjdp
201733965Sjdp      /* bfd_get_target does not return the correct value until
201833965Sjdp         bfd_check_format succeeds.  */
201933965Sjdp      if (output_target == NULL)
202033965Sjdp	output_target = bfd_get_target (ibfd);
202133965Sjdp
202233965Sjdp      obfd = bfd_openw (output_filename, output_target);
202333965Sjdp      if (obfd == NULL)
202460484Sobrien	RETURN_NONFATAL (output_filename);
202533965Sjdp
2026218822Sdim      if (! copy_object (ibfd, obfd))
2027218822Sdim	status = 1;
202833965Sjdp
202933965Sjdp      if (!bfd_close (obfd))
203060484Sobrien	RETURN_NONFATAL (output_filename);
203133965Sjdp
203233965Sjdp      if (!bfd_close (ibfd))
203360484Sobrien	RETURN_NONFATAL (input_filename);
2034130561Sobrien
203533965Sjdp    }
203633965Sjdp  else
203733965Sjdp    {
2038130561Sobrien      bfd_error_type obj_error = bfd_get_error ();
2039130561Sobrien      bfd_error_type core_error;
2040130561Sobrien
2041130561Sobrien      if (bfd_check_format_matches (ibfd, bfd_core, &core_matching))
2042130561Sobrien	{
2043130561Sobrien	  /* This probably can't happen..  */
2044130561Sobrien	  if (obj_error == bfd_error_file_ambiguously_recognized)
2045130561Sobrien	    free (obj_matching);
2046130561Sobrien	  goto do_copy;
2047130561Sobrien	}
2048130561Sobrien
2049130561Sobrien      core_error = bfd_get_error ();
2050130561Sobrien      /* Report the object error in preference to the core error.  */
2051130561Sobrien      if (obj_error != core_error)
2052130561Sobrien	bfd_set_error (obj_error);
2053130561Sobrien
205433965Sjdp      bfd_nonfatal (input_filename);
205560484Sobrien
2056130561Sobrien      if (obj_error == bfd_error_file_ambiguously_recognized)
205733965Sjdp	{
2058130561Sobrien	  list_matching_formats (obj_matching);
2059130561Sobrien	  free (obj_matching);
206033965Sjdp	}
2061130561Sobrien      if (core_error == bfd_error_file_ambiguously_recognized)
2062130561Sobrien	{
2063130561Sobrien	  list_matching_formats (core_matching);
2064130561Sobrien	  free (core_matching);
2065130561Sobrien	}
206660484Sobrien
206733965Sjdp      status = 1;
206833965Sjdp    }
206933965Sjdp}
207033965Sjdp
207189857Sobrien/* Add a name to the section renaming list.  */
207233965Sjdp
207333965Sjdpstatic void
2074130561Sobrienadd_section_rename (const char * old_name, const char * new_name,
2075130561Sobrien		    flagword flags)
207689857Sobrien{
207789857Sobrien  section_rename * rename;
207889857Sobrien
207989857Sobrien  /* Check for conflicts first.  */
208089857Sobrien  for (rename = section_rename_list; rename != NULL; rename = rename->next)
208189857Sobrien    if (strcmp (rename->old_name, old_name) == 0)
208289857Sobrien      {
208389857Sobrien	/* Silently ignore duplicate definitions.  */
208489857Sobrien	if (strcmp (rename->new_name, new_name) == 0
208589857Sobrien	    && rename->flags == flags)
208689857Sobrien	  return;
2087104834Sobrien
208889857Sobrien	fatal (_("Multiple renames of section %s"), old_name);
208989857Sobrien      }
209089857Sobrien
2091130561Sobrien  rename = xmalloc (sizeof (* rename));
209289857Sobrien
209389857Sobrien  rename->old_name = old_name;
209489857Sobrien  rename->new_name = new_name;
209589857Sobrien  rename->flags    = flags;
209689857Sobrien  rename->next     = section_rename_list;
2097104834Sobrien
209889857Sobrien  section_rename_list = rename;
209989857Sobrien}
210089857Sobrien
210189857Sobrien/* Check the section rename list for a new name of the input section
210289857Sobrien   ISECTION.  Return the new name if one is found.
210389857Sobrien   Also set RETURNED_FLAGS to the flags to be used for this section.  */
210489857Sobrien
210589857Sobrienstatic const char *
2106130561Sobrienfind_section_rename (bfd * ibfd ATTRIBUTE_UNUSED, sec_ptr isection,
2107130561Sobrien		     flagword * returned_flags)
210889857Sobrien{
210989857Sobrien  const char * old_name = bfd_section_name (ibfd, isection);
211089857Sobrien  section_rename * rename;
211189857Sobrien
211289857Sobrien  /* Default to using the flags of the input section.  */
211389857Sobrien  * returned_flags = bfd_get_section_flags (ibfd, isection);
211489857Sobrien
211589857Sobrien  for (rename = section_rename_list; rename != NULL; rename = rename->next)
211689857Sobrien    if (strcmp (rename->old_name, old_name) == 0)
211789857Sobrien      {
211889857Sobrien	if (rename->flags != (flagword) -1)
211989857Sobrien	  * returned_flags = rename->flags;
212089857Sobrien
212189857Sobrien	return rename->new_name;
212289857Sobrien      }
212389857Sobrien
212489857Sobrien  return old_name;
212589857Sobrien}
212689857Sobrien
2127218822Sdim/* Once each of the sections is copied, we may still need to do some
2128218822Sdim   finalization work for private section headers.  Do that here.  */
2129218822Sdim
2130218822Sdimstatic void
2131218822Sdimsetup_bfd_headers (bfd *ibfd, bfd *obfd)
2132218822Sdim{
2133218822Sdim  const char *err;
2134218822Sdim
2135218822Sdim  /* Allow the BFD backend to copy any private data it understands
2136218822Sdim     from the input section to the output section.  */
2137218822Sdim  if (! bfd_copy_private_header_data (ibfd, obfd))
2138218822Sdim    {
2139218822Sdim      err = _("private header data");
2140218822Sdim      goto loser;
2141218822Sdim    }
2142218822Sdim
2143218822Sdim  /* All went well.  */
2144218822Sdim  return;
2145218822Sdim
2146218822Sdimloser:
2147218822Sdim  non_fatal (_("%s: error in %s: %s"),
2148218822Sdim	     bfd_get_filename (ibfd),
2149218822Sdim	     err, bfd_errmsg (bfd_get_error ()));
2150218822Sdim  status = 1;
2151218822Sdim}
2152218822Sdim
215389857Sobrien/* Create a section in OBFD with the same
215489857Sobrien   name and attributes as ISECTION in IBFD.  */
215589857Sobrien
215689857Sobrienstatic void
2157130561Sobriensetup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
215833965Sjdp{
2159130561Sobrien  bfd *obfd = obfdarg;
216033965Sjdp  struct section_list *p;
216133965Sjdp  sec_ptr osection;
216260484Sobrien  bfd_size_type size;
216333965Sjdp  bfd_vma vma;
216433965Sjdp  bfd_vma lma;
216533965Sjdp  flagword flags;
216677298Sobrien  const char *err;
216789857Sobrien  const char * name;
2168130561Sobrien  char *prefix = NULL;
2169104834Sobrien
2170130561Sobrien  if (is_strip_section (ibfd, isection))
217133965Sjdp    return;
217233965Sjdp
2173130561Sobrien  p = find_section_list (bfd_section_name (ibfd, isection), FALSE);
217433965Sjdp  if (p != NULL)
2175130561Sobrien    p->used = TRUE;
217633965Sjdp
217789857Sobrien  /* Get the, possibly new, name of the output section.  */
217889857Sobrien  name = find_section_rename (ibfd, isection, & flags);
2179104834Sobrien
2180130561Sobrien  /* Prefix sections.  */
2181130561Sobrien  if ((prefix_alloc_sections_string)
2182130561Sobrien      && (bfd_get_section_flags (ibfd, isection) & SEC_ALLOC))
2183130561Sobrien    prefix = prefix_alloc_sections_string;
2184130561Sobrien  else if (prefix_sections_string)
2185130561Sobrien    prefix = prefix_sections_string;
2186130561Sobrien
2187130561Sobrien  if (prefix)
2188130561Sobrien    {
2189130561Sobrien      char *n;
2190130561Sobrien
2191130561Sobrien      n = xmalloc (strlen (prefix) + strlen (name) + 1);
2192130561Sobrien      strcpy (n, prefix);
2193130561Sobrien      strcat (n, name);
2194130561Sobrien      name = n;
2195130561Sobrien    }
2196130561Sobrien
2197218822Sdim  if (p != NULL && p->set_flags)
2198218822Sdim    flags = p->flags | (flags & (SEC_HAS_CONTENTS | SEC_RELOC));
2199218822Sdim  else if (strip_symbols == STRIP_NONDEBUG
2200218822Sdim	   && obfd->xvec->flavour != bfd_target_elf_flavour
2201218822Sdim	   && (flags & SEC_ALLOC) != 0)
2202218822Sdim    flags &= ~(SEC_HAS_CONTENTS | SEC_LOAD);
220360484Sobrien
2204218822Sdim  osection = bfd_make_section_anyway_with_flags (obfd, name, flags);
2205218822Sdim
220633965Sjdp  if (osection == NULL)
220733965Sjdp    {
220877298Sobrien      err = _("making");
220933965Sjdp      goto loser;
221033965Sjdp    }
221133965Sjdp
2212218822Sdim  if (strip_symbols == STRIP_NONDEBUG
2213218822Sdim      && obfd->xvec->flavour == bfd_target_elf_flavour
2214218822Sdim      && (flags & SEC_ALLOC) != 0
2215218822Sdim      && elf_section_type (osection) != SHT_NOTE
2216218822Sdim      && (ibfd->xvec->flavour != bfd_target_elf_flavour
2217218822Sdim	  || elf_section_type (isection) != SHT_NOTE)
2218218822Sdim      && (p == NULL || !p->set_flags))
2219218822Sdim    elf_section_type (osection) = SHT_NOBITS;
2220218822Sdim
222160484Sobrien  size = bfd_section_size (ibfd, isection);
222260484Sobrien  if (copy_byte >= 0)
222360484Sobrien    size = (size + interleave - 1) / interleave;
2224218822Sdim  else if (extract_symbol)
2225218822Sdim    size = 0;
222660484Sobrien  if (! bfd_set_section_size (obfd, osection, size))
222733965Sjdp    {
222877298Sobrien      err = _("size");
222933965Sjdp      goto loser;
223033965Sjdp    }
223133965Sjdp
223233965Sjdp  vma = bfd_section_vma (ibfd, isection);
223360484Sobrien  if (p != NULL && p->change_vma == CHANGE_MODIFY)
223460484Sobrien    vma += p->vma_val;
223560484Sobrien  else if (p != NULL && p->change_vma == CHANGE_SET)
223660484Sobrien    vma = p->vma_val;
223733965Sjdp  else
223860484Sobrien    vma += change_section_address;
223960484Sobrien
2240218822Sdim  if (! bfd_set_section_vma (obfd, osection, extract_symbol ? 0 : vma))
224133965Sjdp    {
224277298Sobrien      err = _("vma");
224333965Sjdp      goto loser;
224433965Sjdp    }
224533965Sjdp
224633965Sjdp  lma = isection->lma;
224760484Sobrien  if ((p != NULL) && p->change_lma != CHANGE_IGNORE)
224860484Sobrien    {
224960484Sobrien      if (p->change_lma == CHANGE_MODIFY)
225060484Sobrien	lma += p->lma_val;
225160484Sobrien      else if (p->change_lma == CHANGE_SET)
225260484Sobrien	lma = p->lma_val;
225360484Sobrien      else
225460484Sobrien	abort ();
225560484Sobrien    }
225633965Sjdp  else
225760484Sobrien    lma += change_section_address;
225860484Sobrien
2259218822Sdim  osection->lma = extract_symbol ? 0 : lma;
226033965Sjdp
226160484Sobrien  /* FIXME: This is probably not enough.  If we change the LMA we
226260484Sobrien     may have to recompute the header for the file as well.  */
2263130561Sobrien  if (!bfd_set_section_alignment (obfd,
2264130561Sobrien				  osection,
2265130561Sobrien				  bfd_section_alignment (ibfd, isection)))
226633965Sjdp    {
226777298Sobrien      err = _("alignment");
226833965Sjdp      goto loser;
226933965Sjdp    }
227033965Sjdp
227189857Sobrien  /* Copy merge entity size.  */
227289857Sobrien  osection->entsize = isection->entsize;
227389857Sobrien
227433965Sjdp  /* This used to be mangle_section; we do here to avoid using
227533965Sjdp     bfd_get_section_by_name since some formats allow multiple
227633965Sjdp     sections with the same name.  */
227733965Sjdp  isection->output_section = osection;
2278218822Sdim  isection->output_offset = extract_symbol ? vma : 0;
227933965Sjdp
2280218822Sdim  /* Do not copy backend data if --extract-symbol is passed; anything
2281218822Sdim     that needs to look at the section contents will fail.  */
2282218822Sdim  if (extract_symbol)
2283218822Sdim    return;
2284218822Sdim
228533965Sjdp  /* Allow the BFD backend to copy any private data it understands
228633965Sjdp     from the input section to the output section.  */
2287218822Sdim  if (!bfd_copy_private_section_data (ibfd, isection, obfd, osection))
228833965Sjdp    {
228977298Sobrien      err = _("private data");
229033965Sjdp      goto loser;
229133965Sjdp    }
2292218822Sdim  else if ((isection->flags & SEC_GROUP) != 0)
2293218822Sdim    {
2294218822Sdim      asymbol *gsym = group_signature (isection);
229533965Sjdp
2296218822Sdim      if (gsym != NULL)
2297218822Sdim	gsym->flags |= BSF_KEEP;
2298218822Sdim    }
2299218822Sdim
230089857Sobrien  /* All went well.  */
230133965Sjdp  return;
230233965Sjdp
230333965Sjdploser:
230460484Sobrien  non_fatal (_("%s: section `%s': error in %s: %s"),
230560484Sobrien	     bfd_get_filename (ibfd),
230660484Sobrien	     bfd_section_name (ibfd, isection),
230760484Sobrien	     err, bfd_errmsg (bfd_get_error ()));
230833965Sjdp  status = 1;
230933965Sjdp}
231033965Sjdp
231133965Sjdp/* Copy the data of input section ISECTION of IBFD
231233965Sjdp   to an output section with the same name in OBFD.
231333965Sjdp   If stripping then don't copy any relocation info.  */
231433965Sjdp
231533965Sjdpstatic void
2316130561Sobriencopy_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
231733965Sjdp{
2318130561Sobrien  bfd *obfd = obfdarg;
231933965Sjdp  struct section_list *p;
232033965Sjdp  arelent **relpp;
232133965Sjdp  long relcount;
232233965Sjdp  sec_ptr osection;
232333965Sjdp  bfd_size_type size;
232460484Sobrien  long relsize;
2325104834Sobrien  flagword flags;
232633965Sjdp
232789857Sobrien  /* If we have already failed earlier on,
232889857Sobrien     do not keep on generating complaints now.  */
232960484Sobrien  if (status != 0)
233060484Sobrien    return;
233160484Sobrien
2332130561Sobrien  if (is_strip_section (ibfd, isection))
233389857Sobrien    return;
233433965Sjdp
2335130561Sobrien  flags = bfd_get_section_flags (ibfd, isection);
2336104834Sobrien  if ((flags & SEC_GROUP) != 0)
2337104834Sobrien    return;
2338104834Sobrien
233933965Sjdp  osection = isection->output_section;
2340218822Sdim  size = bfd_get_section_size (isection);
234133965Sjdp
234233965Sjdp  if (size == 0 || osection == 0)
234333965Sjdp    return;
234433965Sjdp
2345130561Sobrien  p = find_section_list (bfd_get_section_name (ibfd, isection), FALSE);
2346130561Sobrien
2347104834Sobrien  /* Core files do not need to be relocated.  */
234889857Sobrien  if (bfd_get_format (obfd) == bfd_core)
234989857Sobrien    relsize = 0;
235089857Sobrien  else
2351130561Sobrien    {
2352130561Sobrien      relsize = bfd_get_reloc_upper_bound (ibfd, isection);
235360484Sobrien
2354130561Sobrien      if (relsize < 0)
2355130561Sobrien	{
2356130561Sobrien	  /* Do not complain if the target does not support relocations.  */
2357130561Sobrien	  if (relsize == -1 && bfd_get_error () == bfd_error_invalid_operation)
2358130561Sobrien	    relsize = 0;
2359130561Sobrien	  else
2360130561Sobrien	    RETURN_NONFATAL (bfd_get_filename (ibfd));
2361130561Sobrien	}
2362130561Sobrien    }
236360484Sobrien
236460484Sobrien  if (relsize == 0)
2365130561Sobrien    bfd_set_reloc (obfd, osection, NULL, 0);
236633965Sjdp  else
236733965Sjdp    {
2368130561Sobrien      relpp = xmalloc (relsize);
236960484Sobrien      relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, isympp);
237060484Sobrien      if (relcount < 0)
237160484Sobrien	RETURN_NONFATAL (bfd_get_filename (ibfd));
237233965Sjdp
237360484Sobrien      if (strip_symbols == STRIP_ALL)
237433965Sjdp	{
237560484Sobrien	  /* Remove relocations which are not in
2376104834Sobrien	     keep_strip_specific_list.  */
237760484Sobrien	  arelent **temp_relpp;
237860484Sobrien	  long temp_relcount = 0;
237960484Sobrien	  long i;
238060484Sobrien
2381130561Sobrien	  temp_relpp = xmalloc (relsize);
238260484Sobrien	  for (i = 0; i < relcount; i++)
2383130561Sobrien	    if (is_specified_symbol (bfd_asymbol_name (*relpp[i]->sym_ptr_ptr),
2384130561Sobrien				     keep_specific_list))
238560484Sobrien	      temp_relpp [temp_relcount++] = relpp [i];
238660484Sobrien	  relcount = temp_relcount;
238760484Sobrien	  free (relpp);
238860484Sobrien	  relpp = temp_relpp;
238933965Sjdp	}
239089857Sobrien
2391130561Sobrien      bfd_set_reloc (obfd, osection, relcount == 0 ? NULL : relpp, relcount);
2392130561Sobrien      if (relcount == 0)
2393130561Sobrien	free (relpp);
239433965Sjdp    }
239533965Sjdp
2396218822Sdim  if (extract_symbol)
2397218822Sdim    return;
239833965Sjdp
2399104834Sobrien  if (bfd_get_section_flags (ibfd, isection) & SEC_HAS_CONTENTS
240089857Sobrien      && bfd_get_section_flags (obfd, osection) & SEC_HAS_CONTENTS)
240133965Sjdp    {
2402130561Sobrien      void *memhunk = xmalloc (size);
240333965Sjdp
2404130561Sobrien      if (!bfd_get_section_contents (ibfd, isection, memhunk, 0, size))
240560484Sobrien	RETURN_NONFATAL (bfd_get_filename (ibfd));
240633965Sjdp
2407218822Sdim      if (reverse_bytes)
2408218822Sdim	{
2409218822Sdim	  /* We don't handle leftover bytes (too many possible behaviors,
2410218822Sdim	     and we don't know what the user wants).  The section length
2411218822Sdim	     must be a multiple of the number of bytes to swap.  */
2412218822Sdim	  if ((size % reverse_bytes) == 0)
2413218822Sdim	    {
2414218822Sdim	      unsigned long i, j;
2415218822Sdim	      bfd_byte b;
2416218822Sdim
2417218822Sdim	      for (i = 0; i < size; i += reverse_bytes)
2418218822Sdim		for (j = 0; j < (unsigned long)(reverse_bytes / 2); j++)
2419218822Sdim		  {
2420218822Sdim		    bfd_byte *m = (bfd_byte *) memhunk;
2421218822Sdim
2422218822Sdim		    b = m[i + j];
2423218822Sdim		    m[i + j] = m[(i + reverse_bytes) - (j + 1)];
2424218822Sdim		    m[(i + reverse_bytes) - (j + 1)] = b;
2425218822Sdim		  }
2426218822Sdim	    }
2427218822Sdim	  else
2428218822Sdim	    /* User must pad the section up in order to do this.  */
2429218822Sdim	    fatal (_("cannot reverse bytes: length of section %s must be evenly divisible by %d"),
2430218822Sdim		   bfd_section_name (ibfd, isection), reverse_bytes);
2431218822Sdim	}
2432218822Sdim
243360484Sobrien      if (copy_byte >= 0)
2434130561Sobrien	{
2435130561Sobrien	  /* Keep only every `copy_byte'th byte in MEMHUNK.  */
2436130561Sobrien	  char *from = (char *) memhunk + copy_byte;
2437130561Sobrien	  char *to = memhunk;
2438130561Sobrien	  char *end = (char *) memhunk + size;
243933965Sjdp
2440130561Sobrien	  for (; from < end; from += interleave)
2441130561Sobrien	    *to++ = *from;
2442130561Sobrien
2443130561Sobrien	  size = (size + interleave - 1 - copy_byte) / interleave;
2444130561Sobrien	  osection->lma /= interleave;
2445130561Sobrien	}
2446130561Sobrien
2447130561Sobrien      if (!bfd_set_section_contents (obfd, osection, memhunk, 0, size))
244860484Sobrien	RETURN_NONFATAL (bfd_get_filename (obfd));
244960484Sobrien
245033965Sjdp      free (memhunk);
245133965Sjdp    }
245238889Sjdp  else if (p != NULL && p->set_flags && (p->flags & SEC_HAS_CONTENTS) != 0)
245338889Sjdp    {
2454130561Sobrien      void *memhunk = xmalloc (size);
245538889Sjdp
245638889Sjdp      /* We don't permit the user to turn off the SEC_HAS_CONTENTS
245738889Sjdp	 flag--they can just remove the section entirely and add it
245838889Sjdp	 back again.  However, we do permit them to turn on the
245938889Sjdp	 SEC_HAS_CONTENTS flag, and take it to mean that the section
246038889Sjdp	 contents should be zeroed out.  */
246138889Sjdp
246238889Sjdp      memset (memhunk, 0, size);
2463130561Sobrien      if (! bfd_set_section_contents (obfd, osection, memhunk, 0, size))
246460484Sobrien	RETURN_NONFATAL (bfd_get_filename (obfd));
246538889Sjdp      free (memhunk);
246638889Sjdp    }
246733965Sjdp}
246833965Sjdp
246933965Sjdp/* Get all the sections.  This is used when --gap-fill or --pad-to is
247033965Sjdp   used.  */
247133965Sjdp
247233965Sjdpstatic void
2473130561Sobrienget_sections (bfd *obfd ATTRIBUTE_UNUSED, asection *osection, void *secppparg)
247433965Sjdp{
2475130561Sobrien  asection ***secppp = secppparg;
247633965Sjdp
247733965Sjdp  **secppp = osection;
247833965Sjdp  ++(*secppp);
247933965Sjdp}
248033965Sjdp
248133965Sjdp/* Sort sections by VMA.  This is called via qsort, and is used when
248233965Sjdp   --gap-fill or --pad-to is used.  We force non loadable or empty
248333965Sjdp   sections to the front, where they are easier to ignore.  */
248433965Sjdp
248533965Sjdpstatic int
2486130561Sobriencompare_section_lma (const void *arg1, const void *arg2)
248733965Sjdp{
2488130561Sobrien  const asection *const *sec1 = arg1;
2489130561Sobrien  const asection *const *sec2 = arg2;
249033965Sjdp  flagword flags1, flags2;
249133965Sjdp
249233965Sjdp  /* Sort non loadable sections to the front.  */
249333965Sjdp  flags1 = (*sec1)->flags;
249433965Sjdp  flags2 = (*sec2)->flags;
249533965Sjdp  if ((flags1 & SEC_HAS_CONTENTS) == 0
249633965Sjdp      || (flags1 & SEC_LOAD) == 0)
249733965Sjdp    {
249833965Sjdp      if ((flags2 & SEC_HAS_CONTENTS) != 0
249933965Sjdp	  && (flags2 & SEC_LOAD) != 0)
250033965Sjdp	return -1;
250133965Sjdp    }
250233965Sjdp  else
250333965Sjdp    {
250433965Sjdp      if ((flags2 & SEC_HAS_CONTENTS) == 0
250533965Sjdp	  || (flags2 & SEC_LOAD) == 0)
250633965Sjdp	return 1;
250733965Sjdp    }
250833965Sjdp
250938889Sjdp  /* Sort sections by LMA.  */
251038889Sjdp  if ((*sec1)->lma > (*sec2)->lma)
251133965Sjdp    return 1;
251238889Sjdp  else if ((*sec1)->lma < (*sec2)->lma)
251333965Sjdp    return -1;
251433965Sjdp
251538889Sjdp  /* Sort sections with the same LMA by size.  */
2516218822Sdim  if (bfd_get_section_size (*sec1) > bfd_get_section_size (*sec2))
251733965Sjdp    return 1;
2518218822Sdim  else if (bfd_get_section_size (*sec1) < bfd_get_section_size (*sec2))
251933965Sjdp    return -1;
252033965Sjdp
252133965Sjdp  return 0;
252233965Sjdp}
252333965Sjdp
252433965Sjdp/* Mark all the symbols which will be used in output relocations with
252533965Sjdp   the BSF_KEEP flag so that those symbols will not be stripped.
252633965Sjdp
252733965Sjdp   Ignore relocations which will not appear in the output file.  */
252833965Sjdp
252933965Sjdpstatic void
2530130561Sobrienmark_symbols_used_in_relocations (bfd *ibfd, sec_ptr isection, void *symbolsarg)
253133965Sjdp{
2532130561Sobrien  asymbol **symbols = symbolsarg;
253333965Sjdp  long relsize;
253433965Sjdp  arelent **relpp;
253533965Sjdp  long relcount, i;
253633965Sjdp
253733965Sjdp  /* Ignore an input section with no corresponding output section.  */
253833965Sjdp  if (isection->output_section == NULL)
253933965Sjdp    return;
254033965Sjdp
254133965Sjdp  relsize = bfd_get_reloc_upper_bound (ibfd, isection);
254233965Sjdp  if (relsize < 0)
2543130561Sobrien    {
2544130561Sobrien      /* Do not complain if the target does not support relocations.  */
2545130561Sobrien      if (relsize == -1 && bfd_get_error () == bfd_error_invalid_operation)
2546130561Sobrien	return;
2547130561Sobrien      bfd_fatal (bfd_get_filename (ibfd));
2548130561Sobrien    }
254933965Sjdp
255033965Sjdp  if (relsize == 0)
255133965Sjdp    return;
255233965Sjdp
2553130561Sobrien  relpp = xmalloc (relsize);
255433965Sjdp  relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, symbols);
255533965Sjdp  if (relcount < 0)
255633965Sjdp    bfd_fatal (bfd_get_filename (ibfd));
255733965Sjdp
255833965Sjdp  /* Examine each symbol used in a relocation.  If it's not one of the
255933965Sjdp     special bfd section symbols, then mark it with BSF_KEEP.  */
256033965Sjdp  for (i = 0; i < relcount; i++)
256133965Sjdp    {
256233965Sjdp      if (*relpp[i]->sym_ptr_ptr != bfd_com_section_ptr->symbol
256333965Sjdp	  && *relpp[i]->sym_ptr_ptr != bfd_abs_section_ptr->symbol
256433965Sjdp	  && *relpp[i]->sym_ptr_ptr != bfd_und_section_ptr->symbol)
256533965Sjdp	(*relpp[i]->sym_ptr_ptr)->flags |= BSF_KEEP;
256633965Sjdp    }
256733965Sjdp
256833965Sjdp  if (relpp != NULL)
256933965Sjdp    free (relpp);
257033965Sjdp}
257133965Sjdp
257233965Sjdp/* Write out debugging information.  */
257333965Sjdp
2574130561Sobrienstatic bfd_boolean
2575130561Sobrienwrite_debugging_info (bfd *obfd, void *dhandle,
2576130561Sobrien		      long *symcountp ATTRIBUTE_UNUSED,
2577130561Sobrien		      asymbol ***symppp ATTRIBUTE_UNUSED)
257833965Sjdp{
257933965Sjdp  if (bfd_get_flavour (obfd) == bfd_target_ieee_flavour)
258033965Sjdp    return write_ieee_debugging_info (obfd, dhandle);
258133965Sjdp
258233965Sjdp  if (bfd_get_flavour (obfd) == bfd_target_coff_flavour
258333965Sjdp      || bfd_get_flavour (obfd) == bfd_target_elf_flavour)
258433965Sjdp    {
258533965Sjdp      bfd_byte *syms, *strings;
258633965Sjdp      bfd_size_type symsize, stringsize;
258733965Sjdp      asection *stabsec, *stabstrsec;
2588218822Sdim      flagword flags;
258933965Sjdp
259033965Sjdp      if (! write_stabs_in_sections_debugging_info (obfd, dhandle, &syms,
259133965Sjdp						    &symsize, &strings,
259233965Sjdp						    &stringsize))
2593130561Sobrien	return FALSE;
259433965Sjdp
2595218822Sdim      flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DEBUGGING;
2596218822Sdim      stabsec = bfd_make_section_with_flags (obfd, ".stab", flags);
2597218822Sdim      stabstrsec = bfd_make_section_with_flags (obfd, ".stabstr", flags);
259833965Sjdp      if (stabsec == NULL
259933965Sjdp	  || stabstrsec == NULL
260033965Sjdp	  || ! bfd_set_section_size (obfd, stabsec, symsize)
260133965Sjdp	  || ! bfd_set_section_size (obfd, stabstrsec, stringsize)
260233965Sjdp	  || ! bfd_set_section_alignment (obfd, stabsec, 2)
2603218822Sdim	  || ! bfd_set_section_alignment (obfd, stabstrsec, 0))
260433965Sjdp	{
260560484Sobrien	  non_fatal (_("%s: can't create debugging section: %s"),
260660484Sobrien		     bfd_get_filename (obfd),
260760484Sobrien		     bfd_errmsg (bfd_get_error ()));
2608130561Sobrien	  return FALSE;
260933965Sjdp	}
261033965Sjdp
261133965Sjdp      /* We can get away with setting the section contents now because
261233965Sjdp         the next thing the caller is going to do is copy over the
261333965Sjdp         real sections.  We may someday have to split the contents
261433965Sjdp         setting out of this function.  */
2615130561Sobrien      if (! bfd_set_section_contents (obfd, stabsec, syms, 0, symsize)
2616130561Sobrien	  || ! bfd_set_section_contents (obfd, stabstrsec, strings, 0,
2617130561Sobrien					 stringsize))
261833965Sjdp	{
261960484Sobrien	  non_fatal (_("%s: can't set debugging section contents: %s"),
262060484Sobrien		     bfd_get_filename (obfd),
262160484Sobrien		     bfd_errmsg (bfd_get_error ()));
2622130561Sobrien	  return FALSE;
262333965Sjdp	}
262433965Sjdp
2625130561Sobrien      return TRUE;
262633965Sjdp    }
262733965Sjdp
262860484Sobrien  non_fatal (_("%s: don't know how to write debugging information for %s"),
262960484Sobrien	     bfd_get_filename (obfd), bfd_get_target (obfd));
2630130561Sobrien  return FALSE;
263133965Sjdp}
263233965Sjdp
263333965Sjdpstatic int
2634130561Sobrienstrip_main (int argc, char *argv[])
263533965Sjdp{
2636130561Sobrien  char *input_target = NULL;
2637130561Sobrien  char *output_target = NULL;
2638130561Sobrien  bfd_boolean show_version = FALSE;
2639130561Sobrien  bfd_boolean formats_info = FALSE;
2640130561Sobrien  int c;
2641130561Sobrien  int i;
264233965Sjdp  struct section_list *p;
264333965Sjdp  char *output_file = NULL;
264433965Sjdp
2645130561Sobrien  while ((c = getopt_long (argc, argv, "I:O:F:K:N:R:o:sSpdgxXHhVvw",
264633965Sjdp			   strip_options, (int *) 0)) != EOF)
264733965Sjdp    {
264833965Sjdp      switch (c)
264933965Sjdp	{
265033965Sjdp	case 'I':
265133965Sjdp	  input_target = optarg;
265233965Sjdp	  break;
265333965Sjdp	case 'O':
265433965Sjdp	  output_target = optarg;
265533965Sjdp	  break;
265633965Sjdp	case 'F':
265733965Sjdp	  input_target = output_target = optarg;
265833965Sjdp	  break;
265933965Sjdp	case 'R':
2660130561Sobrien	  p = find_section_list (optarg, TRUE);
2661130561Sobrien	  p->remove = TRUE;
2662130561Sobrien	  sections_removed = TRUE;
266333965Sjdp	  break;
266433965Sjdp	case 's':
266560484Sobrien	  strip_symbols = STRIP_ALL;
266633965Sjdp	  break;
266733965Sjdp	case 'S':
266833965Sjdp	case 'g':
266977298Sobrien	case 'd':	/* Historic BSD alias for -g.  Used by early NetBSD.  */
267060484Sobrien	  strip_symbols = STRIP_DEBUG;
267133965Sjdp	  break;
267233965Sjdp	case OPTION_STRIP_UNNEEDED:
267360484Sobrien	  strip_symbols = STRIP_UNNEEDED;
267433965Sjdp	  break;
267533965Sjdp	case 'K':
267638889Sjdp	  add_specific_symbol (optarg, &keep_specific_list);
267733965Sjdp	  break;
267833965Sjdp	case 'N':
267938889Sjdp	  add_specific_symbol (optarg, &strip_specific_list);
268033965Sjdp	  break;
268133965Sjdp	case 'o':
268233965Sjdp	  output_file = optarg;
268333965Sjdp	  break;
268433965Sjdp	case 'p':
2685130561Sobrien	  preserve_dates = TRUE;
268633965Sjdp	  break;
268733965Sjdp	case 'x':
268860484Sobrien	  discard_locals = LOCALS_ALL;
268933965Sjdp	  break;
269033965Sjdp	case 'X':
269160484Sobrien	  discard_locals = LOCALS_START_L;
269233965Sjdp	  break;
269333965Sjdp	case 'v':
2694130561Sobrien	  verbose = TRUE;
269533965Sjdp	  break;
269633965Sjdp	case 'V':
2697130561Sobrien	  show_version = TRUE;
269833965Sjdp	  break;
2699130561Sobrien	case OPTION_FORMATS_INFO:
2700130561Sobrien	  formats_info = TRUE;
2701130561Sobrien	  break;
2702130561Sobrien	case OPTION_ONLY_KEEP_DEBUG:
2703130561Sobrien	  strip_symbols = STRIP_NONDEBUG;
2704130561Sobrien	  break;
2705218822Sdim	case OPTION_KEEP_FILE_SYMBOLS:
2706218822Sdim	  keep_file_symbols = 1;
2707218822Sdim	  break;
270833965Sjdp	case 0:
270989857Sobrien	  /* We've been given a long option.  */
271089857Sobrien	  break;
2711130561Sobrien	case 'w':
2712130561Sobrien	  wildcard = TRUE;
2713130561Sobrien	  break;
271489857Sobrien	case 'H':
271533965Sjdp	case 'h':
271633965Sjdp	  strip_usage (stdout, 0);
271733965Sjdp	default:
271833965Sjdp	  strip_usage (stderr, 1);
271933965Sjdp	}
272033965Sjdp    }
272133965Sjdp
2722130561Sobrien  if (formats_info)
2723130561Sobrien    {
2724130561Sobrien      display_info ();
2725130561Sobrien      return 0;
2726130561Sobrien    }
2727218822Sdim
272833965Sjdp  if (show_version)
272933965Sjdp    print_version ("strip");
273033965Sjdp
273133965Sjdp  /* Default is to strip all symbols.  */
273260484Sobrien  if (strip_symbols == STRIP_UNDEF
273360484Sobrien      && discard_locals == LOCALS_UNDEF
273433965Sjdp      && strip_specific_list == NULL)
273560484Sobrien    strip_symbols = STRIP_ALL;
273633965Sjdp
2737130561Sobrien  if (output_target == NULL)
273833965Sjdp    output_target = input_target;
273933965Sjdp
274033965Sjdp  i = optind;
274133965Sjdp  if (i == argc
274233965Sjdp      || (output_file != NULL && (i + 1) < argc))
274333965Sjdp    strip_usage (stderr, 1);
274433965Sjdp
274533965Sjdp  for (; i < argc; i++)
274633965Sjdp    {
274733965Sjdp      int hold_status = status;
274838889Sjdp      struct stat statbuf;
274933965Sjdp      char *tmpname;
275033965Sjdp
2751130561Sobrien      if (get_file_size (argv[i]) < 1)
2752218822Sdim	{
2753218822Sdim	  status = 1;
2754218822Sdim	  continue;
2755218822Sdim	}
2756130561Sobrien
275738889Sjdp      if (preserve_dates)
2758130561Sobrien	/* No need to check the return value of stat().
2759130561Sobrien	   It has already been checked in get_file_size().  */
2760130561Sobrien	stat (argv[i], &statbuf);
276138889Sjdp
2762218822Sdim      if (output_file == NULL || strcmp (argv[i], output_file) == 0)
2763218822Sdim	tmpname = make_tempname (argv[i]);
2764218822Sdim      else
276533965Sjdp	tmpname = output_file;
2766218822Sdim
2767218822Sdim      if (tmpname == NULL)
2768218822Sdim	{
2769218822Sdim	  non_fatal (_("could not create temporary file to hold stripped copy of '%s'"),
2770218822Sdim		     argv[i]);
2771218822Sdim	  status = 1;
2772218822Sdim	  continue;
2773218822Sdim	}
2774218822Sdim
277533965Sjdp      status = 0;
277633965Sjdp      copy_file (argv[i], tmpname, input_target, output_target);
277733965Sjdp      if (status == 0)
277833965Sjdp	{
277933965Sjdp	  if (preserve_dates)
278038889Sjdp	    set_times (tmpname, &statbuf);
2781218822Sdim	  if (output_file != tmpname)
2782218822Sdim	    smart_rename (tmpname, output_file ? output_file : argv[i],
2783218822Sdim			  preserve_dates);
278433965Sjdp	  status = hold_status;
278533965Sjdp	}
278633965Sjdp      else
2787218822Sdim	unlink_if_ordinary (tmpname);
2788218822Sdim      if (output_file != tmpname)
278933965Sjdp	free (tmpname);
279033965Sjdp    }
279133965Sjdp
2792218822Sdim  return status;
279333965Sjdp}
279433965Sjdp
279533965Sjdpstatic int
2796130561Sobriencopy_main (int argc, char *argv[])
279733965Sjdp{
279889857Sobrien  char * binary_architecture = NULL;
2799130561Sobrien  char *input_filename = NULL;
2800130561Sobrien  char *output_filename = NULL;
2801218822Sdim  char *tmpname;
2802130561Sobrien  char *input_target = NULL;
2803130561Sobrien  char *output_target = NULL;
2804130561Sobrien  bfd_boolean show_version = FALSE;
2805130561Sobrien  bfd_boolean change_warn = TRUE;
2806130561Sobrien  bfd_boolean formats_info = FALSE;
280733965Sjdp  int c;
280833965Sjdp  struct section_list *p;
280938889Sjdp  struct stat statbuf;
281033965Sjdp
2811130561Sobrien  while ((c = getopt_long (argc, argv, "b:B:i:I:j:K:N:s:O:d:F:L:G:R:SpgxXHhVvW:w",
281233965Sjdp			   copy_options, (int *) 0)) != EOF)
281333965Sjdp    {
281433965Sjdp      switch (c)
281533965Sjdp	{
281633965Sjdp	case 'b':
281760484Sobrien	  copy_byte = atoi (optarg);
281833965Sjdp	  if (copy_byte < 0)
281960484Sobrien	    fatal (_("byte number must be non-negative"));
282033965Sjdp	  break;
282160484Sobrien
2822104834Sobrien	case 'B':
2823104834Sobrien	  binary_architecture = optarg;
2824104834Sobrien	  break;
282589857Sobrien
282633965Sjdp	case 'i':
282760484Sobrien	  interleave = atoi (optarg);
282833965Sjdp	  if (interleave < 1)
282960484Sobrien	    fatal (_("interleave must be positive"));
283033965Sjdp	  break;
283160484Sobrien
283233965Sjdp	case 'I':
283333965Sjdp	case 's':		/* "source" - 'I' is preferred */
283433965Sjdp	  input_target = optarg;
283533965Sjdp	  break;
283660484Sobrien
283733965Sjdp	case 'O':
283833965Sjdp	case 'd':		/* "destination" - 'O' is preferred */
283933965Sjdp	  output_target = optarg;
284033965Sjdp	  break;
284160484Sobrien
284233965Sjdp	case 'F':
284333965Sjdp	  input_target = output_target = optarg;
284433965Sjdp	  break;
284560484Sobrien
284660484Sobrien	case 'j':
2847130561Sobrien	  p = find_section_list (optarg, TRUE);
284860484Sobrien	  if (p->remove)
284960484Sobrien	    fatal (_("%s both copied and removed"), optarg);
2850130561Sobrien	  p->copy = TRUE;
2851130561Sobrien	  sections_copied = TRUE;
285260484Sobrien	  break;
285360484Sobrien
285433965Sjdp	case 'R':
2855130561Sobrien	  p = find_section_list (optarg, TRUE);
285660484Sobrien	  if (p->copy)
285760484Sobrien	    fatal (_("%s both copied and removed"), optarg);
2858130561Sobrien	  p->remove = TRUE;
2859130561Sobrien	  sections_removed = TRUE;
286033965Sjdp	  break;
286160484Sobrien
286233965Sjdp	case 'S':
286360484Sobrien	  strip_symbols = STRIP_ALL;
286433965Sjdp	  break;
286560484Sobrien
286633965Sjdp	case 'g':
286760484Sobrien	  strip_symbols = STRIP_DEBUG;
286833965Sjdp	  break;
286960484Sobrien
287033965Sjdp	case OPTION_STRIP_UNNEEDED:
287160484Sobrien	  strip_symbols = STRIP_UNNEEDED;
287233965Sjdp	  break;
287360484Sobrien
2874130561Sobrien	case OPTION_ONLY_KEEP_DEBUG:
2875130561Sobrien	  strip_symbols = STRIP_NONDEBUG;
2876130561Sobrien	  break;
2877130561Sobrien
2878218822Sdim	case OPTION_KEEP_FILE_SYMBOLS:
2879218822Sdim	  keep_file_symbols = 1;
2880218822Sdim	  break;
2881218822Sdim
2882130561Sobrien	case OPTION_ADD_GNU_DEBUGLINK:
2883130561Sobrien	  gnu_debuglink_filename = optarg;
2884130561Sobrien	  break;
2885130561Sobrien
288633965Sjdp	case 'K':
288738889Sjdp	  add_specific_symbol (optarg, &keep_specific_list);
288833965Sjdp	  break;
288960484Sobrien
289033965Sjdp	case 'N':
289138889Sjdp	  add_specific_symbol (optarg, &strip_specific_list);
289233965Sjdp	  break;
289360484Sobrien
2894218822Sdim	case OPTION_STRIP_UNNEEDED_SYMBOL:
2895218822Sdim	  add_specific_symbol (optarg, &strip_unneeded_list);
2896218822Sdim	  break;
2897218822Sdim
289838889Sjdp	case 'L':
289938889Sjdp	  add_specific_symbol (optarg, &localize_specific_list);
290038889Sjdp	  break;
290160484Sobrien
2902218822Sdim	case OPTION_GLOBALIZE_SYMBOL:
2903218822Sdim	  add_specific_symbol (optarg, &globalize_specific_list);
2904218822Sdim	  break;
2905218822Sdim
290678828Sobrien	case 'G':
290778828Sobrien	  add_specific_symbol (optarg, &keepglobal_specific_list);
290878828Sobrien	  break;
290978828Sobrien
291038889Sjdp	case 'W':
291138889Sjdp	  add_specific_symbol (optarg, &weaken_specific_list);
291238889Sjdp	  break;
291360484Sobrien
291433965Sjdp	case 'p':
2915130561Sobrien	  preserve_dates = TRUE;
291633965Sjdp	  break;
291760484Sobrien
2918130561Sobrien	case 'w':
2919130561Sobrien	  wildcard = TRUE;
2920130561Sobrien	  break;
2921130561Sobrien
292233965Sjdp	case 'x':
292360484Sobrien	  discard_locals = LOCALS_ALL;
292433965Sjdp	  break;
292560484Sobrien
292633965Sjdp	case 'X':
292760484Sobrien	  discard_locals = LOCALS_START_L;
292833965Sjdp	  break;
292960484Sobrien
293033965Sjdp	case 'v':
2931130561Sobrien	  verbose = TRUE;
293233965Sjdp	  break;
293360484Sobrien
293433965Sjdp	case 'V':
2935130561Sobrien	  show_version = TRUE;
293633965Sjdp	  break;
293760484Sobrien
2938130561Sobrien	case OPTION_FORMATS_INFO:
2939130561Sobrien	  formats_info = TRUE;
2940130561Sobrien	  break;
2941130561Sobrien
294233965Sjdp	case OPTION_WEAKEN:
2943130561Sobrien	  weaken = TRUE;
294433965Sjdp	  break;
294560484Sobrien
294633965Sjdp	case OPTION_ADD_SECTION:
294733965Sjdp	  {
294833965Sjdp	    const char *s;
2949130561Sobrien	    off_t size;
295033965Sjdp	    struct section_add *pa;
295133965Sjdp	    int len;
295233965Sjdp	    char *name;
295333965Sjdp	    FILE *f;
295433965Sjdp
295533965Sjdp	    s = strchr (optarg, '=');
295660484Sobrien
295733965Sjdp	    if (s == NULL)
295860484Sobrien	      fatal (_("bad format for %s"), "--add-section");
295933965Sjdp
2960130561Sobrien	    size = get_file_size (s + 1);
2961130561Sobrien	    if (size < 1)
2962218822Sdim	      {
2963218822Sdim		status = 1;
2964218822Sdim		break;
2965218822Sdim	      }
296633965Sjdp
2967130561Sobrien	    pa = xmalloc (sizeof (struct section_add));
296833965Sjdp
296933965Sjdp	    len = s - optarg;
2970130561Sobrien	    name = xmalloc (len + 1);
297133965Sjdp	    strncpy (name, optarg, len);
297233965Sjdp	    name[len] = '\0';
297333965Sjdp	    pa->name = name;
297433965Sjdp
297533965Sjdp	    pa->filename = s + 1;
2976130561Sobrien	    pa->size = size;
2977130561Sobrien	    pa->contents = xmalloc (size);
297833965Sjdp
297933965Sjdp	    f = fopen (pa->filename, FOPEN_RB);
298060484Sobrien
298133965Sjdp	    if (f == NULL)
2982130561Sobrien	      fatal (_("cannot open: %s: %s"),
2983130561Sobrien		     pa->filename, strerror (errno));
298460484Sobrien
298533965Sjdp	    if (fread (pa->contents, 1, pa->size, f) == 0
298633965Sjdp		|| ferror (f))
298760484Sobrien	      fatal (_("%s: fread failed"), pa->filename);
298860484Sobrien
298933965Sjdp	    fclose (f);
299033965Sjdp
299133965Sjdp	    pa->next = add_sections;
299233965Sjdp	    add_sections = pa;
299333965Sjdp	  }
299433965Sjdp	  break;
299560484Sobrien
299660484Sobrien	case OPTION_CHANGE_START:
299760484Sobrien	  change_start = parse_vma (optarg, "--change-start");
299833965Sjdp	  break;
299960484Sobrien
300060484Sobrien	case OPTION_CHANGE_SECTION_ADDRESS:
300160484Sobrien	case OPTION_CHANGE_SECTION_LMA:
300260484Sobrien	case OPTION_CHANGE_SECTION_VMA:
300333965Sjdp	  {
300433965Sjdp	    const char *s;
300533965Sjdp	    int len;
300633965Sjdp	    char *name;
300760484Sobrien	    char *option = NULL;
300860484Sobrien	    bfd_vma val;
300960484Sobrien	    enum change_action what = CHANGE_IGNORE;
301033965Sjdp
301160484Sobrien	    switch (c)
301260484Sobrien	      {
301360484Sobrien	      case OPTION_CHANGE_SECTION_ADDRESS:
301460484Sobrien		option = "--change-section-address";
301560484Sobrien		break;
301660484Sobrien	      case OPTION_CHANGE_SECTION_LMA:
301760484Sobrien		option = "--change-section-lma";
301860484Sobrien		break;
301960484Sobrien	      case OPTION_CHANGE_SECTION_VMA:
302060484Sobrien		option = "--change-section-vma";
302160484Sobrien		break;
302260484Sobrien	      }
302360484Sobrien
302433965Sjdp	    s = strchr (optarg, '=');
302533965Sjdp	    if (s == NULL)
302633965Sjdp	      {
302733965Sjdp		s = strchr (optarg, '+');
302833965Sjdp		if (s == NULL)
302933965Sjdp		  {
303033965Sjdp		    s = strchr (optarg, '-');
303133965Sjdp		    if (s == NULL)
303260484Sobrien		      fatal (_("bad format for %s"), option);
303333965Sjdp		  }
303433965Sjdp	      }
303533965Sjdp
303633965Sjdp	    len = s - optarg;
3037130561Sobrien	    name = xmalloc (len + 1);
303833965Sjdp	    strncpy (name, optarg, len);
303933965Sjdp	    name[len] = '\0';
304033965Sjdp
3041130561Sobrien	    p = find_section_list (name, TRUE);
304233965Sjdp
304360484Sobrien	    val = parse_vma (s + 1, option);
304433965Sjdp
304560484Sobrien	    switch (*s)
304633965Sjdp	      {
304760484Sobrien	      case '=': what = CHANGE_SET; break;
304860484Sobrien	      case '-': val  = - val; /* Drop through.  */
304960484Sobrien	      case '+': what = CHANGE_MODIFY; break;
305033965Sjdp	      }
305160484Sobrien
305260484Sobrien	    switch (c)
305360484Sobrien	      {
305460484Sobrien	      case OPTION_CHANGE_SECTION_ADDRESS:
305560484Sobrien		p->change_vma = what;
305660484Sobrien		p->vma_val    = val;
305760484Sobrien		/* Drop through.  */
305860484Sobrien
305960484Sobrien	      case OPTION_CHANGE_SECTION_LMA:
306060484Sobrien		p->change_lma = what;
306160484Sobrien		p->lma_val    = val;
306260484Sobrien		break;
306360484Sobrien
306460484Sobrien	      case OPTION_CHANGE_SECTION_VMA:
306560484Sobrien		p->change_vma = what;
306660484Sobrien		p->vma_val    = val;
306760484Sobrien		break;
306860484Sobrien	      }
306933965Sjdp	  }
307033965Sjdp	  break;
307160484Sobrien
307260484Sobrien	case OPTION_CHANGE_ADDRESSES:
307360484Sobrien	  change_section_address = parse_vma (optarg, "--change-addresses");
307460484Sobrien	  change_start = change_section_address;
307533965Sjdp	  break;
307660484Sobrien
307760484Sobrien	case OPTION_CHANGE_WARNINGS:
3078130561Sobrien	  change_warn = TRUE;
307933965Sjdp	  break;
308060484Sobrien
308133965Sjdp	case OPTION_CHANGE_LEADING_CHAR:
3082130561Sobrien	  change_leading_char = TRUE;
308333965Sjdp	  break;
308460484Sobrien
308533965Sjdp	case OPTION_DEBUGGING:
3086130561Sobrien	  convert_debugging = TRUE;
308733965Sjdp	  break;
308860484Sobrien
308933965Sjdp	case OPTION_GAP_FILL:
309033965Sjdp	  {
309133965Sjdp	    bfd_vma gap_fill_vma;
309233965Sjdp
309333965Sjdp	    gap_fill_vma = parse_vma (optarg, "--gap-fill");
309433965Sjdp	    gap_fill = (bfd_byte) gap_fill_vma;
309533965Sjdp	    if ((bfd_vma) gap_fill != gap_fill_vma)
309633965Sjdp	      {
309760484Sobrien		char buff[20];
309860484Sobrien
309960484Sobrien		sprintf_vma (buff, gap_fill_vma);
310060484Sobrien
310160484Sobrien		non_fatal (_("Warning: truncating gap-fill from 0x%s to 0x%x"),
310260484Sobrien			   buff, gap_fill);
310333965Sjdp	      }
3104130561Sobrien	    gap_fill_set = TRUE;
310533965Sjdp	  }
310633965Sjdp	  break;
310760484Sobrien
310860484Sobrien	case OPTION_NO_CHANGE_WARNINGS:
3109130561Sobrien	  change_warn = FALSE;
311033965Sjdp	  break;
311160484Sobrien
311233965Sjdp	case OPTION_PAD_TO:
311333965Sjdp	  pad_to = parse_vma (optarg, "--pad-to");
3114130561Sobrien	  pad_to_set = TRUE;
311533965Sjdp	  break;
311660484Sobrien
311733965Sjdp	case OPTION_REMOVE_LEADING_CHAR:
3118130561Sobrien	  remove_leading_char = TRUE;
311933965Sjdp	  break;
312060484Sobrien
312160484Sobrien	case OPTION_REDEFINE_SYM:
312260484Sobrien	  {
312360484Sobrien	    /* Push this redefinition onto redefine_symbol_list.  */
312460484Sobrien
312560484Sobrien	    int len;
312660484Sobrien	    const char *s;
312760484Sobrien	    const char *nextarg;
312860484Sobrien	    char *source, *target;
312960484Sobrien
313060484Sobrien	    s = strchr (optarg, '=');
313160484Sobrien	    if (s == NULL)
313289857Sobrien	      fatal (_("bad format for %s"), "--redefine-sym");
313360484Sobrien
313460484Sobrien	    len = s - optarg;
3135130561Sobrien	    source = xmalloc (len + 1);
313660484Sobrien	    strncpy (source, optarg, len);
313760484Sobrien	    source[len] = '\0';
313860484Sobrien
313960484Sobrien	    nextarg = s + 1;
314060484Sobrien	    len = strlen (nextarg);
3141130561Sobrien	    target = xmalloc (len + 1);
314260484Sobrien	    strcpy (target, nextarg);
314360484Sobrien
3144130561Sobrien	    redefine_list_append ("--redefine-sym", source, target);
314560484Sobrien
314660484Sobrien	    free (source);
314760484Sobrien	    free (target);
314860484Sobrien	  }
314960484Sobrien	  break;
315060484Sobrien
3151130561Sobrien	case OPTION_REDEFINE_SYMS:
3152130561Sobrien	  add_redefine_syms_file (optarg);
3153130561Sobrien	  break;
3154130561Sobrien
315533965Sjdp	case OPTION_SET_SECTION_FLAGS:
315633965Sjdp	  {
315733965Sjdp	    const char *s;
315833965Sjdp	    int len;
315933965Sjdp	    char *name;
316033965Sjdp
316133965Sjdp	    s = strchr (optarg, '=');
316233965Sjdp	    if (s == NULL)
316360484Sobrien	      fatal (_("bad format for %s"), "--set-section-flags");
316433965Sjdp
316533965Sjdp	    len = s - optarg;
3166130561Sobrien	    name = xmalloc (len + 1);
316733965Sjdp	    strncpy (name, optarg, len);
316833965Sjdp	    name[len] = '\0';
316933965Sjdp
3170130561Sobrien	    p = find_section_list (name, TRUE);
317133965Sjdp
3172130561Sobrien	    p->set_flags = TRUE;
317333965Sjdp	    p->flags = parse_flags (s + 1);
317433965Sjdp	  }
317533965Sjdp	  break;
317660484Sobrien
317789857Sobrien	case OPTION_RENAME_SECTION:
317889857Sobrien	  {
317989857Sobrien	    flagword flags;
318089857Sobrien	    const char *eq, *fl;
318189857Sobrien	    char *old_name;
318289857Sobrien	    char *new_name;
318389857Sobrien	    unsigned int len;
318489857Sobrien
318589857Sobrien	    eq = strchr (optarg, '=');
318689857Sobrien	    if (eq == NULL)
318789857Sobrien	      fatal (_("bad format for %s"), "--rename-section");
318889857Sobrien
318989857Sobrien	    len = eq - optarg;
319089857Sobrien	    if (len == 0)
319189857Sobrien	      fatal (_("bad format for %s"), "--rename-section");
319289857Sobrien
3193130561Sobrien	    old_name = xmalloc (len + 1);
319489857Sobrien	    strncpy (old_name, optarg, len);
319589857Sobrien	    old_name[len] = 0;
319689857Sobrien
319789857Sobrien	    eq++;
319889857Sobrien	    fl = strchr (eq, ',');
319989857Sobrien	    if (fl)
320089857Sobrien	      {
320189857Sobrien		flags = parse_flags (fl + 1);
320289857Sobrien		len = fl - eq;
320389857Sobrien	      }
320489857Sobrien	    else
320589857Sobrien	      {
320689857Sobrien		flags = -1;
320789857Sobrien		len = strlen (eq);
320889857Sobrien	      }
320989857Sobrien
321089857Sobrien	    if (len == 0)
321189857Sobrien	      fatal (_("bad format for %s"), "--rename-section");
321289857Sobrien
3213130561Sobrien	    new_name = xmalloc (len + 1);
321489857Sobrien	    strncpy (new_name, eq, len);
321589857Sobrien	    new_name[len] = 0;
321689857Sobrien
321789857Sobrien	    add_section_rename (old_name, new_name, flags);
321889857Sobrien	  }
321989857Sobrien	  break;
322089857Sobrien
322133965Sjdp	case OPTION_SET_START:
322233965Sjdp	  set_start = parse_vma (optarg, "--set-start");
3223130561Sobrien	  set_start_set = TRUE;
322433965Sjdp	  break;
322560484Sobrien
3226104834Sobrien	case OPTION_SREC_LEN:
3227104834Sobrien	  Chunk = parse_vma (optarg, "--srec-len");
3228104834Sobrien	  break;
322977298Sobrien
3230104834Sobrien	case OPTION_SREC_FORCES3:
3231130561Sobrien	  S3Forced = TRUE;
3232104834Sobrien	  break;
323377298Sobrien
323478828Sobrien	case OPTION_STRIP_SYMBOLS:
323578828Sobrien	  add_specific_symbols (optarg, &strip_specific_list);
323678828Sobrien	  break;
323778828Sobrien
3238218822Sdim	case OPTION_STRIP_UNNEEDED_SYMBOLS:
3239218822Sdim	  add_specific_symbols (optarg, &strip_unneeded_list);
3240218822Sdim	  break;
3241218822Sdim
324278828Sobrien	case OPTION_KEEP_SYMBOLS:
324378828Sobrien	  add_specific_symbols (optarg, &keep_specific_list);
324478828Sobrien	  break;
324578828Sobrien
3246218822Sdim	case OPTION_LOCALIZE_HIDDEN:
3247218822Sdim	  localize_hidden = TRUE;
3248218822Sdim	  break;
3249218822Sdim
325078828Sobrien	case OPTION_LOCALIZE_SYMBOLS:
325178828Sobrien	  add_specific_symbols (optarg, &localize_specific_list);
325278828Sobrien	  break;
325378828Sobrien
3254218822Sdim	case OPTION_GLOBALIZE_SYMBOLS:
3255218822Sdim	  add_specific_symbols (optarg, &globalize_specific_list);
3256218822Sdim	  break;
3257218822Sdim
325878828Sobrien	case OPTION_KEEPGLOBAL_SYMBOLS:
325978828Sobrien	  add_specific_symbols (optarg, &keepglobal_specific_list);
326078828Sobrien	  break;
326178828Sobrien
326278828Sobrien	case OPTION_WEAKEN_SYMBOLS:
326378828Sobrien	  add_specific_symbols (optarg, &weaken_specific_list);
326478828Sobrien	  break;
326578828Sobrien
326689857Sobrien	case OPTION_ALT_MACH_CODE:
3267218822Sdim	  use_alt_mach_code = strtoul (optarg, NULL, 0);
3268218822Sdim	  if (use_alt_mach_code == 0)
3269218822Sdim	    fatal (_("unable to parse alternative machine code"));
327089857Sobrien	  break;
327189857Sobrien
3272130561Sobrien	case OPTION_PREFIX_SYMBOLS:
3273130561Sobrien	  prefix_symbols_string = optarg;
3274130561Sobrien	  break;
3275130561Sobrien
3276130561Sobrien	case OPTION_PREFIX_SECTIONS:
3277130561Sobrien	  prefix_sections_string = optarg;
3278130561Sobrien	  break;
3279130561Sobrien
3280130561Sobrien	case OPTION_PREFIX_ALLOC_SECTIONS:
3281130561Sobrien	  prefix_alloc_sections_string = optarg;
3282130561Sobrien	  break;
3283130561Sobrien
3284130561Sobrien	case OPTION_READONLY_TEXT:
3285130561Sobrien	  bfd_flags_to_set |= WP_TEXT;
3286130561Sobrien	  bfd_flags_to_clear &= ~WP_TEXT;
3287130561Sobrien	  break;
3288130561Sobrien
3289130561Sobrien	case OPTION_WRITABLE_TEXT:
3290130561Sobrien	  bfd_flags_to_clear |= WP_TEXT;
3291130561Sobrien	  bfd_flags_to_set &= ~WP_TEXT;
3292130561Sobrien	  break;
3293130561Sobrien
3294130561Sobrien	case OPTION_PURE:
3295130561Sobrien	  bfd_flags_to_set |= D_PAGED;
3296130561Sobrien	  bfd_flags_to_clear &= ~D_PAGED;
3297130561Sobrien	  break;
3298130561Sobrien
3299130561Sobrien	case OPTION_IMPURE:
3300130561Sobrien	  bfd_flags_to_clear |= D_PAGED;
3301130561Sobrien	  bfd_flags_to_set &= ~D_PAGED;
3302130561Sobrien	  break;
3303130561Sobrien
3304218822Sdim	case OPTION_EXTRACT_SYMBOL:
3305218822Sdim	  extract_symbol = TRUE;
3306218822Sdim	  break;
3307218822Sdim
3308218822Sdim	case OPTION_REVERSE_BYTES:
3309218822Sdim          {
3310218822Sdim            int prev = reverse_bytes;
3311218822Sdim
3312218822Sdim            reverse_bytes = atoi (optarg);
3313218822Sdim            if ((reverse_bytes <= 0) || ((reverse_bytes % 2) != 0))
3314218822Sdim              fatal (_("number of bytes to reverse must be positive and even"));
3315218822Sdim
3316218822Sdim            if (prev && prev != reverse_bytes)
3317218822Sdim              non_fatal (_("Warning: ignoring previous --reverse-bytes value of %d"),
3318218822Sdim                         prev);
3319218822Sdim            break;
3320218822Sdim          }
3321218822Sdim
332233965Sjdp	case 0:
3323130561Sobrien	  /* We've been given a long option.  */
3324130561Sobrien	  break;
332560484Sobrien
332689857Sobrien	case 'H':
332733965Sjdp	case 'h':
332833965Sjdp	  copy_usage (stdout, 0);
332960484Sobrien
333033965Sjdp	default:
333133965Sjdp	  copy_usage (stderr, 1);
333233965Sjdp	}
333333965Sjdp    }
333433965Sjdp
3335130561Sobrien  if (formats_info)
3336130561Sobrien    {
3337130561Sobrien      display_info ();
3338130561Sobrien      return 0;
3339130561Sobrien    }
3340218822Sdim
334133965Sjdp  if (show_version)
334233965Sjdp    print_version ("objcopy");
334333965Sjdp
334433965Sjdp  if (copy_byte >= interleave)
334560484Sobrien    fatal (_("byte number must be less than interleave"));
334633965Sjdp
334733965Sjdp  if (optind == argc || optind + 2 < argc)
334833965Sjdp    copy_usage (stderr, 1);
334933965Sjdp
335033965Sjdp  input_filename = argv[optind];
335133965Sjdp  if (optind + 1 < argc)
335233965Sjdp    output_filename = argv[optind + 1];
335333965Sjdp
335433965Sjdp  /* Default is to strip no symbols.  */
335560484Sobrien  if (strip_symbols == STRIP_UNDEF && discard_locals == LOCALS_UNDEF)
335660484Sobrien    strip_symbols = STRIP_NONE;
335733965Sjdp
3358130561Sobrien  if (output_target == NULL)
335933965Sjdp    output_target = input_target;
336033965Sjdp
3361130561Sobrien  if (binary_architecture != NULL)
336289857Sobrien    {
336389857Sobrien      if (input_target && strcmp (input_target, "binary") == 0)
3364104834Sobrien	{
3365104834Sobrien	  const bfd_arch_info_type * temp_arch_info;
336689857Sobrien
336789857Sobrien	  temp_arch_info = bfd_scan_arch (binary_architecture);
336889857Sobrien
3369104834Sobrien	  if (temp_arch_info != NULL)
3370130561Sobrien	    {
3371130561Sobrien	      bfd_external_binary_architecture = temp_arch_info->arch;
3372130561Sobrien	      bfd_external_machine             = temp_arch_info->mach;
3373130561Sobrien	    }
3374104834Sobrien	  else
3375104834Sobrien	    fatal (_("architecture %s unknown"), binary_architecture);
3376104834Sobrien	}
337789857Sobrien      else
337889857Sobrien	{
337989857Sobrien	  non_fatal (_("Warning: input target 'binary' required for binary architecture parameter."));
338089857Sobrien	  non_fatal (_(" Argument %s ignored"), binary_architecture);
338189857Sobrien	}
338289857Sobrien    }
338389857Sobrien
338438889Sjdp  if (preserve_dates)
338580016Sobrien    if (stat (input_filename, & statbuf) < 0)
3386130561Sobrien      fatal (_("warning: could not locate '%s'.  System error message: %s"),
3387130561Sobrien	     input_filename, strerror (errno));
338838889Sjdp
3389130561Sobrien  /* If there is no destination file, or the source and destination files
3390130561Sobrien     are the same, then create a temp and rename the result into the input.  */
3391130561Sobrien  if (output_filename == NULL || strcmp (input_filename, output_filename) == 0)
3392218822Sdim    tmpname = make_tempname (input_filename);
3393218822Sdim  else
3394218822Sdim    tmpname = output_filename;
3395218822Sdim
3396218822Sdim  if (tmpname == NULL)
3397218822Sdim    fatal (_("warning: could not create temporary file whilst copying '%s', (error: %s)"),
3398218822Sdim	   input_filename, strerror (errno));
3399218822Sdim
3400218822Sdim  copy_file (input_filename, tmpname, input_target, output_target);
3401218822Sdim  if (status == 0)
340233965Sjdp    {
3403218822Sdim      if (preserve_dates)
3404218822Sdim	set_times (tmpname, &statbuf);
3405218822Sdim      if (tmpname != output_filename)
3406218822Sdim	smart_rename (tmpname, input_filename, preserve_dates);
340733965Sjdp    }
340833965Sjdp  else
3409218822Sdim    unlink_if_ordinary (tmpname);
341089857Sobrien
341160484Sobrien  if (change_warn)
341233965Sjdp    {
341360484Sobrien      for (p = change_sections; p != NULL; p = p->next)
341433965Sjdp	{
341560484Sobrien	  if (! p->used)
341633965Sjdp	    {
341760484Sobrien	      if (p->change_vma != CHANGE_IGNORE)
341860484Sobrien		{
341960484Sobrien		  char buff [20];
342060484Sobrien
342160484Sobrien		  sprintf_vma (buff, p->vma_val);
342260484Sobrien
342360484Sobrien		  /* xgettext:c-format */
342460484Sobrien		  non_fatal (_("%s %s%c0x%s never used"),
342560484Sobrien			     "--change-section-vma",
342660484Sobrien			     p->name,
342760484Sobrien			     p->change_vma == CHANGE_SET ? '=' : '+',
342860484Sobrien			     buff);
342960484Sobrien		}
343060484Sobrien
343160484Sobrien	      if (p->change_lma != CHANGE_IGNORE)
343260484Sobrien		{
343360484Sobrien		  char buff [20];
343460484Sobrien
343560484Sobrien		  sprintf_vma (buff, p->lma_val);
343660484Sobrien
343760484Sobrien		  /* xgettext:c-format */
343860484Sobrien		  non_fatal (_("%s %s%c0x%s never used"),
343960484Sobrien			     "--change-section-lma",
344060484Sobrien			     p->name,
344160484Sobrien			     p->change_lma == CHANGE_SET ? '=' : '+',
344260484Sobrien			     buff);
344360484Sobrien		}
344433965Sjdp	    }
344533965Sjdp	}
344633965Sjdp    }
344733965Sjdp
344833965Sjdp  return 0;
344933965Sjdp}
345033965Sjdp
345133965Sjdpint
3452130561Sobrienmain (int argc, char *argv[])
345333965Sjdp{
345460484Sobrien#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
345560484Sobrien  setlocale (LC_MESSAGES, "");
345660484Sobrien#endif
345789857Sobrien#if defined (HAVE_SETLOCALE)
345889857Sobrien  setlocale (LC_CTYPE, "");
345989857Sobrien#endif
346060484Sobrien  bindtextdomain (PACKAGE, LOCALEDIR);
346160484Sobrien  textdomain (PACKAGE);
346260484Sobrien
346333965Sjdp  program_name = argv[0];
346433965Sjdp  xmalloc_set_program_name (program_name);
346533965Sjdp
346633965Sjdp  START_PROGRESS (program_name, 0);
346733965Sjdp
3468218822Sdim  expandargv (&argc, &argv);
3469218822Sdim
347060484Sobrien  strip_symbols = STRIP_UNDEF;
347160484Sobrien  discard_locals = LOCALS_UNDEF;
347233965Sjdp
347333965Sjdp  bfd_init ();
347433965Sjdp  set_default_bfd_target ();
347533965Sjdp
347633965Sjdp  if (is_strip < 0)
347733965Sjdp    {
347833965Sjdp      int i = strlen (program_name);
347961843Sobrien#ifdef HAVE_DOS_BASED_FILE_SYSTEM
348061843Sobrien      /* Drop the .exe suffix, if any.  */
348161843Sobrien      if (i > 4 && FILENAME_CMP (program_name + i - 4, ".exe") == 0)
348261843Sobrien	{
348361843Sobrien	  i -= 4;
348461843Sobrien	  program_name[i] = '\0';
348561843Sobrien	}
348661843Sobrien#endif
348761843Sobrien      is_strip = (i >= 5 && FILENAME_CMP (program_name + i - 5, "strip") == 0);
348833965Sjdp    }
348933965Sjdp
349033965Sjdp  if (is_strip)
349133965Sjdp    strip_main (argc, argv);
349233965Sjdp  else
349333965Sjdp    copy_main (argc, argv);
349433965Sjdp
349533965Sjdp  END_PROGRESS (program_name);
349633965Sjdp
349733965Sjdp  return status;
349833965Sjdp}
3499