X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=ld%2Fldlang.c;h=a732525b0b813168d4ade3cacac06c5447b9a3ae;hb=34c8bcbae2e6ea0752c1ebe6e1282cc74a821957;hp=b82a7e55cf6de2502c4fd7c31baecc18d3bd7ace;hpb=ecca98713a19ac7aac31886b4b15b806e63d9a99;p=deliverable%2Fbinutils-gdb.git diff --git a/ld/ldlang.c b/ld/ldlang.c index b82a7e55cf..a732525b0b 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -1,6 +1,6 @@ /* Linker command language support. Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005 + 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. This file is part of GLD, the Gnu Linker. @@ -20,8 +20,8 @@ Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "bfd.h" #include "sysdep.h" +#include "bfd.h" #include "libiberty.h" #include "safe-ctype.h" #include "obstack.h" @@ -52,7 +52,6 @@ static struct obstack map_obstack; #define obstack_chunk_alloc xmalloc #define obstack_chunk_free free static const char *startup_file; -static lang_statement_list_type input_file_chain; static bfd_boolean placed_commons = FALSE; static bfd_boolean stripped_excluded_sections = FALSE; static lang_output_section_statement_type *default_common_section; @@ -62,34 +61,34 @@ static lang_input_statement_type *first_file; static const char *current_target; static const char *output_target; static lang_statement_list_type statement_list; -static struct lang_phdr *lang_phdr_list; static struct bfd_hash_table lang_definedness_table; /* Forward declarations. */ static void exp_init_os (etree_type *); static void init_map_userdata (bfd *, asection *, void *); static lang_input_statement_type *lookup_name (const char *); -static bfd_boolean load_symbols (lang_input_statement_type *, - lang_statement_list_type *); static struct bfd_hash_entry *lang_definedness_newfunc (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); static void insert_undefined (const char *); -static void print_all_symbols (asection *); static bfd_boolean sort_def_symbol (struct bfd_link_hash_entry *, void *); static void print_statement (lang_statement_union_type *, lang_output_section_statement_type *); static void print_statement_list (lang_statement_union_type *, lang_output_section_statement_type *); static void print_statements (void); +static void print_input_section (asection *); static bfd_boolean lang_one_common (struct bfd_link_hash_entry *, void *); static void lang_record_phdrs (void); static void lang_do_version_exports_section (void); +static void lang_finalize_version_expr_head + (struct bfd_elf_version_expr_head *); /* Exported variables. */ lang_output_section_statement_type *abs_output_section; lang_statement_list_type lang_output_section_statement; lang_statement_list_type *stat_ptr = &statement_list; lang_statement_list_type file_chain = { NULL, NULL }; +lang_statement_list_type input_file_chain; struct bfd_sym_chain entry_symbol = { NULL, NULL }; static const char *entry_symbol_default = "start"; const char *entry_section = ".text"; @@ -98,6 +97,7 @@ bfd_boolean lang_has_input_file = FALSE; bfd_boolean had_output_filename = FALSE; bfd_boolean lang_float_flag = FALSE; bfd_boolean delete_output_file_on_failure = FALSE; +struct lang_phdr *lang_phdr_list; struct lang_nocrossrefs *nocrossref_list; static struct unique_sections *unique_section_list; static bfd_boolean ldlang_sysrooted_script = FALSE; @@ -279,7 +279,7 @@ find_section (lang_input_statement_type *file, { section_iterator_callback_data cb_data = { NULL, FALSE }; - bfd_get_section_by_name_if (file->the_bfd, sec->spec.name, + bfd_get_section_by_name_if (file->the_bfd, sec->spec.name, section_iterator_callback, &cb_data); *multiple_sections_found = cb_data.multiple_sections_found; return cb_data.found_section; @@ -316,6 +316,124 @@ match_simple_wild (const char *pattern, const char *name) return TRUE; } +/* Compare sections ASEC and BSEC according to SORT. */ + +static int +compare_section (sort_type sort, asection *asec, asection *bsec) +{ + int ret; + + switch (sort) + { + default: + abort (); + + case by_alignment_name: + ret = (bfd_section_alignment (bsec->owner, bsec) + - bfd_section_alignment (asec->owner, asec)); + if (ret) + break; + /* Fall through. */ + + case by_name: + ret = strcmp (bfd_get_section_name (asec->owner, asec), + bfd_get_section_name (bsec->owner, bsec)); + break; + + case by_name_alignment: + ret = strcmp (bfd_get_section_name (asec->owner, asec), + bfd_get_section_name (bsec->owner, bsec)); + if (ret) + break; + /* Fall through. */ + + case by_alignment: + ret = (bfd_section_alignment (bsec->owner, bsec) + - bfd_section_alignment (asec->owner, asec)); + break; + } + + return ret; +} + +/* Build a Binary Search Tree to sort sections, unlike insertion sort + used in wild_sort(). BST is considerably faster if the number of + of sections are large. */ + +static lang_section_bst_type ** +wild_sort_fast (lang_wild_statement_type *wild, + struct wildcard_list *sec, + lang_input_statement_type *file ATTRIBUTE_UNUSED, + asection *section) +{ + lang_section_bst_type **tree; + + tree = &wild->tree; + if (!wild->filenames_sorted + && (sec == NULL || sec->spec.sorted == none)) + { + /* Append at the right end of tree. */ + while (*tree) + tree = &((*tree)->right); + return tree; + } + + while (*tree) + { + /* Find the correct node to append this section. */ + if (compare_section (sec->spec.sorted, section, (*tree)->section) < 0) + tree = &((*tree)->left); + else + tree = &((*tree)->right); + } + + return tree; +} + +/* Use wild_sort_fast to build a BST to sort sections. */ + +static void +output_section_callback_fast (lang_wild_statement_type *ptr, + struct wildcard_list *sec, + asection *section, + lang_input_statement_type *file, + void *output ATTRIBUTE_UNUSED) +{ + lang_section_bst_type *node; + lang_section_bst_type **tree; + + if (unique_section_p (section)) + return; + + node = xmalloc (sizeof (lang_section_bst_type)); + node->left = 0; + node->right = 0; + node->section = section; + + tree = wild_sort_fast (ptr, sec, file, section); + if (tree != NULL) + *tree = node; +} + +/* Convert a sorted sections' BST back to list form. */ + +static void +output_section_callback_tree_to_list (lang_wild_statement_type *ptr, + lang_section_bst_type *tree, + void *output) +{ + if (tree->left) + output_section_callback_tree_to_list (ptr, tree->left, output); + + lang_add_section (&ptr->children, tree->section, + (lang_output_section_statement_type *) output); + + if (tree->right) + output_section_callback_tree_to_list (ptr, tree->right, output); + + free (tree); +} + /* Specialized, optimized routines for handling different kinds of wildcards */ @@ -543,6 +661,11 @@ analyze_walk_wild_section_handler (lang_wild_statement_type *ptr) int data_counter; ptr->walk_wild_section_handler = walk_wild_section_general; + ptr->handler_data[0] = NULL; + ptr->handler_data[1] = NULL; + ptr->handler_data[2] = NULL; + ptr->handler_data[3] = NULL; + ptr->tree = NULL; /* Count how many wildcard_specs there are, and how many of those actually use wildcards in the name. Also, bail out if any of the @@ -668,7 +791,7 @@ walk_wild (lang_wild_statement_type *s, callback_t callback, void *data) { LANG_FOR_EACH_INPUT_STATEMENT (f) { - if (fnmatch (file_spec, f->filename, FNM_FILE_NAME) == 0) + if (fnmatch (file_spec, f->filename, 0) == 0) walk_wild_file (s, f, callback, data); } } @@ -783,12 +906,21 @@ new_afile (const char *name, else { p = stat_alloc (sizeof (lang_input_statement_type)); + p->header.type = lang_input_statement_enum; p->header.next = NULL; } lang_has_input_file = TRUE; p->target = target; p->sysrooted = FALSE; + + if (file_type == lang_input_file_is_l_enum + && name[0] == ':' && name[1] != '\0') + { + file_type = lang_input_file_is_search_file_enum; + name = name + 1; + } + switch (file_type) { case lang_input_file_is_symbols_only_enum: @@ -864,47 +996,83 @@ lang_add_input_file (const char *name, lang_input_file_enum_type file_type, const char *target) { - lang_has_input_file = TRUE; return new_afile (name, file_type, target, TRUE); } -struct output_statement_hash_entry +struct out_section_hash_entry { struct bfd_hash_entry root; - lang_output_section_statement_type *entry; + lang_statement_union_type s; }; /* The hash table. */ -static struct bfd_hash_table output_statement_table; +static struct bfd_hash_table output_section_statement_table; -/* Support routines for the hash table used by lang_output_section_find_1, +/* Support routines for the hash table used by lang_output_section_find, initialize the table, fill in an entry and remove the table. */ static struct bfd_hash_entry * -output_statement_newfunc (struct bfd_hash_entry *entry ATTRIBUTE_UNUSED, - struct bfd_hash_table *table, - const char *string ATTRIBUTE_UNUSED) +output_section_statement_newfunc (struct bfd_hash_entry *entry, + struct bfd_hash_table *table, + const char *string) { - struct output_statement_hash_entry *ret - = bfd_hash_allocate (table, - sizeof (struct output_statement_hash_entry)); - ret->entry = NULL; - return (struct bfd_hash_entry *) ret; + lang_output_section_statement_type **nextp; + struct out_section_hash_entry *ret; + + if (entry == NULL) + { + entry = bfd_hash_allocate (table, sizeof (*ret)); + if (entry == NULL) + return entry; + } + + entry = bfd_hash_newfunc (entry, table, string); + if (entry == NULL) + return entry; + + ret = (struct out_section_hash_entry *) entry; + memset (&ret->s, 0, sizeof (ret->s)); + ret->s.header.type = lang_output_section_statement_enum; + ret->s.output_section_statement.subsection_alignment = -1; + ret->s.output_section_statement.section_alignment = -1; + ret->s.output_section_statement.block_value = 1; + lang_list_init (&ret->s.output_section_statement.children); + lang_statement_append (stat_ptr, &ret->s, &ret->s.header.next); + + /* For every output section statement added to the list, except the + first one, lang_output_section_statement.tail points to the "next" + field of the last element of the list. */ + if (lang_output_section_statement.head != NULL) + ret->s.output_section_statement.prev + = ((lang_output_section_statement_type *) + ((char *) lang_output_section_statement.tail + - offsetof (lang_output_section_statement_type, next))); + + /* GCC's strict aliasing rules prevent us from just casting the + address, so we store the pointer in a variable and cast that + instead. */ + nextp = &ret->s.output_section_statement.next; + lang_statement_append (&lang_output_section_statement, + &ret->s, + (lang_statement_union_type **) nextp); + return &ret->root; } static void -output_statement_table_init (void) +output_section_statement_table_init (void) { - if (! bfd_hash_table_init_n (&output_statement_table, - output_statement_newfunc, 61)) - einfo (_("%P%F: Failed to create hash table\n")); + if (!bfd_hash_table_init_n (&output_section_statement_table, + output_section_statement_newfunc, + sizeof (struct out_section_hash_entry), + 61)) + einfo (_("%P%F: can not create hash table: %E\n")); } static void -output_statement_table_free (void) +output_section_statement_table_free (void) { - bfd_hash_table_free (&output_statement_table); + bfd_hash_table_free (&output_section_statement_table); } /* Build enough state so that the parser can build its tree. */ @@ -916,7 +1084,7 @@ lang_init (void) stat_ptr = &statement_list; - output_statement_table_init (); + output_section_statement_table_init (); lang_list_init (stat_ptr); @@ -937,14 +1105,16 @@ lang_init (void) of code-complexity here in ld, besides the initialization which just looks like other code here. */ if (!bfd_hash_table_init_n (&lang_definedness_table, - lang_definedness_newfunc, 3)) - einfo (_("%P%F: out of memory during initialization")); + lang_definedness_newfunc, + sizeof (struct lang_definedness_hash_entry), + 3)) + einfo (_("%P%F: can not create hash table: %E\n")); } void lang_finish (void) { - output_statement_table_free (); + output_section_statement_table_free (); } /*---------------------------------------------------------------------- @@ -993,16 +1163,17 @@ lang_memory_region_lookup (const char *const name, bfd_boolean create) new->name = xstrdup (name); new->next = NULL; - - *lang_memory_region_list_tail = new; - lang_memory_region_list_tail = &new->next; new->origin = 0; - new->flags = 0; - new->not_flags = 0; new->length = ~(bfd_size_type) 0; new->current = 0; + new->last_os = NULL; + new->flags = 0; + new->not_flags = 0; new->had_full_message = FALSE; + *lang_memory_region_list_tail = new; + lang_memory_region_list_tail = &new->next; + return new; } @@ -1028,96 +1199,84 @@ lang_memory_default (asection *section) return lang_memory_region_lookup (DEFAULT_MEMORY_REGION, FALSE); } -static lang_output_section_statement_type * -lang_output_section_find_1 (const char *const name, int constraint) +lang_output_section_statement_type * +lang_output_section_find (const char *const name) { - lang_output_section_statement_type *lookup; - struct output_statement_hash_entry *entry; + struct out_section_hash_entry *entry; unsigned long hash; - entry = ((struct output_statement_hash_entry *) - bfd_hash_lookup (&output_statement_table, name, FALSE, - FALSE)); - if (entry == NULL || (lookup = entry->entry) == NULL) + entry = ((struct out_section_hash_entry *) + bfd_hash_lookup (&output_section_statement_table, name, + FALSE, FALSE)); + if (entry == NULL) return NULL; hash = entry->root.hash; do { - if (lookup->constraint != -1 - && (constraint == 0 - || (constraint == lookup->constraint - && constraint != SPECIAL))) - return lookup; - entry = (struct output_statement_hash_entry *) entry->root.next; - lookup = entry ? entry->entry : NULL; + if (entry->s.output_section_statement.constraint != -1) + return &entry->s.output_section_statement; + entry = (struct out_section_hash_entry *) entry->root.next; } while (entry != NULL && entry->root.hash == hash - && strcmp (name, lookup->name) == 0); + && strcmp (name, entry->s.output_section_statement.name) == 0); return NULL; } -lang_output_section_statement_type * -lang_output_section_find (const char *const name) -{ - return lang_output_section_find_1 (name, 0); -} - static lang_output_section_statement_type * lang_output_section_statement_lookup_1 (const char *const name, int constraint) { - lang_output_section_statement_type *lookup; - lang_output_section_statement_type **nextp; - - lookup = lang_output_section_find_1 (name, constraint); - if (lookup == NULL) - { - struct output_statement_hash_entry *entry; - - lookup = new_stat (lang_output_section_statement, stat_ptr); - lookup->region = NULL; - lookup->lma_region = NULL; - lookup->fill = 0; - lookup->block_value = 1; - lookup->name = name; - - lookup->next = NULL; - lookup->bfd_section = NULL; - lookup->processed = FALSE; - lookup->constraint = constraint; - lookup->ignored = FALSE; - lookup->sectype = normal_section; - lookup->addr_tree = NULL; - lang_list_init (&lookup->children); - - lookup->memspec = NULL; - lookup->flags = 0; - lookup->subsection_alignment = -1; - lookup->section_alignment = -1; - lookup->load_base = NULL; - lookup->update_dot_tree = NULL; - lookup->phdrs = NULL; - - entry = ((struct output_statement_hash_entry *) - bfd_hash_lookup (&output_statement_table, name, TRUE, - FALSE)); - if (entry == NULL) - einfo (_("%P%F: bfd_hash_lookup failed creating section `%s'\n"), - name); + struct out_section_hash_entry *entry; + struct out_section_hash_entry *last_ent; + unsigned long hash; - entry->entry = lookup; + entry = ((struct out_section_hash_entry *) + bfd_hash_lookup (&output_section_statement_table, name, + TRUE, FALSE)); + if (entry == NULL) + { + einfo (_("%P%F: failed creating section `%s': %E\n"), name); + return NULL; + } - /* GCC's strict aliasing rules prevent us from just casting the - address, so we store the pointer in a variable and cast that - instead. */ - nextp = &lookup->next; - lang_statement_append (&lang_output_section_statement, - (lang_statement_union_type *) lookup, - (lang_statement_union_type **) nextp); + if (entry->s.output_section_statement.name != NULL) + { + /* We have a section of this name, but it might not have the correct + constraint. */ + hash = entry->root.hash; + do + { + if (entry->s.output_section_statement.constraint != -1 + && (constraint == 0 + || (constraint == entry->s.output_section_statement.constraint + && constraint != SPECIAL))) + return &entry->s.output_section_statement; + last_ent = entry; + entry = (struct out_section_hash_entry *) entry->root.next; + } + while (entry != NULL + && entry->root.hash == hash + && strcmp (name, entry->s.output_section_statement.name) == 0); + + entry + = ((struct out_section_hash_entry *) + output_section_statement_newfunc (NULL, + &output_section_statement_table, + name)); + if (entry == NULL) + { + einfo (_("%P%F: failed creating section `%s': %E\n"), name); + return NULL; + } + entry->root = last_ent->root; + last_ent->root.next = &entry->root; } - return lookup; + + entry->s.output_section_statement.name = name; + entry->s.output_section_statement.constraint = constraint; + return &entry->s.output_section_statement; } lang_output_section_statement_type * @@ -1133,7 +1292,8 @@ lang_output_section_statement_lookup (const char *const name) lang_output_section_statement_type * lang_output_section_find_by_flags (const asection *sec, - lang_output_section_statement_type **exact) + lang_output_section_statement_type **exact, + lang_match_sec_type_func match_type) { lang_output_section_statement_type *first, *look, *found; flagword flags; @@ -1151,9 +1311,8 @@ lang_output_section_find_by_flags (const asection *sec, if (look->bfd_section != NULL) { flags = look->bfd_section->flags; - if (!bfd_match_sections_by_type (output_bfd, - look->bfd_section, - sec->owner, sec)) + if (match_type && !match_type (output_bfd, look->bfd_section, + sec->owner, sec)) continue; } flags ^= sec->flags; @@ -1163,7 +1322,8 @@ lang_output_section_find_by_flags (const asection *sec, } if (found != NULL) { - *exact = found; + if (exact != NULL) + *exact = found; return found; } @@ -1176,9 +1336,8 @@ lang_output_section_find_by_flags (const asection *sec, if (look->bfd_section != NULL) { flags = look->bfd_section->flags; - if (!bfd_match_sections_by_type (output_bfd, - look->bfd_section, - sec->owner, sec)) + if (match_type && !match_type (output_bfd, look->bfd_section, + sec->owner, sec)) continue; } flags ^= sec->flags; @@ -1186,10 +1345,8 @@ lang_output_section_find_by_flags (const asection *sec, | SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL))) found = look; } - return found; } - - if (sec->flags & (SEC_READONLY | SEC_THREAD_LOCAL)) + else if (sec->flags & (SEC_READONLY | SEC_THREAD_LOCAL)) { /* .rodata can go after .text, .sdata2 after .rodata. */ for (look = first; look; look = look->next) @@ -1198,9 +1355,8 @@ lang_output_section_find_by_flags (const asection *sec, if (look->bfd_section != NULL) { flags = look->bfd_section->flags; - if (!bfd_match_sections_by_type (output_bfd, - look->bfd_section, - sec->owner, sec)) + if (match_type && !match_type (output_bfd, look->bfd_section, + sec->owner, sec)) continue; } flags ^= sec->flags; @@ -1209,10 +1365,8 @@ lang_output_section_find_by_flags (const asection *sec, && !(look->flags & (SEC_SMALL_DATA | SEC_THREAD_LOCAL))) found = look; } - return found; } - - if (sec->flags & SEC_SMALL_DATA) + else if (sec->flags & SEC_SMALL_DATA) { /* .sdata goes after .data, .sbss after .sdata. */ for (look = first; look; look = look->next) @@ -1221,9 +1375,8 @@ lang_output_section_find_by_flags (const asection *sec, if (look->bfd_section != NULL) { flags = look->bfd_section->flags; - if (!bfd_match_sections_by_type (output_bfd, - look->bfd_section, - sec->owner, sec)) + if (match_type && !match_type (output_bfd, look->bfd_section, + sec->owner, sec)) continue; } flags ^= sec->flags; @@ -1233,10 +1386,8 @@ lang_output_section_find_by_flags (const asection *sec, && !(sec->flags & SEC_HAS_CONTENTS))) found = look; } - return found; } - - if (sec->flags & SEC_HAS_CONTENTS) + else if (sec->flags & SEC_HAS_CONTENTS) { /* .data goes after .rodata. */ for (look = first; look; look = look->next) @@ -1245,9 +1396,8 @@ lang_output_section_find_by_flags (const asection *sec, if (look->bfd_section != NULL) { flags = look->bfd_section->flags; - if (!bfd_match_sections_by_type (output_bfd, - look->bfd_section, - sec->owner, sec)) + if (match_type && !match_type (output_bfd, look->bfd_section, + sec->owner, sec)) continue; } flags ^= sec->flags; @@ -1255,27 +1405,30 @@ lang_output_section_find_by_flags (const asection *sec, | SEC_SMALL_DATA | SEC_THREAD_LOCAL))) found = look; } - return found; } - - /* .bss goes last. */ - for (look = first; look; look = look->next) + else { - flags = look->flags; - if (look->bfd_section != NULL) + /* .bss goes last. */ + for (look = first; look; look = look->next) { - flags = look->bfd_section->flags; - if (!bfd_match_sections_by_type (output_bfd, - look->bfd_section, - sec->owner, sec)) - continue; + flags = look->flags; + if (look->bfd_section != NULL) + { + flags = look->bfd_section->flags; + if (match_type && !match_type (output_bfd, look->bfd_section, + sec->owner, sec)) + continue; + } + flags ^= sec->flags; + if (!(flags & SEC_ALLOC)) + found = look; } - flags ^= sec->flags; - if (!(flags & SEC_ALLOC)) - found = look; } - return found; + if (found || !match_type) + return found; + + return lang_output_section_find_by_flags (sec, NULL, NULL); } /* Find the last output section before given output statement. @@ -1284,28 +1437,22 @@ lang_output_section_find_by_flags (const asection *sec, static asection * output_prev_sec_find (lang_output_section_statement_type *os) { - asection *s = (asection *) NULL; lang_output_section_statement_type *lookup; - for (lookup = &lang_output_section_statement.head->output_section_statement; - lookup != NULL; - lookup = lookup->next) + for (lookup = os->prev; lookup != NULL; lookup = lookup->prev) { if (lookup->constraint == -1) continue; - if (lookup == os) - return s; if (lookup->bfd_section != NULL && lookup->bfd_section->owner != NULL) - s = lookup->bfd_section; + return lookup->bfd_section; } return NULL; } lang_output_section_statement_type * -lang_insert_orphan (lang_input_statement_type *file, - asection *s, +lang_insert_orphan (asection *s, const char *secname, lang_output_section_statement_type *after, struct orphan_save *place, @@ -1315,7 +1462,6 @@ lang_insert_orphan (lang_input_statement_type *file, lang_statement_list_type *old; lang_statement_list_type add; const char *ps; - etree_type *load_base; lang_output_section_statement_type *os; lang_output_section_statement_type **os_tail; @@ -1351,32 +1497,23 @@ lang_insert_orphan (lang_input_statement_type *file, e_align = exp_unop (ALIGN_K, exp_intop ((bfd_vma) 1 << s->alignment_power)); lang_add_assignment (exp_assop ('=', ".", e_align)); - lang_add_assignment (exp_assop ('=', symname, - exp_nameop (NAME, "."))); + lang_add_assignment (exp_provide (symname, + exp_nameop (NAME, "."), + FALSE)); } } if (link_info.relocatable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0) address = exp_intop (0); - load_base = NULL; - if (after != NULL && after->load_base != NULL) - { - etree_type *lma_from_vma; - lma_from_vma = exp_binop ('-', after->load_base, - exp_nameop (ADDR, after->name)); - load_base = exp_binop ('+', lma_from_vma, - exp_nameop (ADDR, secname)); - } - os_tail = ((lang_output_section_statement_type **) lang_output_section_statement.tail); os = lang_enter_output_section_statement (secname, address, 0, NULL, NULL, - load_base, 0); + NULL, 0); if (add_child == NULL) add_child = &os->children; - lang_add_section (add_child, s, os, file); + lang_add_section (add_child, s, os); lang_leave_output_section_statement (0, "*default*", NULL, NULL); @@ -1392,8 +1529,9 @@ lang_insert_orphan (lang_input_statement_type *file, symname = (char *) xmalloc (ps - secname + sizeof "__stop_" + 1); symname[0] = bfd_get_symbol_leading_char (output_bfd); sprintf (symname + (symname[0] != 0), "__stop_%s", secname); - lang_add_assignment (exp_assop ('=', symname, - exp_nameop (NAME, "."))); + lang_add_assignment (exp_provide (symname, + exp_nameop (NAME, "."), + FALSE)); } /* Restore the global list pointer. */ @@ -1429,7 +1567,18 @@ lang_insert_orphan (lang_input_statement_type *file, place->section = &output_bfd->sections; as = *place->section; - if (as != snew && as->prev != snew) + + if (!as) + { + /* Put the section at the end of the list. */ + + /* Unlink the section. */ + bfd_section_list_remove (output_bfd, snew); + + /* Now tack it back on in the right place. */ + bfd_section_list_append (output_bfd, snew); + } + else if (as != snew && as->prev != snew) { /* Unlink the section. */ bfd_section_list_remove (output_bfd, snew); @@ -1459,13 +1608,20 @@ lang_insert_orphan (lang_input_statement_type *file, { lang_statement_union_type **where; lang_statement_union_type **assign = NULL; + bfd_boolean ignore_first; /* Look for a suitable place for the new statement list. The idea is to skip over anything that might be inside a SECTIONS {} statement in a script, before we find another output_section_statement. Assignments to "dot" before an output section statement are assumed to - belong to it. */ + belong to it. An exception to this rule is made for + the first assignment to dot, otherwise we might put an + orphan before . = . + SIZEOF_HEADERS or similar + assignments that set the initial address. */ + + ignore_first = after == (&lang_output_section_statement.head + ->output_section_statement); for (where = &after->header.next; *where != NULL; where = &(*where)->header.next) @@ -1479,9 +1635,11 @@ lang_insert_orphan (lang_input_statement_type *file, ass = &(*where)->assignment_statement; if (ass->exp->type.node_class != etree_assert && ass->exp->assign.dst[0] == '.' - && ass->exp->assign.dst[1] == 0) + && ass->exp->assign.dst[1] == 0 + && !ignore_first) assign = where; } + ignore_first = FALSE; continue; case lang_wild_statement_enum: case lang_input_section_enum: @@ -1530,7 +1688,12 @@ lang_insert_orphan (lang_input_statement_type *file, /* Do the same for the list of output section statements. */ newly_added_os = *os_tail; *os_tail = NULL; + newly_added_os->prev = (lang_output_section_statement_type *) + ((char *) place->os_tail + - offsetof (lang_output_section_statement_type, next)); newly_added_os->next = *place->os_tail; + if (newly_added_os->next != NULL) + newly_added_os->next->prev = newly_added_os; *place->os_tail = newly_added_os; place->os_tail = &newly_added_os->next; @@ -1570,8 +1733,32 @@ void lang_map (void) { lang_memory_region_type *m; + bfd_boolean dis_header_printed = FALSE; bfd *p; + LANG_FOR_EACH_INPUT_STATEMENT (file) + { + asection *s; + + if ((file->the_bfd->flags & (BFD_LINKER_CREATED | DYNAMIC)) != 0 + || file->just_syms_flag) + continue; + + for (s = file->the_bfd->sections; s != NULL; s = s->next) + if ((s->output_section == NULL + || s->output_section->owner != output_bfd) + && (s->flags & (SEC_LINKER_CREATED | SEC_KEEP)) == 0) + { + if (! dis_header_printed) + { + fprintf (config.map_file, _("\nDiscarded input sections\n\n")); + dis_header_printed = TRUE; + } + + print_input_section (s); + } + } + minfo (_("\nMemory Configuration\n\n")); fprintf (config.map_file, "%-16s %-18s %-18s %s\n", _("Name"), _("Origin"), _("Length"), _("Attributes")); @@ -1616,7 +1803,7 @@ lang_map (void) fprintf (config.map_file, _("\nLinker script and memory map\n\n")); - if (! command_line.reduce_memory_overheads) + if (! link_info.reduce_memory_overheads) { obstack_begin (&map_obstack, 1000); for (p = link_info.input_bfds; p != (bfd *) NULL; p = p->link_next) @@ -1674,7 +1861,8 @@ sort_def_symbol (hash_entry, info) /* Initialize an output section. */ static void -init_os (lang_output_section_statement_type *s) +init_os (lang_output_section_statement_type *s, asection *isec, + flagword flags) { if (s->bfd_section != NULL) return; @@ -1684,18 +1872,17 @@ init_os (lang_output_section_statement_type *s) s->bfd_section = bfd_get_section_by_name (output_bfd, s->name); if (s->bfd_section == NULL) - s->bfd_section = bfd_make_section (output_bfd, s->name); + s->bfd_section = bfd_make_section_with_flags (output_bfd, s->name, + flags); if (s->bfd_section == NULL) { einfo (_("%P%F: output format %s cannot represent section called %s\n"), output_bfd->xvec->name, s->name); } s->bfd_section->output_section = s->bfd_section; - - /* We initialize an output sections output offset to minus its own - vma to allow us to output a section through itself. */ s->bfd_section->output_offset = 0; - if (!command_line.reduce_memory_overheads) + + if (!link_info.reduce_memory_overheads) { fat_section_userdata_type *new = stat_alloc (sizeof (fat_section_userdata_type)); @@ -1703,7 +1890,6 @@ init_os (lang_output_section_statement_type *s) get_userdata (s->bfd_section) = new; } - /* If there is a base address, make sure that any sections it might mention are initialized. */ if (s->addr_tree != NULL) @@ -1711,6 +1897,15 @@ init_os (lang_output_section_statement_type *s) if (s->load_base != NULL) exp_init_os (s->load_base); + + /* If supplied an alignment, set it. */ + if (s->section_alignment != -1) + s->bfd_section->alignment_power = s->section_alignment; + + if (isec) + bfd_init_private_section_data (isec->owner, isec, + output_bfd, s->bfd_section, + &link_info); } /* Make sure that all output sections mentioned in an expression are @@ -1756,7 +1951,7 @@ exp_init_os (etree_type *exp) os = lang_output_section_find (exp->name.name); if (os != NULL && os->bfd_section == NULL) - init_os (os); + init_os (os, NULL, 0); } } break; @@ -1780,7 +1975,7 @@ section_already_linked (bfd *abfd, asection *sec, void *data) } if (!(abfd->flags & DYNAMIC)) - bfd_section_already_linked (abfd, sec); + bfd_section_already_linked (abfd, sec, &link_info); } /* The wild routines. @@ -1796,8 +1991,7 @@ section_already_linked (bfd *abfd, asection *sec, void *data) void lang_add_section (lang_statement_list_type *ptr, asection *section, - lang_output_section_statement_type *output, - lang_input_statement_type *file) + lang_output_section_statement_type *output) { flagword flags = section->flags; bfd_boolean discard; @@ -1832,8 +2026,33 @@ lang_add_section (lang_statement_list_type *ptr, lang_input_section_type *new; flagword flags; + flags = section->flags; + + /* We don't copy the SEC_NEVER_LOAD flag from an input section + to an output section, because we want to be able to include a + SEC_NEVER_LOAD section in the middle of an otherwise loaded + section (I don't know why we want to do this, but we do). + build_link_order in ldwrite.c handles this case by turning + the embedded SEC_NEVER_LOAD section into a fill. */ + + flags &= ~ SEC_NEVER_LOAD; + + switch (output->sectype) + { + case normal_section: + case overlay_section: + break; + case noalloc_section: + flags &= ~SEC_ALLOC; + break; + case noload_section: + flags &= ~SEC_LOAD; + flags |= SEC_NEVER_LOAD; + break; + } + if (output->bfd_section == NULL) - init_os (output); + init_os (output, section, flags); first = ! output->bfd_section->linker_has_input; output->bfd_section->linker_has_input = 1; @@ -1855,20 +2074,8 @@ lang_add_section (lang_statement_list_type *ptr, new = new_stat (lang_input_section, ptr); new->section = section; - new->ifile = file; section->output_section = output->bfd_section; - flags = section->flags; - - /* We don't copy the SEC_NEVER_LOAD flag from an input section - to an output section, because we want to be able to include a - SEC_NEVER_LOAD section in the middle of an otherwise loaded - section (I don't know why we want to do this, but we do). - build_link_order in ldwrite.c handles this case by turning - the embedded SEC_NEVER_LOAD section into a fill. */ - - flags &= ~ SEC_NEVER_LOAD; - /* If final link, don't copy the SEC_LINK_ONCE flags, they've already been processed. One reason to do this is that on pe format targets, .text$foo sections go into .text and it's odd @@ -1905,22 +2112,6 @@ lang_add_section (lang_statement_list_type *ptr, if ((section->flags & SEC_READONLY) == 0) output->bfd_section->flags &= ~SEC_READONLY; - switch (output->sectype) - { - case normal_section: - break; - case dsect_section: - case copy_section: - case info_section: - case overlay_section: - output->bfd_section->flags &= ~SEC_ALLOC; - break; - case noload_section: - output->bfd_section->flags &= ~SEC_LOAD; - output->bfd_section->flags |= SEC_NEVER_LOAD; - break; - } - /* Copy over SEC_SMALL_DATA. */ if (section->flags & SEC_SMALL_DATA) output->bfd_section->flags |= SEC_SMALL_DATA; @@ -1928,10 +2119,6 @@ lang_add_section (lang_statement_list_type *ptr, if (section->alignment_power > output->bfd_section->alignment_power) output->bfd_section->alignment_power = section->alignment_power; - /* If supplied an alignment, then force it. */ - if (output->section_alignment != -1) - output->bfd_section->alignment_power = output->section_alignment; - if (bfd_get_arch (section->owner) == bfd_arch_tic54x && (section->flags & SEC_TIC54X_BLOCK) != 0) { @@ -1942,46 +2129,6 @@ lang_add_section (lang_statement_list_type *ptr, } } -/* Compare sections ASEC and BSEC according to SORT. */ - -static int -compare_section (sort_type sort, asection *asec, asection *bsec) -{ - int ret; - - switch (sort) - { - default: - abort (); - - case by_alignment_name: - ret = (bfd_section_alignment (bsec->owner, bsec) - - bfd_section_alignment (asec->owner, asec)); - if (ret) - break; - /* Fall through. */ - - case by_name: - ret = strcmp (bfd_get_section_name (asec->owner, asec), - bfd_get_section_name (bsec->owner, bsec)); - break; - - case by_name_alignment: - ret = strcmp (bfd_get_section_name (asec->owner, asec), - bfd_get_section_name (bsec->owner, bsec)); - if (ret) - break; - /* Fall through. */ - - case by_alignment: - ret = (bfd_section_alignment (bsec->owner, bsec) - - bfd_section_alignment (asec->owner, asec)); - break; - } - - return ret; -} - /* Handle wildcard sorting. This returns the lang_input_section which should follow the one we are going to create for SECTION and FILE, based on the sorting requirements of WILD. It returns NULL if the @@ -2035,15 +2182,14 @@ wild_sort (lang_wild_statement_type *wild, fa = FALSE; } - if (ls->ifile->the_bfd != NULL - && bfd_my_archive (ls->ifile->the_bfd) != NULL) + if (bfd_my_archive (ls->section->owner) != NULL) { - ln = bfd_get_filename (bfd_my_archive (ls->ifile->the_bfd)); + ln = bfd_get_filename (bfd_my_archive (ls->section->owner)); la = TRUE; } else { - ln = ls->ifile->filename; + ln = ls->section->owner->filename; la = FALSE; } @@ -2058,7 +2204,7 @@ wild_sort (lang_wild_statement_type *wild, if (fa) fn = file->filename; if (la) - ln = ls->ifile->filename; + ln = ls->section->owner->filename; i = strcmp (fn, ln); if (i > 0) @@ -2104,8 +2250,7 @@ output_section_callback (lang_wild_statement_type *ptr, if (before == NULL) lang_add_section (&ptr->children, section, - (lang_output_section_statement_type *) output, - file); + (lang_output_section_statement_type *) output); else { lang_statement_list_type list; @@ -2113,8 +2258,7 @@ output_section_callback (lang_wild_statement_type *ptr, lang_list_init (&list); lang_add_section (&list, section, - (lang_output_section_statement_type *) output, - file); + (lang_output_section_statement_type *) output); /* If we are discarding the section, LIST.HEAD will be NULL. */ @@ -2167,12 +2311,9 @@ lookup_name (const char *name) /* Use the local_sym_name as the name of the file that has already been loaded as filename might have been transformed via the search directory lookup mechanism. */ - const char * filename = search->local_sym_name; + const char *filename = search->local_sym_name; - if (filename == NULL && name == NULL) - return search; if (filename != NULL - && name != NULL && strcmp (filename, name) == 0) break; } @@ -2182,11 +2323,8 @@ lookup_name (const char *name) default_target, FALSE); /* If we have already added this file, or this file is not real - (FIXME: can that ever actually happen?) or the name is NULL - (FIXME: can that ever actually happen?) don't add this file. */ - if (search->loaded - || ! search->real - || search->filename == NULL) + don't add this file. */ + if (search->loaded || !search->real) return search; if (! load_symbols (search, NULL)) @@ -2222,7 +2360,7 @@ add_excluded_libs (const char *list) entry->name[end - p] = '\0'; excluded_libs = entry; if (*end == '\0') - break; + break; p = end + 1; } } @@ -2258,7 +2396,7 @@ check_excluded_libs (bfd *abfd) /* Get the symbols for an input file. */ -static bfd_boolean +bfd_boolean load_symbols (lang_input_statement_type *entry, lang_statement_list_type *place) { @@ -2276,6 +2414,7 @@ load_symbols (lang_input_statement_type *entry, lang_statement_list_type *hold; bfd_boolean bad_load = TRUE; bfd_boolean save_ldlang_sysrooted_script; + bfd_boolean save_as_needed, save_add_needed; err = bfd_get_error (); @@ -2309,6 +2448,10 @@ load_symbols (lang_input_statement_type *entry, stat_ptr = place; save_ldlang_sysrooted_script = ldlang_sysrooted_script; ldlang_sysrooted_script = entry->sysrooted; + save_as_needed = as_needed; + as_needed = entry->as_needed; + save_add_needed = add_needed; + add_needed = entry->add_needed; ldfile_assumed_script = TRUE; parser_input = input_script; @@ -2319,6 +2462,8 @@ load_symbols (lang_input_statement_type *entry, ldfile_assumed_script = FALSE; ldlang_sysrooted_script = save_ldlang_sysrooted_script; + as_needed = save_as_needed; + add_needed = save_add_needed; stat_ptr = hold; return ! bad_load; @@ -2402,19 +2547,33 @@ wild (lang_wild_statement_type *s, { struct wildcard_list *sec; - walk_wild (s, output_section_callback, output); - - for (sec = s->section_list; sec != NULL; sec = sec->next) + if (s->handler_data[0] + && s->handler_data[0]->spec.sorted == by_name + && !s->filenames_sorted) { - if (default_common_section != NULL) - break; + lang_section_bst_type *tree; + + walk_wild (s, output_section_callback_fast, output); + + tree = s->tree; + if (tree) + { + output_section_callback_tree_to_list (s, tree, output); + s->tree = NULL; + } + } + else + walk_wild (s, output_section_callback, output); + + if (default_common_section == NULL) + for (sec = s->section_list; sec != NULL; sec = sec->next) if (sec->spec.name != NULL && strcmp (sec->spec.name, "COMMON") == 0) { /* Remember the section that common is going to in case we later get something which doesn't know where to put it. */ default_common_section = output; + break; } - } } /* Return TRUE iff target is the sought target. */ @@ -2669,7 +2828,7 @@ open_output (const char *name) link_info.hash = bfd_link_hash_table_create (output); if (link_info.hash == NULL) - einfo (_("%P%F: can not create link hash table: %E\n")); + einfo (_("%P%F: can not create hash table: %E\n")); bfd_set_gp_size (output, g_switch_value); return output; @@ -3003,7 +3162,8 @@ update_wild_statements (lang_statement_union_type *s) case lang_wild_statement_enum: sec = s->wild_statement.section_list; - if (sec != NULL) + for (sec = s->wild_statement.section_list; sec != NULL; + sec = sec->next) { switch (sec->spec.sorted) { @@ -3049,6 +3209,8 @@ map_input_to_output_sections (lang_statement_union_type *s, const char *target, lang_output_section_statement_type *os) { + flagword flags; + for (; s != NULL; s = s->header.next) { switch (s->header.type) @@ -3098,26 +3260,29 @@ map_input_to_output_sections /* Make sure that any sections mentioned in the expression are initialized. */ exp_init_os (s->data_statement.exp); - if (os != NULL && os->bfd_section == NULL) - init_os (os); + flags = SEC_HAS_CONTENTS; /* The output section gets contents, and then we inspect for any flags set in the input script which override any ALLOC. */ - os->bfd_section->flags |= SEC_HAS_CONTENTS; if (!(os->flags & SEC_NEVER_LOAD)) - os->bfd_section->flags |= SEC_ALLOC | SEC_LOAD; + flags |= SEC_ALLOC | SEC_LOAD; + if (os->bfd_section == NULL) + init_os (os, NULL, flags); + else + os->bfd_section->flags |= flags; break; - case lang_fill_statement_enum: case lang_input_section_enum: + break; + case lang_fill_statement_enum: case lang_object_symbols_statement_enum: case lang_reloc_statement_enum: case lang_padding_statement_enum: case lang_input_statement_enum: if (os != NULL && os->bfd_section == NULL) - init_os (os); + init_os (os, NULL, 0); break; case lang_assignment_statement_enum: if (os != NULL && os->bfd_section == NULL) - init_os (os); + init_os (os, NULL, 0); /* Make sure that any sections mentioned in the assignment are initialized. */ @@ -3127,7 +3292,7 @@ map_input_to_output_sections FAIL (); break; case lang_address_statement_enum: - /* Mark the specified section with the supplied address. + /* Mark the specified section with the supplied address. If this section was actually a segment marker, then the directive is ignored if the linker script explicitly @@ -3137,15 +3302,15 @@ map_input_to_output_sections section directive semantics for backwards compatibilty; linker scripts that do not specifically check for SEGMENT_START automatically get the old semantics. */ - if (!s->address_statement.segment + if (!s->address_statement.segment || !s->address_statement.segment->used) { lang_output_section_statement_type *aos = (lang_output_section_statement_lookup (s->address_statement.section_name)); - + if (aos->bfd_section == NULL) - init_os (aos); + init_os (aos, NULL, 0); aos->addr_tree = s->address_statement.address; } break; @@ -3215,7 +3380,8 @@ strip_excluded_output_sections (void) { /* We don't set bfd_section to NULL since bfd_section of the removed output section statement may still be used. */ - os->ignored = TRUE; + if (!os->section_relative_symbol) + os->ignored = TRUE; output_section->flags |= SEC_EXCLUDE; bfd_section_list_remove (output_bfd, output_section); output_bfd->section_count--; @@ -3256,14 +3422,8 @@ print_output_section_statement minfo ("0x%V %W", section->vma, section->size); - if (output_section_statement->load_base != NULL) - { - bfd_vma addr; - - addr = exp_get_abs_int (output_section_statement->load_base, 0, - "load base"); - minfo (_(" load address 0x%V"), addr); - } + if (section->vma != section->lma) + minfo (_(" load address 0x%V"), section->lma); } print_nl (); @@ -3278,7 +3438,7 @@ print_output_section_statement correct expression, since the value of DST that is used on the right hand side will be its final value, not its value just before this expression is evaluated. */ - + static bfd_boolean scan_for_self_assignment (const char * dst, etree_type * rhs) { @@ -3435,8 +3595,7 @@ print_one_symbol (struct bfd_link_hash_entry *hash_entry, void *ptr) } static void -print_all_symbols (sec) - asection *sec; +print_all_symbols (asection *sec) { struct fat_user_section_struct *ud = get_userdata (sec); struct map_symbol_def *def; @@ -3452,68 +3611,64 @@ print_all_symbols (sec) /* Print information about an input section to the map file. */ static void -print_input_section (lang_input_section_type *in) +print_input_section (asection *i) { - asection *i = in->section; bfd_size_type size = i->size; + int len; + bfd_vma addr; init_opb (); - if (size != 0) - { - int len; - bfd_vma addr; - print_space (); - minfo ("%s", i->name); + print_space (); + minfo ("%s", i->name); - len = 1 + strlen (i->name); - if (len >= SECTION_NAME_MAP_LENGTH - 1) - { - print_nl (); - len = 0; - } - while (len < SECTION_NAME_MAP_LENGTH) - { - print_space (); - ++len; - } + len = 1 + strlen (i->name); + if (len >= SECTION_NAME_MAP_LENGTH - 1) + { + print_nl (); + len = 0; + } + while (len < SECTION_NAME_MAP_LENGTH) + { + print_space (); + ++len; + } - if (i->output_section != NULL && (i->flags & SEC_EXCLUDE) == 0) - addr = i->output_section->vma + i->output_offset; - else - { - addr = print_dot; - size = 0; - } + if (i->output_section != NULL && i->output_section->owner == output_bfd) + addr = i->output_section->vma + i->output_offset; + else + { + addr = print_dot; + size = 0; + } - minfo ("0x%V %W %B\n", addr, TO_ADDR (size), i->owner); + minfo ("0x%V %W %B\n", addr, TO_ADDR (size), i->owner); - if (size != i->rawsize && i->rawsize != 0) - { - len = SECTION_NAME_MAP_LENGTH + 3; + if (size != i->rawsize && i->rawsize != 0) + { + len = SECTION_NAME_MAP_LENGTH + 3; #ifdef BFD64 - len += 16; + len += 16; #else - len += 8; + len += 8; #endif - while (len > 0) - { - print_space (); - --len; - } - - minfo (_("%W (size before relaxing)\n"), i->rawsize); + while (len > 0) + { + print_space (); + --len; } - if (i->output_section != NULL && (i->flags & SEC_EXCLUDE) == 0) - { - if (command_line.reduce_memory_overheads) - bfd_link_hash_traverse (link_info.hash, print_one_symbol, i); - else - print_all_symbols (i); + minfo (_("%W (size before relaxing)\n"), i->rawsize); + } - print_dot = addr + TO_ADDR (size); - } + if (i->output_section != NULL && i->output_section->owner == output_bfd) + { + if (link_info.reduce_memory_overheads) + bfd_link_hash_traverse (link_info.hash, print_one_symbol, i); + else + print_all_symbols (i); + + print_dot = addr + TO_ADDR (size); } } @@ -3540,7 +3695,7 @@ print_data_statement (lang_data_statement_type *data) for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++) print_space (); - addr = data->output_vma; + addr = data->output_offset; if (data->output_section != NULL) addr += data->output_section->vma; @@ -3607,7 +3762,7 @@ print_reloc_statement (lang_reloc_statement_type *reloc) for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++) print_space (); - addr = reloc->output_vma; + addr = reloc->output_offset; if (reloc->output_section != NULL) addr += reloc->output_section->vma; @@ -3774,7 +3929,7 @@ print_statement (lang_statement_union_type *s, print_reloc_statement (&s->reloc_statement); break; case lang_input_section_enum: - print_input_section (&s->input_section); + print_input_section (s->input_section.section); break; case lang_padding_statement_enum: print_padding_statement (&s->padding_statement); @@ -3892,7 +4047,8 @@ size_input_section lang_input_section_type *is = &((*this_ptr)->input_section); asection *i = is->section; - if (!is->ifile->just_syms_flag && (i->flags & SEC_EXCLUDE) == 0) + if (!((lang_input_statement_type *) i->owner->usrdata)->just_syms_flag + && (i->flags & SEC_EXCLUDE) == 0) { unsigned int alignment_needed; asection *o; @@ -3988,7 +4144,7 @@ lang_check_section_addresses (void) sections[count] = s; count++; } - + if (count <= 1) return; @@ -4005,7 +4161,7 @@ lang_check_section_addresses (void) addresses because overlay sections can have overlapping VMAs but they must have distinct LMAs. */ os = s; - os_start = s_start; + os_start = s_start; os_end = s_end; s = *spp++; s_start = bfd_section_lma (output_bfd, s); @@ -4078,11 +4234,12 @@ lang_size_sections_1 { bfd_vma newdot, after; lang_output_section_statement_type *os; + lang_memory_region_type *r; os = &s->output_section_statement; if (os->addr_tree != NULL) { - os->processed = FALSE; + os->processed_vma = FALSE; exp_fold_tree (os->addr_tree, bfd_abs_section_ptr, &dot); if (!expld.result.valid_p @@ -4131,6 +4288,8 @@ lang_size_sections_1 } else { + int align; + if (os->addr_tree == NULL) { /* No address specified for this section, get one @@ -4147,7 +4306,8 @@ lang_size_sections_1 /* If a loadable section is using the default memory region, and some non default memory regions were defined, issue an error message. */ - if (!IGNORE_SECTION (os->bfd_section) + if (!os->ignored + && !IGNORE_SECTION (os->bfd_section) && ! link_info.relocatable && check_regions && strcmp (os->region->name, @@ -4180,27 +4340,25 @@ lang_size_sections_1 } newdot = os->region->current; - - if (os->section_alignment == -1) - { - bfd_vma savedot = newdot; - newdot = align_power (newdot, - os->bfd_section->alignment_power); - - if (newdot != savedot - && config.warn_section_align - && expld.phase != lang_mark_phase_enum) - einfo (_("%P: warning: changing start of section" - " %s by %lu bytes\n"), - os->name, (unsigned long) (newdot - savedot)); - } + align = os->bfd_section->alignment_power; } + else + align = os->section_alignment; - /* The section starts here. - First, align to what the section needs. */ + /* Align to what the section needs. */ + if (align > 0) + { + bfd_vma savedot = newdot; + newdot = align_power (newdot, align); - if (os->section_alignment != -1) - newdot = align_power (newdot, os->section_alignment); + if (newdot != savedot + && (config.warn_section_align + || os->addr_tree != NULL) + && expld.phase != lang_mark_phase_enum) + einfo (_("%P: warning: changing start of section" + " %s by %lu bytes\n"), + os->name, (unsigned long) (newdot - savedot)); + } bfd_set_section_vma (0, os->bfd_section, newdot); @@ -4210,24 +4368,117 @@ lang_size_sections_1 lang_size_sections_1 (os->children.head, os, &os->children.head, os->fill, newdot, relax, check_regions); - os->processed = TRUE; + os->processed_vma = TRUE; if (bfd_is_abs_section (os->bfd_section) || os->ignored) + /* Except for some special linker created sections, + no output section should change from zero size + after strip_excluded_output_sections. A non-zero + size on an ignored section indicates that some + input section was not sized early enough. */ + ASSERT (os->bfd_section->size == 0); + else { - ASSERT (os->bfd_section->size == 0); - break; + dot = os->bfd_section->vma; + + /* Put the section within the requested block size, or + align at the block boundary. */ + after = ((dot + + TO_ADDR (os->bfd_section->size) + + os->block_value - 1) + & - (bfd_vma) os->block_value); + + os->bfd_section->size = TO_SIZE (after - os->bfd_section->vma); } - dot = os->bfd_section->vma; + /* Set section lma. */ + r = os->region; + if (r == NULL) + r = lang_memory_region_lookup (DEFAULT_MEMORY_REGION, FALSE); + + if (os->load_base) + { + bfd_vma lma = exp_get_abs_int (os->load_base, 0, "load base"); + os->bfd_section->lma = lma; + } + else if (os->region != NULL + && os->lma_region != NULL + && os->lma_region != os->region) + { + bfd_vma lma = os->lma_region->current; + + if (os->section_alignment != -1) + lma = align_power (lma, os->section_alignment); + os->bfd_section->lma = lma; + } + else if (r->last_os != NULL + && (os->bfd_section->flags & SEC_ALLOC) != 0) + { + bfd_vma lma; + asection *last; + + last = r->last_os->output_section_statement.bfd_section; + + /* A backwards move of dot should be accompanied by + an explicit assignment to the section LMA (ie. + os->load_base set) because backwards moves can + create overlapping LMAs. */ + if (dot < last->vma + && os->bfd_section->size != 0 + && dot + os->bfd_section->size <= last->vma) + { + /* If dot moved backwards then leave lma equal to + vma. This is the old default lma, which might + just happen to work when the backwards move is + sufficiently large. Nag if this changes anything, + so people can fix their linker scripts. */ + + if (last->vma != last->lma) + einfo (_("%P: warning: dot moved backwards before `%s'\n"), + os->name); + } + else + { + /* If this is an overlay, set the current lma to that + at the end of the previous section. */ + if (os->sectype == overlay_section) + lma = last->lma + last->size; + + /* Otherwise, keep the same lma to vma relationship + as the previous section. */ + else + lma = dot + last->lma - last->vma; + + if (os->section_alignment != -1) + lma = align_power (lma, os->section_alignment); + os->bfd_section->lma = lma; + } + } + os->processed_lma = TRUE; - /* Put the section within the requested block size, or - align at the block boundary. */ - after = ((dot - + TO_ADDR (os->bfd_section->size) - + os->block_value - 1) - & - (bfd_vma) os->block_value); + if (bfd_is_abs_section (os->bfd_section) || os->ignored) + break; - os->bfd_section->size = TO_SIZE (after - os->bfd_section->vma); + /* Keep track of normal sections using the default + lma region. We use this to set the lma for + following sections. Overlays or other linker + script assignment to lma might mean that the + default lma == vma is incorrect. + To avoid warnings about dot moving backwards when using + -Ttext, don't start tracking sections until we find one + of non-zero size or with lma set differently to vma. */ + if (((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0 + || (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0) + && (os->bfd_section->flags & SEC_ALLOC) != 0 + && (os->bfd_section->size != 0 + || (r->last_os == NULL + && os->bfd_section->vma != os->bfd_section->lma) + || (r->last_os != NULL + && dot >= (r->last_os->output_section_statement + .bfd_section->vma))) + && os->lma_region == NULL + && !link_info.relocatable) + r->last_os = s; /* .tbss sections effectively have zero size. */ if ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0 @@ -4257,17 +4508,11 @@ lang_size_sections_1 os_region_check (os, os->region, os->addr_tree, os->bfd_section->vma); - /* If there's no load address specified, use the run - region as the load region. */ - if (os->lma_region == NULL && os->load_base == NULL) - os->lma_region = os->region; - if (os->lma_region != NULL && os->lma_region != os->region) { - /* Set load_base, which will be handled later. */ - os->load_base = exp_intop (os->lma_region->current); - os->lma_region->current += - TO_ADDR (os->bfd_section->size); + os->lma_region->current + = os->bfd_section->lma + TO_ADDR (os->bfd_section->size); + if (check_regions) os_region_check (os, os->lma_region, NULL, os->bfd_section->lma); @@ -4287,7 +4532,7 @@ lang_size_sections_1 { unsigned int size = 0; - s->data_statement.output_vma = + s->data_statement.output_offset = dot - output_section_statement->bfd_section->vma; s->data_statement.output_section = output_section_statement->bfd_section; @@ -4325,7 +4570,7 @@ lang_size_sections_1 { int size; - s->reloc_statement.output_vma = + s->reloc_statement.output_offset = dot - output_section_statement->bfd_section->vma; s->reloc_statement.output_section = output_section_statement->bfd_section; @@ -4383,12 +4628,20 @@ lang_size_sections_1 case lang_assignment_statement_enum: { bfd_vma newdot = dot; + etree_type *tree = s->assignment_statement.exp; - exp_fold_tree (s->assignment_statement.exp, + exp_fold_tree (tree, output_section_statement->bfd_section, &newdot); - if (newdot != dot && !output_section_statement->ignored) + /* This symbol is relative to this section. */ + if ((tree->type.node_class == etree_provided + || tree->type.node_class == etree_assign) + && (tree->assign.dst [0] != '.' + || tree->assign.dst [1] != '\0')) + output_section_statement->section_relative_symbol = 1; + + if (!output_section_statement->ignored) { if (output_section_statement == abs_output_section) { @@ -4397,7 +4650,7 @@ lang_size_sections_1 lang_memory_region_lookup (DEFAULT_MEMORY_REGION, FALSE)->current = newdot; } - else + else if (newdot != dot) { /* Insert a pad after this statement. We can't put the pad before when relaxing, in case the @@ -4458,6 +4711,48 @@ lang_size_sections_1 return dot; } +/* Callback routine that is used in _bfd_elf_map_sections_to_segments. + The BFD library has set NEW_SEGMENT to TRUE iff it thinks that + CURRENT_SECTION and PREVIOUS_SECTION ought to be placed into different + segments. We are allowed an opportunity to override this decision. */ + +bfd_boolean +ldlang_override_segment_assignment (struct bfd_link_info * info ATTRIBUTE_UNUSED, + bfd * abfd ATTRIBUTE_UNUSED, + asection * current_section, + asection * previous_section, + bfd_boolean new_segment) +{ + lang_output_section_statement_type * cur; + lang_output_section_statement_type * prev; + + /* The checks below are only necessary when the BFD library has decided + that the two sections ought to be placed into the same segment. */ + if (new_segment) + return TRUE; + + /* Paranoia checks. */ + if (current_section == NULL || previous_section == NULL) + return new_segment; + + /* Find the memory regions associated with the two sections. + We call lang_output_section_find() here rather than scanning the list + of output sections looking for a matching section pointer because if + we have a large number of sections then a hash lookup is faster. */ + cur = lang_output_section_find (current_section->name); + prev = lang_output_section_find (previous_section->name); + + /* More paranoia. */ + if (cur == NULL || prev == NULL) + return new_segment; + + /* If the regions are different then force the sections to live in + different segments. See the email thread starting at the following + URL for the reasons why this is necessary: + http://sourceware.org/ml/binutils/2007-02/msg00216.html */ + return cur->region != prev->region; +} + void one_lang_size_sections_pass (bfd_boolean *relax, bfd_boolean check_regions) { @@ -4493,6 +4788,7 @@ lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions) expld.dataseg.base -= maxpage; relro_end -= maxpage; } + lang_reset_memory_regions (); one_lang_size_sections_pass (relax, check_regions); if (expld.dataseg.relro_end > relro_end) { @@ -4516,6 +4812,7 @@ lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions) < old_min_base) expld.dataseg.base += expld.dataseg.pagesize; expld.dataseg.base -= (1 << max_alignment_power); + lang_reset_memory_regions (); one_lang_size_sections_pass (relax, check_regions); } } @@ -4536,6 +4833,7 @@ lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions) && first + last <= expld.dataseg.pagesize) { expld.dataseg.phase = exp_dataseg_adjust; + lang_reset_memory_regions (); one_lang_size_sections_pass (relax, check_regions); } } @@ -4546,11 +4844,10 @@ lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions) /* Worker function for lang_do_assignments. Recursiveness goes here. */ static bfd_vma -lang_do_assignments_1 - (lang_statement_union_type *s, - lang_output_section_statement_type *output_section_statement, - fill_type *fill, - bfd_vma dot) +lang_do_assignments_1 (lang_statement_union_type *s, + lang_output_section_statement_type *current_os, + fill_type *fill, + bfd_vma dot) { for (; s != NULL; s = s->header.next) { @@ -4558,9 +4855,7 @@ lang_do_assignments_1 { case lang_constructors_statement_enum: dot = lang_do_assignments_1 (constructor_list.head, - output_section_statement, - fill, - dot); + current_os, fill, dot); break; case lang_output_section_statement_enum: @@ -4571,31 +4866,22 @@ lang_do_assignments_1 if (os->bfd_section != NULL && !os->ignored) { dot = os->bfd_section->vma; + lang_do_assignments_1 (os->children.head, os, os->fill, dot); + /* .tbss sections effectively have zero size. */ if ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0 || (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0 || link_info.relocatable) dot += TO_ADDR (os->bfd_section->size); } - if (os->load_base) - { - /* If nothing has been placed into the output section then - it won't have a bfd_section. */ - if (os->bfd_section && !os->ignored) - { - os->bfd_section->lma - = exp_get_abs_int (os->load_base, 0, "load base"); - } - } } break; case lang_wild_statement_enum: dot = lang_do_assignments_1 (s->wild_statement.children.head, - output_section_statement, - fill, dot); + current_os, fill, dot); break; case lang_object_symbols_statement_enum: @@ -4664,7 +4950,7 @@ lang_do_assignments_1 case lang_assignment_statement_enum: exp_fold_tree (s->assignment_statement.exp, - output_section_statement->bfd_section, + current_os->bfd_section, &dot); break; @@ -4674,8 +4960,7 @@ lang_do_assignments_1 case lang_group_statement_enum: dot = lang_do_assignments_1 (s->group_statement.children.head, - output_section_statement, - fill, dot); + current_os, fill, dot); break; default: @@ -4871,7 +5156,7 @@ lang_check (void) if (compatible == NULL) { if (command_line.warn_mismatch) - einfo (_("%P: warning: %s architecture of input file `%B'" + einfo (_("%P%X: %s architecture of input file `%B'" " is incompatible with %s output\n"), bfd_printable_name (input_bfd), input_bfd, bfd_printable_name (output_bfd)); @@ -4982,10 +5267,19 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info) header_printed = TRUE; } - name = demangle (h->root.string); - minfo ("%s", name); - len = strlen (name); - free (name); + name = bfd_demangle (output_bfd, h->root.string, + DMGL_ANSI | DMGL_PARAMS); + if (name == NULL) + { + minfo ("%s", h->root.string); + len = strlen (h->root.string); + } + else + { + minfo ("%s", name); + len = strlen (name); + free (name); + } if (len >= 19) { @@ -5055,17 +5349,17 @@ lang_place_orphans (void) } lang_add_section (&default_common_section->children, s, - default_common_section, file); + default_common_section); } } - else if (ldemul_place_orphan (file, s)) + else if (ldemul_place_orphan (s)) ; else { lang_output_section_statement_type *os; os = lang_output_section_statement_lookup (s->name); - lang_add_section (&os->children, s, os, file); + lang_add_section (&os->children, s, os); } } } @@ -5141,8 +5435,6 @@ lang_for_each_file (void (*func) (lang_input_statement_type *)) void ldlang_add_file (lang_input_statement_type *entry) { - bfd **pp; - lang_statement_append (&file_chain, (lang_statement_union_type *) entry, &entry->next); @@ -5151,9 +5443,9 @@ ldlang_add_file (lang_input_statement_type *entry) a link. */ ASSERT (entry->the_bfd->link_next == NULL); ASSERT (entry->the_bfd != output_bfd); - for (pp = &link_info.input_bfds; *pp != NULL; pp = &(*pp)->link_next) - ; - *pp = entry->the_bfd; + + *link_info.input_bfds_tail = entry->the_bfd; + link_info.input_bfds_tail = &entry->the_bfd->link_next; entry->the_bfd->usrdata = entry; bfd_set_gp_size (entry->the_bfd, g_switch_value); @@ -5213,10 +5505,9 @@ lang_enter_output_section_statement (const char *output_section_statement_name, { lang_output_section_statement_type *os; - current_section = - os = - lang_output_section_statement_lookup_1 (output_section_statement_name, - constraint); + os = lang_output_section_statement_lookup_1 (output_section_statement_name, + constraint); + current_section = os; /* Make next things chain into subchain of this. */ @@ -5244,9 +5535,9 @@ lang_enter_output_section_statement (const char *output_section_statement_name, void lang_final (void) { - lang_output_statement_type *new = - new_stat (lang_output_statement, stat_ptr); + lang_output_statement_type *new; + new = new_stat (lang_output_statement, stat_ptr); new->name = output_filename; } @@ -5261,14 +5552,17 @@ lang_reset_memory_regions (void) for (p = lang_memory_region_list; p != NULL; p = p->next) { - p->old_length = (bfd_size_type) (p->current - p->origin); p->current = p->origin; + p->last_os = NULL; } for (os = &lang_output_section_statement.head->output_section_statement; os != NULL; os = os->next) - os->processed = FALSE; + { + os->processed_vma = FALSE; + os->processed_lma = FALSE; + } for (o = output_bfd->sections; o != NULL; o = o->next) { @@ -5365,9 +5659,46 @@ lang_gc_sections (void) bfd_gc_sections (output_bfd, &link_info); } +/* Relax all sections until bfd_relax_section gives up. */ + +static void +relax_sections (void) +{ + /* Keep relaxing until bfd_relax_section gives up. */ + bfd_boolean relax_again; + + link_info.relax_trip = -1; + do + { + relax_again = FALSE; + link_info.relax_trip++; + + /* Note: pe-dll.c does something like this also. If you find + you need to change this code, you probably need to change + pe-dll.c also. DJ */ + + /* Do all the assignments with our current guesses as to + section sizes. */ + lang_do_assignments (); + + /* We must do this after lang_do_assignments, because it uses + size. */ + lang_reset_memory_regions (); + + /* Perform another relax pass - this time we know where the + globals are, so can make a better guess. */ + lang_size_sections (&relax_again, FALSE); + } + while (relax_again); +} + void lang_process (void) { + /* Finalize dynamic list. */ + if (link_info.dynamic_list) + lang_finalize_version_expr_head (&link_info.dynamic_list->head); + current_target = default_target; /* Open the output file. */ @@ -5461,38 +5792,17 @@ lang_process (void) /* Now run around and relax if we can. */ if (command_line.relax) { - /* Keep relaxing until bfd_relax_section gives up. */ - bfd_boolean relax_again; - - do - { - relax_again = FALSE; - - /* Note: pe-dll.c does something like this also. If you find - you need to change this code, you probably need to change - pe-dll.c also. DJ */ + /* We may need more than one relaxation pass. */ + int i = link_info.relax_pass; - /* Do all the assignments with our current guesses as to - section sizes. */ - lang_do_assignments (); + /* The backend can use it to determine the current pass. */ + link_info.relax_pass = 0; - /* We must do this after lang_do_assignments, because it uses - size. */ - lang_reset_memory_regions (); - - /* Perform another relax pass - this time we know where the - globals are, so can make a better guess. */ - lang_size_sections (&relax_again, FALSE); - - /* If the normal relax is done and the relax finalize pass - is not performed yet, we perform another relax pass. */ - if (!relax_again && link_info.need_relax_finalize) - { - link_info.need_relax_finalize = FALSE; - relax_again = TRUE; - } + while (i--) + { + relax_sections (); + link_info.relax_pass++; } - while (relax_again); /* Final extra sizing to report errors. */ lang_do_assignments (); @@ -5512,13 +5822,13 @@ lang_process (void) lang_do_assignments (); + ldemul_finish (); + /* Make sure that the section addresses make sense. */ if (! link_info.relocatable && command_line.check_section_addresses) lang_check_section_addresses (); - /* Final stuffs. */ - ldemul_finish (); lang_end (); } @@ -5608,11 +5918,10 @@ lang_default_entry (const char *name) void lang_add_target (const char *name) { - lang_target_statement_type *new = new_stat (lang_target_statement, - stat_ptr); + lang_target_statement_type *new; + new = new_stat (lang_target_statement, stat_ptr); new->target = name; - } void @@ -5633,22 +5942,20 @@ lang_add_map (const char *name) void lang_add_fill (fill_type *fill) { - lang_fill_statement_type *new = new_stat (lang_fill_statement, - stat_ptr); + lang_fill_statement_type *new; + new = new_stat (lang_fill_statement, stat_ptr); new->fill = fill; } void lang_add_data (int type, union etree_union *exp) { + lang_data_statement_type *new; - lang_data_statement_type *new = new_stat (lang_data_statement, - stat_ptr); - + new = new_stat (lang_data_statement, stat_ptr); new->exp = exp; new->type = type; - } /* Create a new reloc statement. RELOC is the BFD relocation type to @@ -5675,15 +5982,15 @@ lang_add_reloc (bfd_reloc_code_real_type reloc, p->addend_value = 0; p->output_section = NULL; - p->output_vma = 0; + p->output_offset = 0; } lang_assignment_statement_type * lang_add_assignment (etree_type *exp) { - lang_assignment_statement_type *new = new_stat (lang_assignment_statement, - stat_ptr); + lang_assignment_statement_type *new; + new = new_stat (lang_assignment_statement, stat_ptr); new->exp = exp; return new; } @@ -5691,7 +5998,7 @@ lang_add_assignment (etree_type *exp) void lang_add_attribute (enum statement_enum attribute) { - new_statement (attribute, sizeof (lang_statement_union_type), stat_ptr); + new_statement (attribute, sizeof (lang_statement_header_type), stat_ptr); } void @@ -5924,6 +6231,7 @@ lang_record_phdrs (void) alc = 10; secs = xmalloc (alc * sizeof (asection *)); last = NULL; + for (l = lang_phdr_list; l != NULL; l = l->next) { unsigned int c; @@ -5949,7 +6257,26 @@ lang_record_phdrs (void) || os->bfd_section == NULL || (os->bfd_section->flags & SEC_ALLOC) == 0) continue; - pl = last; + + if (last) + pl = last; + else + { + lang_output_section_statement_type * tmp_os; + + /* If we have not run across a section with a program + header assigned to it yet, then scan forwards to find + one. This prevents inconsistencies in the linker's + behaviour when a script has specified just a single + header and there are sections in that script which are + not assigned to it, and which occur before the first + use of that header. See here for more details: + http://sourceware.org/ml/binutils/2007-02/msg00291.html */ + for (tmp_os = os; tmp_os; tmp_os = tmp_os->next) + if (tmp_os->phdrs) + break; + pl = tmp_os->phdrs; + } } if (os->bfd_section == NULL) @@ -6068,7 +6395,7 @@ lang_enter_overlay_section (const char *name) struct overlay_list *n; etree_type *size; - lang_enter_output_section_statement (name, overlay_vma, normal_section, + lang_enter_output_section_statement (name, overlay_vma, overlay_section, 0, overlay_subalign, 0, 0); /* If this is the first section, then base the VMA of future @@ -6123,15 +6450,17 @@ lang_leave_overlay_section (fill_type *fill, buf = xmalloc (strlen (clean) + sizeof "__load_start_"); sprintf (buf, "__load_start_%s", clean); - lang_add_assignment (exp_assop ('=', buf, - exp_nameop (LOADADDR, name))); + lang_add_assignment (exp_provide (buf, + exp_nameop (LOADADDR, name), + FALSE)); buf = xmalloc (strlen (clean) + sizeof "__load_stop_"); sprintf (buf, "__load_stop_%s", clean); - lang_add_assignment (exp_assop ('=', buf, - exp_binop ('+', - exp_nameop (LOADADDR, name), - exp_nameop (SIZEOF, name)))); + lang_add_assignment (exp_provide (buf, + exp_binop ('+', + exp_nameop (LOADADDR, name), + exp_nameop (SIZEOF, name)), + FALSE)); free (clean); } @@ -6180,12 +6509,10 @@ lang_leave_overlay (etree_type *lma_expr, The base address is not needed (and should be null) if an LMA region was specified. */ if (l->next == 0) - l->os->load_base = lma_expr; - else if (lma_region == 0) - l->os->load_base = exp_binop ('+', - exp_nameop (LOADADDR, l->next->os->name), - exp_nameop (SIZEOF, l->next->os->name)); - + { + l->os->load_base = lma_expr; + l->os->sectype = normal_section; + } if (phdrs != NULL && l->os->phdrs == NULL) l->os->phdrs = phdrs; @@ -6676,7 +7003,7 @@ lang_do_version_exports_section (void) /* Do not free the contents, as we used them creating the regex. */ /* Do not include this section in the link. */ - sec->flags |= SEC_EXCLUDE; + sec->flags |= SEC_EXCLUDE | SEC_KEEP; } lreg = lang_new_vers_pattern (NULL, "*", NULL, FALSE); @@ -6698,3 +7025,69 @@ lang_add_unique (const char *name) ent->next = unique_section_list; unique_section_list = ent; } + +/* Append the list of dynamic symbols to the existing one. */ + +void +lang_append_dynamic_list (struct bfd_elf_version_expr *dynamic) +{ + if (link_info.dynamic_list) + { + struct bfd_elf_version_expr *tail; + for (tail = dynamic; tail->next != NULL; tail = tail->next) + ; + tail->next = link_info.dynamic_list->head.list; + link_info.dynamic_list->head.list = dynamic; + } + else + { + struct bfd_elf_dynamic_list *d; + + d = xcalloc (1, sizeof *d); + d->head.list = dynamic; + d->match = lang_vers_match; + link_info.dynamic_list = d; + } +} + +/* Append the list of C++ typeinfo dynamic symbols to the existing + one. */ + +void +lang_append_dynamic_list_cpp_typeinfo (void) +{ + const char * symbols [] = + { + "typeinfo name for*", + "typeinfo for*" + }; + struct bfd_elf_version_expr *dynamic = NULL; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE (symbols); i++) + dynamic = lang_new_vers_pattern (dynamic, symbols [i], "C++", + FALSE); + + lang_append_dynamic_list (dynamic); +} + +/* Append the list of C++ operator new and delete dynamic symbols to the + existing one. */ + +void +lang_append_dynamic_list_cpp_new (void) +{ + const char * symbols [] = + { + "operator new*", + "operator delete*" + }; + struct bfd_elf_version_expr *dynamic = NULL; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE (symbols); i++) + dynamic = lang_new_vers_pattern (dynamic, symbols [i], "C++", + FALSE); + + lang_append_dynamic_list (dynamic); +}