aboutsummaryrefslogtreecommitdiff
path: root/binutils/objcopy.c
diff options
context:
space:
mode:
Diffstat (limited to 'binutils/objcopy.c')
-rw-r--r--binutils/objcopy.c240
1 files changed, 196 insertions, 44 deletions
diff --git a/binutils/objcopy.c b/binutils/objcopy.c
index bd30eaa..e8b710f 100644
--- a/binutils/objcopy.c
+++ b/binutils/objcopy.c
@@ -38,6 +38,14 @@ struct symlist
struct symlist *next;
};
+/* A list to support redefine_sym. */
+struct redefine_node
+{
+ char *source;
+ char *target;
+ struct redefine_node *next;
+};
+
static void copy_usage PARAMS ((FILE *, int));
static void strip_usage PARAMS ((FILE *, int));
static flagword parse_flags PARAMS ((const char *));
@@ -60,6 +68,8 @@ static void copy_file
PARAMS ((const char *, const char *, const char *, const char *));
static int strip_main PARAMS ((int, char **));
static int copy_main PARAMS ((int, char **));
+static const char *lookup_sym_redefinition PARAMS((const char *));
+static void redefine_list_append PARAMS ((const char *, const char *));
#define RETURN_NONFATAL(s) {bfd_nonfatal (s); status = 1; return;}
@@ -172,12 +182,13 @@ static boolean change_leading_char = false;
static boolean remove_leading_char = false;
-/* List of symbols to strip, keep, localize, and weaken. */
+/* List of symbols to strip, keep, localize, weaken, or redefine. */
static struct symlist *strip_specific_list = NULL;
static struct symlist *keep_specific_list = NULL;
static struct symlist *localize_specific_list = NULL;
static struct symlist *weaken_specific_list = NULL;
+static struct redefine_node *redefine_sym_list = NULL;
/* If this is true, we weaken global symbols (set BSF_WEAK). */
@@ -202,6 +213,7 @@ static boolean weaken = false;
#define OPTION_SET_START (OPTION_SET_SECTION_FLAGS + 1)
#define OPTION_STRIP_UNNEEDED (OPTION_SET_START + 1)
#define OPTION_WEAKEN (OPTION_STRIP_UNNEEDED + 1)
+#define OPTION_REDEFINE_SYM (OPTION_WEAKEN + 1)
/* Options to handle if running as "strip". */
@@ -276,6 +288,7 @@ static struct option copy_options[] =
{"version", no_argument, 0, 'V'},
{"weaken", no_argument, 0, OPTION_WEAKEN},
{"weaken-symbol", required_argument, 0, 'W'},
+ {"redefine-sym", required_argument, 0, OPTION_REDEFINE_SYM},
{0, no_argument, 0, 0}
};
@@ -335,6 +348,7 @@ copy_usage (stream, exit_status)
--add-section <name>=<file> Add section <name> found in <file> to output\n\
--change-leading-char Force output format's leading character style\n\
--remove-leading-char Remove leading character from global symbols\n\
+ --redefine-sym <old>=<new> Redefine symbol name <old> to <new>\n\
-v --verbose List all object files modified\n\
-V --version Display this program's version number\n\
-h --help Display this output\n\
@@ -423,7 +437,8 @@ parse_flags (s)
strncpy (copy, s, len);
copy[len] = '\0';
non_fatal (_("unrecognized section flag `%s'"), copy);
- fatal (_("supported flags: alloc, load, noload, readonly, debug, code, data, rom, share, contents"));
+ fatal (_("supported flags: %s"),
+ "alloc, load, noload, readonly, debug, code, data, rom, share, contents");
}
s = snext;
@@ -469,7 +484,7 @@ find_section_list (name, add)
/* Add a symbol to strip_specific_list. */
-static void
+static void
add_specific_symbol (name, list)
const char *name;
struct symlist **list;
@@ -549,6 +564,15 @@ filter_symbols (abfd, obfd, osyms, isyms, symcount)
const char *name = bfd_asymbol_name (sym);
int keep;
+ if (redefine_sym_list)
+ {
+ const char *old_name, *new_name;
+
+ old_name = bfd_asymbol_name (sym);
+ new_name = lookup_sym_redefinition (old_name);
+ name = bfd_asymbol_name (sym) = new_name;
+ }
+
if (change_leading_char
&& (bfd_get_symbol_leading_char (abfd)
!= bfd_get_symbol_leading_char (obfd))
@@ -630,6 +654,64 @@ filter_symbols (abfd, obfd, osyms, isyms, symcount)
return dst_count;
}
+static const char *
+lookup_sym_redefinition (source)
+ const char *source;
+{
+ const char *result;
+ struct redefine_node *list;
+
+ result = source;
+
+ for (list = redefine_sym_list; list != NULL; list = list->next)
+ {
+ if (strcmp (source, list->source) == 0)
+ {
+ result = list->target;
+ break;
+ }
+ }
+ return result;
+}
+
+/* Add a node to a symbol redefine list */
+
+static void
+redefine_list_append (source, target)
+ const char *source;
+ const char *target;
+{
+ struct redefine_node **p;
+ struct redefine_node *list;
+ struct redefine_node *new_node;
+
+ for (p = &redefine_sym_list; (list = *p) != NULL; p = &list->next)
+ {
+ if (strcmp (source, list->source) == 0)
+ {
+ fatal (_("%s: Multiple redefinition of symbol \"%s\""),
+ "--redefine-sym",
+ source);
+ }
+
+ if (strcmp (target, list->target) == 0)
+ {
+ fatal (_("%s: Symbol \"%s\" is target of more than one redefinition"),
+ "--redefine-sym",
+ target);
+ }
+ }
+
+ new_node = (struct redefine_node *) xmalloc (sizeof (struct redefine_node));
+
+ new_node->source = strdup (source);
+ new_node->target = strdup (target);
+ new_node->next = NULL;
+
+ *p = new_node;
+}
+
+
/* Keep only every `copy_byte'th byte in MEMHUNK, which is *SIZE bytes long.
Adjust *SIZE. */
@@ -690,13 +772,13 @@ copy_object (ibfd, obfd)
non_fatal (_("Warning: Output file cannot represent architecture %s"),
bfd_printable_arch_mach (bfd_get_arch (ibfd),
bfd_get_mach (ibfd)));
-
+
if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
RETURN_NONFATAL (bfd_get_filename (ibfd));
if (isympp)
free (isympp);
-
+
if (osympp != isympp)
free (osympp);
@@ -722,7 +804,7 @@ copy_object (ibfd, obfd)
else
{
flagword flags;
-
+
if (! bfd_set_section_size (obfd, padd->section, padd->size))
RETURN_NONFATAL (bfd_get_filename (obfd));
@@ -734,7 +816,7 @@ copy_object (ibfd, obfd)
flags = pset->flags | SEC_HAS_CONTENTS;
else
flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DATA;
-
+
if (! bfd_set_section_flags (obfd, padd->section, flags))
RETURN_NONFATAL (bfd_get_filename (obfd));
@@ -743,11 +825,11 @@ copy_object (ibfd, obfd)
if (pset->change_vma != CHANGE_IGNORE)
if (! bfd_set_section_vma (obfd, padd->section, pset->vma_val))
RETURN_NONFATAL (bfd_get_filename (obfd));
-
+
if (pset->change_lma != CHANGE_IGNORE)
{
padd->section->lma = pset->lma_val;
-
+
if (! bfd_set_section_alignment
(obfd, padd->section,
bfd_section_alignment (obfd, padd->section)))
@@ -846,16 +928,16 @@ copy_object (ibfd, obfd)
symsize = bfd_get_symtab_upper_bound (ibfd);
if (symsize < 0)
RETURN_NONFATAL (bfd_get_filename (ibfd));
-
+
osympp = isympp = (asymbol **) xmalloc (symsize);
symcount = bfd_canonicalize_symtab (ibfd, isympp);
if (symcount < 0)
RETURN_NONFATAL (bfd_get_filename (ibfd));
-
+
if (convert_debugging)
dhandle = read_debugging_info (ibfd, isympp, symcount);
-
- if (strip_symbols == STRIP_DEBUG
+
+ if (strip_symbols == STRIP_DEBUG
|| strip_symbols == STRIP_ALL
|| strip_symbols == STRIP_UNNEEDED
|| discard_locals != LOCALS_UNDEF
@@ -868,11 +950,12 @@ copy_object (ibfd, obfd)
|| convert_debugging
|| change_leading_char
|| remove_leading_char
+ || redefine_sym_list
|| weaken)
{
/* 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
@@ -1135,13 +1218,13 @@ copy_file (input_filename, output_filename, input_target, output_target)
else
{
bfd_nonfatal (input_filename);
-
+
if (bfd_get_error () == bfd_error_file_ambiguously_recognized)
{
list_matching_formats (matching);
free (matching);
}
-
+
status = 1;
}
}
@@ -1182,7 +1265,7 @@ setup_section (ibfd, isection, obfdarg)
return;
osection = bfd_make_section_anyway (obfd, bfd_section_name (ibfd, isection));
-
+
if (osection == NULL)
{
err = "making";
@@ -1197,7 +1280,7 @@ setup_section (ibfd, isection, obfdarg)
err = "size";
goto loser;
}
-
+
vma = bfd_section_vma (ibfd, isection);
if (p != NULL && p->change_vma == CHANGE_MODIFY)
vma += p->vma_val;
@@ -1205,7 +1288,7 @@ setup_section (ibfd, isection, obfdarg)
vma = p->vma_val;
else
vma += change_section_address;
-
+
if (! bfd_set_section_vma (obfd, osection, vma))
{
err = "vma";
@@ -1224,7 +1307,7 @@ setup_section (ibfd, isection, obfdarg)
}
else
lma += change_section_address;
-
+
osection->lma = lma;
/* FIXME: This is probably not enough. If we change the LMA we
@@ -1294,7 +1377,7 @@ copy_section (ibfd, isection, obfdarg)
complaints now. */
if (status != 0)
return;
-
+
if ((bfd_get_section_flags (ibfd, isection) & SEC_DEBUGGING) != 0
&& (strip_symbols == STRIP_DEBUG
|| strip_symbols == STRIP_UNNEEDED
@@ -1322,7 +1405,7 @@ copy_section (ibfd, isection, obfdarg)
relsize = bfd_get_reloc_upper_bound (ibfd, isection);
if (relsize < 0)
RETURN_NONFATAL (bfd_get_filename (ibfd));
-
+
if (relsize == 0)
bfd_set_reloc (obfd, osection, (arelent **) NULL, 0);
else
@@ -1331,7 +1414,7 @@ copy_section (ibfd, isection, obfdarg)
relcount = bfd_canonicalize_reloc (ibfd, isection, relpp, isympp);
if (relcount < 0)
RETURN_NONFATAL (bfd_get_filename (ibfd));
-
+
if (strip_symbols == STRIP_ALL)
{
/* Remove relocations which are not in
@@ -1339,7 +1422,7 @@ copy_section (ibfd, isection, obfdarg)
arelent **temp_relpp;
long temp_relcount = 0;
long i;
-
+
temp_relpp = (arelent **) xmalloc (relsize);
for (i = 0; i < relcount; i++)
if (is_specified_symbol
@@ -1353,7 +1436,7 @@ copy_section (ibfd, isection, obfdarg)
bfd_set_reloc (obfd, osection,
(relcount == 0 ? (arelent **) NULL : relpp), relcount);
}
-
+
isection->_cooked_size = isection->_raw_size;
isection->reloc_done = true;
@@ -1365,7 +1448,7 @@ copy_section (ibfd, isection, obfdarg)
size))
RETURN_NONFATAL (bfd_get_filename (ibfd));
- if (copy_byte >= 0)
+ if (copy_byte >= 0)
filter_bytes (memhunk, &size);
if (!bfd_set_section_contents (obfd, osection, memhunk, (file_ptr) 0,
@@ -1720,22 +1803,27 @@ copy_main (argc, argv)
if (copy_byte < 0)
fatal (_("byte number must be non-negative"));
break;
+
case 'i':
interleave = atoi (optarg);
if (interleave < 1)
fatal (_("interleave must be positive"));
break;
+
case 'I':
case 's': /* "source" - 'I' is preferred */
input_target = optarg;
break;
+
case 'O':
case 'd': /* "destination" - 'O' is preferred */
output_target = optarg;
break;
+
case 'F':
input_target = output_target = optarg;
break;
+
case 'j':
p = find_section_list (optarg, true);
if (p->remove)
@@ -1743,6 +1831,7 @@ copy_main (argc, argv)
p->copy = true;
sections_copied = true;
break;
+
case 'R':
p = find_section_list (optarg, true);
if (p->copy)
@@ -1750,45 +1839,59 @@ copy_main (argc, argv)
p->remove = true;
sections_removed = true;
break;
+
case 'S':
strip_symbols = STRIP_ALL;
break;
+
case 'g':
strip_symbols = STRIP_DEBUG;
break;
+
case OPTION_STRIP_UNNEEDED:
strip_symbols = STRIP_UNNEEDED;
break;
+
case 'K':
add_specific_symbol (optarg, &keep_specific_list);
break;
+
case 'N':
add_specific_symbol (optarg, &strip_specific_list);
break;
+
case 'L':
add_specific_symbol (optarg, &localize_specific_list);
break;
+
case 'W':
add_specific_symbol (optarg, &weaken_specific_list);
break;
+
case 'p':
preserve_dates = true;
break;
+
case 'x':
discard_locals = LOCALS_ALL;
break;
+
case 'X':
discard_locals = LOCALS_START_L;
break;
+
case 'v':
verbose = true;
break;
+
case 'V':
show_version = true;
break;
+
case OPTION_WEAKEN:
weaken = true;
break;
+
case OPTION_ADD_SECTION:
{
const char *s;
@@ -1799,9 +1902,9 @@ copy_main (argc, argv)
FILE *f;
s = strchr (optarg, '=');
-
+
if (s == NULL)
- fatal (_("bad format for --add-section NAME=FILENAME"));
+ fatal (_("bad format for %s"), "--add-section");
if (stat (s + 1, & st) < 0)
fatal (_("cannot stat: %s: %s"), s + 1, strerror (errno));
@@ -1820,10 +1923,10 @@ copy_main (argc, argv)
pa->contents = (bfd_byte *) xmalloc (pa->size);
f = fopen (pa->filename, FOPEN_RB);
-
+
if (f == NULL)
fatal (_("cannot open: %s: %s"), pa->filename, strerror (errno));
-
+
if (fread (pa->contents, 1, pa->size, f) == 0
|| ferror (f))
fatal (_("%s: fread failed"), pa->filename);
@@ -1834,9 +1937,11 @@ copy_main (argc, argv)
add_sections = pa;
}
break;
+
case OPTION_CHANGE_START:
change_start = parse_vma (optarg, "--change-start");
break;
+
case OPTION_CHANGE_SECTION_ADDRESS:
case OPTION_CHANGE_SECTION_LMA:
case OPTION_CHANGE_SECTION_VMA:
@@ -1847,7 +1952,7 @@ copy_main (argc, argv)
char *option = NULL;
bfd_vma val;
enum change_action what = CHANGE_IGNORE;
-
+
switch (c)
{
case OPTION_CHANGE_SECTION_ADDRESS:
@@ -1860,7 +1965,7 @@ copy_main (argc, argv)
option = "--change-section-vma";
break;
}
-
+
s = strchr (optarg, '=');
if (s == NULL)
{
@@ -1888,19 +1993,19 @@ copy_main (argc, argv)
case '-': val = - val; /* Drop through. */
case '+': what = CHANGE_MODIFY; break;
}
-
+
switch (c)
{
case OPTION_CHANGE_SECTION_ADDRESS:
p->change_vma = what;
p->vma_val = val;
/* Drop through. */
-
+
case OPTION_CHANGE_SECTION_LMA:
p->change_lma = what;
p->lma_val = val;
break;
-
+
case OPTION_CHANGE_SECTION_VMA:
p->change_vma = what;
p->vma_val = val;
@@ -1908,19 +2013,24 @@ copy_main (argc, argv)
}
}
break;
+
case OPTION_CHANGE_ADDRESSES:
change_section_address = parse_vma (optarg, "--change-addresses");
change_start = change_section_address;
break;
+
case OPTION_CHANGE_WARNINGS:
change_warn = true;
break;
+
case OPTION_CHANGE_LEADING_CHAR:
change_leading_char = true;
break;
+
case OPTION_DEBUGGING:
convert_debugging = true;
break;
+
case OPTION_GAP_FILL:
{
bfd_vma gap_fill_vma;
@@ -1930,25 +2040,61 @@ copy_main (argc, argv)
if ((bfd_vma) gap_fill != gap_fill_vma)
{
char buff[20];
-
+
sprintf_vma (buff, gap_fill_vma);
-
+
non_fatal (_("Warning: truncating gap-fill from 0x%s to 0x%x"),
buff, gap_fill);
}
gap_fill_set = true;
}
break;
+
case OPTION_NO_CHANGE_WARNINGS:
change_warn = false;
break;
+
case OPTION_PAD_TO:
pad_to = parse_vma (optarg, "--pad-to");
pad_to_set = true;
break;
+
case OPTION_REMOVE_LEADING_CHAR:
remove_leading_char = true;
break;
+
+ case OPTION_REDEFINE_SYM:
+ {
+ /* Push this redefinition onto redefine_symbol_list. */
+
+ int len;
+ const char *s;
+ const char *nextarg;
+ char *source, *target;
+
+ s = strchr (optarg, '=');
+ if (s == NULL)
+ {
+ fatal (_("bad format for %s"), "--redefine-sym");
+ }
+
+ len = s - optarg;
+ source = (char *) xmalloc (len + 1);
+ strncpy (source, optarg, len);
+ source[len] = '\0';
+
+ nextarg = s + 1;
+ len = strlen (nextarg);
+ target = (char *) xmalloc (len + 1);
+ strcpy (target, nextarg);
+
+ redefine_list_append (source, target);
+
+ free (source);
+ free (target);
+ }
+ break;
+
case OPTION_SET_SECTION_FLAGS:
{
const char *s;
@@ -1957,7 +2103,7 @@ copy_main (argc, argv)
s = strchr (optarg, '=');
if (s == NULL)
- fatal (_("bad format for --set-section-flags"));
+ fatal (_("bad format for %s"), "--set-section-flags");
len = s - optarg;
name = (char *) xmalloc (len + 1);
@@ -1970,14 +2116,18 @@ copy_main (argc, argv)
p->flags = parse_flags (s + 1);
}
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_usage (stdout, 0);
+
default:
copy_usage (stderr, 1);
}
@@ -2018,7 +2168,7 @@ copy_main (argc, argv)
copy_file (input_filename, tmpname, input_target, output_target);
if (status == 0)
- {
+ {
if (preserve_dates)
set_times (tmpname, &statbuf);
smart_rename (tmpname, input_filename, preserve_dates);
@@ -2044,22 +2194,24 @@ copy_main (argc, argv)
char buff [20];
sprintf_vma (buff, p->vma_val);
-
+
/* xgettext:c-format */
- non_fatal (_("Warning: --change-section-vma %s%c0x%s never used"),
+ non_fatal (_("%s %s%c0x%s never used"),
+ "--change-section-vma",
p->name,
p->change_vma == CHANGE_SET ? '=' : '+',
buff);
}
-
+
if (p->change_lma != CHANGE_IGNORE)
{
char buff [20];
sprintf_vma (buff, p->lma_val);
-
+
/* xgettext:c-format */
- non_fatal (_("Warning: --change-section-lma %s%c0x%s never used"),
+ non_fatal (_("%s %s%c0x%s never used"),
+ "--change-section-lma",
p->name,
p->change_lma == CHANGE_SET ? '=' : '+',
buff);