X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=ld%2Fldlang.c;h=0d6419d91ddaadc7d5449bd7ddcb77f8fc35d7d3;hb=00e52e5376c7ec604a739e6242e6be36221162d7;hp=1bffa937c6f7c1ddd5f4c75f8f4da02661d30c4a;hpb=2aa9aad989850c1a650701e507266edbad9864d2;p=deliverable%2Fbinutils-gdb.git diff --git a/ld/ldlang.c b/ld/ldlang.c index 1bffa937c6..0d6419d91d 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -1,7 +1,5 @@ /* Linker command language support. - Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 - Free Software Foundation, Inc. + Copyright (C) 1991-2015 Free Software Foundation, Inc. This file is part of the GNU Binutils. @@ -42,6 +40,7 @@ #include "demangle.h" #include "hashtab.h" #include "libbfd.h" +#include "elf-bfd.h" #ifdef ENABLE_PLUGINS #include "plugin.h" #endif /* ENABLE_PLUGINS */ @@ -58,25 +57,21 @@ static struct obstack map_obstack; #define obstack_chunk_free free static const char *entry_symbol_default = "start"; static bfd_boolean placed_commons = FALSE; -static bfd_boolean stripped_excluded_sections = FALSE; +static bfd_boolean map_head_is_link_order = FALSE; static lang_output_section_statement_type *default_common_section; static bfd_boolean map_option_f; static bfd_vma print_dot; static lang_input_statement_type *first_file; static const char *current_target; static lang_statement_list_type statement_list; -static struct bfd_hash_table lang_definedness_table; static lang_statement_list_type *stat_save[10]; static lang_statement_list_type **stat_save_ptr = &stat_save[0]; static struct unique_sections *unique_section_list; -static bfd_boolean ldlang_sysrooted_script = FALSE; +static struct asneeded_minfo *asneeded_list_head; /* 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 struct bfd_hash_entry *lang_definedness_newfunc - (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); static void insert_undefined (const char *); static bfd_boolean sort_def_symbol (struct bfd_link_hash_entry *, void *); static void print_statement (lang_statement_union_type *, @@ -90,6 +85,7 @@ 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 *); +static void lang_do_memory_regions (void); /* Exported variables. */ const char *output_target; @@ -100,6 +96,7 @@ lang_statement_list_type file_chain = { NULL, NULL }; lang_statement_list_type input_file_chain; struct bfd_sym_chain entry_symbol = { NULL, NULL }; const char *entry_section = ".text"; +struct lang_input_statement_flags input_flags; bfd_boolean entry_from_cmdline; bfd_boolean undef_from_cmdline; bfd_boolean lang_has_input_file = FALSE; @@ -108,14 +105,12 @@ 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; -bfd_boolean missing_file = FALSE; +struct asneeded_minfo **asneeded_list_tail; /* Functions that traverse the linker script and might evaluate - DEFINED() need to increment this. */ + DEFINED() need to increment this at the start of the traversal. */ int lang_statement_iteration = 0; -etree_type *base; /* Relocation base - or null */ - /* Return TRUE if the PATTERN argument is a wildcard pattern. Although backslashes are treated specially if a pattern contains wildcards, we do not consider the mere presence of a backslash to @@ -237,9 +232,6 @@ walk_wild_consider_section (lang_wild_statement_type *ptr, { struct name_list *list_tmp; - /* Propagate the section_flag_info from the wild statement to the section. */ - s->section_flag_info = ptr->section_flag_list; - /* Don't process sections from files which were excluded. */ for (list_tmp = sec->spec.exclude_name_list; list_tmp; @@ -266,7 +258,7 @@ walk_wild_consider_section (lang_wild_statement_type *ptr, return; } - (*callback) (ptr, sec, s, file, data); + (*callback) (ptr, sec, s, ptr->section_flag_list, file, data); } /* Lowest common denominator routine that can handle everything correctly, @@ -285,7 +277,7 @@ walk_wild_section_general (lang_wild_statement_type *ptr, { sec = ptr->section_list; if (sec == NULL) - (*callback) (ptr, sec, s, file, data); + (*callback) (ptr, sec, s, ptr->section_flag_list, file, data); while (sec != NULL) { @@ -391,7 +383,7 @@ get_init_priority (const char *name) decimal numerical value of the init_priority attribute. The order of execution in .init_array is forward and .fini_array is backward. - 2: .ctors.NNNN/.ctors.NNNN: Where NNNN is 65535 minus the + 2: .ctors.NNNN/.dtors.NNNN: Where NNNN is 65535 minus the decimal numerical value of the init_priority attribute. The order of execution in .ctors is backward and .dtors is forward. @@ -507,6 +499,7 @@ static void output_section_callback_fast (lang_wild_statement_type *ptr, struct wildcard_list *sec, asection *section, + struct flag_info *sflag_list ATTRIBUTE_UNUSED, lang_input_statement_type *file, void *output) { @@ -539,7 +532,7 @@ output_section_callback_tree_to_list (lang_wild_statement_type *ptr, if (tree->left) output_section_callback_tree_to_list (ptr, tree->left, output); - lang_add_section (&ptr->children, tree->section, + lang_add_section (&ptr->children, tree->section, NULL, (lang_output_section_statement_type *) output); if (tree->right) @@ -731,7 +724,7 @@ walk_wild_section (lang_wild_statement_type *ptr, callback_t callback, void *data) { - if (file->just_syms_flag) + if (file->flags.just_syms) return; (*ptr->walk_wild_section_handler) (ptr, file, callback, data); @@ -881,8 +874,8 @@ walk_wild_file (lang_wild_statement_type *s, if (member->usrdata != NULL) { walk_wild_section (s, - (lang_input_statement_type *) member->usrdata, - callback, data); + (lang_input_statement_type *) member->usrdata, + callback, data); } member = bfd_openr_next_archived_file (f->the_bfd, member); @@ -1046,95 +1039,71 @@ new_afile (const char *name, { lang_input_statement_type *p; + lang_has_input_file = TRUE; + if (add_to_list) p = (lang_input_statement_type *) new_stat (lang_input_statement, stat_ptr); else { p = (lang_input_statement_type *) - stat_alloc (sizeof (lang_input_statement_type)); + stat_alloc (sizeof (lang_input_statement_type)); p->header.type = lang_input_statement_enum; p->header.next = NULL; } - lang_has_input_file = TRUE; + memset (&p->the_bfd, 0, + sizeof (*p) - offsetof (lang_input_statement_type, the_bfd)); 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; - } + p->flags.dynamic = input_flags.dynamic; + p->flags.add_DT_NEEDED_for_dynamic = input_flags.add_DT_NEEDED_for_dynamic; + p->flags.add_DT_NEEDED_for_regular = input_flags.add_DT_NEEDED_for_regular; + p->flags.whole_archive = input_flags.whole_archive; + p->flags.sysrooted = input_flags.sysrooted; switch (file_type) { case lang_input_file_is_symbols_only_enum: p->filename = name; - p->maybe_archive = FALSE; - p->real = TRUE; p->local_sym_name = name; - p->just_syms_flag = TRUE; - p->search_dirs_flag = FALSE; + p->flags.real = TRUE; + p->flags.just_syms = TRUE; break; case lang_input_file_is_fake_enum: p->filename = name; - p->maybe_archive = FALSE; - p->real = FALSE; p->local_sym_name = name; - p->just_syms_flag = FALSE; - p->search_dirs_flag = FALSE; break; case lang_input_file_is_l_enum: - p->maybe_archive = TRUE; - p->filename = name; - p->real = TRUE; + if (name[0] == ':' && name[1] != '\0') + { + p->filename = name + 1; + p->flags.full_name_provided = TRUE; + } + else + p->filename = name; p->local_sym_name = concat ("-l", name, (const char *) NULL); - p->just_syms_flag = FALSE; - p->search_dirs_flag = TRUE; + p->flags.maybe_archive = TRUE; + p->flags.real = TRUE; + p->flags.search_dirs = TRUE; break; case lang_input_file_is_marker_enum: p->filename = name; - p->maybe_archive = FALSE; - p->real = FALSE; p->local_sym_name = name; - p->just_syms_flag = FALSE; - p->search_dirs_flag = TRUE; + p->flags.search_dirs = TRUE; break; case lang_input_file_is_search_file_enum: - p->sysrooted = ldlang_sysrooted_script; p->filename = name; - p->maybe_archive = FALSE; - p->real = TRUE; p->local_sym_name = name; - p->just_syms_flag = FALSE; - p->search_dirs_flag = TRUE; + p->flags.real = TRUE; + p->flags.search_dirs = TRUE; break; case lang_input_file_is_file_enum: p->filename = name; - p->maybe_archive = FALSE; - p->real = TRUE; p->local_sym_name = name; - p->just_syms_flag = FALSE; - p->search_dirs_flag = FALSE; + p->flags.real = TRUE; break; default: FAIL (); } - p->the_bfd = NULL; - p->next_real_file = NULL; - p->next = NULL; - p->dynamic = config.dynamic_link; - p->add_DT_NEEDED_for_dynamic = add_DT_NEEDED_for_dynamic; - p->add_DT_NEEDED_for_regular = add_DT_NEEDED_for_regular; - p->whole_archive = whole_archive; - p->loaded = FALSE; - p->missing_file = FALSE; -#ifdef ENABLE_PLUGINS - p->claimed = FALSE; - p->claim_archive = FALSE; - p->reload = FALSE; -#endif /* ENABLE_PLUGINS */ lang_statement_append (&input_file_chain, (lang_statement_union_type *) p, @@ -1147,6 +1116,26 @@ lang_add_input_file (const char *name, lang_input_file_enum_type file_type, const char *target) { + if (name != NULL && *name == '=') + { + lang_input_statement_type *ret; + char *sysrooted_name + = concat (ld_sysroot, name + 1, (const char *) NULL); + + /* We've now forcibly prepended the sysroot, making the input + file independent of the context. Therefore, temporarily + force a non-sysrooted context for this statement, so it won't + get the sysroot prepended again when opened. (N.B. if it's a + script, any child nodes with input files starting with "/" + will be handled as "sysrooted" as they'll be found to be + within the sysroot subdirectory.) */ + unsigned int outer_sysrooted = input_flags.sysrooted; + input_flags.sysrooted = 0; + ret = new_afile (sysrooted_name, file_type, target, TRUE); + input_flags.sysrooted = outer_sysrooted; + return ret; + } + return new_afile (name, file_type, target, TRUE); } @@ -1174,7 +1163,7 @@ output_section_statement_newfunc (struct bfd_hash_entry *entry, if (entry == NULL) { entry = (struct bfd_hash_entry *) bfd_hash_allocate (table, - sizeof (*ret)); + sizeof (*ret)); if (entry == NULL) return entry; } @@ -1250,17 +1239,8 @@ lang_init (void) abs_output_section->bfd_section = bfd_abs_section_ptr; - /* The value "3" is ad-hoc, somewhat related to the expected number of - DEFINED expressions in a linker script. For most default linker - scripts, there are none. Why a hash table then? Well, it's somewhat - simpler to re-use working machinery than using a linked list in terms - 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, - sizeof (struct lang_definedness_hash_entry), - 3)) - einfo (_("%P%F: can not create hash table: %E\n")); + asneeded_list_head = NULL; + asneeded_list_tail = &asneeded_list_head; } void @@ -1309,12 +1289,12 @@ lang_memory_region_lookup (const char *const name, bfd_boolean create) for (r = lang_memory_region_list; r != NULL; r = r->next) for (n = &r->name_list; n != NULL; n = n->next) if (strcmp (n->name, name) == 0) - { - if (create) - einfo (_("%P:%S: warning: redeclaration of memory region `%s'\n"), - NULL, name); - return r; - } + { + if (create) + einfo (_("%P:%S: warning: redeclaration of memory region `%s'\n"), + NULL, name); + return r; + } if (!create && strcmp (name, DEFAULT_MEMORY_REGION)) einfo (_("%P:%S: warning: memory region `%s' not declared\n"), @@ -1326,7 +1306,9 @@ lang_memory_region_lookup (const char *const name, bfd_boolean create) new_region->name_list.name = xstrdup (name); new_region->name_list.next = NULL; new_region->next = NULL; + new_region->origin_exp = NULL; new_region->origin = 0; + new_region->length_exp = NULL; new_region->length = ~(bfd_size_type) 0; new_region->current = 0; new_region->last_os = NULL; @@ -1360,19 +1342,19 @@ lang_memory_region_alias (const char * alias, const char * region_name) for (r = lang_memory_region_list; r != NULL; r = r->next) for (n = &r->name_list; n != NULL; n = n->next) { - if (region == NULL && strcmp (n->name, region_name) == 0) - region = r; - if (strcmp (n->name, alias) == 0) - einfo (_("%F%P:%S: error: redefinition of memory region " - "alias `%s'\n"), - NULL, alias); + if (region == NULL && strcmp (n->name, region_name) == 0) + region = r; + if (strcmp (n->name, alias) == 0) + einfo (_("%F%P:%S: error: redefinition of memory region " + "alias `%s'\n"), + NULL, alias); } /* Check if the target region exists. */ if (region == NULL) einfo (_("%F%P:%S: error: memory region `%s' " - "for alias `%s' does not exist\n"), - NULL, region_name, alias); + "for alias `%s' does not exist\n"), + NULL, region_name, alias); /* Add alias to region name list. */ n = (lang_memory_region_name *) stat_alloc (sizeof (lang_memory_region_name)); @@ -1403,6 +1385,14 @@ lang_memory_default (asection * section) return lang_memory_region_lookup (DEFAULT_MEMORY_REGION, FALSE); } +/* Get the output section statement directly from the userdata. */ + +lang_output_section_statement_type * +lang_output_section_get (const asection *output_section) +{ + return get_userdata (output_section); +} + /* Find or create an output_section_statement with the given NAME. If CONSTRAINT is non-zero match one with that constraint, otherwise match any non-negative constraint. If CREATE, always make a @@ -1513,7 +1503,7 @@ lang_output_section_find_by_flags (const asection *sec, lang_match_sec_type_func match_type) { lang_output_section_statement_type *first, *look, *found; - flagword flags; + flagword look_flags, sec_flags, differ; /* We know the first statement on this list is *ABS*. May as well skip it. */ @@ -1521,21 +1511,22 @@ lang_output_section_find_by_flags (const asection *sec, first = first->next; /* First try for an exact match. */ + sec_flags = sec->flags; found = NULL; for (look = first; look; look = look->next) { - flags = look->flags; + look_flags = look->flags; if (look->bfd_section != NULL) { - flags = look->bfd_section->flags; + look_flags = look->bfd_section->flags; if (match_type && !match_type (link_info.output_bfd, look->bfd_section, sec->owner, sec)) continue; } - flags ^= sec->flags; - if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY - | SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL))) + differ = look_flags ^ sec_flags; + if (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY + | SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL))) found = look; } if (found != NULL) @@ -1545,115 +1536,144 @@ lang_output_section_find_by_flags (const asection *sec, return found; } - if ((sec->flags & SEC_CODE) != 0 - && (sec->flags & SEC_ALLOC) != 0) + if ((sec_flags & SEC_CODE) != 0 + && (sec_flags & SEC_ALLOC) != 0) { /* Try for a rw code section. */ for (look = first; look; look = look->next) { - flags = look->flags; + look_flags = look->flags; if (look->bfd_section != NULL) { - flags = look->bfd_section->flags; + look_flags = look->bfd_section->flags; if (match_type && !match_type (link_info.output_bfd, look->bfd_section, sec->owner, sec)) continue; } - flags ^= sec->flags; - if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD - | SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL))) + differ = look_flags ^ sec_flags; + if (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD + | SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL))) found = look; } } - else if ((sec->flags & (SEC_READONLY | SEC_THREAD_LOCAL)) != 0 - && (sec->flags & SEC_ALLOC) != 0) + else if ((sec_flags & SEC_READONLY) != 0 + && (sec_flags & SEC_ALLOC) != 0) { /* .rodata can go after .text, .sdata2 after .rodata. */ for (look = first; look; look = look->next) { - flags = look->flags; + look_flags = look->flags; if (look->bfd_section != NULL) { - flags = look->bfd_section->flags; + look_flags = look->bfd_section->flags; if (match_type && !match_type (link_info.output_bfd, look->bfd_section, sec->owner, sec)) continue; } - flags ^= sec->flags; - if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD - | SEC_READONLY | SEC_SMALL_DATA)) - || (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD - | SEC_READONLY)) - && !(look->flags & SEC_SMALL_DATA)) - || (!(flags & (SEC_THREAD_LOCAL | SEC_ALLOC)) - && (look->flags & SEC_THREAD_LOCAL) - && (!(flags & SEC_LOAD) - || (look->flags & SEC_LOAD)))) + differ = look_flags ^ sec_flags; + if (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD + | SEC_READONLY | SEC_SMALL_DATA)) + || (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD + | SEC_READONLY)) + && !(look_flags & SEC_SMALL_DATA))) + found = look; + } + } + else if ((sec_flags & SEC_THREAD_LOCAL) != 0 + && (sec_flags & SEC_ALLOC) != 0) + { + /* .tdata can go after .data, .tbss after .tdata. Treat .tbss + as if it were a loaded section, and don't use match_type. */ + bfd_boolean seen_thread_local = FALSE; + + match_type = NULL; + for (look = first; look; look = look->next) + { + look_flags = look->flags; + if (look->bfd_section != NULL) + look_flags = look->bfd_section->flags; + + differ = look_flags ^ (sec_flags | SEC_LOAD | SEC_HAS_CONTENTS); + if (!(differ & (SEC_THREAD_LOCAL | SEC_ALLOC))) + { + /* .tdata and .tbss must be adjacent and in that order. */ + if (!(look_flags & SEC_LOAD) + && (sec_flags & SEC_LOAD)) + /* ..so if we're at a .tbss section and we're placing + a .tdata section stop looking and return the + previous section. */ + break; + found = look; + seen_thread_local = TRUE; + } + else if (seen_thread_local) + break; + else if (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD))) found = look; } } - else if ((sec->flags & SEC_SMALL_DATA) != 0 - && (sec->flags & SEC_ALLOC) != 0) + else if ((sec_flags & SEC_SMALL_DATA) != 0 + && (sec_flags & SEC_ALLOC) != 0) { /* .sdata goes after .data, .sbss after .sdata. */ for (look = first; look; look = look->next) { - flags = look->flags; + look_flags = look->flags; if (look->bfd_section != NULL) { - flags = look->bfd_section->flags; + look_flags = look->bfd_section->flags; if (match_type && !match_type (link_info.output_bfd, look->bfd_section, sec->owner, sec)) continue; } - flags ^= sec->flags; - if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD - | SEC_THREAD_LOCAL)) - || ((look->flags & SEC_SMALL_DATA) - && !(sec->flags & SEC_HAS_CONTENTS))) + differ = look_flags ^ sec_flags; + if (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD + | SEC_THREAD_LOCAL)) + || ((look_flags & SEC_SMALL_DATA) + && !(sec_flags & SEC_HAS_CONTENTS))) found = look; } } - else if ((sec->flags & SEC_HAS_CONTENTS) != 0 - && (sec->flags & SEC_ALLOC) != 0) + else if ((sec_flags & SEC_HAS_CONTENTS) != 0 + && (sec_flags & SEC_ALLOC) != 0) { /* .data goes after .rodata. */ for (look = first; look; look = look->next) { - flags = look->flags; + look_flags = look->flags; if (look->bfd_section != NULL) { - flags = look->bfd_section->flags; + look_flags = look->bfd_section->flags; if (match_type && !match_type (link_info.output_bfd, look->bfd_section, sec->owner, sec)) continue; } - flags ^= sec->flags; - if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD - | SEC_SMALL_DATA | SEC_THREAD_LOCAL))) + differ = look_flags ^ sec_flags; + if (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD + | SEC_SMALL_DATA | SEC_THREAD_LOCAL))) found = look; } } - else if ((sec->flags & SEC_ALLOC) != 0) + else if ((sec_flags & SEC_ALLOC) != 0) { /* .bss goes after any other alloc section. */ for (look = first; look; look = look->next) { - flags = look->flags; + look_flags = look->flags; if (look->bfd_section != NULL) { - flags = look->bfd_section->flags; + look_flags = look->bfd_section->flags; if (match_type && !match_type (link_info.output_bfd, look->bfd_section, sec->owner, sec)) continue; } - flags ^= sec->flags; - if (!(flags & SEC_ALLOC)) + differ = look_flags ^ sec_flags; + if (!(differ & SEC_ALLOC)) found = look; } } @@ -1662,11 +1682,11 @@ lang_output_section_find_by_flags (const asection *sec, /* non-alloc go last. */ for (look = first; look; look = look->next) { - flags = look->flags; + look_flags = look->flags; if (look->bfd_section != NULL) - flags = look->bfd_section->flags; - flags ^= sec->flags; - if (!(flags & SEC_DEBUGGING)) + look_flags = look->bfd_section->flags; + differ = look_flags ^ sec_flags; + if (!(differ & SEC_DEBUGGING)) found = look; } return found; @@ -1803,7 +1823,7 @@ lang_insert_orphan (asection *s, os_tail = ((lang_output_section_statement_type **) lang_output_section_statement.tail); os = lang_enter_output_section_statement (secname, address, normal_section, - NULL, NULL, NULL, constraint); + NULL, NULL, NULL, constraint, 0); ps = NULL; if (config.build_constructors && *os_tail == os) @@ -1816,24 +1836,19 @@ lang_insert_orphan (asection *s, if (*ps == '\0') { char *symname; - etree_type *e_align; symname = (char *) xmalloc (ps - secname + sizeof "__start_" + 1); symname[0] = bfd_get_symbol_leading_char (link_info.output_bfd); sprintf (symname + (symname[0] != 0), "__start_%s", secname); - e_align = exp_unop (ALIGN_K, - exp_intop ((bfd_vma) 1 << s->alignment_power)); - lang_add_assignment (exp_assign (".", e_align)); lang_add_assignment (exp_provide (symname, - exp_unop (ABSOLUTE, - exp_nameop (NAME, ".")), + exp_nameop (NAME, "."), FALSE)); } } if (add_child == NULL) add_child = &os->children; - lang_add_section (add_child, s, os); + lang_add_section (add_child, s, NULL, os); if (after && (s->flags & (SEC_LOAD | SEC_ALLOC)) != 0) { @@ -1981,6 +1996,43 @@ lang_insert_orphan (asection *s, return os; } +static void +lang_print_asneeded (void) +{ + struct asneeded_minfo *m; + char buf[100]; + + if (asneeded_list_head == NULL) + return; + + sprintf (buf, _("\nAs-needed library included " + "to satisfy reference by file (symbol)\n\n")); + minfo ("%s", buf); + + for (m = asneeded_list_head; m != NULL; m = m->next) + { + size_t len; + + minfo ("%s", m->soname); + len = strlen (m->soname); + + if (len >= 29) + { + print_nl (); + len = 0; + } + while (len < 30) + { + print_space (); + ++len; + } + + if (m->ref != NULL) + minfo ("%B ", m->ref); + minfo ("(%T)\n", m->name); + } +} + static void lang_map_flags (flagword flag) { @@ -2005,14 +2057,13 @@ 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) + || file->flags.just_syms) continue; for (s = file->the_bfd->sections; s != NULL; s = s->next) @@ -2077,50 +2128,36 @@ lang_map (void) if (! link_info.reduce_memory_overheads) { obstack_begin (&map_obstack, 1000); - for (p = link_info.input_bfds; p != (bfd *) NULL; p = p->link_next) - bfd_map_over_sections (p, init_map_userdata, 0); bfd_link_hash_traverse (link_info.hash, sort_def_symbol, 0); } - lang_statement_iteration ++; + lang_statement_iteration++; print_statements (); -} -static void -init_map_userdata (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec, - void *data ATTRIBUTE_UNUSED) -{ - fat_section_userdata_type *new_data - = ((fat_section_userdata_type *) (stat_alloc - (sizeof (fat_section_userdata_type)))); - - ASSERT (get_userdata (sec) == NULL); - get_userdata (sec) = new_data; - new_data->map_symbol_def_tail = &new_data->map_symbol_def_head; - new_data->map_symbol_def_count = 0; + ldemul_extra_map_file_text (link_info.output_bfd, &link_info, config.map_file); } static bfd_boolean sort_def_symbol (struct bfd_link_hash_entry *hash_entry, void *info ATTRIBUTE_UNUSED) { - if (hash_entry->type == bfd_link_hash_defined - || hash_entry->type == bfd_link_hash_defweak) + if ((hash_entry->type == bfd_link_hash_defined + || hash_entry->type == bfd_link_hash_defweak) + && hash_entry->u.def.section->owner != link_info.output_bfd + && hash_entry->u.def.section->owner != NULL) { - struct fat_user_section_struct *ud; + input_section_userdata_type *ud; struct map_symbol_def *def; - ud = (struct fat_user_section_struct *) - get_userdata (hash_entry->u.def.section); - if (! ud) + ud = ((input_section_userdata_type *) + get_userdata (hash_entry->u.def.section)); + if (!ud) { - /* ??? What do we have to do to initialize this beforehand? */ - /* The first time we get here is bfd_abs_section... */ - init_map_userdata (0, hash_entry->u.def.section, 0); - ud = (struct fat_user_section_struct *) - get_userdata (hash_entry->u.def.section); + ud = (input_section_userdata_type *) stat_alloc (sizeof (*ud)); + get_userdata (hash_entry->u.def.section) = ud; + ud->map_symbol_def_tail = &ud->map_symbol_def_head; + ud->map_symbol_def_count = 0; } - else if (!ud->map_symbol_def_tail) + else if (!ud->map_symbol_def_tail) ud->map_symbol_def_tail = &ud->map_symbol_def_head; def = (struct map_symbol_def *) obstack_alloc (&map_obstack, sizeof *def); @@ -2153,13 +2190,9 @@ init_os (lang_output_section_statement_type *s, flagword flags) s->bfd_section->output_section = s->bfd_section; s->bfd_section->output_offset = 0; - if (!link_info.reduce_memory_overheads) - { - fat_section_userdata_type *new_userdata = (fat_section_userdata_type *) - stat_alloc (sizeof (fat_section_userdata_type)); - memset (new_userdata, 0, sizeof (fat_section_userdata_type)); - get_userdata (s->bfd_section) = new_userdata; - } + /* Set the userdata of the output section to the output section + statement to avoid lookup. */ + get_userdata (s->bfd_section) = s; /* If there is a base address, make sure that any sections it might mention are initialized. */ @@ -2234,7 +2267,7 @@ section_already_linked (bfd *abfd, asection *sec, void *data) /* If we are only reading symbols from this object, then we want to discard all sections. */ - if (entry->just_syms_flag) + if (entry->flags.just_syms) { bfd_link_just_syms (abfd, sec, &link_info); return; @@ -2251,16 +2284,15 @@ section_already_linked (bfd *abfd, asection *sec, void *data) foo.o(.text, .data). */ /* Add SECTION to the output section OUTPUT. Do this by creating a - lang_input_section statement which is placed at PTR. FILE is the - input file which holds SECTION. */ + lang_input_section statement which is placed at PTR. */ void lang_add_section (lang_statement_list_type *ptr, asection *section, + struct flag_info *sflag_info, lang_output_section_statement_type *output) { flagword flags = section->flags; - struct flag_info *sflag_info = section->section_flag_info; bfd_boolean discard; lang_input_section_type *new_section; @@ -2292,23 +2324,10 @@ lang_add_section (lang_statement_list_type *ptr, if (sflag_info) { - if (sflag_info->flags_initialized == FALSE) - bfd_lookup_section_flags (&link_info, sflag_info); + bfd_boolean keep; - if (sflag_info->only_with_flags != 0 - && sflag_info->not_with_flags != 0 - && ((sflag_info->not_with_flags & flags) != 0 - || (sflag_info->only_with_flags & flags) - != sflag_info->only_with_flags)) - return; - - if (sflag_info->only_with_flags != 0 - && (sflag_info->only_with_flags & flags) - != sflag_info->only_with_flags) - return; - - if (sflag_info->not_with_flags != 0 - && (sflag_info->not_with_flags & flags) != 0) + keep = bfd_lookup_section_flags (&link_info, sflag_info, section); + if (!keep) return; } @@ -2403,8 +2422,7 @@ lang_add_section (lang_statement_list_type *ptr, section->output_section = output->bfd_section; - if (!link_info.relocatable - && !stripped_excluded_sections) + if (!map_head_is_link_order) { asection *s = output->bfd_section->map_tail.s; output->bfd_section->map_tail.s = section; @@ -2507,7 +2525,9 @@ wild_sort (lang_wild_statement_type *wild, /* Here either the files are not sorted by name, or we are looking at the sections for this file. */ - if (sec != NULL && sec->spec.sorted != none) + if (sec != NULL + && sec->spec.sorted != none + && sec->spec.sorted != by_none) if (compare_section (sec->spec.sorted, section, ls->section) < 0) break; } @@ -2522,6 +2542,7 @@ static void output_section_callback (lang_wild_statement_type *ptr, struct wildcard_list *sec, asection *section, + struct flag_info *sflag_info, lang_input_statement_type *file, void *output) { @@ -2542,14 +2563,14 @@ output_section_callback (lang_wild_statement_type *ptr, of the current list. */ if (before == NULL) - lang_add_section (&ptr->children, section, os); + lang_add_section (&ptr->children, section, sflag_info, os); else { lang_statement_list_type list; lang_statement_union_type **pp; lang_list_init (&list); - lang_add_section (&list, section, os); + lang_add_section (&list, section, sflag_info, os); /* If we are discarding the section, LIST.HEAD will be NULL. */ @@ -2575,6 +2596,7 @@ static void check_section_callback (lang_wild_statement_type *ptr ATTRIBUTE_UNUSED, struct wildcard_list *sec ATTRIBUTE_UNUSED, asection *section, + struct flag_info *sflag_info ATTRIBUTE_UNUSED, lang_input_statement_type *file ATTRIBUTE_UNUSED, void *output) { @@ -2619,7 +2641,7 @@ lookup_name (const char *name) /* If we have already added this file, or this file is not real don't add this file. */ - if (search->loaded || !search->real) + if (search->flags.loaded || !search->flags.real) return search; if (! load_symbols (search, NULL)) @@ -2697,23 +2719,21 @@ load_symbols (lang_input_statement_type *entry, { char **matching; - if (entry->loaded) + if (entry->flags.loaded) return TRUE; ldfile_open_file (entry); /* Do not process further if the file was missing. */ - if (entry->missing_file) + if (entry->flags.missing_file) return TRUE; if (! bfd_check_format (entry->the_bfd, bfd_archive) && ! bfd_check_format_matches (entry->the_bfd, bfd_object, &matching)) { bfd_error_type err; - bfd_boolean save_ldlang_sysrooted_script; - bfd_boolean save_add_DT_NEEDED_for_regular; - bfd_boolean save_add_DT_NEEDED_for_dynamic; - bfd_boolean save_whole_archive; + struct lang_input_statement_flags save_flags; + extern FILE *yyin; err = bfd_get_error (); @@ -2739,31 +2759,31 @@ load_symbols (lang_input_statement_type *entry, entry->the_bfd = NULL; /* Try to interpret the file as a linker script. */ + save_flags = input_flags; ldfile_open_command_file (entry->filename); push_stat_ptr (place); - save_ldlang_sysrooted_script = ldlang_sysrooted_script; - ldlang_sysrooted_script = entry->sysrooted; - save_add_DT_NEEDED_for_regular = add_DT_NEEDED_for_regular; - add_DT_NEEDED_for_regular = entry->add_DT_NEEDED_for_regular; - save_add_DT_NEEDED_for_dynamic = add_DT_NEEDED_for_dynamic; - add_DT_NEEDED_for_dynamic = entry->add_DT_NEEDED_for_dynamic; - save_whole_archive = whole_archive; - whole_archive = entry->whole_archive; + input_flags.add_DT_NEEDED_for_regular + = entry->flags.add_DT_NEEDED_for_regular; + input_flags.add_DT_NEEDED_for_dynamic + = entry->flags.add_DT_NEEDED_for_dynamic; + input_flags.whole_archive = entry->flags.whole_archive; + input_flags.dynamic = entry->flags.dynamic; ldfile_assumed_script = TRUE; parser_input = input_script; - /* We want to use the same -Bdynamic/-Bstatic as the one for - ENTRY. */ - config.dynamic_link = entry->dynamic; yyparse (); ldfile_assumed_script = FALSE; - ldlang_sysrooted_script = save_ldlang_sysrooted_script; - add_DT_NEEDED_for_regular = save_add_DT_NEEDED_for_regular; - add_DT_NEEDED_for_dynamic = save_add_DT_NEEDED_for_dynamic; - whole_archive = save_whole_archive; + /* missing_file is sticky. sysrooted will already have been + restored when seeing EOF in yyparse, but no harm to restore + again. */ + save_flags.missing_file |= input_flags.missing_file; + input_flags = save_flags; pop_stat_ptr (); + fclose (yyin); + yyin = NULL; + entry->flags.loaded = TRUE; return TRUE; } @@ -2781,18 +2801,16 @@ load_symbols (lang_input_statement_type *entry, break; case bfd_object: -#ifdef ENABLE_PLUGINS - if (!entry->reload) -#endif + if (!entry->flags.reload) ldlang_add_file (entry); - if (trace_files || trace_file_tries) + if (trace_files || verbose) info_msg ("%I\n", entry); break; case bfd_archive: check_excluded_libs (entry->the_bfd); - if (entry->whole_archive) + if (entry->flags.whole_archive) { bfd *member = NULL; bfd_boolean loaded = TRUE; @@ -2822,23 +2840,23 @@ load_symbols (lang_input_statement_type *entry, substitute BFD for us. */ if (!bfd_link_add_symbols (subsbfd, &link_info)) { - einfo (_("%F%B: could not read symbols: %E\n"), member); + einfo (_("%F%B: error adding symbols: %E\n"), member); loaded = FALSE; } } - entry->loaded = loaded; + entry->flags.loaded = loaded; return loaded; } break; } if (bfd_link_add_symbols (entry->the_bfd, &link_info)) - entry->loaded = TRUE; + entry->flags.loaded = TRUE; else - einfo (_("%F%B: could not read symbols: %E\n"), entry->the_bfd); + einfo (_("%F%B: error adding symbols: %E\n"), entry->the_bfd); - return entry->loaded; + return entry->flags.loaded; } /* Handle a wild statement. S->FILENAME or S->SECTION_LIST or both @@ -3022,7 +3040,7 @@ get_first_input_target (void) LANG_FOR_EACH_INPUT_STATEMENT (s) { if (s->header.type == lang_input_statement_enum - && s->real) + && s->flags.real) { ldfile_open_file (s); @@ -3255,40 +3273,37 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode) current_target = s->target_statement.target; break; case lang_input_statement_enum: - if (s->input_statement.real) + if (s->input_statement.flags.real) { lang_statement_union_type **os_tail; lang_statement_list_type add; + bfd *abfd; s->input_statement.target = current_target; /* If we are being called from within a group, and this is an archive which has already been searched, then force it to be researched unless the whole archive - has been loaded already. Do the same for a rescan. */ + has been loaded already. Do the same for a rescan. + Likewise reload --as-needed shared libs. */ if (mode != OPEN_BFD_NORMAL #ifdef ENABLE_PLUGINS && ((mode & OPEN_BFD_RESCAN) == 0 || plugin_insert == NULL) #endif - && !s->input_statement.whole_archive - && s->input_statement.loaded - && bfd_check_format (s->input_statement.the_bfd, - bfd_archive)) - s->input_statement.loaded = FALSE; -#ifdef ENABLE_PLUGINS - /* When rescanning, reload --as-needed shared libs. */ - else if ((mode & OPEN_BFD_RESCAN) != 0 - && plugin_insert == NULL - && s->input_statement.loaded - && s->input_statement.add_DT_NEEDED_for_regular - && ((s->input_statement.the_bfd->flags) & DYNAMIC) != 0 - && plugin_should_reload (s->input_statement.the_bfd)) + && s->input_statement.flags.loaded + && (abfd = s->input_statement.the_bfd) != NULL + && ((bfd_get_format (abfd) == bfd_archive + && !s->input_statement.flags.whole_archive) + || (bfd_get_format (abfd) == bfd_object + && ((abfd->flags) & DYNAMIC) != 0 + && s->input_statement.flags.add_DT_NEEDED_for_regular + && bfd_get_flavour (abfd) == bfd_target_elf_flavour + && (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0))) { - s->input_statement.loaded = FALSE; - s->input_statement.reload = TRUE; + s->input_statement.flags.loaded = FALSE; + s->input_statement.flags.reload = TRUE; } -#endif os_tail = lang_output_section_statement.tail; lang_list_init (&add); @@ -3327,7 +3342,7 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode) #endif break; case lang_assignment_statement_enum: - if (s->assignment_statement.exp->assign.hidden) + if (s->assignment_statement.exp->assign.defsym) /* This is from a --defsym on the command line. */ exp_fold_tree_no_dot (s->assignment_statement.exp); break; @@ -3337,89 +3352,10 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode) } /* Exit if any of the files were missing. */ - if (missing_file) + if (input_flags.missing_file) einfo ("%F"); } -/* Add a symbol to a hash of symbols used in DEFINED (NAME) expressions. */ - -void -lang_track_definedness (const char *name) -{ - if (bfd_hash_lookup (&lang_definedness_table, name, TRUE, FALSE) == NULL) - einfo (_("%P%F: bfd_hash_lookup failed creating symbol %s\n"), name); -} - -/* New-function for the definedness hash table. */ - -static struct bfd_hash_entry * -lang_definedness_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table ATTRIBUTE_UNUSED, - const char *name ATTRIBUTE_UNUSED) -{ - struct lang_definedness_hash_entry *ret - = (struct lang_definedness_hash_entry *) entry; - - if (ret == NULL) - ret = (struct lang_definedness_hash_entry *) - bfd_hash_allocate (table, sizeof (struct lang_definedness_hash_entry)); - - if (ret == NULL) - einfo (_("%P%F: bfd_hash_allocate failed creating symbol %s\n"), name); - - ret->iteration = -1; - return &ret->root; -} - -/* Return the iteration when the definition of NAME was last updated. A - value of -1 means that the symbol is not defined in the linker script - or the command line, but may be defined in the linker symbol table. */ - -int -lang_symbol_definition_iteration (const char *name) -{ - struct lang_definedness_hash_entry *defentry - = (struct lang_definedness_hash_entry *) - bfd_hash_lookup (&lang_definedness_table, name, FALSE, FALSE); - - /* We've already created this one on the presence of DEFINED in the - script, so it can't be NULL unless something is borked elsewhere in - the code. */ - if (defentry == NULL) - FAIL (); - - return defentry->iteration; -} - -/* Update the definedness state of NAME. */ - -void -lang_update_definedness (const char *name, struct bfd_link_hash_entry *h) -{ - struct lang_definedness_hash_entry *defentry - = (struct lang_definedness_hash_entry *) - bfd_hash_lookup (&lang_definedness_table, name, FALSE, FALSE); - - /* We don't keep track of symbols not tested with DEFINED. */ - if (defentry == NULL) - return; - - /* If the symbol was already defined, and not from an earlier statement - iteration, don't update the definedness iteration, because that'd - make the symbol seem defined in the linker script at this point, and - it wasn't; it was defined in some object. If we do anyway, DEFINED - would start to yield false before this point and the construct "sym = - DEFINED (sym) ? sym : X;" would change sym to X despite being defined - in an object. */ - if (h->type != bfd_link_hash_undefined - && h->type != bfd_link_hash_common - && h->type != bfd_link_hash_new - && defentry->iteration == -1) - return; - - defentry->iteration = lang_statement_iteration; -} - /* Add the supplied name to the symbol table as an undefined reference. This is a two step process as the symbol table doesn't even exist at the time the ld command line is processed. First we put the name @@ -3477,6 +3413,55 @@ lang_place_undefineds (void) insert_undefined (ptr->name); } +/* Structure used to build the list of symbols that the user has required + be defined. */ + +struct require_defined_symbol +{ + const char *name; + struct require_defined_symbol *next; +}; + +/* The list of symbols that the user has required be defined. */ + +static struct require_defined_symbol *require_defined_symbol_list; + +/* Add a new symbol NAME to the list of symbols that are required to be + defined. */ + +void +ldlang_add_require_defined (const char * const name) +{ + struct require_defined_symbol *ptr; + + ldlang_add_undef (name, TRUE); + ptr = (struct require_defined_symbol *) stat_alloc (sizeof (*ptr)); + ptr->next = require_defined_symbol_list; + ptr->name = strdup (name); + require_defined_symbol_list = ptr; +} + +/* Check that all symbols the user required to be defined, are defined, + raise an error if we find a symbol that is not defined. */ + +static void +ldlang_check_require_defined_symbols (void) +{ + struct require_defined_symbol *ptr; + + for (ptr = require_defined_symbol_list; ptr != NULL; ptr = ptr->next) + { + struct bfd_link_hash_entry *h; + + h = bfd_link_hash_lookup (link_info.hash, ptr->name, + FALSE, FALSE, TRUE); + if (h == NULL + || (h->type != bfd_link_hash_defined + && h->type != bfd_link_hash_defweak)) + einfo(_("%P%X: required symbol `%s' not defined\n"), ptr->name); + } +} + /* Check for all readonly or some readwrite sections. */ static void @@ -3537,7 +3522,6 @@ update_wild_statements (lang_statement_union_type *s) break; case lang_wild_statement_enum: - sec = s->wild_statement.section_list; for (sec = s->wild_statement.section_list; sec != NULL; sec = sec->next) { @@ -3565,8 +3549,11 @@ update_wild_statements (lang_statement_union_type *s) break; case lang_output_section_statement_enum: - update_wild_statements - (s->output_section_statement.children.head); + /* Don't sort .init/.fini sections. */ + if (strcmp (s->output_section_statement.name, ".init") != 0 + && strcmp (s->output_section_statement.name, ".fini") != 0) + update_wild_statements + (s->output_section_statement.children.head); break; case lang_group_statement_enum: @@ -3916,34 +3903,62 @@ strip_excluded_output_sections (void) asection *s; for (s = output_section->map_head.s; s != NULL; s = s->map_head.s) - if ((s->flags & SEC_LINKER_CREATED) != 0 - && (s->flags & SEC_EXCLUDE) == 0) + if ((s->flags & SEC_EXCLUDE) == 0 + && ((s->flags & SEC_LINKER_CREATED) != 0 + || link_info.emitrelocations)) { exclude = FALSE; break; } } - /* TODO: Don't just junk map_head.s, turn them into link_orders. */ - output_section->map_head.link_order = NULL; - output_section->map_tail.link_order = NULL; - if (exclude) { /* We don't set bfd_section to NULL since bfd_section of the removed output section statement may still be used. */ - if (!os->section_relative_symbol - && !os->update_dot_tree) + if (!os->update_dot) os->ignored = TRUE; output_section->flags |= SEC_EXCLUDE; bfd_section_list_remove (link_info.output_bfd, output_section); link_info.output_bfd->section_count--; } } +} + +/* Called from ldwrite to clear out asection.map_head and + asection.map_tail for use as link_orders in ldwrite. + FIXME: Except for sh64elf.em which starts creating link_orders in + its after_allocation routine so needs to call it early. */ + +void +lang_clear_os_map (void) +{ + lang_output_section_statement_type *os; + + if (map_head_is_link_order) + return; + + for (os = &lang_output_section_statement.head->output_section_statement; + os != NULL; + os = os->next) + { + asection *output_section; + + if (os->constraint < 0) + continue; + + output_section = os->bfd_section; + if (output_section == NULL) + continue; + + /* TODO: Don't just junk map_head.s, turn them into link_orders. */ + output_section->map_head.link_order = NULL; + output_section->map_tail.link_order = NULL; + } /* Stop future calls to lang_add_section from messing with map_head and map_tail link_order fields. */ - stripped_excluded_sections = TRUE; + map_head_is_link_order = TRUE; } static void @@ -3990,63 +4005,12 @@ print_output_section_statement output_section_statement); } -/* Scan for the use of the destination in the right hand side - of an expression. In such cases we will not compute the - 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) -{ - if (rhs == NULL || dst == NULL) - return FALSE; - - switch (rhs->type.node_class) - { - case etree_binary: - return (scan_for_self_assignment (dst, rhs->binary.lhs) - || scan_for_self_assignment (dst, rhs->binary.rhs)); - - case etree_trinary: - return (scan_for_self_assignment (dst, rhs->trinary.lhs) - || scan_for_self_assignment (dst, rhs->trinary.rhs)); - - case etree_assign: - case etree_provided: - case etree_provide: - if (strcmp (dst, rhs->assign.dst) == 0) - return TRUE; - return scan_for_self_assignment (dst, rhs->assign.src); - - case etree_unary: - return scan_for_self_assignment (dst, rhs->unary.child); - - case etree_value: - if (rhs->value.str) - return strcmp (dst, rhs->value.str) == 0; - return FALSE; - - case etree_name: - if (rhs->name.name) - return strcmp (dst, rhs->name.name) == 0; - return FALSE; - - default: - break; - } - - return FALSE; -} - - static void print_assignment (lang_assignment_statement_type *assignment, lang_output_section_statement_type *output_section) { unsigned int i; bfd_boolean is_dot; - bfd_boolean computation_is_valid = TRUE; etree_type *tree; asection *osec; @@ -4057,26 +4021,33 @@ print_assignment (lang_assignment_statement_type *assignment, { is_dot = FALSE; tree = assignment->exp->assert_s.child; - computation_is_valid = TRUE; } else { const char *dst = assignment->exp->assign.dst; is_dot = (dst[0] == '.' && dst[1] == 0); + if (!is_dot) + expld.assign_name = dst; tree = assignment->exp->assign.src; - computation_is_valid = is_dot || !scan_for_self_assignment (dst, tree); } osec = output_section->bfd_section; if (osec == NULL) osec = bfd_abs_section_ptr; - exp_fold_tree (tree, osec, &print_dot); + + if (assignment->exp->type.node_class != etree_provide) + exp_fold_tree (tree, osec, &print_dot); + else + expld.result.valid_p = FALSE; + if (expld.result.valid_p) { bfd_vma value; - if (computation_is_valid) + if (assignment->exp->type.node_class == etree_assert + || is_dot + || expld.assign_name != NULL) { value = expld.result.value; @@ -4107,11 +4078,15 @@ print_assignment (lang_assignment_statement_type *assignment, } else { - minfo ("*undef* "); + if (assignment->exp->type.node_class == etree_provide) + minfo ("[!provide]"); + else + minfo ("*undef* "); #ifdef BFD64 minfo (" "); #endif } + expld.assign_name = NULL; minfo (" "); exp_print_tree (assignment->exp); @@ -4171,8 +4146,8 @@ hash_entry_addr_cmp (const void *a, const void *b) static void print_all_symbols (asection *sec) { - struct fat_user_section_struct *ud = - (struct fat_user_section_struct *) get_userdata (sec); + input_section_userdata_type *ud + = (input_section_userdata_type *) get_userdata (sec); struct map_symbol_def *def; struct bfd_link_hash_entry **entries; unsigned int i; @@ -4190,7 +4165,7 @@ print_all_symbols (asection *sec) entries[i] = def->entry; qsort (entries, ud->map_symbol_def_count, sizeof (*entries), - hash_entry_addr_cmp); + hash_entry_addr_cmp); /* Print the symbols. */ for (i = 0; i < ud->map_symbol_def_count; i++) @@ -4622,7 +4597,7 @@ insert_pad (lang_statement_union_type **ptr, { /* Make a new padding statement, linked into existing chain. */ pad = (lang_statement_union_type *) - stat_alloc (sizeof (lang_padding_statement_type)); + stat_alloc (sizeof (lang_padding_statement_type)); pad->header.next = *ptr; *ptr = pad; pad->header.type = lang_padding_statement_enum; @@ -4633,7 +4608,8 @@ insert_pad (lang_statement_union_type **ptr, } pad->padding_statement.output_offset = dot - output_section->vma; pad->padding_statement.size = alignment_needed; - output_section->size += alignment_needed; + output_section->size = TO_SIZE (dot + TO_ADDR (alignment_needed) + - output_section->vma); } /* Work out how much this section will move the dot point. */ @@ -4647,12 +4623,15 @@ size_input_section { lang_input_section_type *is = &((*this_ptr)->input_section); asection *i = is->section; + asection *o = output_section_statement->bfd_section; - if (!((lang_input_statement_type *) i->owner->usrdata)->just_syms_flag - && (i->flags & SEC_EXCLUDE) == 0) + if (i->sec_info_type == SEC_INFO_TYPE_JUST_SYMS) + i->output_offset = i->vma - o->vma; + else if ((i->flags & SEC_EXCLUDE) != 0) + i->output_offset = dot - o->vma; + else { bfd_size_type alignment_needed; - asection *o; /* Align this section first to the input sections requirement, then to the output section's requirement. If this alignment @@ -4662,7 +4641,6 @@ size_input_section if (output_section_statement->subsection_alignment != -1) i->alignment_power = output_section_statement->subsection_alignment; - o = output_section_statement->bfd_section; if (o->alignment_power < i->alignment_power) o->alignment_power = i->alignment_power; @@ -4675,17 +4653,12 @@ size_input_section } /* Remember where in the output section this input section goes. */ - i->output_offset = dot - o->vma; /* Mark how big the output section must be to contain this now. */ dot += TO_ADDR (i->size); o->size = TO_SIZE (dot - o->vma); } - else - { - i->output_offset = i->vma - output_section_statement->bfd_section->vma; - } return dot; } @@ -4860,7 +4833,7 @@ lang_size_sections_1 { case lang_output_section_statement_enum: { - bfd_vma newdot, after; + bfd_vma newdot, after, dotdelta; lang_output_section_statement_type *os; lang_memory_region_type *r; int section_alignment = 0; @@ -4926,6 +4899,7 @@ lang_size_sections_1 } newdot = dot; + dotdelta = 0; if (bfd_is_abs_section (os->bfd_section)) { /* No matter what happens, an abs section starts at zero. */ @@ -4994,13 +4968,14 @@ lang_size_sections_1 bfd_vma savedot = newdot; newdot = align_power (newdot, section_alignment); - if (newdot != savedot + dotdelta = newdot - savedot; + if (dotdelta != 0 && (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)); + os->name, (unsigned long) dotdelta); } bfd_set_section_vma (0, os->bfd_section, newdot); @@ -5048,8 +5023,20 @@ lang_size_sections_1 { bfd_vma lma = os->lma_region->current; - if (section_alignment > 0) - lma = align_power (lma, section_alignment); + if (os->align_lma_with_input) + lma += dotdelta; + else + { + /* When LMA_REGION is the same as REGION, align the LMA + as we did for the VMA, possibly including alignment + from the bfd section. If a different region, then + only align according to the value in the output + statement. */ + if (os->lma_region != os->region) + section_alignment = os->section_alignment; + if (section_alignment > 0) + lma = align_power (lma, section_alignment); + } os->bfd_section->lma = lma; } else if (r->last_os != NULL @@ -5125,7 +5112,10 @@ lang_size_sections_1 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); + dotdelta = TO_ADDR (os->bfd_section->size); + else + dotdelta = 0; + dot += dotdelta; if (os->update_dot_tree != 0) exp_fold_tree (os->update_dot_tree, bfd_abs_section_ptr, &dot); @@ -5145,10 +5135,10 @@ lang_size_sections_1 os->bfd_section->vma); if (os->lma_region != NULL && os->lma_region != os->region - && (os->bfd_section->flags & SEC_LOAD)) + && ((os->bfd_section->flags & SEC_LOAD) + || os->align_lma_with_input)) { - os->lma_region->current - = os->bfd_section->lma + TO_ADDR (os->bfd_section->size); + os->lma_region->current = os->bfd_section->lma + dotdelta; if (check_regions) os_region_check (os, os->lma_region, NULL, @@ -5198,7 +5188,9 @@ lang_size_sections_1 if (size < TO_SIZE ((unsigned) 1)) size = TO_SIZE ((unsigned) 1); dot += TO_ADDR (size); - output_section_statement->bfd_section->size += size; + output_section_statement->bfd_section->size + = TO_SIZE (dot - output_section_statement->bfd_section->vma); + } break; @@ -5212,7 +5204,8 @@ lang_size_sections_1 output_section_statement->bfd_section; size = bfd_get_reloc_size (s->reloc_statement.howto); dot += TO_ADDR (size); - output_section_statement->bfd_section->size += size; + output_section_statement->bfd_section->size + = TO_SIZE (dot - output_section_statement->bfd_section->vma); } break; @@ -5246,7 +5239,7 @@ lang_size_sections_1 *relax = TRUE; } dot = size_input_section (prev, output_section_statement, - output_section_statement->fill, dot); + fill, dot); } break; @@ -5291,12 +5284,12 @@ lang_size_sections_1 } expld.dataseg.relro = exp_dataseg_relro_none; - /* This symbol is relative to this section. */ + /* This symbol may be 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; + output_section_statement->update_dot = 1; if (!output_section_statement->ignored) { @@ -5396,6 +5389,12 @@ ldlang_override_segment_assignment (struct bfd_link_info * info ATTRIBUTE_UNUSED if (current_section == NULL || previous_section == NULL) return new_segment; + /* If this flag is set, the target never wants code and non-code + sections comingled in the same segment. */ + if (config.separate_code + && ((current_section->flags ^ previous_section->flags) & SEC_CODE)) + return TRUE; + /* 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 @@ -5432,57 +5431,51 @@ lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions) if (expld.dataseg.phase == exp_dataseg_end_seen && link_info.relro && expld.dataseg.relro_end) { - /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END pair was seen, try - to put expld.dataseg.relro on a (common) page boundary. */ - bfd_vma min_base, old_base, relro_end, maxpage; + bfd_vma initial_base, relro_end, desired_end; + asection *sec; - expld.dataseg.phase = exp_dataseg_relro_adjust; - maxpage = expld.dataseg.maxpagesize; - /* MIN_BASE is the absolute minimum address we are allowed to start the - read-write segment (byte before will be mapped read-only). */ - min_base = (expld.dataseg.min_base + maxpage - 1) & ~(maxpage - 1); - /* OLD_BASE is the address for a feasible minimum address which will - still not cause a data overlap inside MAXPAGE causing file offset skip - by MAXPAGE. */ - old_base = expld.dataseg.base; - expld.dataseg.base += (-expld.dataseg.relro_end - & (expld.dataseg.pagesize - 1)); /* Compute the expected PT_GNU_RELRO segment end. */ relro_end = ((expld.dataseg.relro_end + expld.dataseg.pagesize - 1) & ~(expld.dataseg.pagesize - 1)); - if (min_base + maxpage < expld.dataseg.base) - { - expld.dataseg.base -= maxpage; - relro_end -= maxpage; - } + + /* Adjust by the offset arg of DATA_SEGMENT_RELRO_END. */ + desired_end = relro_end - expld.dataseg.relro_offset; + + /* For sections in the relro segment.. */ + for (sec = link_info.output_bfd->section_last; sec; sec = sec->prev) + if (!IGNORE_SECTION (sec) + && sec->vma >= expld.dataseg.base + && sec->vma < expld.dataseg.relro_end - expld.dataseg.relro_offset) + { + /* Where do we want to put this section so that it ends as + desired? */ + bfd_vma start = sec->vma; + bfd_vma end = start + sec->size; + bfd_vma bump = desired_end - end; + /* We'd like to increase START by BUMP, but we must heed + alignment so the increase might be less than optimum. */ + start += bump & ~(((bfd_vma) 1 << sec->alignment_power) - 1); + /* This is now the desired end for the previous section. */ + desired_end = start; + } + + expld.dataseg.phase = exp_dataseg_relro_adjust; + ASSERT (desired_end >= expld.dataseg.base); + initial_base = expld.dataseg.base; + expld.dataseg.base = desired_end; lang_reset_memory_regions (); one_lang_size_sections_pass (relax, check_regions); + if (expld.dataseg.relro_end > relro_end) { - /* The alignment of sections between DATA_SEGMENT_ALIGN - and DATA_SEGMENT_RELRO_END caused huge padding to be - inserted at DATA_SEGMENT_RELRO_END. Try to start a bit lower so - that the section alignments will fit in. */ - asection *sec; - unsigned int max_alignment_power = 0; - - /* Find maximum alignment power of sections between - DATA_SEGMENT_ALIGN and DATA_SEGMENT_RELRO_END. */ - for (sec = link_info.output_bfd->sections; sec; sec = sec->next) - if (sec->vma >= expld.dataseg.base - && sec->vma < expld.dataseg.relro_end - && sec->alignment_power > max_alignment_power) - max_alignment_power = sec->alignment_power; - - if (((bfd_vma) 1 << max_alignment_power) < expld.dataseg.pagesize) - { - if (expld.dataseg.base - (1 << max_alignment_power) < old_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); - } + /* Assignments to dot, or to output section address in a + user script have increased padding over the original. + Revert. */ + expld.dataseg.base = initial_base; + lang_reset_memory_regions (); + one_lang_size_sections_pass (relax, check_regions); } + link_info.relro_start = expld.dataseg.base; link_info.relro_end = expld.dataseg.relro_end; } @@ -5510,13 +5503,18 @@ lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions) expld.dataseg.phase = exp_dataseg_done; } +static lang_output_section_statement_type *current_section; +static lang_assignment_statement_type *current_assign; +static bfd_boolean prefer_next_section; + /* 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 *current_os, fill_type *fill, - bfd_vma dot) + bfd_vma dot, + bfd_boolean *found_end) { for (; s != NULL; s = s->header.next) { @@ -5524,7 +5522,7 @@ lang_do_assignments_1 (lang_statement_union_type *s, { case lang_constructors_statement_enum: dot = lang_do_assignments_1 (constructor_list.head, - current_os, fill, dot); + current_os, fill, dot, found_end); break; case lang_output_section_statement_enum: @@ -5532,11 +5530,18 @@ lang_do_assignments_1 (lang_statement_union_type *s, lang_output_section_statement_type *os; os = &(s->output_section_statement); + os->after_end = *found_end; if (os->bfd_section != NULL && !os->ignored) { + if ((os->bfd_section->flags & SEC_ALLOC) != 0) + { + current_section = os; + prefer_next_section = FALSE; + } dot = os->bfd_section->vma; - lang_do_assignments_1 (os->children.head, os, os->fill, dot); + lang_do_assignments_1 (os->children.head, + os, os->fill, dot, found_end); /* .tbss sections effectively have zero size. */ if ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0 @@ -5553,7 +5558,7 @@ lang_do_assignments_1 (lang_statement_union_type *s, case lang_wild_statement_enum: dot = lang_do_assignments_1 (s->wild_statement.children.head, - current_os, fill, dot); + current_os, fill, dot, found_end); break; case lang_object_symbols_statement_enum: @@ -5624,6 +5629,19 @@ lang_do_assignments_1 (lang_statement_union_type *s, break; case lang_assignment_statement_enum: + current_assign = &s->assignment_statement; + if (current_assign->exp->type.node_class != etree_assert) + { + const char *p = current_assign->exp->assign.dst; + + if (current_os == abs_output_section && p[0] == '.' && p[1] == 0) + prefer_next_section = TRUE; + + while (*p == '_') + ++p; + if (strcmp (p, "end") == 0) + *found_end = TRUE; + } exp_fold_tree (s->assignment_statement.exp, current_os->bfd_section, &dot); @@ -5635,7 +5653,7 @@ lang_do_assignments_1 (lang_statement_union_type *s, case lang_group_statement_enum: dot = lang_do_assignments_1 (s->group_statement.children.head, - current_os, fill, dot); + current_os, fill, dot, found_end); break; case lang_insert_statement_enum: @@ -5655,9 +5673,89 @@ lang_do_assignments_1 (lang_statement_union_type *s, void lang_do_assignments (lang_phase_type phase) { + bfd_boolean found_end = FALSE; + + current_section = NULL; + prefer_next_section = FALSE; expld.phase = phase; lang_statement_iteration++; - lang_do_assignments_1 (statement_list.head, abs_output_section, NULL, 0); + lang_do_assignments_1 (statement_list.head, + abs_output_section, NULL, 0, &found_end); +} + +/* For an assignment statement outside of an output section statement, + choose the best of neighbouring output sections to use for values + of "dot". */ + +asection * +section_for_dot (void) +{ + asection *s; + + /* Assignments belong to the previous output section, unless there + has been an assignment to "dot", in which case following + assignments belong to the next output section. (The assumption + is that an assignment to "dot" is setting up the address for the + next output section.) Except that past the assignment to "_end" + we always associate with the previous section. This exception is + for targets like SH that define an alloc .stack or other + weirdness after non-alloc sections. */ + if (current_section == NULL || prefer_next_section) + { + lang_statement_union_type *stmt; + lang_output_section_statement_type *os; + + for (stmt = (lang_statement_union_type *) current_assign; + stmt != NULL; + stmt = stmt->header.next) + if (stmt->header.type == lang_output_section_statement_enum) + break; + + os = &stmt->output_section_statement; + while (os != NULL + && !os->after_end + && (os->bfd_section == NULL + || (os->bfd_section->flags & SEC_EXCLUDE) != 0 + || bfd_section_removed_from_list (link_info.output_bfd, + os->bfd_section))) + os = os->next; + + if (current_section == NULL || os == NULL || !os->after_end) + { + if (os != NULL) + s = os->bfd_section; + else + s = link_info.output_bfd->section_last; + while (s != NULL + && ((s->flags & SEC_ALLOC) == 0 + || (s->flags & SEC_THREAD_LOCAL) != 0)) + s = s->prev; + if (s != NULL) + return s; + + return bfd_abs_section_ptr; + } + } + + s = current_section->bfd_section; + + /* The section may have been stripped. */ + while (s != NULL + && ((s->flags & SEC_EXCLUDE) != 0 + || (s->flags & SEC_ALLOC) == 0 + || (s->flags & SEC_THREAD_LOCAL) != 0 + || bfd_section_removed_from_list (link_info.output_bfd, s))) + s = s->prev; + if (s == NULL) + s = link_info.output_bfd->sections; + while (s != NULL + && ((s->flags & SEC_ALLOC) == 0 + || (s->flags & SEC_THREAD_LOCAL) != 0)) + s = s->next; + if (s != NULL) + return s; + + return bfd_abs_section_ptr; } /* Fix any .startof. or .sizeof. symbols. When the assemblers see the @@ -5689,8 +5787,8 @@ lang_set_startof (void) if (h != NULL && h->type == bfd_link_hash_undefined) { h->type = bfd_link_hash_defined; - h->u.def.value = bfd_get_section_vma (link_info.output_bfd, s); - h->u.def.section = bfd_abs_section_ptr; + h->u.def.value = 0; + h->u.def.section = s; } sprintf (buf, ".sizeof.%s", secname); @@ -5790,9 +5888,6 @@ lang_end (void) } } } - - /* Don't bfd_hash_table_free (&lang_definedness_table); - map file output may result in a call of lang_track_definedness. */ } /* This is a small function used when we want to ignore errors from @@ -5819,7 +5914,7 @@ lang_check (void) { #ifdef ENABLE_PLUGINS /* Don't check format of files claimed by plugin. */ - if (file->input_statement.claimed) + if (file->input_statement.flags.claimed) continue; #endif /* ENABLE_PLUGINS */ input_bfd = file->input_statement.the_bfd; @@ -5912,7 +6007,7 @@ lang_common (void) for (power = 0; power <= 4; power++) bfd_link_hash_traverse (link_info.hash, lang_one_common, &power); - power = UINT_MAX; + power = (unsigned int) -1; bfd_link_hash_traverse (link_info.hash, lang_one_common, &power); } } @@ -6022,7 +6117,7 @@ lang_place_orphans (void) /* This section of the file is not attached, root around for a sensible place for it to go. */ - if (file->just_syms_flag) + if (file->flags.just_syms) bfd_link_just_syms (file->the_bfd, s, &link_info); else if ((s->flags & SEC_EXCLUDE) != 0) s->output_section = bfd_abs_section_ptr; @@ -6039,7 +6134,7 @@ lang_place_orphans (void) = lang_output_section_statement_lookup (".bss", 0, TRUE); lang_add_section (&default_common_section->children, s, - default_common_section); + NULL, default_common_section); } } else @@ -6061,7 +6156,7 @@ lang_place_orphans (void) && (link_info.relocatable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)) os->addr_tree = exp_intop (0); - lang_add_section (&os->children, s, os); + lang_add_section (&os->children, s, NULL, os); } } } @@ -6075,10 +6170,18 @@ lang_set_flags (lang_memory_region_type *ptr, const char *flags, int invert) flagword *ptr_flags; ptr_flags = invert ? &ptr->not_flags : &ptr->flags; + while (*flags) { switch (*flags) { + /* PR 17900: An exclamation mark in the attributes reverses + the sense of any of the attributes that follow. */ + case '!': + invert = ! invert; + ptr_flags = invert ? &ptr->not_flags : &ptr->flags; + break; + case 'A': case 'a': *ptr_flags |= SEC_ALLOC; break; @@ -6101,7 +6204,7 @@ lang_set_flags (lang_memory_region_type *ptr, const char *flags, int invert) break; default: - einfo (_("%P%F: invalid syntax in flags\n")); + einfo (_("%P%F: invalid character %c (%d) in flags\n"), * flags, * flags); break; } flags++; @@ -6144,11 +6247,11 @@ ldlang_add_file (lang_input_statement_type *entry) /* The BFD linker needs to have a list of all input BFDs involved in a link. */ - ASSERT (entry->the_bfd->link_next == NULL); + ASSERT (entry->the_bfd->link.next == NULL); ASSERT (entry->the_bfd != link_info.output_bfd); *link_info.input_bfds_tail = entry->the_bfd; - link_info.input_bfds_tail = &entry->the_bfd->link_next; + 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); @@ -6176,8 +6279,6 @@ lang_add_output (const char *name, int from_script) } } -static lang_output_section_statement_type *current_section; - static int topower (int x) { @@ -6204,7 +6305,8 @@ lang_enter_output_section_statement (const char *output_section_statement_name, etree_type *align, etree_type *subalign, etree_type *ebase, - int constraint) + int constraint, + int align_with_input) { lang_output_section_statement_type *os; @@ -6226,6 +6328,10 @@ lang_enter_output_section_statement (const char *output_section_statement_name, /* Make next things chain into subchain of this. */ push_stat_ptr (&os->children); + os->align_lma_with_input = align_with_input == ALIGN_WITH_INPUT; + if (os->align_lma_with_input && align != NULL) + einfo (_("%F%P:%S: error: align with input and explicit align specified\n"), NULL); + os->subsection_alignment = topower (exp_get_value_int (subalign, -1, "subsection alignment")); os->section_alignment = @@ -6242,7 +6348,6 @@ lang_final (void) new_stmt = new_stat (lang_output_statement, stat_ptr); new_stmt->name = output_filename; - } /* Reset the current counters in the regions. */ @@ -6282,6 +6387,7 @@ static void gc_section_callback (lang_wild_statement_type *ptr, struct wildcard_list *sec ATTRIBUTE_UNUSED, asection *section, + struct flag_info *sflag_info ATTRIBUTE_UNUSED, lang_input_statement_type *file ATTRIBUTE_UNUSED, void *data ATTRIBUTE_UNUSED) { @@ -6334,7 +6440,7 @@ lang_gc_sections (void) { asection *sec; #ifdef ENABLE_PLUGINS - if (f->claimed) + if (f->flags.claimed) continue; #endif for (sec = f->the_bfd->sections; sec != NULL; sec = sec->next) @@ -6353,6 +6459,7 @@ static void find_relro_section_callback (lang_wild_statement_type *ptr ATTRIBUTE_UNUSED, struct wildcard_list *sec ATTRIBUTE_UNUSED, asection *section, + struct flag_info *sflag_info ATTRIBUTE_UNUSED, lang_input_statement_type *file ATTRIBUTE_UNUSED, void *data) { @@ -6499,8 +6606,8 @@ find_replacements_insert_point (void) claim1 != NULL; claim1 = &claim1->next->input_statement) { - if (claim1->claimed) - return claim1->claim_archive ? lastobject : claim1; + if (claim1->flags.claimed) + return claim1->flags.claim_archive ? lastobject : claim1; /* Update lastobject if this is a real object file. */ if (claim1->the_bfd && (claim1->the_bfd->my_archive == NULL)) lastobject = claim1; @@ -6570,7 +6677,7 @@ lang_process (void) open_input_bfds (statement_list.head, OPEN_BFD_NORMAL); #ifdef ENABLE_PLUGINS - if (plugin_active_plugins_p ()) + if (link_info.lto_plugin_active) { lang_statement_list_type added; lang_statement_list_type files, inputfiles; @@ -6589,7 +6696,6 @@ lang_process (void) einfo (_("%P%F: %s: plugin reported error after all symbols read\n"), plugin_error_plugin ()); /* Open any newly added files, updating the file chains. */ - link_info.loading_lto_outputs = TRUE; open_input_bfds (*added.tail, OPEN_BFD_NORMAL); /* Restore the global list pointer now they have all been added. */ lang_list_remove_tail (stat_ptr, &added); @@ -6630,8 +6736,26 @@ lang_process (void) link_info.gc_sym_list = &entry_symbol; if (entry_symbol.name == NULL) link_info.gc_sym_list = ldlang_undef_chain_list_head; + if (link_info.init_function != NULL) + { + struct bfd_sym_chain *sym + = (struct bfd_sym_chain *) stat_alloc (sizeof (*sym)); + sym->next = link_info.gc_sym_list; + sym->name = link_info.init_function; + link_info.gc_sym_list = sym; + } + if (link_info.fini_function != NULL) + { + struct bfd_sym_chain *sym + = (struct bfd_sym_chain *) stat_alloc (sizeof (*sym)); + sym->next = link_info.gc_sym_list; + sym->name = link_info.fini_function; + link_info.gc_sym_list = sym; + } ldemul_after_open (); + if (config.map_file != NULL) + lang_print_asneeded (); bfd_section_already_linked_table_free (); @@ -6653,14 +6777,16 @@ lang_process (void) /* PR 13683: We must rerun the assignments prior to running garbage collection in order to make sure that all symbol aliases are resolved. */ lang_do_assignments (lang_mark_phase_enum); - expld.phase = lang_first_phase_enum; - /* Remove unreferenced sections if asked to. */ - lang_gc_sections (); + lang_do_memory_regions(); + expld.phase = lang_first_phase_enum; /* Size up the common data. */ lang_common (); + /* Remove unreferenced sections if asked to. */ + lang_gc_sections (); + /* Update wild statements. */ update_wild_statements (statement_list.head); @@ -6728,6 +6854,9 @@ lang_process (void) if (command_line.check_section_addresses) lang_check_section_addresses (); + /* Check any required symbols are known. */ + ldlang_check_require_defined_symbols (); + lang_end (); } @@ -6911,7 +7040,7 @@ lang_startup (const char *name) } first_file->filename = name; first_file->local_sym_name = name; - first_file->real = TRUE; + first_file->flags.real = TRUE; } void @@ -6983,69 +7112,6 @@ lang_leave_output_section_statement (fill_type *fill, const char *memspec, pop_stat_ptr (); } -/* Create an absolute symbol with the given name with the value of the - address of first byte of the section named. - - If the symbol already exists, then do nothing. */ - -void -lang_abs_symbol_at_beginning_of (const char *secname, const char *name) -{ - struct bfd_link_hash_entry *h; - - h = bfd_link_hash_lookup (link_info.hash, name, TRUE, TRUE, TRUE); - if (h == NULL) - einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n")); - - if (h->type == bfd_link_hash_new - || h->type == bfd_link_hash_undefined) - { - asection *sec; - - h->type = bfd_link_hash_defined; - - sec = bfd_get_section_by_name (link_info.output_bfd, secname); - if (sec == NULL) - h->u.def.value = 0; - else - h->u.def.value = bfd_get_section_vma (link_info.output_bfd, sec); - - h->u.def.section = bfd_abs_section_ptr; - } -} - -/* Create an absolute symbol with the given name with the value of the - address of the first byte after the end of the section named. - - If the symbol already exists, then do nothing. */ - -void -lang_abs_symbol_at_end_of (const char *secname, const char *name) -{ - struct bfd_link_hash_entry *h; - - h = bfd_link_hash_lookup (link_info.hash, name, TRUE, TRUE, TRUE); - if (h == NULL) - einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n")); - - if (h->type == bfd_link_hash_new - || h->type == bfd_link_hash_undefined) - { - asection *sec; - - h->type = bfd_link_hash_defined; - - sec = bfd_get_section_by_name (link_info.output_bfd, secname); - if (sec == NULL) - h->u.def.value = 0; - else - h->u.def.value = (bfd_get_section_vma (link_info.output_bfd, sec) - + TO_ADDR (sec->size)); - - h->u.def.section = bfd_abs_section_ptr; - } -} - void lang_statement_append (lang_statement_list_type *list, lang_statement_union_type *element, @@ -7230,7 +7296,7 @@ lang_record_phdrs (void) { alc *= 2; secs = (asection **) xrealloc (secs, - alc * sizeof (asection *)); + alc * sizeof (asection *)); } secs[c] = os->bfd_section; ++c; @@ -7337,7 +7403,7 @@ lang_enter_overlay_section (const char *name) etree_type *size; lang_enter_output_section_statement (name, overlay_vma, overlay_section, - 0, overlay_subalign, 0, 0); + 0, overlay_subalign, 0, 0, 0); /* If this is the first section, then base the VMA of future sections on this one. This will work correctly even if `.' is @@ -7431,8 +7497,11 @@ lang_leave_overlay (etree_type *lma_expr, /* After setting the size of the last section, set '.' to end of the overlay region. */ if (overlay_list != NULL) - overlay_list->os->update_dot_tree - = exp_assign (".", exp_binop ('+', overlay_vma, overlay_max)); + { + overlay_list->os->update_dot = 1; + overlay_list->os->update_dot_tree + = exp_assign (".", exp_binop ('+', overlay_vma, overlay_max), FALSE); + } l = overlay_list; while (l != NULL) @@ -7529,7 +7598,7 @@ lang_vers_match (struct bfd_elf_version_expr_head *head, { e.pattern = c_sym; expr = (struct bfd_elf_version_expr *) - htab_find ((htab_t) head->htab, &e); + htab_find ((htab_t) head->htab, &e); while (expr && strcmp (expr->pattern, c_sym) == 0) if (expr->mask == BFD_ELF_VERSION_C_TYPE) goto out_ret; @@ -7542,7 +7611,7 @@ lang_vers_match (struct bfd_elf_version_expr_head *head, { e.pattern = cxx_sym; expr = (struct bfd_elf_version_expr *) - htab_find ((htab_t) head->htab, &e); + htab_find ((htab_t) head->htab, &e); while (expr && strcmp (expr->pattern, cxx_sym) == 0) if (expr->mask == BFD_ELF_VERSION_CXX_TYPE) goto out_ret; @@ -7555,7 +7624,7 @@ lang_vers_match (struct bfd_elf_version_expr_head *head, { e.pattern = java_sym; expr = (struct bfd_elf_version_expr *) - htab_find ((htab_t) head->htab, &e); + htab_find ((htab_t) head->htab, &e); while (expr && strcmp (expr->pattern, java_sym) == 0) if (expr->mask == BFD_ELF_VERSION_JAVA_TYPE) goto out_ret; @@ -7852,7 +7921,7 @@ lang_register_vers_node (const char *name, if (t->locals.htab && e1->literal) { e2 = (struct bfd_elf_version_expr *) - htab_find ((htab_t) t->locals.htab, e1); + htab_find ((htab_t) t->locals.htab, e1); while (e2 && strcmp (e1->pattern, e2->pattern) == 0) { if (e1->mask == e2->mask) @@ -7879,7 +7948,7 @@ lang_register_vers_node (const char *name, if (t->globals.htab && e1->literal) { e2 = (struct bfd_elf_version_expr *) - htab_find ((htab_t) t->globals.htab, e1); + htab_find ((htab_t) t->globals.htab, e1); while (e2 && strcmp (e1->pattern, e2->pattern) == 0) { if (e1->mask == e2->mask) @@ -7976,6 +8045,37 @@ lang_do_version_exports_section (void) lang_new_vers_node (greg, lreg), NULL); } +/* Evaluate LENGTH and ORIGIN parts of MEMORY spec */ + +static void +lang_do_memory_regions (void) +{ + lang_memory_region_type *r = lang_memory_region_list; + + for (; r != NULL; r = r->next) + { + if (r->origin_exp) + { + exp_fold_tree_no_dot (r->origin_exp); + if (expld.result.valid_p) + { + r->origin = expld.result.value; + r->current = r->origin; + } + else + einfo (_("%F%P: invalid origin for memory region %s\n"), r->name_list.name); + } + if (r->length_exp) + { + exp_fold_tree_no_dot (r->length_exp); + if (expld.result.valid_p) + r->length = expld.result.value; + else + einfo (_("%F%P: invalid length for memory region %s\n"), r->name_list.name); + } + } +} + void lang_add_unique (const char *name) { @@ -8085,3 +8185,41 @@ lang_ld_feature (char *str) p = q; } } + +/* Pretty print memory amount. */ + +static void +lang_print_memory_size (bfd_vma sz) +{ + if ((sz & 0x3fffffff) == 0) + printf ("%10" BFD_VMA_FMT "u GB", sz >> 30); + else if ((sz & 0xfffff) == 0) + printf ("%10" BFD_VMA_FMT "u MB", sz >> 20); + else if ((sz & 0x3ff) == 0) + printf ("%10" BFD_VMA_FMT "u KB", sz >> 10); + else + printf (" %10" BFD_VMA_FMT "u B", sz); +} + +/* Implement --print-memory-usage: disply per region memory usage. */ + +void +lang_print_memory_usage (void) +{ + lang_memory_region_type *r; + + printf ("Memory region Used Size Region Size %%age Used\n"); + for (r = lang_memory_region_list; r->next != NULL; r = r->next) + { + bfd_vma used_length = r->current - r->origin; + double percent; + + printf ("%16s: ",r->name_list.name); + lang_print_memory_size (used_length); + lang_print_memory_size ((bfd_vma) r->length); + + percent = used_length * 100.0 / r->length; + + printf (" %6.2f%%\n", percent); + } +}