/* Filling gaps between sections. */
static boolean gap_fill_set = false;
-static bfd_byte gap_fill;
+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". */
#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_SET_START (OPTION_NO_ADJUST_WARNINGS + 1)
+#define OPTION_PAD_TO (OPTION_NO_ADJUST_WARNINGS + 1)
+#define OPTION_SET_START (OPTION_PAD_TO + 1)
static struct option copy_options[] =
{
{"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'},
[-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\
- [--remove-section=section] [--gap-fill=val] [--set-start=val]\n\
- [--adjust-start=incr] [--adjust-vma=incr]\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",
any output is done. Thus, we traverse all sections multiple times. */
bfd_map_over_sections (ibfd, setup_section, (void *) obfd);
- if (gap_fill_set)
+ if (gap_fill_set || pad_to_set)
{
asection **set;
unsigned int c, i;
- /* We must fill in gaps between the sections. We do this by
+ /* 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
- adding new sections to occupy any gaps. */
+ 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 *));
qsort (osections, c, sizeof (asection *), compare_section_vma);
gaps = (bfd_size_type *) xmalloc (c * sizeof (bfd_size_type));
- for (i = 0; i < c - 1; i++)
+ 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)
{
- flagword flags;
+ bfd_vma vma;
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)
- gaps[i] = 0;
- else
+
+ 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[i],
- size + (gap_stop - gap_start)))
+ if (! bfd_set_section_size (obfd, osections[c - 1],
+ pad_to - vma))
{
- fprintf (stderr, "%s: Can't fill gap after %s: %s\n",
+ fprintf (stderr, "%s: Can't add padding to %s: %s\n",
program_name,
- bfd_get_section_name (obfd, osections[i]),
- bfd_errmsg (bfd_get_error()));
+ bfd_get_section_name (obfd, osections[c - 1]),
+ 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;
+ 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
/* This has to happen after the symbol table has been set. */
bfd_map_over_sections (ibfd, copy_section, (void *) obfd);
- if (gap_fill_set)
+ if (gap_fill_set || pad_to_set)
{
bfd_byte *buf;
int c, i;
memset (buf, gap_fill, max_gap);
c = bfd_count_sections (obfd);
- for (i = 0; i < c - 1; i++)
+ for (i = 0; i < c; i++)
{
if (gaps[i] != 0)
{
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 = make_tempname (bfd_get_filename (obfd));
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));
}
}
-/* Get all the sections. This is used when --gap-fill is used. */
+/* Get all the sections. This is used when --gap-fill or --pad-to is
+ used. */
static void
get_sections (obfd, osection, secppparg)
}
/* Sort sections by VMA. This is called via qsort, and is used when
- --gap-fill is used. */
+ --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 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;
- else
- return 0;
+
+ /* 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
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;
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)