/* objcopy.c -- copy object file from input to output, optionally massaging it.
Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
This file is part of GNU Binutils.
#include <sys/stat.h>
#include "libbfd.h"
-/* A list of symbols to explicitly strip out, or to keep. A linked
- list is good enough for a small number from the command line, but
- this will slow things down a lot if many symbols are being
- deleted. */
-
-struct symlist
+struct is_specified_symbol_predicate_data
{
- const char *name;
- struct symlist *next;
+ const char *name;
+ bfd_boolean found;
};
/* A list to support redefine_sym. */
/* List of symbols to strip, keep, localize, keep-global, weaken,
or redefine. */
-static struct symlist *strip_specific_list = NULL;
-static struct symlist *strip_unneeded_list = NULL;
-static struct symlist *keep_specific_list = NULL;
-static struct symlist *localize_specific_list = NULL;
-static struct symlist *globalize_specific_list = NULL;
-static struct symlist *keepglobal_specific_list = NULL;
-static struct symlist *weaken_specific_list = NULL;
+static htab_t strip_specific_htab = NULL;
+static htab_t strip_unneeded_htab = NULL;
+static htab_t keep_specific_htab = NULL;
+static htab_t localize_specific_htab = NULL;
+static htab_t globalize_specific_htab = NULL;
+static htab_t keepglobal_specific_htab = NULL;
+static htab_t weaken_specific_htab = NULL;
static struct redefine_node *redefine_sym_list = NULL;
/* If this is TRUE, we weaken global symbols (set BSF_WEAK). */
return p;
}
-/* Add a symbol to strip_specific_list. */
+/* There is htab_hash_string but no htab_eq_string. Makes sense. */
+
+static int
+eq_string (const void *s1, const void *s2)
+{
+ return strcmp (s1, s2) == 0;
+}
+
+static htab_t
+create_symbol_htab (void)
+{
+ return htab_create_alloc (16, htab_hash_string, eq_string, NULL, xcalloc, free);
+}
static void
-add_specific_symbol (const char *name, struct symlist **list)
+create_symbol_htabs (void)
{
- struct symlist *tmp_list;
+ strip_specific_htab = create_symbol_htab ();
+ strip_unneeded_htab = create_symbol_htab ();
+ keep_specific_htab = create_symbol_htab ();
+ localize_specific_htab = create_symbol_htab ();
+ globalize_specific_htab = create_symbol_htab ();
+ keepglobal_specific_htab = create_symbol_htab ();
+ weaken_specific_htab = create_symbol_htab ();
+}
- tmp_list = xmalloc (sizeof (struct symlist));
- tmp_list->name = name;
- tmp_list->next = *list;
- *list = tmp_list;
+/* Add a symbol to strip_specific_list. */
+
+static void
+add_specific_symbol (const char *name, htab_t htab)
+{
+ *htab_find_slot (htab, name, INSERT) = (char *) name;
}
/* Add symbols listed in `filename' to strip_specific_list. */
#define IS_LINE_TERMINATOR(c) ((c) == '\n' || (c) == '\r' || (c) == '\0')
static void
-add_specific_symbols (const char *filename, struct symlist **list)
+add_specific_symbols (const char *filename, htab_t htab)
{
off_t size;
FILE * f;
* name_end = '\0';
if (name_end > name)
- add_specific_symbol (name, list);
+ add_specific_symbol (name, htab);
/* 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. */
}
}
-/* See whether a symbol should be stripped or kept based on
- strip_specific_list and keep_symbols. */
+/* See whether a symbol should be stripped or kept
+ based on strip_specific_list and keep_symbols. */
-static bfd_boolean
-is_specified_symbol (const char *name, struct symlist *list)
+static int
+is_specified_symbol_predicate (void **slot, void *data)
{
- struct symlist *tmp_list;
+ struct is_specified_symbol_predicate_data *d = data;
+ const char *slot_name = *slot;
- if (wildcard)
+ if (*slot_name != '!')
{
- for (tmp_list = list; tmp_list; tmp_list = tmp_list->next)
- if (*(tmp_list->name) != '!')
- {
- if (!fnmatch (tmp_list->name, name, 0))
- return TRUE;
- }
- else
- {
- if (fnmatch (tmp_list->name + 1, name, 0))
- return TRUE;
- }
+ if (! fnmatch (slot_name, d->name, 0))
+ {
+ d->found = TRUE;
+ /* Stop traversal. */
+ return 0;
+ }
}
else
{
- for (tmp_list = list; tmp_list; tmp_list = tmp_list->next)
- if (strcmp (name, tmp_list->name) == 0)
- return TRUE;
+ if (fnmatch (slot_name + 1, d->name, 0))
+ {
+ d->found = TRUE;
+ /* Stop traversal. */
+ return 0;
+ }
}
- return FALSE;
+ /* Continue traversal. */
+ return 1;
+}
+
+static bfd_boolean
+is_specified_symbol (const char *name, htab_t htab)
+{
+ if (wildcard)
+ {
+ struct is_specified_symbol_predicate_data data;
+
+ data.name = name;
+ data.found = FALSE;
+
+ htab_traverse (htab, is_specified_symbol_predicate, &data);
+
+ return data.found;
+ }
+
+ return htab_find (htab, name) != NULL;
}
/* Return a pointer to the symbol used as a signature for GROUP. */
else
gname = sec->name;
if ((strip_symbols == STRIP_ALL
- && !is_specified_symbol (gname, keep_specific_list))
- || is_specified_symbol (gname, strip_specific_list))
+ && !is_specified_symbol (gname, keep_specific_htab))
+ || is_specified_symbol (gname, strip_specific_htab))
return TRUE;
}
&& (discard_locals != LOCALS_START_L
|| ! bfd_is_local_label (abfd, sym))));
- if (keep && is_specified_symbol (name, strip_specific_list))
+ if (keep && is_specified_symbol (name, strip_specific_htab))
{
/* There are multiple ways to set 'keep' above, but if it
was the relocatable symbol case, then that's an error. */
if (keep
&& !(flags & BSF_KEEP)
- && is_specified_symbol (name, strip_unneeded_list))
+ && is_specified_symbol (name, strip_unneeded_htab))
keep = FALSE;
if (!keep
&& ((keep_file_symbols && (flags & BSF_FILE))
- || is_specified_symbol (name, keep_specific_list)))
+ || is_specified_symbol (name, keep_specific_htab)))
keep = TRUE;
if (keep && is_strip_section (abfd, bfd_get_section (sym)))
if (keep)
{
if ((flags & BSF_GLOBAL) != 0
- && (weaken || is_specified_symbol (name, weaken_specific_list)))
+ && (weaken || is_specified_symbol (name, weaken_specific_htab)))
{
sym->flags &= ~ BSF_GLOBAL;
sym->flags |= BSF_WEAK;
if (!undefined
&& (flags & (BSF_GLOBAL | BSF_WEAK))
- && (is_specified_symbol (name, localize_specific_list)
- || (keepglobal_specific_list != NULL
- && ! is_specified_symbol (name, keepglobal_specific_list))
+ && (is_specified_symbol (name, localize_specific_htab)
+ || (htab_elements (keepglobal_specific_htab) != 0
+ && ! is_specified_symbol (name, keepglobal_specific_htab))
|| (localize_hidden && is_hidden_symbol (sym))))
{
sym->flags &= ~ (BSF_GLOBAL | BSF_WEAK);
if (!undefined
&& (flags & BSF_LOCAL)
- && is_specified_symbol (name, globalize_specific_list))
+ && is_specified_symbol (name, globalize_specific_htab))
{
sym->flags &= ~ BSF_LOCAL;
sym->flags |= BSF_GLOBAL;
any output is done. Thus, we traverse all sections multiple times. */
bfd_map_over_sections (ibfd, setup_section, obfd);
- setup_bfd_headers (ibfd, obfd);
+ if (!extract_symbol)
+ setup_bfd_headers (ibfd, obfd);
if (add_sections != NULL)
{
have been created, but before their contents are set. */
dhandle = NULL;
if (convert_debugging)
- dhandle = read_debugging_info (ibfd, isympp, symcount);
+ dhandle = read_debugging_info (ibfd, isympp, symcount, FALSE);
if (strip_symbols == STRIP_DEBUG
|| strip_symbols == STRIP_ALL
|| strip_symbols == STRIP_NONDEBUG
|| discard_locals != LOCALS_UNDEF
|| localize_hidden
- || strip_specific_list != NULL
- || keep_specific_list != NULL
- || localize_specific_list != NULL
- || globalize_specific_list != NULL
- || keepglobal_specific_list != NULL
- || weaken_specific_list != NULL
+ || htab_elements (strip_specific_htab) != 0
+ || htab_elements (keep_specific_htab) != 0
+ || htab_elements (localize_specific_htab) != 0
+ || htab_elements (globalize_specific_htab) != 0
+ || htab_elements (keepglobal_specific_htab) != 0
+ || htab_elements (weaken_specific_htab) != 0
|| prefix_symbols_string
|| sections_removed
|| sections_copied
strerror (errno));
obfd->has_armap = ibfd->has_armap;
+ obfd->is_thin_archive = ibfd->is_thin_archive;
list = NULL;
else
vma += change_section_address;
- if (! bfd_set_section_vma (obfd, osection, extract_symbol ? 0 : vma))
+ if (! bfd_set_section_vma (obfd, osection, vma))
{
err = _("failed to set vma");
goto loser;
else
lma += change_section_address;
- osection->lma = extract_symbol ? 0 : lma;
+ osection->lma = lma;
/* FIXME: This is probably not enough. If we change the LMA we
may have to recompute the header for the file as well. */
bfd_get_section_by_name since some formats allow multiple
sections with the same name. */
isection->output_section = osection;
- isection->output_offset = extract_symbol ? vma : 0;
+ isection->output_offset = 0;
/* Do not copy backend data if --extract-symbol is passed; anything
that needs to look at the section contents will fail. */
if (extract_symbol)
return;
+ if ((isection->flags & SEC_GROUP) != 0)
+ {
+ asymbol *gsym = group_signature (isection);
+
+ if (gsym != NULL)
+ {
+ gsym->flags |= BSF_KEEP;
+ if (ibfd->xvec->flavour == bfd_target_elf_flavour)
+ elf_group_id (isection) = gsym;
+ }
+ }
+
/* 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 = _("failed to copy private data");
goto loser;
}
- else if ((isection->flags & SEC_GROUP) != 0)
- {
- asymbol *gsym = group_signature (isection);
-
- if (gsym != NULL)
- gsym->flags |= BSF_KEEP;
- }
/* All went well. */
return;
if (size == 0 || osection == 0)
return;
+ if (extract_symbol)
+ return;
+
p = find_section_list (bfd_get_section_name (ibfd, isection), FALSE);
/* Core files do not need to be relocated. */
temp_relpp = xmalloc (relsize);
for (i = 0; i < relcount; i++)
if (is_specified_symbol (bfd_asymbol_name (*relpp[i]->sym_ptr_ptr),
- keep_specific_list))
+ keep_specific_htab))
temp_relpp [temp_relcount++] = relpp [i];
relcount = temp_relcount;
free (relpp);
free (relpp);
}
- if (extract_symbol)
- return;
-
if (bfd_get_section_flags (ibfd, isection) & SEC_HAS_CONTENTS
&& bfd_get_section_flags (obfd, osection) & SEC_HAS_CONTENTS)
{
strip_symbols = STRIP_UNNEEDED;
break;
case 'K':
- add_specific_symbol (optarg, &keep_specific_list);
+ add_specific_symbol (optarg, keep_specific_htab);
break;
case 'N':
- add_specific_symbol (optarg, &strip_specific_list);
+ add_specific_symbol (optarg, strip_specific_htab);
break;
case 'o':
output_file = optarg;
/* Default is to strip all symbols. */
if (strip_symbols == STRIP_UNDEF
&& discard_locals == LOCALS_UNDEF
- && strip_specific_list == NULL)
+ && htab_elements (strip_specific_htab) == 0)
strip_symbols = STRIP_ALL;
if (output_target == NULL)
break;
case 'K':
- add_specific_symbol (optarg, &keep_specific_list);
+ add_specific_symbol (optarg, keep_specific_htab);
break;
case 'N':
- add_specific_symbol (optarg, &strip_specific_list);
+ add_specific_symbol (optarg, strip_specific_htab);
break;
case OPTION_STRIP_UNNEEDED_SYMBOL:
- add_specific_symbol (optarg, &strip_unneeded_list);
+ add_specific_symbol (optarg, strip_unneeded_htab);
break;
case 'L':
- add_specific_symbol (optarg, &localize_specific_list);
+ add_specific_symbol (optarg, localize_specific_htab);
break;
case OPTION_GLOBALIZE_SYMBOL:
- add_specific_symbol (optarg, &globalize_specific_list);
+ add_specific_symbol (optarg, globalize_specific_htab);
break;
case 'G':
- add_specific_symbol (optarg, &keepglobal_specific_list);
+ add_specific_symbol (optarg, keepglobal_specific_htab);
break;
case 'W':
- add_specific_symbol (optarg, &weaken_specific_list);
+ add_specific_symbol (optarg, weaken_specific_htab);
break;
case 'p':
break;
case OPTION_STRIP_SYMBOLS:
- add_specific_symbols (optarg, &strip_specific_list);
+ add_specific_symbols (optarg, strip_specific_htab);
break;
case OPTION_STRIP_UNNEEDED_SYMBOLS:
- add_specific_symbols (optarg, &strip_unneeded_list);
+ add_specific_symbols (optarg, strip_unneeded_htab);
break;
case OPTION_KEEP_SYMBOLS:
- add_specific_symbols (optarg, &keep_specific_list);
+ add_specific_symbols (optarg, keep_specific_htab);
break;
case OPTION_LOCALIZE_HIDDEN:
break;
case OPTION_LOCALIZE_SYMBOLS:
- add_specific_symbols (optarg, &localize_specific_list);
+ add_specific_symbols (optarg, localize_specific_htab);
break;
case OPTION_GLOBALIZE_SYMBOLS:
- add_specific_symbols (optarg, &globalize_specific_list);
+ add_specific_symbols (optarg, globalize_specific_htab);
break;
case OPTION_KEEPGLOBAL_SYMBOLS:
- add_specific_symbols (optarg, &keepglobal_specific_list);
+ add_specific_symbols (optarg, keepglobal_specific_htab);
break;
case OPTION_WEAKEN_SYMBOLS:
- add_specific_symbols (optarg, &weaken_specific_list);
+ add_specific_symbols (optarg, weaken_specific_htab);
break;
case OPTION_ALT_MACH_CODE:
is_strip = (i >= 5 && FILENAME_CMP (program_name + i - 5, "strip") == 0);
}
+ create_symbol_htabs ();
+
if (is_strip)
strip_main (argc, argv);
else