#include "sysdep.h"
#include "bucomm.h"
#include <getopt.h>
+#include "libiberty.h"
-static void setup_section ();
-static void copy_section ();
-static void mangle_section ();
+static bfd_vma parse_vma PARAMS ((const char *, const char *));
+static void setup_section PARAMS ((bfd *, asection *, PTR));
+static void copy_section PARAMS ((bfd *, asection *, PTR));
+static void get_sections PARAMS ((bfd *, asection *, PTR));
+static int compare_section_vma PARAMS ((const PTR, const PTR));
+static void mark_symbols_used_in_relocations PARAMS ((bfd *, asection *, PTR));
#define nonfatal(s) {bfd_nonfatal(s); status = 1; return;}
/* Which local symbols to remove. Overrides strip_all. */
static enum locals_action discard_locals;
+/* Structure used to hold lists of sections and actions to take. */
+
+struct section_list
+{
+ /* Next section to adjust. */
+ struct section_list *next;
+ /* Section name. */
+ const char *name;
+ /* Whether this entry was used. */
+ boolean used;
+ /* Remaining fields only used if not on remove_sections list. */
+ /* Whether to adjust or set VMA. */
+ boolean adjust;
+ /* Amount to adjust by or set to. */
+ bfd_vma val;
+};
+
+/* List of sections to remove. */
+
+static struct section_list *remove_sections;
+
+/* Adjustments to the start address. */
+static bfd_vma adjust_start = 0;
+static boolean set_start_set = false;
+static bfd_vma set_start;
+
+/* Adjustments to section VMA's. */
+static bfd_vma adjust_section_vma = 0;
+static struct section_list *adjust_sections;
+
+/* Filling gaps between sections. */
+static boolean gap_fill_set = false;
+static bfd_byte gap_fill = 0;
+
+/* Pad to a given address. */
+static boolean pad_to_set = false;
+static bfd_vma pad_to;
+
/* Options to handle if running as "strip". */
static struct option strip_options[] =
{"input-target", required_argument, 0, 'I'},
{"output-format", required_argument, 0, 'O'}, /* Obsolete */
{"output-target", required_argument, 0, 'O'},
+ {"remove-section", required_argument, 0, 'R'},
{"strip-all", no_argument, 0, 's'},
{"strip-debug", no_argument, 0, 'S'},
{"target", required_argument, 0, 'F'},
/* Options to handle if running as "objcopy". */
+/* 150 isn't special; it's just an arbitrary non-ASCII char value. */
+
+#define OPTION_ADJUST_START 150
+#define OPTION_ADJUST_VMA (OPTION_ADJUST_START + 1)
+#define OPTION_ADJUST_SECTION_VMA (OPTION_ADJUST_VMA + 1)
+#define OPTION_ADJUST_WARNINGS (OPTION_ADJUST_SECTION_VMA + 1)
+#define OPTION_GAP_FILL (OPTION_ADJUST_WARNINGS + 1)
+#define OPTION_NO_ADJUST_WARNINGS (OPTION_GAP_FILL + 1)
+#define OPTION_PAD_TO (OPTION_NO_ADJUST_WARNINGS + 1)
+#define OPTION_SET_START (OPTION_PAD_TO + 1)
+
static struct option copy_options[] =
{
+ {"adjust-start", required_argument, 0, OPTION_ADJUST_START},
+ {"adjust-vma", required_argument, 0, OPTION_ADJUST_VMA},
+ {"adjust-section-vma", required_argument, 0, OPTION_ADJUST_SECTION_VMA},
+ {"adjust-warnings", no_argument, 0, OPTION_ADJUST_WARNINGS},
{"byte", required_argument, 0, 'b'},
{"discard-all", no_argument, 0, 'x'},
{"discard-locals", no_argument, 0, 'X'},
{"format", required_argument, 0, 'F'}, /* Obsolete */
+ {"gap-fill", required_argument, 0, OPTION_GAP_FILL},
{"help", no_argument, 0, 'h'},
{"input-format", required_argument, 0, 'I'}, /* Obsolete */
{"input-target", required_argument, 0, 'I'},
{"interleave", required_argument, 0, 'i'},
+ {"no-adjust-warnings", no_argument, 0, OPTION_NO_ADJUST_WARNINGS},
{"output-format", required_argument, 0, 'O'}, /* Obsolete */
{"output-target", required_argument, 0, 'O'},
+ {"pad-to", required_argument, 0, OPTION_PAD_TO},
+ {"remove-section", required_argument, 0, 'R'},
+ {"set-start", required_argument, 0, OPTION_SET_START},
{"strip-all", no_argument, 0, 'S'},
{"strip-debug", no_argument, 0, 'g'},
{"target", required_argument, 0, 'F'},
{
fprintf (stream, "\
Usage: %s [-vVSgxX] [-I bfdname] [-O bfdname] [-F bfdname] [-b byte]\n\
- [-i interleave] [--interleave=interleave] [--byte=byte]\n\
+ [-R section] [-i interleave] [--interleave=interleave] [--byte=byte]\n\
[--input-target=bfdname] [--output-target=bfdname] [--target=bfdname]\n\
[--strip-all] [--strip-debug] [--discard-all] [--discard-locals]\n\
- [--verbose] [--version] [--help] in-file [out-file]\n",
+ [--remove-section=section] [--gap-fill=val] [--pad-to=address]\n\
+ [--set-start=val] [--adjust-start=incr] [--adjust-vma=incr]\n\
+ [--adjust-section-vma=section{=,+,-}val] [--adjust-warnings]\n\
+ [--no-adjust-warnings] [--verbose] [--version] [--help]\n\
+ in-file [out-file]\n",
program_name);
exit (status);
}
int status;
{
fprintf (stream, "\
-Usage: %s [-vVsSgxX] [-I bfdname] [-O bfdname] [-F bfdname]\n\
+Usage: %s [-vVsSgxX] [-I bfdname] [-O bfdname] [-F bfdname] [-R section]\n\
[--input-target=bfdname] [--output-target=bfdname] [--target=bfdname]\n\
[--strip-all] [--strip-debug] [--discard-all] [--discard-locals]\n\
- [--verbose] [--version] [--help] file...\n",
+ [--remove-section=section] [--verbose] [--version] [--help] file...\n",
program_name);
exit (status);
}
+/* Parse a string into a VMA, with a fatal error if it can't be
+ parsed. */
+
+static bfd_vma
+parse_vma (s, arg)
+ const char *s;
+ const char *arg;
+{
+ bfd_vma ret;
+ const char *end;
+
+ ret = bfd_scan_vma (s, &end, 0);
+ if (*end != '\0')
+ {
+ fprintf (stderr, "%s: %s: bad number: %s\n", program_name, arg, s);
+ exit (1);
+ }
+ return ret;
+}
/* Return the name of a temporary file in the same directory as FILENAME. */
filter_symbols (abfd, osyms, isyms, symcount)
bfd *abfd;
asymbol **osyms, **isyms;
- unsigned long symcount;
+ long symcount;
{
register asymbol **from = isyms, **to = osyms;
- char locals_prefix = bfd_get_symbol_leading_char (abfd) == '_' ? 'L' : '.';
- unsigned int src_count = 0, dst_count = 0;
+ long src_count = 0, dst_count = 0;
for (; src_count < symcount; src_count++)
{
int keep;
if ((flags & BSF_GLOBAL) /* Keep if external. */
- || bfd_get_section (sym) == &bfd_und_section
+ || (flags & BSF_KEEP) /* Keep if used in a relocation. */
+ || bfd_is_und_section (bfd_get_section (sym))
|| bfd_is_com_section (bfd_get_section (sym)))
keep = 1;
else if ((flags & BSF_DEBUGGING) != 0) /* Debugging symbol. */
else /* Local symbol. */
keep = discard_locals != locals_all
&& (discard_locals != locals_start_L ||
- bfd_asymbol_name (sym)[0] != locals_prefix);
+ ! bfd_is_local_label (abfd, sym));
if (keep)
to[dst_count++] = sym;
}
bfd *ibfd;
bfd *obfd;
{
- unsigned int symcount;
+ bfd_vma start;
+ long symcount;
+ asection **osections = NULL;
+ bfd_size_type *gaps = NULL;
+ bfd_size_type max_gap = 0;
if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
{
bfd_get_filename(ibfd), bfd_get_target(ibfd),
bfd_get_filename(obfd), bfd_get_target(obfd));
- if (!bfd_set_start_address (obfd, bfd_get_start_address (ibfd))
+ if (set_start_set)
+ start = set_start;
+ else
+ start = bfd_get_start_address (ibfd);
+ start += adjust_start;
+
+ if (!bfd_set_start_address (obfd, start)
|| !bfd_set_file_flags (obfd,
(bfd_get_file_flags (ibfd)
& bfd_applicable_file_flags (obfd))))
if (osympp != isympp)
free (osympp);
+ /* bfd mandates that all output sections be created and sizes set before
+ any output is done. Thus, we traverse all sections multiple times. */
+ bfd_map_over_sections (ibfd, setup_section, (void *) obfd);
+
+ if (gap_fill_set || pad_to_set)
+ {
+ asection **set;
+ unsigned int c, i;
+
+ /* We must fill in gaps between the sections and/or we must pad
+ the last section to a specified address. We do this by
+ grabbing a list of the sections, sorting them by VMA, and
+ increasing the section sizes as required to fill the gaps.
+ We write out the gap contents below. */
+
+ c = bfd_count_sections (obfd);
+ osections = (asection **) xmalloc (c * sizeof (asection *));
+ set = osections;
+ bfd_map_over_sections (obfd, get_sections, (void *) &set);
+
+ qsort (osections, c, sizeof (asection *), compare_section_vma);
+
+ gaps = (bfd_size_type *) xmalloc (c * sizeof (bfd_size_type));
+ memset (gaps, 0, c * sizeof (bfd_size_type));
+
+ if (gap_fill_set)
+ {
+ for (i = 0; i < c - 1; i++)
+ {
+ flagword flags;
+ bfd_size_type size;
+ bfd_vma gap_start, gap_stop;
+
+ flags = bfd_get_section_flags (obfd, osections[i]);
+ if ((flags & SEC_HAS_CONTENTS) == 0
+ || (flags & SEC_LOAD) == 0)
+ continue;
+
+ size = bfd_section_size (obfd, osections[i]);
+ gap_start = bfd_section_vma (obfd, osections[i]) + size;
+ gap_stop = bfd_section_vma (obfd, osections[i + 1]);
+ if (gap_start < gap_stop)
+ {
+ if (! bfd_set_section_size (obfd, osections[i],
+ size + (gap_stop - gap_start)))
+ {
+ fprintf (stderr, "%s: Can't fill gap after %s: %s\n",
+ program_name,
+ bfd_get_section_name (obfd, osections[i]),
+ bfd_errmsg (bfd_get_error()));
+ status = 1;
+ break;
+ }
+ gaps[i] = gap_stop - gap_start;
+ if (max_gap < gap_stop - gap_start)
+ max_gap = gap_stop - gap_start;
+ }
+ }
+ }
+
+ if (pad_to_set)
+ {
+ bfd_vma vma;
+ bfd_size_type size;
+
+ vma = bfd_section_vma (obfd, osections[c - 1]);
+ size = bfd_section_size (obfd, osections[c - 1]);
+ if (vma + size < pad_to)
+ {
+ if (! bfd_set_section_size (obfd, osections[c - 1],
+ pad_to - vma))
+ {
+ fprintf (stderr, "%s: Can't add padding to %s: %s\n",
+ program_name,
+ bfd_get_section_name (obfd, osections[c - 1]),
+ bfd_errmsg (bfd_get_error ()));
+ status = 1;
+ }
+ else
+ {
+ gaps[c - 1] = pad_to - (vma + size);
+ if (max_gap < pad_to - (vma + size))
+ max_gap = pad_to - (vma + size);
+ }
+ }
+ }
+ }
+
+ /* Symbol filtering must happen after the output sections have
+ been created, but before their contents are set. */
if (strip_symbols == strip_all && discard_locals == locals_undef)
{
osympp = isympp = NULL;
}
else
{
- osympp = isympp = (asymbol **) xmalloc (get_symtab_upper_bound (ibfd));
+ long symsize;
+
+ symsize = bfd_get_symtab_upper_bound (ibfd);
+ if (symsize < 0)
+ {
+ nonfatal (bfd_get_filename (ibfd));
+ }
+
+ osympp = isympp = (asymbol **) xmalloc (symsize);
symcount = bfd_canonicalize_symtab (ibfd, isympp);
+ if (symcount < 0)
+ {
+ nonfatal (bfd_get_filename (ibfd));
+ }
if (strip_symbols == strip_debug || discard_locals != locals_undef)
{
+ /* Mark symbols used in output relocations so that they
+ are kept, even if they are local labels or static symbols.
+
+ Note we iterate over the input sections examining their
+ relocations since the relocations for the output sections
+ haven't been set yet. mark_symbols_used_in_relocations will
+ ignore input sections which have no corresponding output
+ section. */
+ bfd_map_over_sections (ibfd,
+ mark_symbols_used_in_relocations,
+ (PTR)isympp);
osympp = (asymbol **) xmalloc (symcount * sizeof (asymbol *));
symcount = filter_symbols (ibfd, osympp, isympp, symcount);
}
bfd_set_symtab (obfd, osympp, symcount);
- /* bfd mandates that all output sections be created and sizes set before
- any output is done. Thus, we traverse all sections multiple times. */
- bfd_map_over_sections (ibfd, setup_section, (void *) obfd);
+ /* This has to happen after the symbol table has been set. */
bfd_map_over_sections (ibfd, copy_section, (void *) obfd);
- bfd_map_over_sections (ibfd, mangle_section, (void *) obfd);
+
+ if (gap_fill_set || pad_to_set)
+ {
+ bfd_byte *buf;
+ int c, i;
+
+ /* Fill in the gaps. */
+
+ if (max_gap > 8192)
+ max_gap = 8192;
+ buf = (bfd_byte *) xmalloc (max_gap);
+ memset (buf, gap_fill, max_gap);
+
+ c = bfd_count_sections (obfd);
+ for (i = 0; i < c; i++)
+ {
+ if (gaps[i] != 0)
+ {
+ bfd_size_type left;
+ file_ptr off;
+
+ left = gaps[i];
+ off = bfd_section_size (obfd, osections[i]) - left;
+ while (left > 0)
+ {
+ bfd_size_type now;
+
+ if (left > 8192)
+ now = 8192;
+ else
+ now = left;
+ if (! bfd_set_section_contents (obfd, osections[i], buf,
+ off, now))
+ {
+ nonfatal (bfd_get_filename (obfd));
+ status = 1;
+ }
+ left -= now;
+ off += now;
+ }
+ }
+ }
+ }
+
+ /* Allow the BFD backend to copy any private data it understands
+ from the input BFD to the output BFD. This is done last to
+ permit the routine to look at the filtered symbol table, which is
+ important for the ECOFF code at least. */
+ if (!bfd_copy_private_bfd_data (ibfd, obfd))
+ {
+ fprintf (stderr, "%s: %s: error copying private BFD data: %s\n",
+ program_name, bfd_get_filename (obfd),
+ bfd_errmsg (bfd_get_error ()));
+ status = 1;
+ return;
+ }
}
static char *
bfd *obfd;
char *output_target;
{
+ struct name_list
+ {
+ struct name_list *next;
+ char *name;
+ } *list, *l;
bfd **ptr = &obfd->archive_head;
bfd *this_element;
- char *dir = cat ("./#", make_tempname (""), "cd");
+ char *dir = make_tempname (bfd_get_filename (obfd));
/* Make a temp directory to hold the contents. */
- mkdir (dir, 0777);
+ mkdir (dir, 0700);
obfd->has_armap = ibfd->has_armap;
+ list = NULL;
+
this_element = bfd_openr_next_archived_file (ibfd, NULL);
- ibfd->archive_head = this_element;
while (this_element != (bfd *) NULL)
{
/* Create an output file for this member. */
char *output_name = cat (dir, "/", bfd_get_filename(this_element));
bfd *output_bfd = bfd_openw (output_name, output_target);
+ bfd *last_element;
+
+ l = (struct name_list *) xmalloc (sizeof (struct name_list));
+ l->name = output_name;
+ l->next = list;
+ list = l;
if (output_bfd == (bfd *) NULL)
{
}
bfd_close (output_bfd);
- /* Open the newly output file and attatch to our list. */
+
+ /* Open the newly output file and attach to our list. */
output_bfd = bfd_openr (output_name, output_target);
- /* Mark it for deletion. */
*ptr = output_bfd;
ptr = &output_bfd->next;
- this_element->next = bfd_openr_next_archived_file (ibfd, this_element);
- this_element = this_element->next;
+
+ last_element = this_element;
+
+ this_element = bfd_openr_next_archived_file (ibfd, last_element);
+
+ bfd_close (last_element);
}
*ptr = (bfd *) NULL;
nonfatal (bfd_get_filename (obfd));
}
- /* Delete all the files that we opened.
- Construct their names again, unfortunately, but
- we're about to exit anyway. */
- for (this_element = ibfd->archive_head;
- this_element != (bfd *) NULL;
- this_element = this_element->next)
- {
- unlink (cat (dir, "/", bfd_get_filename (this_element)));
- }
+ /* Delete all the files that we opened. */
+ for (l = list; l != NULL; l = l->next)
+ unlink (l->name);
rmdir (dir);
+
if (!bfd_close (ibfd))
{
nonfatal (bfd_get_filename (ibfd));
if (bfd_check_format (ibfd, bfd_archive))
{
- bfd *obfd = bfd_openw (output_filename, output_target);
+ bfd *obfd;
+
+ /* bfd_get_target does not return the correct value until
+ bfd_check_format succeeds. */
+ if (output_target == NULL)
+ output_target = bfd_get_target (ibfd);
+
+ obfd = bfd_openw (output_filename, output_target);
if (obfd == NULL)
{
nonfatal (output_filename);
}
else if (bfd_check_format_matches (ibfd, bfd_object, &matching))
{
- bfd *obfd = bfd_openw (output_filename, output_target);
+ bfd *obfd;
+
+ /* bfd_get_target does not return the correct value until
+ bfd_check_format succeeds. */
+ if (output_target == NULL)
+ output_target = bfd_get_target (ibfd);
+
+ obfd = bfd_openw (output_filename, output_target);
if (obfd == NULL)
{
nonfatal (output_filename);
else
{
bfd_nonfatal (input_filename);
- if (bfd_error == file_ambiguously_recognized)
+ if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
{
list_matching_formats (matching);
free (matching);
as ISECTION in IBFD. */
static void
-setup_section (ibfd, isection, obfd)
+setup_section (ibfd, isection, obfdarg)
bfd *ibfd;
sec_ptr isection;
- bfd *obfd;
+ PTR obfdarg;
{
+ bfd *obfd = (bfd *) obfdarg;
+ struct section_list *p;
sec_ptr osection;
+ bfd_vma vma;
char *err;
if ((bfd_get_section_flags (ibfd, isection) & SEC_DEBUGGING) != 0
|| discard_locals == locals_all))
return;
- osection = bfd_get_section_by_name (obfd, bfd_section_name (ibfd, isection));
- if (osection == NULL)
+ for (p = remove_sections; p != NULL; p = p->next)
{
- osection = bfd_make_section (obfd, bfd_section_name (ibfd, isection));
- if (osection == NULL)
+ if (strcmp (p->name, bfd_section_name (ibfd, isection)) == 0)
{
- err = "making";
- goto loser;
+ p->used = true;
+ return;
}
}
+ osection = bfd_make_section_anyway (obfd, bfd_section_name (ibfd, isection));
+ if (osection == NULL)
+ {
+ err = "making";
+ goto loser;
+ }
+
if (!bfd_set_section_size (obfd,
osection,
bfd_section_size (ibfd, isection)))
goto loser;
}
- if (bfd_set_section_vma (obfd,
- osection,
- bfd_section_vma (ibfd, isection))
- == false)
+ vma = bfd_section_vma (ibfd, isection);
+ for (p = adjust_sections; p != NULL; p = p->next)
+ {
+ if (strcmp (p->name, bfd_section_name (ibfd, isection)) == 0)
+ {
+ if (p->adjust)
+ vma += p->val;
+ else
+ vma = p->val;
+ p->used = true;
+ break;
+ }
+ }
+ if (p == NULL)
+ vma += adjust_section_vma;
+
+ if (! bfd_set_section_vma (obfd, osection, vma))
{
err = "vma";
goto loser;
goto loser;
}
+ /* This used to be mangle_section; we do here to avoid using
+ bfd_get_section_by_name since some formats allow multiple
+ sections with the same name. */
+ isection->output_section = osection;
+ isection->output_offset = 0;
+
+ /* Allow the BFD backend to copy any private data it understands
+ from the input section to the output section. */
+ if (!bfd_copy_private_section_data (ibfd, isection, obfd, osection))
+ {
+ err = "private data";
+ goto loser;
+ }
+
/* All went well */
return;
fprintf (stderr, "%s: %s: section `%s': error in %s: %s\n",
program_name,
bfd_get_filename (ibfd), bfd_section_name (ibfd, isection),
- err, bfd_errmsg (bfd_error));
+ err, bfd_errmsg (bfd_get_error ()));
status = 1;
}
If stripping then don't copy any relocation info. */
static void
-copy_section (ibfd, isection, obfd)
+copy_section (ibfd, isection, obfdarg)
bfd *ibfd;
sec_ptr isection;
- bfd *obfd;
+ PTR obfdarg;
{
+ bfd *obfd = (bfd *) obfdarg;
+ struct section_list *p;
arelent **relpp;
- int relcount;
+ long relcount;
sec_ptr osection;
bfd_size_type size;
return;
}
- osection = bfd_get_section_by_name (obfd,
- bfd_section_name (ibfd, isection));
+ for (p = remove_sections; p != NULL; p = p->next)
+ if (strcmp (p->name, bfd_section_name (ibfd, isection)) == 0)
+ return;
+ osection = isection->output_section;
size = bfd_get_section_size_before_reloc (isection);
- if (size == 0)
+ if (size == 0 || osection == 0)
return;
- if (strip_symbols == strip_all
- || bfd_get_reloc_upper_bound (ibfd, isection) == 0)
- {
- bfd_set_reloc (obfd, osection, (arelent **) NULL, 0);
- }
+ if (strip_symbols == strip_all)
+ bfd_set_reloc (obfd, osection, (arelent **) NULL, 0);
else
{
- relpp = (arelent **) xmalloc (bfd_get_reloc_upper_bound (ibfd, isection));
- relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, isympp);
- bfd_set_reloc (obfd, osection, relpp, relcount);
+ long relsize;
+
+ relsize = bfd_get_reloc_upper_bound (ibfd, isection);
+ if (relsize < 0)
+ {
+ nonfatal (bfd_get_filename (ibfd));
+ }
+ if (relsize == 0)
+ bfd_set_reloc (obfd, osection, (arelent **) NULL, 0);
+ else
+ {
+ relpp = (arelent **) xmalloc (relsize);
+ relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, isympp);
+ if (relcount < 0)
+ {
+ nonfatal (bfd_get_filename (ibfd));
+ }
+ bfd_set_reloc (obfd, osection, relpp, relcount);
+ }
}
isection->_cooked_size = isection->_raw_size;
nonfatal (bfd_get_filename (ibfd));
}
- if (copy_byte >= 0)
- filter_bytes (memhunk, &size);
+ if (copy_byte >= 0)
+ {
+ filter_bytes (memhunk, &size);
+ /* The section has gotten smaller. */
+ if (!bfd_set_section_size (obfd, osection, size))
+ nonfatal (bfd_get_filename (obfd));
+ }
if (!bfd_set_section_contents (obfd, osection, memhunk, (file_ptr) 0,
size))
}
}
-/* All the symbols have been read in and point to their owning input section.
- They have been relocated so that they are all relative to the base of
- their owning section. On the way out, all the symbols will be relocated to
- their new location in the output file, through some complex sums. */
+/* Get all the sections. This is used when --gap-fill or --pad-to is
+ used. */
static void
-mangle_section (ibfd, p, obfd)
- bfd *ibfd;
- asection *p;
+get_sections (obfd, osection, secppparg)
bfd *obfd;
+ asection *osection;
+ PTR secppparg;
{
- p->output_section = bfd_get_section_by_name (obfd, p->name);
- p->output_offset = 0;
+ asection ***secppp = (asection ***) secppparg;
+
+ **secppp = osection;
+ ++(*secppp);
+}
+
+/* Sort sections by VMA. This is called via qsort, and is used when
+ --gap-fill or --pad-to is used. We force non loadable or empty
+ sections to the front, where they are easier to ignore. */
+
+static int
+compare_section_vma (arg1, arg2)
+ const PTR arg1;
+ const PTR arg2;
+{
+ const asection **sec1 = (const asection **) arg1;
+ const asection **sec2 = (const asection **) arg2;
+ flagword flags1, flags2;
+
+ /* Sort non loadable sections to the front. */
+ flags1 = (*sec1)->flags;
+ flags2 = (*sec2)->flags;
+ if ((flags1 & SEC_HAS_CONTENTS) == 0
+ || (flags1 & SEC_LOAD) == 0)
+ {
+ if ((flags2 & SEC_HAS_CONTENTS) != 0
+ && (flags2 & SEC_LOAD) != 0)
+ return -1;
+ }
+ else
+ {
+ if ((flags2 & SEC_HAS_CONTENTS) == 0
+ || (flags2 & SEC_LOAD) == 0)
+ return 1;
+ }
+
+ /* Sort sections by VMA. */
+ if ((*sec1)->vma > (*sec2)->vma)
+ return 1;
+ else if ((*sec1)->vma < (*sec2)->vma)
+ return -1;
+
+ /* Sort sections with the same VMA by size. */
+ if ((*sec1)->_raw_size > (*sec2)->_raw_size)
+ return 1;
+ else if ((*sec1)->_raw_size < (*sec2)->_raw_size)
+ return -1;
+
+ return 0;
+}
+
+/* Mark all the symbols which will be used in output relocations with
+ the BSF_KEEP flag so that those symbols will not be stripped.
+
+ Ignore relocations which will not appear in the output file. */
+
+static void
+mark_symbols_used_in_relocations (ibfd, isection, symbolsarg)
+ bfd *ibfd;
+ sec_ptr isection;
+ PTR symbolsarg;
+{
+ asymbol **symbols = (asymbol **) symbolsarg;
+ long relsize;
+ arelent **relpp;
+ long relcount, i;
+
+ /* Ignore an input section with no corresponding output section. */
+ if (isection->output_section == NULL)
+ return;
+
+ relsize = bfd_get_reloc_upper_bound (ibfd, isection);
+ if (relsize < 0)
+ bfd_fatal (bfd_get_filename (ibfd));
+
+ relpp = (arelent **) xmalloc (relsize);
+ relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, symbols);
+ if (relcount < 0)
+ bfd_fatal (bfd_get_filename (ibfd));
+
+ /* Examine each symbol used in a relocation. If it's not one of the
+ special bfd section symbols, then mark it with BSF_KEEP. */
+ for (i = 0; i < relcount; i++)
+ {
+ if (*relpp[i]->sym_ptr_ptr != bfd_com_section_ptr->symbol
+ && *relpp[i]->sym_ptr_ptr != bfd_abs_section_ptr->symbol
+ && *relpp[i]->sym_ptr_ptr != bfd_und_section_ptr->symbol)
+ (*relpp[i]->sym_ptr_ptr)->flags |= BSF_KEEP;
+ }
+
+ if (relpp != NULL)
+ free (relpp);
}
/* The number of bytes to copy at once. */
boolean show_version = false;
int c, i;
- while ((c = getopt_long (argc, argv, "I:O:F:sSgxXVv",
+ while ((c = getopt_long (argc, argv, "I:O:F:R:sSgxXVv",
strip_options, (int *) 0)) != EOF)
{
switch (c)
{
case 'I':
input_target = optarg;
+ break;
case 'O':
output_target = optarg;
break;
case 'F':
input_target = output_target = optarg;
break;
+ case 'R':
+ {
+ struct section_list *n;
+
+ n = (struct section_list *) xmalloc (sizeof (struct section_list));
+ n->name = optarg;
+ n->used = false;
+ n->next = remove_sections;
+ remove_sections = n;
+ }
+ break;
case 's':
strip_symbols = strip_all;
break;
int argc;
char *argv[];
{
- char *input_filename, *output_filename;
+ char *input_filename = NULL, *output_filename = NULL;
char *input_target = NULL, *output_target = NULL;
boolean show_version = false;
+ boolean adjust_warn = true;
int c;
+ struct section_list *p;
- while ((c = getopt_long (argc, argv, "b:i:I:s:O:d:F:SgxXVv",
+ while ((c = getopt_long (argc, argv, "b:i:I:s:O:d:F:R:SgxXVv",
copy_options, (int *) 0)) != EOF)
{
switch (c)
case 'I':
case 's': /* "source" - 'I' is preferred */
input_target = optarg;
+ break;
case 'O':
case 'd': /* "destination" - 'O' is preferred */
output_target = optarg;
case 'F':
input_target = output_target = optarg;
break;
+ case 'R':
+ p = (struct section_list *) xmalloc (sizeof (struct section_list));
+ p->name = optarg;
+ p->used = false;
+ p->next = remove_sections;
+ remove_sections = p;
+ break;
case 'S':
strip_symbols = strip_all;
break;
case 'V':
show_version = true;
break;
+ case OPTION_ADJUST_START:
+ adjust_start = parse_vma (optarg, "--adjust-start");
+ break;
+ case OPTION_ADJUST_SECTION_VMA:
+ {
+ const char *s;
+ int len;
+ char *name;
+
+ p = (struct section_list *) xmalloc (sizeof (struct section_list));
+ s = strchr (optarg, '=');
+ if (s != NULL)
+ {
+ p->adjust = false;
+ p->val = parse_vma (s + 1, "--adjust-section-vma");
+ }
+ else
+ {
+ s = strchr (optarg, '+');
+ if (s == NULL)
+ {
+ s = strchr (optarg, '-');
+ if (s == NULL)
+ {
+ fprintf (stderr,
+ "%s: bad format for --adjust-section-vma\n",
+ program_name);
+ exit (1);
+ }
+ }
+ p->adjust = true;
+ p->val = parse_vma (s + 1, "--adjust-section-vma");
+ if (*s == '-')
+ p->val = - p->val;
+ }
+
+ len = s - optarg;
+ name = (char *) xmalloc (len + 1);
+ strncpy (name, optarg, len);
+ name[len] = '\0';
+ p->name = name;
+
+ p->used = false;
+
+ p->next = adjust_sections;
+ adjust_sections = p;
+ }
+ break;
+ case OPTION_ADJUST_VMA:
+ adjust_section_vma = parse_vma (optarg, "--adjust-vma");
+ adjust_start = adjust_section_vma;
+ break;
+ case OPTION_ADJUST_WARNINGS:
+ adjust_warn = true;
+ break;
+ case OPTION_GAP_FILL:
+ {
+ bfd_vma gap_fill_vma;
+
+ gap_fill_vma = parse_vma (optarg, "--gap-fill");
+ gap_fill = (bfd_byte) gap_fill_vma;
+ if ((bfd_vma) gap_fill != gap_fill_vma)
+ {
+ fprintf (stderr, "%s: warning: truncating gap-fill from 0x",
+ program_name);
+ fprintf_vma (stderr, gap_fill_vma);
+ fprintf (stderr, "to 0x%x\n", (unsigned int) gap_fill);
+ }
+ gap_fill_set = true;
+ }
+ break;
+ case OPTION_NO_ADJUST_WARNINGS:
+ adjust_warn = false;
+ break;
+ case OPTION_PAD_TO:
+ pad_to = parse_vma (optarg, "--pad-to");
+ pad_to_set = true;
+ break;
+ case OPTION_SET_START:
+ set_start = parse_vma (optarg, "--set-start");
+ set_start_set = true;
+ break;
case 0:
break; /* we've been given a long option */
case 'h':
copy_file (input_filename, output_filename, input_target, output_target);
}
+ if (adjust_warn)
+ {
+ for (p = adjust_sections; p != NULL; p = p->next)
+ {
+ if (! p->used)
+ {
+ fprintf (stderr, "%s: warning: --adjust-section-vma %s%c0x",
+ program_name, p->name,
+ p->adjust ? '=' : '+');
+ fprintf_vma (stderr, p->val);
+ fprintf (stderr, " never used\n");
+ }
+ }
+ }
+
+ /* We could issue similar warnings for remove_sections, but I don't
+ think that would be as useful. */
+
return 0;
}
char *argv[];
{
program_name = argv[0];
+ xmalloc_set_program_name (program_name);
strip_symbols = strip_undef;
discard_locals = locals_undef;
if (is_strip < 0)
{
int i = strlen (program_name);
- is_strip = (i >= 5 && strcmp (program_name + i - 5, "strip"));
+ is_strip = (i >= 5 && strcmp (program_name + i - 5, "strip") == 0);
}
if (is_strip)