aboutsummaryrefslogtreecommitdiff
path: root/binutils/objcopy.c
diff options
context:
space:
mode:
Diffstat (limited to 'binutils/objcopy.c')
-rw-r--r--binutils/objcopy.c175
1 files changed, 172 insertions, 3 deletions
diff --git a/binutils/objcopy.c b/binutils/objcopy.c
index de053b1..4afec5b 100644
--- a/binutils/objcopy.c
+++ b/binutils/objcopy.c
@@ -57,6 +57,7 @@ static void copy_section PARAMS ((bfd *, asection *, PTR));
static void get_sections PARAMS ((bfd *, asection *, PTR));
static int compare_section_lma PARAMS ((const PTR, const PTR));
static void add_specific_symbol PARAMS ((const char *, struct symlist **));
+static void add_specific_symbols PARAMS ((const char *, struct symlist **));
static boolean is_specified_symbol PARAMS ((const char *, struct symlist *));
static boolean is_strip_section PARAMS ((bfd *, asection *));
static unsigned int filter_symbols
@@ -184,11 +185,13 @@ static boolean change_leading_char = false;
static boolean remove_leading_char = false;
-/* List of symbols to strip, keep, localize, weaken, or redefine. */
+/* List of symbols to strip, keep, localize, keep-global, 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 *keepglobal_specific_list = NULL;
static struct symlist *weaken_specific_list = NULL;
static struct redefine_node *redefine_sym_list = NULL;
@@ -218,6 +221,11 @@ static boolean weaken = false;
#define OPTION_REDEFINE_SYM (OPTION_WEAKEN + 1)
#define OPTION_SREC_LEN (OPTION_REDEFINE_SYM + 1)
#define OPTION_SREC_FORCES3 (OPTION_SREC_LEN + 1)
+#define OPTION_STRIP_SYMBOLS (OPTION_SREC_FORCES3 + 1)
+#define OPTION_KEEP_SYMBOLS (OPTION_STRIP_SYMBOLS + 1)
+#define OPTION_LOCALIZE_SYMBOLS (OPTION_KEEP_SYMBOLS + 1)
+#define OPTION_KEEPGLOBAL_SYMBOLS (OPTION_LOCALIZE_SYMBOLS + 1)
+#define OPTION_WEAKEN_SYMBOLS (OPTION_KEEPGLOBAL_SYMBOLS + 1)
/* Options to handle if running as "strip". */
@@ -280,6 +288,7 @@ static struct option copy_options[] =
{"pad-to", required_argument, 0, OPTION_PAD_TO},
{"preserve-dates", no_argument, 0, 'p'},
{"localize-symbol", required_argument, 0, 'L'},
+ {"keep-global-symbol", required_argument, 0, 'G'},
{"remove-leading-char", no_argument, 0, OPTION_REMOVE_LEADING_CHAR},
{"remove-section", required_argument, 0, 'R'},
{"set-section-flags", required_argument, 0, OPTION_SET_SECTION_FLAGS},
@@ -296,6 +305,11 @@ static struct option copy_options[] =
{"redefine-sym", required_argument, 0, OPTION_REDEFINE_SYM},
{"srec-len", required_argument, 0, OPTION_SREC_LEN},
{"srec-forceS3", no_argument, 0, OPTION_SREC_FORCES3},
+ {"keep-symbols", required_argument, 0, OPTION_KEEP_SYMBOLS},
+ {"strip-symbols", required_argument, 0, OPTION_STRIP_SYMBOLS},
+ {"keep-global-symbols", required_argument, 0, OPTION_KEEPGLOBAL_SYMBOLS},
+ {"localize-symbols", required_argument, 0, OPTION_LOCALIZE_SYMBOLS},
+ {"weaken-symbols", required_argument, 0, OPTION_WEAKEN_SYMBOLS},
{0, no_argument, 0, 0}
};
@@ -341,6 +355,7 @@ copy_usage (stream, exit_status)
-N --strip-symbol <name> Do not copy symbol <name>\n\
-K --keep-symbol <name> Only copy symbol <name>\n\
-L --localize-symbol <name> Force symbol <name> to be marked as a local\n\
+ -G --keep-global-symbol <name> Localize all symbols except <name>\n\
-W --weaken-symbol <name> Force symbol <name> to be marked as a weak\n\
--weaken Force all global symbols to be marked as weak\n\
-x --discard-all Remove all non-global symbols\n\
@@ -370,6 +385,11 @@ copy_usage (stream, exit_status)
--redefine-sym <old>=<new> Redefine symbol name <old> to <new>\n\
--srec-len <number> Restrict the length of generated Srecords\n\
--srec-forceS3 Restrict the type of generated Srecords to S3\n\
+ --strip-symbols <file> -N for all symbols listed in <file>\n\
+ --keep-symbols <file> -K for all symbols listed in <file>\n\
+ --localize-symbols <file> -L for all symbols listed in <file>\n\
+ --keep-global-symbols <file> -G for all symbols listed in <file>\n\
+ --weaken-symbols <file> -W for all symbols listed in <file>\n\
-v --verbose List all object files modified\n\
-V --version Display this program's version number\n\
-h --help Display this output\n\
@@ -518,6 +538,122 @@ add_specific_symbol (name, list)
*list = tmp_list;
}
+/* Add symbols listed in `filename' to strip_specific_list. */
+
+#define IS_WHITESPACE(c) ((c) == ' ' || (c) == '\t')
+#define IS_LINE_TERMINATOR(c) ((c) == '\n' || (c) == '\r' || (c) == '\0')
+
+static void
+add_specific_symbols (filename, list)
+ const char *filename;
+ struct symlist **list;
+{
+ struct stat st;
+ FILE * f;
+ char * line;
+ char * buffer;
+ unsigned int line_count;
+
+ if (stat (filename, & st) < 0)
+ fatal (_("cannot stat: %s: %s"), filename, strerror (errno));
+ if (st.st_size == 0)
+ return;
+
+ buffer = (char *) xmalloc (st.st_size + 2);
+ f = fopen (filename, FOPEN_RT);
+ if (f == NULL)
+ fatal (_("cannot open: %s: %s"), filename, strerror (errno));
+
+ if (fread (buffer, 1, st.st_size, f) == 0 || ferror (f))
+ fatal (_("%s: fread failed"), filename);
+
+ fclose (f);
+ buffer [st.st_size] = '\n';
+ buffer [st.st_size + 1] = '\0';
+
+ line_count = 1;
+
+ for (line = buffer; * line != '\0'; line ++)
+ {
+ char * eol;
+ char * name;
+ char * name_end;
+ int finished = false;
+
+ for (eol = line;; eol ++)
+ {
+ switch (* eol)
+ {
+ case '\n':
+ * eol = '\0';
+ /* Cope with \n\r. */
+ if (eol[1] == '\r')
+ ++ eol;
+ finished = true;
+ break;
+
+ case '\r':
+ * eol = '\0';
+ /* Cope with \r\n. */
+ if (eol[1] == '\n')
+ ++ eol;
+ finished = true;
+ break;
+
+ case 0:
+ finished = true;
+ break;
+
+ case '#':
+ /* Line comment, Terminate the line here, in case a
+ name is present and then allow the rest of the
+ loop to find the real end of the line. */
+ * eol = '\0';
+ break;
+
+ default:
+ break;
+ }
+
+ if (finished)
+ break;
+ }
+
+ /* A name may now exist somewhere between 'line' and 'eol'.
+ Strip off leading whitespace and trailing whitespace,
+ then add it to the list. */
+ for (name = line; IS_WHITESPACE (* name); name ++)
+ ;
+ for (name_end = name;
+ (! IS_WHITESPACE (* name_end))
+ && (! IS_LINE_TERMINATOR (* name_end));
+ name_end ++)
+ ;
+
+ if (! IS_LINE_TERMINATOR (* name_end))
+ {
+ char * extra;
+
+ for (extra = name_end + 1; IS_WHITESPACE (* extra); extra ++)
+ ;
+
+ if (! IS_LINE_TERMINATOR (* extra))
+ non_fatal (_("Ignoring rubbish found on line %d of %s"),
+ line_count, filename);
+ }
+
+ * name_end = '\0';
+
+ if (name_end > name)
+ add_specific_symbol (name, list);
+
+ /* Advance line pointer to end of line. The 'eol ++' in the for
+ loop above will then advance us to the start of the next line. */
+ line = eol;
+ line_count ++;
+ }
+}
+
/* See whether a symbol should be stripped or kept based on
strip_specific_list and keep_symbols. */
@@ -636,6 +772,12 @@ filter_symbols (abfd, obfd, osyms, isyms, symcount)
else if (relocatable /* Relocatable file. */
&& (flags & (BSF_GLOBAL | BSF_WEAK)) != 0)
keep = 1;
+ else if (bfd_decode_symclass (sym) == 'I')
+ /* Global symbols in $idata sections need to be retained
+ even if relocatable is false. External users of the
+ library containing the $idata section may reference these
+ symbols. */
+ keep = 1;
else if ((flags & BSF_GLOBAL) != 0 /* Global symbol. */
|| (flags & BSF_WEAK) != 0
|| bfd_is_und_section (bfd_get_section (sym))
@@ -665,7 +807,9 @@ filter_symbols (abfd, obfd, osyms, isyms, symcount)
sym->flags |= BSF_WEAK;
}
if (keep && (flags & (BSF_GLOBAL | BSF_WEAK))
- && is_specified_symbol (name, localize_specific_list))
+ && (is_specified_symbol (name, localize_specific_list)
+ || (keepglobal_specific_list != NULL
+ && ! is_specified_symbol (name, keepglobal_specific_list))))
{
sym->flags &= ~(BSF_GLOBAL | BSF_WEAK);
sym->flags |= BSF_LOCAL;
@@ -977,6 +1121,7 @@ copy_object (ibfd, obfd)
|| strip_specific_list != NULL
|| keep_specific_list != NULL
|| localize_specific_list != NULL
+ || keepglobal_specific_list != NULL
|| weaken_specific_list != NULL
|| sections_removed
|| sections_copied
@@ -1695,7 +1840,7 @@ strip_main (argc, argv)
struct section_list *p;
char *output_file = NULL;
- while ((c = getopt_long (argc, argv, "I:O:F:K:N:R:o:sSpdgxXVv",
+ while ((c = getopt_long (argc, argv, "b:i:I:j:K:N:s:O:d:F:L:G:R:SpgxXVvW:",
strip_options, (int *) 0)) != EOF)
{
switch (c)
@@ -1903,6 +2048,10 @@ copy_main (argc, argv)
add_specific_symbol (optarg, &localize_specific_list);
break;
+ case 'G':
+ add_specific_symbol (optarg, &keepglobal_specific_list);
+ break;
+
case 'W':
add_specific_symbol (optarg, &weaken_specific_list);
break;
@@ -2169,6 +2318,26 @@ copy_main (argc, argv)
S3Forced = true;
break;
+ case OPTION_STRIP_SYMBOLS:
+ add_specific_symbols (optarg, &strip_specific_list);
+ break;
+
+ case OPTION_KEEP_SYMBOLS:
+ add_specific_symbols (optarg, &keep_specific_list);
+ break;
+
+ case OPTION_LOCALIZE_SYMBOLS:
+ add_specific_symbols (optarg, &localize_specific_list);
+ break;
+
+ case OPTION_KEEPGLOBAL_SYMBOLS:
+ add_specific_symbols (optarg, &keepglobal_specific_list);
+ break;
+
+ case OPTION_WEAKEN_SYMBOLS:
+ add_specific_symbols (optarg, &weaken_specific_list);
+ break;
+
case 0:
break; /* we've been given a long option */