X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=ld%2Fldlang.c;h=0d6419d91ddaadc7d5449bd7ddcb77f8fc35d7d3;hb=00e52e5376c7ec604a739e6242e6be36221162d7;hp=899f71086d897af876bfa03b8e48365122e03a57;hpb=18cd5bce47dc4a33dd1d8e3036b99d2fa7e3234f;p=deliverable%2Fbinutils-gdb.git diff --git a/ld/ldlang.c b/ld/ldlang.c index 899f71086d..0d6419d91d 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -1,5 +1,5 @@ /* Linker command language support. - Copyright (C) 1991-2014 Free Software Foundation, Inc. + Copyright (C) 1991-2015 Free Software Foundation, Inc. This file is part of the GNU Binutils. @@ -64,7 +64,6 @@ 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; @@ -73,8 +72,6 @@ static struct asneeded_minfo *asneeded_list_head; /* Forward declarations. */ static void exp_init_os (etree_type *); 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 *, @@ -88,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; @@ -1118,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); } @@ -1221,14 +1239,6 @@ lang_init (void) abs_output_section->bfd_section = bfd_abs_section_ptr; - /* 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), - 13)) - einfo (_("%P%F: can not create hash table: %E\n")); - asneeded_list_head = NULL; asneeded_list_tail = &asneeded_list_head; } @@ -1236,7 +1246,6 @@ lang_init (void) void lang_finish (void) { - bfd_hash_table_free (&lang_definedness_table); output_section_statement_table_free (); } @@ -1297,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; @@ -2411,8 +2422,7 @@ lang_add_section (lang_statement_list_type *ptr, section->output_section = output->bfd_section; - if (!link_info.relocatable - && !map_head_is_link_order) + if (!map_head_is_link_order) { asection *s = output->bfd_section->map_tail.s; output->bfd_section->map_tail.s = section; @@ -3346,65 +3356,6 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode) einfo ("%F"); } -/* 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->by_object = 0; - ret->by_script = 0; - ret->iteration = 0; - return &ret->root; -} - -/* 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. */ - -struct lang_definedness_hash_entry * -lang_symbol_defined (const char *name) -{ - return ((struct lang_definedness_hash_entry *) - bfd_hash_lookup (&lang_definedness_table, name, FALSE, FALSE)); -} - -/* 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, TRUE, FALSE); - - if (defentry == NULL) - einfo (_("%P%F: bfd_hash_lookup failed creating symbol %s\n"), name); - - /* 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->by_object = 1; - - defentry->by_script = 1; - 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 @@ -3462,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 @@ -4035,7 +4035,12 @@ print_assignment (lang_assignment_statement_type *assignment, 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; @@ -4073,7 +4078,10 @@ 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 @@ -5423,55 +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_end on a (common) page boundary. */ - bfd_vma min_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); - 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 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; - - /* 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) - { - /* 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); - } + /* 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; } @@ -6166,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; @@ -6192,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++; @@ -6336,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. */ @@ -6666,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; @@ -6685,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); @@ -6726,6 +6736,22 @@ 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) @@ -6751,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); @@ -6826,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 (); } @@ -8014,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) { @@ -8123,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); + } +}