X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=ld%2Fldlang.c;h=c4da07f5013fb40197796b266bb0aae2254e346d;hb=1903aa3536a887f693088b0404a8dd2214dfb6fc;hp=7851615dac08f632ac4ae8d1f2ad35dbe2524c43;hpb=43a8475ca01b676fb764aaed0c4ed1cc16fc3c87;p=platform%2Fupstream%2Fbinutils.git diff --git a/ld/ldlang.c b/ld/ldlang.c index 7851615..c4da07f 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -1,5 +1,5 @@ /* Linker command language support. - Copyright 1991-2013 Free Software Foundation, Inc. + Copyright (C) 1991-2014 Free Software Foundation, Inc. This file is part of the GNU Binutils. @@ -40,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 */ @@ -56,7 +57,7 @@ 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; @@ -67,10 +68,10 @@ 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 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 *); @@ -106,13 +107,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; +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 @@ -1062,13 +1062,6 @@ new_afile (const char *name, p->flags.whole_archive = input_flags.whole_archive; p->flags.sysrooted = input_flags.sysrooted; - 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: @@ -1082,7 +1075,13 @@ new_afile (const char *name, p->local_sym_name = name; break; case lang_input_file_is_l_enum: - p->filename = name; + 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->flags.maybe_archive = TRUE; p->flags.real = TRUE; @@ -1119,6 +1118,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); } @@ -1222,23 +1241,21 @@ 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. */ + /* The value "13" is ad-hoc, somewhat related to the expected number of + assignments in a linker script. */ if (!bfd_hash_table_init_n (&lang_definedness_table, lang_definedness_newfunc, sizeof (struct lang_definedness_hash_entry), - 3)) + 13)) einfo (_("%P%F: can not create hash table: %E\n")); + + asneeded_list_head = NULL; + asneeded_list_tail = &asneeded_list_head; } void lang_finish (void) { - bfd_link_hash_table_free (link_info.output_bfd, link_info.hash); bfd_hash_table_free (&lang_definedness_table); output_section_statement_table_free (); } @@ -1377,6 +1394,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 @@ -1487,7 +1512,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. */ @@ -1495,21 +1520,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) @@ -1519,115 +1545,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_SMALL_DATA) != 0 - && (sec->flags & SEC_ALLOC) != 0) + 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) { /* .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; } } @@ -1636,11 +1691,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; @@ -1951,6 +2006,43 @@ lang_insert_orphan (asection *s, } 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) { if (flag & SEC_ALLOC) @@ -1974,7 +2066,6 @@ lang_map (void) { lang_memory_region_type *m; bfd_boolean dis_header_printed = FALSE; - bfd *p; LANG_FOR_EACH_INPUT_STATEMENT (file) { @@ -2046,50 +2137,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); @@ -2122,13 +2199,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. */ @@ -2358,8 +2431,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; @@ -2738,9 +2810,7 @@ load_symbols (lang_input_statement_type *entry, break; case bfd_object: -#ifdef ENABLE_PLUGINS if (!entry->flags.reload) -#endif ldlang_add_file (entry); if (trace_files || verbose) info_msg ("%I\n", entry); @@ -3216,38 +3286,33 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode) { 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.flags.whole_archive && s->input_statement.flags.loaded - && s->input_statement.the_bfd != NULL - && bfd_check_format (s->input_statement.the_bfd, - bfd_archive)) - s->input_statement.flags.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.flags.loaded - && s->input_statement.flags.add_DT_NEEDED_for_regular - && s->input_statement.the_bfd != NULL - && ((s->input_statement.the_bfd->flags) & DYNAMIC) != 0 - && plugin_should_reload (s->input_statement.the_bfd)) + && (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.flags.loaded = FALSE; s->input_statement.flags.reload = TRUE; } -#endif os_tail = lang_output_section_statement.tail; lang_list_init (&add); @@ -3300,15 +3365,6 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode) 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 * @@ -3326,28 +3382,22 @@ lang_definedness_newfunc (struct bfd_hash_entry *entry, if (ret == NULL) einfo (_("%P%F: bfd_hash_allocate failed creating symbol %s\n"), name); - ret->iteration = -1; + ret->by_object = 0; + ret->by_script = 0; + ret->iteration = 0; 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. */ +/* Called during processing of linker script script expressions. + For symbols assigned in a linker script, return a struct describing + where the symbol is defined relative to the current expression, + otherwise return NULL. */ -int -lang_symbol_definition_iteration (const char *name) +struct lang_definedness_hash_entry * +lang_symbol_defined (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; + return ((struct lang_definedness_hash_entry *) + bfd_hash_lookup (&lang_definedness_table, name, FALSE, FALSE)); } /* Update the definedness state of NAME. */ @@ -3357,25 +3407,20 @@ 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); + bfd_hash_lookup (&lang_definedness_table, name, TRUE, FALSE); - /* We don't keep track of symbols not tested with DEFINED. */ if (defentry == NULL) - return; + einfo (_("%P%F: bfd_hash_lookup failed creating symbol %s\n"), name); - /* 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 + /* If the symbol was already defined, and not by a script, then it + must be defined by an object file. */ + if (!defentry->by_script + && h->type != bfd_link_hash_undefined && h->type != bfd_link_hash_common - && h->type != bfd_link_hash_new - && defentry->iteration == -1) - return; + && h->type != bfd_link_hash_new) + defentry->by_object = 1; + defentry->by_script = 1; defentry->iteration = lang_statement_iteration; } @@ -3886,10 +3931,6 @@ strip_excluded_output_sections (void) } } - /* 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 @@ -3901,10 +3942,42 @@ strip_excluded_output_sections (void) 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 @@ -3973,7 +4046,8 @@ print_assignment (lang_assignment_statement_type *assignment, const char *dst = assignment->exp->assign.dst; is_dot = (dst[0] == '.' && dst[1] == 0); - expld.assign_name = dst; + if (!is_dot) + expld.assign_name = dst; tree = assignment->exp->assign.src; } @@ -4083,8 +4157,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; @@ -4560,12 +4634,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 (i->sec_info_type != SEC_INFO_TYPE_JUST_SYMS - && (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 @@ -4575,7 +4652,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; @@ -4588,17 +4664,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; } @@ -4773,7 +4844,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; @@ -4839,6 +4910,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. */ @@ -4907,13 +4979,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); @@ -4961,15 +5034,20 @@ lang_size_sections_1 { bfd_vma lma = os->lma_region->current; - /* 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 unless specified otherwise. */ - if (os->lma_region != os->region && !os->align_lma_with_input) - section_alignment = os->section_alignment; - 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 @@ -5045,7 +5123,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); @@ -5065,10 +5146,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, @@ -5169,7 +5250,7 @@ lang_size_sections_1 *relax = TRUE; } dot = size_input_section (prev, output_section_statement, - output_section_statement->fill, dot); + fill, dot); } break; @@ -5362,18 +5443,14 @@ lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions) && 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; + to put expld.dataseg.relro_end on a (common) page boundary. */ + bfd_vma min_base, relro_end, maxpage; 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. */ @@ -5389,9 +5466,9 @@ lang_size_sections (bfd_boolean *relax, bfd_boolean 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. */ + and DATA_SEGMENT_RELRO_END can cause excessive 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; @@ -5405,9 +5482,10 @@ lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions) 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; - /* Properly align base to max_alignment_power. */ + /* Aligning the adjusted base guarantees the padding + between sections won't change. This is better than + simply subtracting 1 << max_alignment_power which is + what we used to do here. */ expld.dataseg.base &= ~((1 << max_alignment_power) - 1); lang_reset_memory_regions (); one_lang_size_sections_pass (relax, check_regions); @@ -5944,7 +6022,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); } } @@ -6176,11 +6254,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); @@ -6669,6 +6747,8 @@ lang_process (void) link_info.gc_sym_list = ldlang_undef_chain_list_head; ldemul_after_open (); + if (config.map_file != NULL) + lang_print_asneeded (); bfd_section_already_linked_table_free ();