X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=ld%2Fldlang.c;h=be9ac36ede430456456d14e97afcb0356cfb515c;hb=3312f67c0957196e41db149343d04ee7b30cdc65;hp=96947da974ba920ee44e5023535ba69962b285a5;hpb=4f3b23b390640efdc36c575dbda2175e61154bc9;p=deliverable%2Fbinutils-gdb.git diff --git a/ld/ldlang.c b/ld/ldlang.c index 96947da974..be9ac36ede 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -1,5 +1,5 @@ /* Linker command language support. - Copyright (C) 1991-2016 Free Software Foundation, Inc. + Copyright (C) 1991-2020 Free Software Foundation, Inc. This file is part of the GNU Binutils. @@ -19,12 +19,14 @@ MA 02110-1301, USA. */ #include "sysdep.h" +#include #include "bfd.h" #include "libiberty.h" #include "filenames.h" #include "safe-ctype.h" #include "obstack.h" #include "bfdlink.h" +#include "ctf-api.h" #include "ld.h" #include "ldmain.h" @@ -39,7 +41,6 @@ #include "fnmatch.h" #include "demangle.h" #include "hashtab.h" -#include "libbfd.h" #include "elf-bfd.h" #ifdef ENABLE_PLUGINS #include "plugin.h" @@ -62,13 +63,18 @@ static struct obstack map_obstack; #define obstack_chunk_alloc xmalloc #define obstack_chunk_free free static const char *entry_symbol_default = "start"; -static bfd_boolean placed_commons = 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; +/* Header for list of statements corresponding to any files involved in the + link, either specified from the command-line or added implicitely (eg. + archive member used to resolved undefined symbol, wildcard statement from + linker script, etc.). Next pointer is in next field of a + lang_statement_header_type (reached via header field in a + lang_statement_union). */ static lang_statement_list_type statement_list; static lang_statement_list_type *stat_save[10]; static lang_statement_list_type **stat_save_ptr = &stat_save[0]; @@ -97,9 +103,19 @@ static void lang_do_memory_regions (void); /* Exported variables. */ const char *output_target; lang_output_section_statement_type *abs_output_section; -lang_statement_list_type lang_output_section_statement; +lang_statement_list_type lang_os_list; lang_statement_list_type *stat_ptr = &statement_list; +/* Header for list of statements corresponding to files used in the final + executable. This can be either object file specified on the command-line + or library member resolving an undefined reference. Next pointer is in next + field of a lang_input_statement_type (reached via input_statement field in a + lang_statement_union). */ lang_statement_list_type file_chain = { NULL, NULL }; +/* Header for list of statements corresponding to files specified on the + command-line for linking. It thus contains real object files and archive + but not archive members. Next pointer is in next_real_file field of a + lang_input_statement_type statement (reached via input_statement field in a + lang_statement_union). */ lang_statement_list_type input_file_chain; struct bfd_sym_chain entry_symbol = { NULL, NULL }; const char *entry_section = ".text"; @@ -113,6 +129,7 @@ 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; +static ctf_file_t *ctf_output; /* Functions that traverse the linker script and might evaluate DEFINED() need to increment this at the start of the traversal. */ @@ -136,6 +153,12 @@ int lang_statement_iteration = 0; #define SECTION_NAME_MAP_LENGTH (16) +/* CTF sections smaller than this are not compressed: compression of + dictionaries this small doesn't gain much, and this lets consumers mmap the + sections directly out of the ELF file and use them with no decompression + overhead if they want to. */ +#define CTF_COMPRESSION_THRESHOLD 4096 + void * stat_alloc (size_t size) { @@ -208,7 +231,7 @@ unique_section_p (const asection *sec, struct unique_sections *unam; const char *secnam; - if (bfd_link_relocatable (&link_info) + if (!link_info.resolve_section_groups && sec->owner != NULL && bfd_is_group_section (sec->owner, sec)) return !(os != NULL @@ -224,23 +247,16 @@ unique_section_p (const asection *sec, /* Generic traversal routines for finding matching sections. */ -/* Try processing a section against a wildcard. This just calls - the callback unless the filename exclusion list is present - and excludes the file. It's hardly ever present so this - function is very fast. */ +/* Return true if FILE matches a pattern in EXCLUDE_LIST, otherwise return + false. */ -static void -walk_wild_consider_section (lang_wild_statement_type *ptr, - lang_input_statement_type *file, - asection *s, - struct wildcard_list *sec, - callback_t callback, - void *data) +static bfd_boolean +walk_wild_file_in_exclude_list (struct name_list *exclude_list, + lang_input_statement_type *file) { struct name_list *list_tmp; - /* Don't process sections from files which were excluded. */ - for (list_tmp = sec->spec.exclude_name_list; + for (list_tmp = exclude_list; list_tmp; list_tmp = list_tmp->next) { @@ -249,11 +265,11 @@ walk_wild_consider_section (lang_wild_statement_type *ptr, if (p != NULL) { if (input_statement_is_archive_path (list_tmp->name, p, file)) - return; + return TRUE; } else if (name_match (list_tmp->name, file->filename) == 0) - return; + return TRUE; /* FIXME: Perhaps remove the following at some stage? Matching unadorned archives like this was never documented and has @@ -262,9 +278,29 @@ walk_wild_consider_section (lang_wild_statement_type *ptr, && file->the_bfd->my_archive != NULL && name_match (list_tmp->name, file->the_bfd->my_archive->filename) == 0) - return; + return TRUE; } + return FALSE; +} + +/* Try processing a section against a wildcard. This just calls + the callback unless the filename exclusion list is present + and excludes the file. It's hardly ever present so this + function is very fast. */ + +static void +walk_wild_consider_section (lang_wild_statement_type *ptr, + lang_input_statement_type *file, + asection *s, + struct wildcard_list *sec, + callback_t callback, + void *data) +{ + /* Don't process sections from files which were excluded. */ + if (walk_wild_file_in_exclude_list (sec->spec.exclude_name_list, file)) + return; + (*callback) (ptr, sec, s, ptr->section_flag_list, file, data); } @@ -292,7 +328,7 @@ walk_wild_section_general (lang_wild_statement_type *ptr, if (sec->spec.name != NULL) { - const char *sname = bfd_get_section_name (file->the_bfd, s); + const char *sname = bfd_section_name (s); skip = name_match (sec->spec.name, sname) != 0; } @@ -376,39 +412,50 @@ match_simple_wild (const char *pattern, const char *name) /* Return the numerical value of the init_priority attribute from section name NAME. */ -static unsigned long -get_init_priority (const char *name) +static int +get_init_priority (const asection *sec) { - char *end; - unsigned long init_priority; + const char *name = bfd_section_name (sec); + const char *dot; /* GCC uses the following section names for the init_priority - attribute with numerical values 101 and 65535 inclusive. A + attribute with numerical values 101 to 65535 inclusive. A lower value means a higher priority. - 1: .init_array.NNNN/.fini_array.NNNN: Where NNNN is the + 1: .init_array.NNNNN/.fini_array.NNNNN: Where NNNNN is the 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/.dtors.NNNN: Where NNNN is 65535 minus the + 2: .ctors.NNNNN/.dtors.NNNNN: Where NNNNN is 65535 minus the decimal numerical value of the init_priority attribute. The order of execution in .ctors is backward and .dtors is forward. - */ - if (strncmp (name, ".init_array.", 12) == 0 - || strncmp (name, ".fini_array.", 12) == 0) - { - init_priority = strtoul (name + 12, &end, 10); - return *end ? 0 : init_priority; - } - else if (strncmp (name, ".ctors.", 7) == 0 - || strncmp (name, ".dtors.", 7) == 0) - { - init_priority = strtoul (name + 7, &end, 10); - return *end ? 0 : 65535 - init_priority; - } - return 0; + .init_array.NNNNN sections would normally be placed in an output + .init_array section, .fini_array.NNNNN in .fini_array, + .ctors.NNNNN in .ctors, and .dtors.NNNNN in .dtors. This means + we should sort by increasing number (and could just use + SORT_BY_NAME in scripts). However if .ctors.NNNNN sections are + being placed in .init_array (which may also contain + .init_array.NNNNN sections) or .dtors.NNNNN sections are being + placed in .fini_array then we need to extract the init_priority + attribute and sort on that. */ + dot = strrchr (name, '.'); + if (dot != NULL && ISDIGIT (dot[1])) + { + char *end; + unsigned long init_priority = strtoul (dot + 1, &end, 10); + if (*end == 0) + { + if (dot == name + 6 + && (strncmp (name, ".ctors", 6) == 0 + || strncmp (name, ".dtors", 6) == 0)) + init_priority = 65535 - init_priority; + if (init_priority <= INT_MAX) + return init_priority; + } + } + return -1; } /* Compare sections ASEC and BSEC according to SORT. */ @@ -417,7 +464,7 @@ static int compare_section (sort_type sort, asection *asec, asection *bsec) { int ret; - unsigned long ainit_priority, binit_priority; + int a_priority, b_priority; switch (sort) { @@ -425,41 +472,35 @@ compare_section (sort_type sort, asection *asec, asection *bsec) abort (); case by_init_priority: - ainit_priority - = get_init_priority (bfd_get_section_name (asec->owner, asec)); - binit_priority - = get_init_priority (bfd_get_section_name (bsec->owner, bsec)); - if (ainit_priority == 0 || binit_priority == 0) + a_priority = get_init_priority (asec); + b_priority = get_init_priority (bsec); + if (a_priority < 0 || b_priority < 0) goto sort_by_name; - ret = ainit_priority - binit_priority; + ret = a_priority - b_priority; if (ret) break; else goto sort_by_name; case by_alignment_name: - ret = (bfd_section_alignment (bsec->owner, bsec) - - bfd_section_alignment (asec->owner, asec)); + ret = bfd_section_alignment (bsec) - bfd_section_alignment (asec); if (ret) break; /* Fall through. */ case by_name: -sort_by_name: - ret = strcmp (bfd_get_section_name (asec->owner, asec), - bfd_get_section_name (bsec->owner, bsec)); + sort_by_name: + ret = strcmp (bfd_section_name (asec), bfd_section_name (bsec)); break; case by_name_alignment: - ret = strcmp (bfd_get_section_name (asec->owner, asec), - bfd_get_section_name (bsec->owner, bsec)); + ret = strcmp (bfd_section_name (asec), bfd_section_name (bsec)); if (ret) break; /* Fall through. */ case by_alignment: - ret = (bfd_section_alignment (bsec->owner, bsec) - - bfd_section_alignment (asec->owner, asec)); + ret = bfd_section_alignment (bsec) - bfd_section_alignment (asec); break; } @@ -583,7 +624,7 @@ walk_wild_section_specs1_wild1 (lang_wild_statement_type *ptr, for (s = file->the_bfd->sections; s != NULL; s = s->next) { - const char *sname = bfd_get_section_name (file->the_bfd, s); + const char *sname = bfd_section_name (s); bfd_boolean skip = !match_simple_wild (wildsec0->spec.name, sname); if (!skip) @@ -620,7 +661,7 @@ walk_wild_section_specs2_wild1 (lang_wild_statement_type *ptr, walk_wild_consider_section (ptr, file, s, sec0, callback, data); else { - const char *sname = bfd_get_section_name (file->the_bfd, s); + const char *sname = bfd_section_name (s); bfd_boolean skip = !match_simple_wild (wildsec1->spec.name, sname); if (!skip) @@ -655,7 +696,7 @@ walk_wild_section_specs3_wild2 (lang_wild_statement_type *ptr, walk_wild_consider_section (ptr, file, s, sec0, callback, data); else { - const char *sname = bfd_get_section_name (file->the_bfd, s); + const char *sname = bfd_section_name (s); bfd_boolean skip = !match_simple_wild (wildsec1->spec.name, sname); if (!skip) @@ -707,7 +748,7 @@ walk_wild_section_specs4_wild2 (lang_wild_statement_type *ptr, walk_wild_consider_section (ptr, file, s, sec1, callback, data); else { - const char *sname = bfd_get_section_name (file->the_bfd, s); + const char *sname = bfd_section_name (s); bfd_boolean skip = !match_simple_wild (wildsec2->spec.name, sname); @@ -861,8 +902,11 @@ walk_wild_file (lang_wild_statement_type *s, callback_t callback, void *data) { + if (walk_wild_file_in_exclude_list (s->exclude_name_list, f)) + return; + if (f->the_bfd == NULL - || ! bfd_check_format (f->the_bfd, bfd_archive)) + || !bfd_check_format (f->the_bfd, bfd_archive)) walk_wild_section (s, f, callback, data); else { @@ -878,12 +922,8 @@ walk_wild_file (lang_wild_statement_type *s, archive which is included, BFD will call ldlang_add_file, which will set the usrdata field of the member to the lang_input_statement. */ - if (member->usrdata != NULL) - { - walk_wild_section (s, - (lang_input_statement_type *) member->usrdata, - callback, data); - } + if (bfd_usrdata (member) != NULL) + walk_wild_section (s, bfd_usrdata (member), callback, data); member = bfd_openr_next_archived_file (f->the_bfd, member); } @@ -996,6 +1036,15 @@ lang_list_init (lang_statement_list_type *list) list->tail = &list->head; } +static void +lang_statement_append (lang_statement_list_type *list, + void *element, + void *field) +{ + *(list->tail) = element; + list->tail = field; +} + void push_stat_ptr (lang_statement_list_type *new_ptr) { @@ -1022,7 +1071,7 @@ new_statement (enum statement_enum type, { lang_statement_union_type *new_stmt; - new_stmt = (lang_statement_union_type *) stat_alloc (size); + new_stmt = stat_alloc (size); new_stmt->header.type = type; new_stmt->header.next = NULL; lang_statement_append (list, new_stmt, &new_stmt->header.next); @@ -1041,23 +1090,13 @@ new_statement (enum statement_enum type, static lang_input_statement_type * new_afile (const char *name, lang_input_file_enum_type file_type, - const char *target, - bfd_boolean add_to_list) + const char *target) { 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)); - p->header.type = lang_input_statement_enum; - p->header.next = NULL; - } - + p = new_stat (lang_input_statement, stat_ptr); memset (&p->the_bfd, 0, sizeof (*p) - offsetof (lang_input_statement_type, the_bfd)); p->target = target; @@ -1081,12 +1120,12 @@ new_afile (const char *name, break; case lang_input_file_is_l_enum: if (name[0] == ':' && name[1] != '\0') - { - p->filename = name + 1; - p->flags.full_name_provided = TRUE; - } + { + p->filename = name + 1; + p->flags.full_name_provided = TRUE; + } else - p->filename = name; + p->filename = name; p->local_sym_name = concat ("-l", name, (const char *) NULL); p->flags.maybe_archive = TRUE; p->flags.real = TRUE; @@ -1112,9 +1151,7 @@ new_afile (const char *name, FAIL (); } - lang_statement_append (&input_file_chain, - (lang_statement_union_type *) p, - &p->next_real_file); + lang_statement_append (&input_file_chain, p, &p->next_real_file); return p; } @@ -1123,11 +1160,14 @@ lang_add_input_file (const char *name, lang_input_file_enum_type file_type, const char *target) { - if (name != NULL && *name == '=') + if (name != NULL + && (*name == '=' || CONST_STRNEQ (name, "$SYSROOT"))) { lang_input_statement_type *ret; char *sysrooted_name - = concat (ld_sysroot, name + 1, (const char *) NULL); + = concat (ld_sysroot, + name + (*name == '=' ? 1 : strlen ("$SYSROOT")), + (const char *) NULL); /* We've now forcibly prepended the sysroot, making the input file independent of the context. Therefore, temporarily @@ -1138,12 +1178,12 @@ lang_add_input_file (const char *name, within the sysroot subdirectory.) */ unsigned int outer_sysrooted = input_flags.sysrooted; input_flags.sysrooted = 0; - ret = new_afile (sysrooted_name, file_type, target, TRUE); + ret = new_afile (sysrooted_name, file_type, target); input_flags.sysrooted = outer_sysrooted; return ret; } - return new_afile (name, file_type, target, TRUE); + return new_afile (name, file_type, target); } struct out_section_hash_entry @@ -1182,28 +1222,26 @@ output_section_statement_newfunc (struct bfd_hash_entry *entry, ret = (struct out_section_hash_entry *) entry; memset (&ret->s, 0, sizeof (ret->s)); ret->s.header.type = lang_output_section_statement_enum; - ret->s.output_section_statement.subsection_alignment = -1; - ret->s.output_section_statement.section_alignment = -1; + ret->s.output_section_statement.subsection_alignment = NULL; + ret->s.output_section_statement.section_alignment = NULL; ret->s.output_section_statement.block_value = 1; lang_list_init (&ret->s.output_section_statement.children); lang_statement_append (stat_ptr, &ret->s, &ret->s.header.next); /* For every output section statement added to the list, except the - first one, lang_output_section_statement.tail points to the "next" + first one, lang_os_list.tail points to the "next" field of the last element of the list. */ - if (lang_output_section_statement.head != NULL) + if (lang_os_list.head != NULL) ret->s.output_section_statement.prev = ((lang_output_section_statement_type *) - ((char *) lang_output_section_statement.tail + ((char *) lang_os_list.tail - offsetof (lang_output_section_statement_type, next))); /* GCC's strict aliasing rules prevent us from just casting the address, so we store the pointer in a variable and cast that instead. */ nextp = &ret->s.output_section_statement.next; - lang_statement_append (&lang_output_section_statement, - &ret->s, - (lang_statement_union_type **) nextp); + lang_statement_append (&lang_os_list, &ret->s, nextp); return &ret->root; } @@ -1214,7 +1252,7 @@ output_section_statement_table_init (void) output_section_statement_newfunc, sizeof (struct out_section_hash_entry), 61)) - einfo (_("%P%F: can not create hash table: %E\n")); + einfo (_("%F%P: can not create hash table: %E\n")); } static void @@ -1237,7 +1275,7 @@ lang_init (void) lang_list_init (stat_ptr); lang_list_init (&input_file_chain); - lang_list_init (&lang_output_section_statement); + lang_list_init (&lang_os_list); lang_list_init (&file_chain); first_file = lang_add_input_file (NULL, lang_input_file_is_marker_enum, NULL); @@ -1298,17 +1336,16 @@ lang_memory_region_lookup (const char *const name, bfd_boolean create) if (strcmp (n->name, name) == 0) { if (create) - einfo (_("%P:%S: warning: redeclaration of memory region `%s'\n"), + einfo (_("%P:%pS: 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"), + einfo (_("%P:%pS: warning: memory region `%s' not declared\n"), NULL, name); - new_region = (lang_memory_region_type *) - stat_alloc (sizeof (lang_memory_region_type)); + new_region = stat_alloc (sizeof (lang_memory_region_type)); new_region->name_list.name = xstrdup (name); new_region->name_list.next = NULL; @@ -1330,18 +1367,18 @@ lang_memory_region_lookup (const char *const name, bfd_boolean create) } void -lang_memory_region_alias (const char * alias, const char * region_name) +lang_memory_region_alias (const char *alias, const char *region_name) { - lang_memory_region_name * n; - lang_memory_region_type * r; - lang_memory_region_type * region; + lang_memory_region_name *n; + lang_memory_region_type *r; + lang_memory_region_type *region; /* The default region must be unique. This ensures that it is not necessary to iterate through the name list if someone wants the check if a region is the default memory region. */ if (strcmp (region_name, DEFAULT_MEMORY_REGION) == 0 || strcmp (alias, DEFAULT_MEMORY_REGION) == 0) - einfo (_("%F%P:%S: error: alias for default memory region\n"), NULL); + einfo (_("%F%P:%pS: error: alias for default memory region\n"), NULL); /* Look for the target region and check if the alias is not already in use. */ @@ -1352,26 +1389,26 @@ lang_memory_region_alias (const char * alias, const char * region_name) 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 " + einfo (_("%F%P:%pS: 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' " + einfo (_("%F%P:%pS: error: memory region `%s' " "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)); + n = stat_alloc (sizeof (lang_memory_region_name)); n->name = xstrdup (alias); n->next = region->name_list.next; region->name_list.next = n; } static lang_memory_region_type * -lang_memory_default (asection * section) +lang_memory_default (asection *section) { lang_memory_region_type *p; @@ -1397,7 +1434,7 @@ lang_memory_default (asection * section) lang_output_section_statement_type * lang_output_section_get (const asection *output_section) { - return get_userdata (output_section); + return bfd_section_userdata (output_section); } /* Find or create an output_section_statement with the given NAME. @@ -1418,7 +1455,7 @@ lang_output_section_statement_lookup (const char *name, if (entry == NULL) { if (create) - einfo (_("%P%F: failed creating section `%s': %E\n"), name); + einfo (_("%F%P: failed creating section `%s': %E\n"), name); return NULL; } @@ -1457,7 +1494,7 @@ lang_output_section_statement_lookup (const char *name, name)); if (entry == NULL) { - einfo (_("%P%F: failed creating section `%s': %E\n"), name); + einfo (_("%F%P: failed creating section `%s': %E\n"), name); return NULL; } entry->root = last_ent->root; @@ -1515,7 +1552,7 @@ lang_output_section_find_by_flags (const asection *sec, /* We know the first statement on this list is *ABS*. May as well skip it. */ - first = &lang_output_section_statement.head->output_section_statement; + first = (void *) lang_os_list.head; first = first->next; /* First try for an exact match. */ @@ -1743,8 +1780,7 @@ insert_os_after (lang_output_section_statement_type *after) lang_statement_union_type **assign = NULL; bfd_boolean ignore_first; - ignore_first - = after == &lang_output_section_statement.head->output_section_statement; + ignore_first = after == (void *) lang_os_list.head; for (where = &after->header.next; *where != NULL; @@ -1760,11 +1796,13 @@ insert_os_after (lang_output_section_statement_type *after) ass = &(*where)->assignment_statement; if (ass->exp->type.node_class != etree_assert && ass->exp->assign.dst[0] == '.' - && ass->exp->assign.dst[1] == 0 - && !ignore_first) - assign = where; + && ass->exp->assign.dst[1] == 0) + { + if (!ignore_first) + assign = where; + ignore_first = FALSE; + } } - ignore_first = FALSE; continue; case lang_wild_statement_enum: case lang_input_section_enum: @@ -1775,6 +1813,7 @@ insert_os_after (lang_output_section_statement_type *after) case lang_padding_statement_enum: case lang_constructors_statement_enum: assign = NULL; + ignore_first = FALSE; continue; case lang_output_section_statement_enum: if (assign != NULL) @@ -1811,8 +1850,6 @@ lang_insert_orphan (asection *s, lang_statement_list_type *add_child) { lang_statement_list_type add; - const char *ps; - lang_assignment_statement_type *start_assign; lang_output_section_statement_type *os; lang_output_section_statement_type **os_tail; @@ -1829,34 +1866,10 @@ lang_insert_orphan (asection *s, || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0) address = exp_intop (0); - os_tail = ((lang_output_section_statement_type **) - lang_output_section_statement.tail); + os_tail = (lang_output_section_statement_type **) lang_os_list.tail; os = lang_enter_output_section_statement (secname, address, normal_section, NULL, NULL, NULL, constraint, 0); - ps = NULL; - start_assign = NULL; - if (config.build_constructors && *os_tail == os) - { - /* If the name of the section is representable in C, then create - symbols to mark the start and the end of the section. */ - for (ps = secname; *ps != '\0'; ps++) - if (! ISALNUM ((unsigned char) *ps) && *ps != '_') - break; - if (*ps == '\0') - { - char *symname; - - 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); - start_assign - = lang_add_assignment (exp_provide (symname, - exp_nameop (NAME, "."), - FALSE)); - } - } - if (add_child == NULL) add_child = &os->children; lang_add_section (add_child, s, NULL, os); @@ -1876,27 +1889,6 @@ lang_insert_orphan (asection *s, lang_leave_output_section_statement (NULL, DEFAULT_MEMORY_REGION, NULL, NULL); - if (start_assign != NULL) - { - char *symname; - lang_assignment_statement_type *stop_assign; - bfd_vma dot; - - symname = (char *) xmalloc (ps - secname + sizeof "__stop_" + 1); - symname[0] = bfd_get_symbol_leading_char (link_info.output_bfd); - sprintf (symname + (symname[0] != 0), "__stop_%s", secname); - stop_assign - = lang_add_assignment (exp_provide (symname, - exp_nameop (NAME, "."), - FALSE)); - /* Evaluate the expression to define the symbol if referenced, - before sizing dynamic sections. */ - dot = os->bfd_section->vma; - exp_fold_tree (start_assign->exp, os->bfd_section, &dot); - dot += TO_ADDR (s->size); - exp_fold_tree (stop_assign->exp, os->bfd_section, &dot); - } - /* Restore the global list pointer. */ if (after != NULL) pop_stat_ptr (); @@ -1904,14 +1896,15 @@ lang_insert_orphan (asection *s, if (after != NULL && os->bfd_section != NULL) { asection *snew, *as; + bfd_boolean place_after = place->stmt == NULL; + bfd_boolean insert_after = TRUE; snew = os->bfd_section; /* Shuffle the bfd section list to make the output file look neater. This is really only cosmetic. */ if (place->section == NULL - && after != (&lang_output_section_statement.head - ->output_section_statement)) + && after != (void *) lang_os_list.head) { asection *bfd_section = after->bfd_section; @@ -1941,6 +1934,181 @@ lang_insert_orphan (asection *s, /* Now tack it back on in the right place. */ bfd_section_list_append (link_info.output_bfd, snew); } + else if ((bfd_get_flavour (link_info.output_bfd) + == bfd_target_elf_flavour) + && (bfd_get_flavour (s->owner) + == bfd_target_elf_flavour) + && ((elf_section_type (s) == SHT_NOTE + && (s->flags & SEC_LOAD) != 0) + || (elf_section_type (as) == SHT_NOTE + && (as->flags & SEC_LOAD) != 0))) + { + /* Make sure that output note sections are grouped and sorted + by alignments when inserting a note section or insert a + section after a note section, */ + asection *sec; + /* A specific section after which the output note section + should be placed. */ + asection *after_sec; + /* True if we need to insert the orphan section after a + specific section to maintain output note section order. */ + bfd_boolean after_sec_note = FALSE; + + static asection *first_orphan_note = NULL; + + /* Group and sort output note section by alignments in + ascending order. */ + after_sec = NULL; + if (elf_section_type (s) == SHT_NOTE + && (s->flags & SEC_LOAD) != 0) + { + /* Search from the beginning for the last output note + section with equal or larger alignments. NB: Don't + place orphan note section after non-note sections. */ + + first_orphan_note = NULL; + for (sec = link_info.output_bfd->sections; + (sec != NULL + && !bfd_is_abs_section (sec)); + sec = sec->next) + if (sec != snew + && elf_section_type (sec) == SHT_NOTE + && (sec->flags & SEC_LOAD) != 0) + { + if (!first_orphan_note) + first_orphan_note = sec; + if (sec->alignment_power >= s->alignment_power) + after_sec = sec; + } + else if (first_orphan_note) + { + /* Stop if there is non-note section after the first + orphan note section. */ + break; + } + + /* If this will be the first orphan note section, it can + be placed at the default location. */ + after_sec_note = first_orphan_note != NULL; + if (after_sec == NULL && after_sec_note) + { + /* If all output note sections have smaller + alignments, place the section before all + output orphan note sections. */ + after_sec = first_orphan_note; + insert_after = FALSE; + } + } + else if (first_orphan_note) + { + /* Don't place non-note sections in the middle of orphan + note sections. */ + after_sec_note = TRUE; + after_sec = as; + for (sec = as->next; + (sec != NULL + && !bfd_is_abs_section (sec)); + sec = sec->next) + if (elf_section_type (sec) == SHT_NOTE + && (sec->flags & SEC_LOAD) != 0) + after_sec = sec; + } + + if (after_sec_note) + { + if (after_sec) + { + /* Search forward to insert OS after AFTER_SEC output + statement. */ + lang_output_section_statement_type *stmt, *next; + bfd_boolean found = FALSE; + for (stmt = after; stmt != NULL; stmt = next) + { + next = stmt->next; + if (insert_after) + { + if (stmt->bfd_section == after_sec) + { + place_after = TRUE; + found = TRUE; + after = stmt; + break; + } + } + else + { + /* If INSERT_AFTER is FALSE, place OS before + AFTER_SEC output statement. */ + if (next && next->bfd_section == after_sec) + { + place_after = TRUE; + found = TRUE; + after = stmt; + break; + } + } + } + + /* Search backward to insert OS after AFTER_SEC output + statement. */ + if (!found) + for (stmt = after; stmt != NULL; stmt = stmt->prev) + { + if (insert_after) + { + if (stmt->bfd_section == after_sec) + { + place_after = TRUE; + after = stmt; + break; + } + } + else + { + /* If INSERT_AFTER is FALSE, place OS before + AFTER_SEC output statement. */ + if (stmt->next->bfd_section == after_sec) + { + place_after = TRUE; + after = stmt; + break; + } + } + } + } + + if (after_sec == NULL + || (insert_after && after_sec->next != snew) + || (!insert_after && after_sec->prev != snew)) + { + /* Unlink the section. */ + bfd_section_list_remove (link_info.output_bfd, snew); + + /* Place SNEW after AFTER_SEC. If AFTER_SEC is NULL, + prepend SNEW. */ + if (after_sec) + { + if (insert_after) + bfd_section_list_insert_after (link_info.output_bfd, + after_sec, snew); + else + bfd_section_list_insert_before (link_info.output_bfd, + after_sec, snew); + } + else + bfd_section_list_prepend (link_info.output_bfd, snew); + } + } + else if (as != snew && as->prev != snew) + { + /* Unlink the section. */ + bfd_section_list_remove (link_info.output_bfd, snew); + + /* Now tack it back on in the right place. */ + bfd_section_list_insert_before (link_info.output_bfd, + as, snew); + } + } else if (as != snew && as->prev != snew) { /* Unlink the section. */ @@ -1967,7 +2135,8 @@ lang_insert_orphan (asection *s, { lang_output_section_statement_type *newly_added_os; - if (place->stmt == NULL) + /* Place OS after AFTER if AFTER_NOTE is TRUE. */ + if (place_after) { lang_statement_union_type **where = insert_os_after (after); @@ -2009,8 +2178,7 @@ lang_insert_orphan (asection *s, assigning *os_tail = NULL, but possibly added it back in the same place when assigning *place->os_tail. */ if (*os_tail == NULL) - lang_output_section_statement.tail - = (lang_statement_union_type **) os_tail; + lang_os_list.tail = (lang_statement_union_type **) os_tail; } } return os; @@ -2020,14 +2188,11 @@ 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); + minfo (_("\nAs-needed library included to satisfy reference by file (symbol)\n\n")); for (m = asneeded_list_head; m != NULL; m = m->next) { @@ -2048,8 +2213,8 @@ lang_print_asneeded (void) } if (m->ref != NULL) - minfo ("%B ", m->ref); - minfo ("(%T)\n", m->name); + minfo ("%pB ", m->ref); + minfo ("(%pT)\n", m->name); } } @@ -2086,19 +2251,20 @@ lang_map (void) || file->flags.just_syms) continue; - for (s = file->the_bfd->sections; s != NULL; s = s->next) - if ((s->output_section == NULL - || s->output_section->owner != link_info.output_bfd) - && (s->flags & (SEC_LINKER_CREATED | SEC_KEEP)) == 0) - { - if (! dis_header_printed) - { - fprintf (config.map_file, _("\nDiscarded input sections\n\n")); - dis_header_printed = TRUE; - } + if (config.print_map_discarded) + for (s = file->the_bfd->sections; s != NULL; s = s->next) + if ((s->output_section == NULL + || s->output_section->owner != link_info.output_bfd) + && (s->flags & (SEC_LINKER_CREATED | SEC_KEEP)) == 0) + { + if (! dis_header_printed) + { + fprintf (config.map_file, _("\nDiscarded input sections\n\n")); + dis_header_printed = TRUE; + } - print_input_section (s, TRUE); - } + print_input_section (s, TRUE); + } } minfo (_("\nMemory Configuration\n\n")); @@ -2145,15 +2311,17 @@ lang_map (void) fprintf (config.map_file, _("\nLinker script and memory map\n\n")); - if (! link_info.reduce_memory_overheads) + if (!link_info.reduce_memory_overheads) { obstack_begin (&map_obstack, 1000); bfd_link_hash_traverse (link_info.hash, sort_def_symbol, 0); } + expld.phase = lang_fixed_phase_enum; lang_statement_iteration++; print_statements (); - ldemul_extra_map_file_text (link_info.output_bfd, &link_info, config.map_file); + ldemul_extra_map_file_text (link_info.output_bfd, &link_info, + config.map_file); } static bfd_boolean @@ -2168,12 +2336,11 @@ sort_def_symbol (struct bfd_link_hash_entry *hash_entry, input_section_userdata_type *ud; struct map_symbol_def *def; - ud = ((input_section_userdata_type *) - get_userdata (hash_entry->u.def.section)); + ud = bfd_section_userdata (hash_entry->u.def.section); if (!ud) { - ud = (input_section_userdata_type *) stat_alloc (sizeof (*ud)); - get_userdata (hash_entry->u.def.section) = ud; + ud = stat_alloc (sizeof (*ud)); + bfd_set_section_userdata (hash_entry->u.def.section, ud); ud->map_symbol_def_tail = &ud->map_symbol_def_head; ud->map_symbol_def_count = 0; } @@ -2195,7 +2362,7 @@ static void init_os (lang_output_section_statement_type *s, flagword flags) { if (strcmp (s->name, DISCARD_SECTION_NAME) == 0) - einfo (_("%P%F: Illegal use of `%s' section\n"), DISCARD_SECTION_NAME); + einfo (_("%F%P: illegal use of `%s' section\n"), DISCARD_SECTION_NAME); if (s->constraint != SPECIAL) s->bfd_section = bfd_get_section_by_name (link_info.output_bfd, s->name); @@ -2204,7 +2371,8 @@ init_os (lang_output_section_statement_type *s, flagword flags) s->name, flags); if (s->bfd_section == NULL) { - einfo (_("%P%F: output format %s cannot represent section called %s\n"), + einfo (_("%F%P: output format %s cannot represent section" + " called %s: %E\n"), link_info.output_bfd->xvec->name, s->name); } s->bfd_section->output_section = s->bfd_section; @@ -2212,7 +2380,7 @@ init_os (lang_output_section_statement_type *s, flagword flags) /* Set the userdata of the output section to the output section statement to avoid lookup. */ - get_userdata (s->bfd_section) = s; + bfd_set_section_userdata (s->bfd_section, s); /* If there is a base address, make sure that any sections it might mention are initialized. */ @@ -2223,8 +2391,9 @@ init_os (lang_output_section_statement_type *s, flagword flags) exp_init_os (s->load_base); /* If supplied an alignment, set it. */ - if (s->section_alignment != -1) - s->bfd_section->alignment_power = s->section_alignment; + if (s->section_alignment != NULL) + s->bfd_section->alignment_power = exp_get_power (s->section_alignment, + "section alignment"); } /* Make sure that all output sections mentioned in an expression are @@ -2237,6 +2406,7 @@ exp_init_os (etree_type *exp) { case etree_assign: case etree_provide: + case etree_provided: exp_init_os (exp->assign.src); break; @@ -2293,10 +2463,44 @@ section_already_linked (bfd *abfd, asection *sec, void *data) return; } + /* Deal with SHF_EXCLUDE ELF sections. */ + if (!bfd_link_relocatable (&link_info) + && (abfd->flags & BFD_PLUGIN) == 0 + && (sec->flags & (SEC_GROUP | SEC_KEEP | SEC_EXCLUDE)) == SEC_EXCLUDE) + sec->output_section = bfd_abs_section_ptr; + if (!(abfd->flags & DYNAMIC)) bfd_section_already_linked (abfd, sec, &link_info); } + +/* Returns true if SECTION is one we know will be discarded based on its + section flags, otherwise returns false. */ + +static bfd_boolean +lang_discard_section_p (asection *section) +{ + bfd_boolean discard; + flagword flags = section->flags; + + /* Discard sections marked with SEC_EXCLUDE. */ + discard = (flags & SEC_EXCLUDE) != 0; + + /* Discard the group descriptor sections when we're finally placing the + sections from within the group. */ + if ((flags & SEC_GROUP) != 0 + && link_info.resolve_section_groups) + discard = TRUE; + + /* Discard debugging sections if we are stripping debugging + information. */ + if ((link_info.strip == strip_debugger || link_info.strip == strip_all) + && (flags & SEC_DEBUGGING) != 0) + discard = TRUE; + + return discard; +} + /* The wild routines. These expand statements like *(.text) and foo.o to a list of @@ -2318,20 +2522,14 @@ lang_add_section (lang_statement_list_type *ptr, lang_input_section_type *new_section; bfd *abfd = link_info.output_bfd; - /* Discard sections marked with SEC_EXCLUDE. */ - discard = (flags & SEC_EXCLUDE) != 0; + /* Is this section one we know should be discarded? */ + discard = lang_discard_section_p (section); /* Discard input sections which are assigned to a section named DISCARD_SECTION_NAME. */ if (strcmp (output->name, DISCARD_SECTION_NAME) == 0) discard = TRUE; - /* Discard debugging sections if we are stripping debugging - information. */ - if ((link_info.strip == strip_debugger || link_info.strip == strip_all) - && (flags & SEC_DEBUGGING) != 0) - discard = TRUE; - if (discard) { if (section->output_section == NULL) @@ -2366,14 +2564,21 @@ lang_add_section (lang_statement_list_type *ptr, already been processed. One reason to do this is that on pe format targets, .text$foo sections go into .text and it's odd to see .text with SEC_LINK_ONCE set. */ - - if (!bfd_link_relocatable (&link_info)) + if ((flags & (SEC_LINK_ONCE | SEC_GROUP)) == (SEC_LINK_ONCE | SEC_GROUP)) + { + if (link_info.resolve_section_groups) + flags &= ~(SEC_LINK_ONCE | SEC_LINK_DUPLICATES | SEC_RELOC); + else + flags &= ~(SEC_LINK_DUPLICATES | SEC_RELOC); + } + else if (!bfd_link_relocatable (&link_info)) flags &= ~(SEC_LINK_ONCE | SEC_LINK_DUPLICATES | SEC_RELOC); switch (output->sectype) { case normal_section: case overlay_section: + case first_overlay_section: break; case noalloc_section: flags &= ~SEC_ALLOC; @@ -2499,9 +2704,9 @@ wild_sort (lang_wild_statement_type *wild, archive. */ if (file->the_bfd != NULL - && bfd_my_archive (file->the_bfd) != NULL) + && file->the_bfd->my_archive != NULL) { - fn = bfd_get_filename (bfd_my_archive (file->the_bfd)); + fn = bfd_get_filename (file->the_bfd->my_archive); fa = TRUE; } else @@ -2510,9 +2715,9 @@ wild_sort (lang_wild_statement_type *wild, fa = FALSE; } - if (bfd_my_archive (ls->section->owner) != NULL) + if (ls->section->owner->my_archive != NULL) { - ln = bfd_get_filename (bfd_my_archive (ls->section->owner)); + ln = bfd_get_filename (ls->section->owner->my_archive); la = TRUE; } else @@ -2641,9 +2846,9 @@ lookup_name (const char *name) { lang_input_statement_type *search; - for (search = (lang_input_statement_type *) input_file_chain.head; + for (search = (void *) input_file_chain.head; search != NULL; - search = (lang_input_statement_type *) search->next_real_file) + search = search->next_real_file) { /* Use the local_sym_name as the name of the file that has already been loaded as filename might have been transformed @@ -2656,15 +2861,32 @@ lookup_name (const char *name) } if (search == NULL) - search = new_afile (name, lang_input_file_is_search_file_enum, - default_target, FALSE); + { + /* Arrange to splice the input statement added by new_afile into + statement_list after the current input_file_chain tail. + We know input_file_chain is not an empty list, and that + lookup_name was called via open_input_bfds. Later calls to + lookup_name should always match an existing input_statement. */ + lang_statement_union_type **tail = stat_ptr->tail; + lang_statement_union_type **after + = (void *) ((char *) input_file_chain.tail + - offsetof (lang_input_statement_type, next_real_file) + + offsetof (lang_input_statement_type, header.next)); + lang_statement_union_type *rest = *after; + stat_ptr->tail = after; + search = new_afile (name, lang_input_file_is_search_file_enum, + default_target); + *stat_ptr->tail = rest; + if (*tail == NULL) + stat_ptr->tail = tail; + } /* If we have already added this file, or this file is not real don't add this file. */ if (search->flags.loaded || !search->flags.real) return search; - if (! load_symbols (search, NULL)) + if (!load_symbols (search, NULL)) return NULL; return search; @@ -2748,8 +2970,11 @@ load_symbols (lang_input_statement_type *entry, 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)) + if (trace_files || verbose) + info_msg ("%pI\n", entry); + + if (!bfd_check_format (entry->the_bfd, bfd_archive) + && !bfd_check_format_matches (entry->the_bfd, bfd_object, &matching)) { bfd_error_type err; struct lang_input_statement_flags save_flags; @@ -2765,15 +2990,15 @@ load_symbols (lang_input_statement_type *entry, { char **p; - einfo (_("%B: file not recognized: %E\n"), entry->the_bfd); - einfo (_("%B: matching formats:"), entry->the_bfd); + einfo (_("%P: %pB: file not recognized: %E;" + " matching formats:"), entry->the_bfd); for (p = matching; *p != NULL; p++) einfo (" %s", *p); einfo ("%F\n"); } else if (err != bfd_error_file_not_recognized || place == NULL) - einfo (_("%F%B: file not recognized: %E\n"), entry->the_bfd); + einfo (_("%F%P: %pB: file not recognized: %E\n"), entry->the_bfd); bfd_close (entry->the_bfd); entry->the_bfd = NULL; @@ -2823,13 +3048,12 @@ load_symbols (lang_input_statement_type *entry, case bfd_object: if (!entry->flags.reload) ldlang_add_file (entry); - if (trace_files || verbose) - info_msg ("%I\n", entry); break; case bfd_archive: check_excluded_libs (entry->the_bfd); + bfd_set_usrdata (entry->the_bfd, entry); if (entry->flags.whole_archive) { bfd *member = NULL; @@ -2843,9 +3067,9 @@ load_symbols (lang_input_statement_type *entry, if (member == NULL) break; - if (! bfd_check_format (member, bfd_object)) + if (!bfd_check_format (member, bfd_object)) { - einfo (_("%F%B: member %B in archive is not an object\n"), + einfo (_("%F%P: %pB: member %pB in archive is not an object\n"), entry->the_bfd, member); loaded = FALSE; } @@ -2860,7 +3084,7 @@ load_symbols (lang_input_statement_type *entry, substitute BFD for us. */ if (!bfd_link_add_symbols (subsbfd, &link_info)) { - einfo (_("%F%B: error adding symbols: %E\n"), member); + einfo (_("%F%P: %pB: error adding symbols: %E\n"), member); loaded = FALSE; } } @@ -2874,7 +3098,7 @@ load_symbols (lang_input_statement_type *entry, if (bfd_link_add_symbols (entry->the_bfd, &link_info)) entry->flags.loaded = TRUE; else - einfo (_("%F%B: error adding symbols: %E\n"), entry->the_bfd); + einfo (_("%F%P: %pB: error adding symbols: %E\n"), entry->the_bfd); return entry->flags.loaded; } @@ -2934,7 +3158,7 @@ get_target (const bfd_target *target, void *data) /* Like strcpy() but convert to lower case as well. */ static void -stricpy (char *dest, char *src) +stricpy (char *dest, const char *src) { char c; @@ -2948,7 +3172,7 @@ stricpy (char *dest, char *src) from haystack. */ static void -strcut (char *haystack, char *needle) +strcut (char *haystack, const char *needle) { haystack = strstr (haystack, needle); @@ -2967,7 +3191,7 @@ strcut (char *haystack, char *needle) Return a value indicating how "similar" they are. */ static int -name_compare (char *first, char *second) +name_compare (const char *first, const char *second) { char *copy1; char *copy2; @@ -3052,10 +3276,10 @@ closest_target_match (const bfd_target *target, void *data) /* Return the BFD target format of the first input file. */ -static char * +static const char * get_first_input_target (void) { - char *target = NULL; + const char *target = NULL; LANG_FOR_EACH_INPUT_STATEMENT (s) { @@ -3112,15 +3336,15 @@ open_output (const char *name) line? */ if (command_line.endian != ENDIAN_UNSET) { - const bfd_target *target; - enum bfd_endian desired_endian; - /* Get the chosen target. */ - target = bfd_search_for_target (get_target, (void *) output_target); + const bfd_target *target + = bfd_iterate_over_targets (get_target, (void *) output_target); /* If the target is not supported, we cannot do anything. */ if (target != NULL) { + enum bfd_endian desired_endian; + if (command_line.endian == ENDIAN_BIG) desired_endian = BFD_ENDIAN_BIG; else @@ -3142,8 +3366,8 @@ open_output (const char *name) /* Try to find a target as similar as possible to the default target, but which has the desired endian characteristic. */ - bfd_search_for_target (closest_target_match, - (void *) target); + bfd_iterate_over_targets (closest_target_match, + (void *) target); /* Oh dear - we could not find any targets that satisfy our requirements. */ @@ -3162,23 +3386,23 @@ open_output (const char *name) if (link_info.output_bfd == NULL) { if (bfd_get_error () == bfd_error_invalid_target) - einfo (_("%P%F: target %s not found\n"), output_target); + einfo (_("%F%P: target %s not found\n"), output_target); - einfo (_("%P%F: cannot open output file %s: %E\n"), name); + einfo (_("%F%P: cannot open output file %s: %E\n"), name); } delete_output_file_on_failure = TRUE; - if (! bfd_set_format (link_info.output_bfd, bfd_object)) - einfo (_("%P%F:%s: can not make object file: %E\n"), name); - if (! bfd_set_arch_mach (link_info.output_bfd, + if (!bfd_set_format (link_info.output_bfd, bfd_object)) + einfo (_("%F%P: %s: can not make object file: %E\n"), name); + if (!bfd_set_arch_mach (link_info.output_bfd, ldfile_output_architecture, ldfile_output_machine)) - einfo (_("%P%F:%s: can not set architecture: %E\n"), name); + einfo (_("%F%P: %s: can not set architecture: %E\n"), name); link_info.hash = bfd_link_hash_table_create (link_info.output_bfd); if (link_info.hash == NULL) - einfo (_("%P%F: can not create hash table: %E\n")); + einfo (_("%F%P: can not create hash table: %E\n")); bfd_set_gp_size (link_info.output_bfd, g_switch_value); } @@ -3216,11 +3440,18 @@ ldlang_open_output (lang_statement_union_type *statement) } static void -init_opb (void) +init_opb (asection *s) { - unsigned x = bfd_arch_mach_octets_per_byte (ldfile_output_architecture, - ldfile_output_machine); + unsigned int x; + opb_shift = 0; + if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour + && s != NULL + && (s->flags & SEC_ELF_OCTETS) != 0) + return; + + x = bfd_arch_mach_octets_per_byte (ldfile_output_architecture, + ldfile_output_machine); if (x > 1) while ((x & 1) == 0) { @@ -3240,6 +3471,7 @@ enum open_bfd_mode }; #ifdef ENABLE_PLUGINS static lang_input_statement_type *plugin_insert = NULL; +static struct bfd_link_hash_entry *plugin_undefs = NULL; #endif static void @@ -3267,6 +3499,9 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode) case lang_group_statement_enum: { struct bfd_link_hash_entry *undefs; +#ifdef ENABLE_PLUGINS + lang_input_statement_type *plugin_insert_save; +#endif /* We must continually search the entries in the group until no new symbols are added to the list of undefined @@ -3274,11 +3509,21 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode) do { +#ifdef ENABLE_PLUGINS + plugin_insert_save = plugin_insert; +#endif undefs = link_info.hash->undefs_tail; open_input_bfds (s->group_statement.children.head, mode | OPEN_BFD_FORCE); } - while (undefs != link_info.hash->undefs_tail); + while (undefs != link_info.hash->undefs_tail +#ifdef ENABLE_PLUGINS + /* Objects inserted by a plugin, which are loaded + before we hit this loop, may have added new + undefs. */ + || (plugin_insert != plugin_insert_save && plugin_undefs) +#endif + ); } break; case lang_target_statement_enum: @@ -3317,10 +3562,10 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode) s->input_statement.flags.reload = TRUE; } - os_tail = lang_output_section_statement.tail; + os_tail = lang_os_list.tail; lang_list_init (&add); - if (! load_symbols (&s->input_statement, &add)) + if (!load_symbols (&s->input_statement, &add)) config.make_executable = FALSE; if (add.head != NULL) @@ -3331,7 +3576,7 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode) section statement list. Very likely the user forgot -T, and whatever we do here will not meet naive user expectations. */ - if (os_tail != lang_output_section_statement.tail) + if (os_tail != lang_os_list.tail) { einfo (_("%P: warning: %s contains output sections;" " did you forget -T?\n"), @@ -3354,8 +3599,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.defsym) - /* This is from a --defsym on the command line. */ + if (s->assignment_statement.exp->type.node_class != etree_assert) exp_fold_tree_no_dot (s->assignment_statement.exp); break; default: @@ -3368,86 +3612,269 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode) einfo ("%F"); } -/* 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 - on a list, then, once the output file has been opened, transfer the - name to the symbol table. */ - -typedef struct bfd_sym_chain ldlang_undef_chain_list_type; - -#define ldlang_undef_chain_list_head entry_symbol.next +/* Open the CTF sections in the input files with libctf: if any were opened, + create a fake input file that we'll write the merged CTF data to later + on. */ -void -ldlang_add_undef (const char *const name, bfd_boolean cmdline) +static void +ldlang_open_ctf (void) { - ldlang_undef_chain_list_type *new_undef; + int any_ctf = 0; + int err; - undef_from_cmdline = undef_from_cmdline || cmdline; - new_undef = (ldlang_undef_chain_list_type *) stat_alloc (sizeof (*new_undef)); - new_undef->next = ldlang_undef_chain_list_head; - ldlang_undef_chain_list_head = new_undef; + LANG_FOR_EACH_INPUT_STATEMENT (file) + { + asection *sect; - new_undef->name = xstrdup (name); + /* Incoming files from the compiler have a single ctf_file_t in them + (which is presented to us by the libctf API in a ctf_archive_t + wrapper): files derived from a previous relocatable link have a CTF + archive containing possibly many CTF files. */ - if (link_info.output_bfd != NULL) - insert_undefined (new_undef->name); -} + if ((file->the_ctf = ctf_bfdopen (file->the_bfd, &err)) == NULL) + { + if (err != ECTF_NOCTFDATA) + einfo (_("%P: warning: CTF section in `%pI' not loaded: " + "its types will be discarded: `%s'\n"), file, + ctf_errmsg (err)); + continue; + } -/* Insert NAME as undefined in the symbol table. */ + /* Prevent the contents of this section from being written, while + requiring the section itself to be duplicated in the output. */ + /* This section must exist if ctf_bfdopen() succeeded. */ + sect = bfd_get_section_by_name (file->the_bfd, ".ctf"); + sect->size = 0; + sect->flags |= SEC_NEVER_LOAD | SEC_HAS_CONTENTS | SEC_LINKER_CREATED; -static void -insert_undefined (const char *name) -{ - struct bfd_link_hash_entry *h; + any_ctf = 1; + } - h = bfd_link_hash_lookup (link_info.hash, name, TRUE, FALSE, TRUE); - if (h == NULL) - einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n")); - if (h->type == bfd_link_hash_new) + if (!any_ctf) { - h->type = bfd_link_hash_undefined; - h->u.undef.abfd = NULL; - bfd_link_add_undef (link_info.hash, h); + ctf_output = NULL; + return; } -} -/* Run through the list of undefineds created above and place them - into the linker hash table as undefined symbols belonging to the - script file. */ + if ((ctf_output = ctf_create (&err)) != NULL) + return; -static void -lang_place_undefineds (void) -{ - ldlang_undef_chain_list_type *ptr; + einfo (_("%P: warning: CTF output not created: `%s'\n"), + ctf_errmsg (err)); - for (ptr = ldlang_undef_chain_list_head; ptr != NULL; ptr = ptr->next) - insert_undefined (ptr->name); + LANG_FOR_EACH_INPUT_STATEMENT (errfile) + ctf_close (errfile->the_ctf); } -/* Structure used to build the list of symbols that the user has required - be defined. */ +/* Merge together CTF sections. After this, only the symtab-dependent + function and data object sections need adjustment. */ -struct require_defined_symbol +static void +lang_merge_ctf (void) { - const char *name; - struct require_defined_symbol *next; -}; + asection *output_sect; -/* The list of symbols that the user has required be defined. */ + if (!ctf_output) + return; -static struct require_defined_symbol *require_defined_symbol_list; + output_sect = bfd_get_section_by_name (link_info.output_bfd, ".ctf"); -/* Add a new symbol NAME to the list of symbols that are required to be - defined. */ + /* If the section was discarded, don't waste time merging. */ + if (output_sect == NULL) + { + ctf_file_close (ctf_output); + ctf_output = NULL; -void -ldlang_add_require_defined (const char * const name) -{ - struct require_defined_symbol *ptr; + LANG_FOR_EACH_INPUT_STATEMENT (file) + { + ctf_close (file->the_ctf); + file->the_ctf = NULL; + } + return; + } - ldlang_add_undef (name, TRUE); - ptr = (struct require_defined_symbol *) stat_alloc (sizeof (*ptr)); + LANG_FOR_EACH_INPUT_STATEMENT (file) + { + if (!file->the_ctf) + continue; + + /* Takes ownership of file->u.the_ctfa. */ + if (ctf_link_add_ctf (ctf_output, file->the_ctf, file->filename) < 0) + { + einfo (_("%F%P: cannot link with CTF in %pB: %s\n"), file->the_bfd, + ctf_errmsg (ctf_errno (ctf_output))); + ctf_close (file->the_ctf); + file->the_ctf = NULL; + continue; + } + } + + if (ctf_link (ctf_output, CTF_LINK_SHARE_UNCONFLICTED) < 0) + { + einfo (_("%F%P: CTF linking failed; output will have no CTF section: %s\n"), + ctf_errmsg (ctf_errno (ctf_output))); + if (output_sect) + { + output_sect->size = 0; + output_sect->flags |= SEC_EXCLUDE; + } + } +} + +/* Let the emulation examine the symbol table and strtab to help it optimize the + CTF, if supported. */ + +void +ldlang_ctf_apply_strsym (struct elf_sym_strtab *syms, bfd_size_type symcount, + struct elf_strtab_hash *symstrtab) +{ + ldemul_examine_strtab_for_ctf (ctf_output, syms, symcount, symstrtab); +} + +/* Write out the CTF section. Called early, if the emulation isn't going to + need to dedup against the strtab and symtab, then possibly called from the + target linker code if the dedup has happened. */ +static void +lang_write_ctf (int late) +{ + size_t output_size; + asection *output_sect; + + if (!ctf_output) + return; + + if (late) + { + /* Emit CTF late if this emulation says it can do so. */ + if (ldemul_emit_ctf_early ()) + return; + } + else + { + if (!ldemul_emit_ctf_early ()) + return; + } + + /* Emit CTF. */ + + output_sect = bfd_get_section_by_name (link_info.output_bfd, ".ctf"); + if (output_sect) + { + output_sect->contents = ctf_link_write (ctf_output, &output_size, + CTF_COMPRESSION_THRESHOLD); + output_sect->size = output_size; + output_sect->flags |= SEC_IN_MEMORY | SEC_KEEP; + + if (!output_sect->contents) + { + einfo (_("%F%P: CTF section emission failed; output will have no " + "CTF section: %s\n"), ctf_errmsg (ctf_errno (ctf_output))); + output_sect->size = 0; + output_sect->flags |= SEC_EXCLUDE; + } + } + + /* This also closes every CTF input file used in the link. */ + ctf_file_close (ctf_output); + ctf_output = NULL; + + LANG_FOR_EACH_INPUT_STATEMENT (file) + file->the_ctf = NULL; +} + +/* Write out the CTF section late, if the emulation needs that. */ + +void +ldlang_write_ctf_late (void) +{ + /* Trigger a "late call", if the emulation needs one. */ + + lang_write_ctf (1); +} + +/* 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 + on a list, then, once the output file has been opened, transfer the + name to the symbol table. */ + +typedef struct bfd_sym_chain ldlang_undef_chain_list_type; + +#define ldlang_undef_chain_list_head entry_symbol.next + +void +ldlang_add_undef (const char *const name, bfd_boolean cmdline) +{ + ldlang_undef_chain_list_type *new_undef; + + undef_from_cmdline = undef_from_cmdline || cmdline; + new_undef = stat_alloc (sizeof (*new_undef)); + new_undef->next = ldlang_undef_chain_list_head; + ldlang_undef_chain_list_head = new_undef; + + new_undef->name = xstrdup (name); + + if (link_info.output_bfd != NULL) + insert_undefined (new_undef->name); +} + +/* Insert NAME as undefined in the symbol table. */ + +static void +insert_undefined (const char *name) +{ + struct bfd_link_hash_entry *h; + + h = bfd_link_hash_lookup (link_info.hash, name, TRUE, FALSE, TRUE); + if (h == NULL) + einfo (_("%F%P: bfd_link_hash_lookup failed: %E\n")); + if (h->type == bfd_link_hash_new) + { + h->type = bfd_link_hash_undefined; + h->u.undef.abfd = NULL; + h->non_ir_ref_regular = TRUE; + if (is_elf_hash_table (link_info.hash)) + ((struct elf_link_hash_entry *) h)->mark = 1; + bfd_link_add_undef (link_info.hash, h); + } +} + +/* Run through the list of undefineds created above and place them + into the linker hash table as undefined symbols belonging to the + script file. */ + +static void +lang_place_undefineds (void) +{ + ldlang_undef_chain_list_type *ptr; + + for (ptr = ldlang_undef_chain_list_head; ptr != NULL; ptr = ptr->next) + 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 = stat_alloc (sizeof (*ptr)); ptr->next = require_defined_symbol_list; ptr->name = strdup (name); require_defined_symbol_list = ptr; @@ -3466,11 +3893,11 @@ ldlang_check_require_defined_symbols (void) struct bfd_link_hash_entry *h; h = bfd_link_hash_lookup (link_info.hash, ptr->name, - FALSE, FALSE, TRUE); + 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); + || (h->type != bfd_link_hash_defined + && h->type != bfd_link_hash_defweak)) + einfo(_("%X%P: required symbol `%s' not defined\n"), ptr->name); } } @@ -3481,26 +3908,26 @@ check_input_sections (lang_statement_union_type *s, lang_output_section_statement_type *output_section_statement) { - for (; s != (lang_statement_union_type *) NULL; s = s->header.next) + for (; s != NULL; s = s->header.next) { switch (s->header.type) { case lang_wild_statement_enum: walk_wild (&s->wild_statement, check_section_callback, output_section_statement); - if (! output_section_statement->all_input_readonly) + if (!output_section_statement->all_input_readonly) return; break; case lang_constructors_statement_enum: check_input_sections (constructor_list.head, output_section_statement); - if (! output_section_statement->all_input_readonly) + if (!output_section_statement->all_input_readonly) return; break; case lang_group_statement_enum: check_input_sections (s->group_statement.children.head, output_section_statement); - if (! output_section_statement->all_input_readonly) + if (!output_section_statement->all_input_readonly) return; break; default: @@ -3536,7 +3963,9 @@ update_wild_statements (lang_statement_union_type *s) case lang_wild_statement_enum: for (sec = s->wild_statement.section_list; sec != NULL; sec = sec->next) - { + /* Don't sort .init/.fini sections. */ + if (strcmp (sec->spec.name, ".init") != 0 + && strcmp (sec->spec.name, ".fini") != 0) switch (sec->spec.sorted) { case none: @@ -3553,7 +3982,6 @@ update_wild_statements (lang_statement_union_type *s) default: break; } - } break; case lang_constructors_statement_enum: @@ -3561,11 +3989,8 @@ update_wild_statements (lang_statement_union_type *s) break; case lang_output_section_statement_enum: - /* 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); + update_wild_statements + (s->output_section_statement.children.head); break; case lang_group_statement_enum: @@ -3639,6 +4064,7 @@ map_input_to_output_sections { case normal_section: case overlay_section: + case first_overlay_section: break; case noalloc_section: flags = SEC_HAS_CONTENTS; @@ -3681,7 +4107,7 @@ map_input_to_output_sections processed the segment marker. Originally, the linker treated segment directives (like -Ttext on the command-line) as section directives. We honor the - section directive semantics for backwards compatibilty; + section directive semantics for backwards compatibility; linker scripts that do not specifically check for SEGMENT_START automatically get the old semantics. */ if (!s->address_statement.segment @@ -3711,21 +4137,26 @@ map_input_to_output_sections start of the list and places them after the output section statement specified by the insert. This operation is complicated by the fact that we keep a doubly linked list of output section - statements as well as the singly linked list of all statements. */ + statements as well as the singly linked list of all statements. + FIXME someday: Twiddling with the list not only moves statements + from the user's script but also input and group statements that are + built from command line object files and --start-group. We only + get away with this because the list pointers used by file_chain + and input_file_chain are not reordered, and processing via + statement_list after this point mostly ignores input statements. + One exception is the map file, where LOAD and START GROUP/END GROUP + can end up looking odd. */ static void -process_insert_statements (void) +process_insert_statements (lang_statement_union_type **start) { lang_statement_union_type **s; lang_output_section_statement_type *first_os = NULL; lang_output_section_statement_type *last_os = NULL; lang_output_section_statement_type *os; - /* "start of list" is actually the statement immediately after - the special abs_section output statement, so that it isn't - reordered. */ - s = &lang_output_section_statement.head; - while (*(s = &(*s)->header.next) != NULL) + s = start; + while (*s != NULL) { if ((*s)->header.type == lang_output_section_statement_enum) { @@ -3744,6 +4175,18 @@ process_insert_statements (void) if (first_os == NULL) first_os = last_os; } + else if ((*s)->header.type == lang_group_statement_enum) + { + /* A user might put -T between --start-group and + --end-group. One way this odd construct might arise is + from a wrapper around ld to change library search + behaviour. For example: + #! /bin/sh + exec real_ld --start-group "$@" --end-group + This isn't completely unreasonable so go looking inside a + group statement for insert statements. */ + process_insert_statements (&(*s)->group_statement.children.head); + } else if ((*s)->header.type == lang_insert_statement_enum) { lang_insert_statement_type *i = &(*s)->insert_statement; @@ -3775,8 +4218,7 @@ process_insert_statements (void) if (last_os->next == NULL) { next = &first_os->prev->next; - lang_output_section_statement.tail - = (lang_statement_union_type **) next; + lang_os_list.tail = (lang_statement_union_type **) next; } else last_os->next->prev = first_os->prev; @@ -3785,8 +4227,7 @@ process_insert_statements (void) if (where->next == NULL) { next = &last_os->next; - lang_output_section_statement.tail - = (lang_statement_union_type **) next; + lang_os_list.tail = (lang_statement_union_type **) next; } else where->next->prev = last_os; @@ -3846,18 +4287,19 @@ process_insert_statements (void) } ptr = insert_os_after (where); - /* Snip everything after the abs_section output statement we - know is at the start of the list, up to and including - the insert statement we are currently processing. */ - first = lang_output_section_statement.head->header.next; - lang_output_section_statement.head->header.next = (*s)->header.next; - /* Add them back where they belong. */ + /* Snip everything from the start of the list, up to and + including the insert statement we are currently processing. */ + first = *start; + *start = (*s)->header.next; + /* Add them back where they belong, minus the insert. */ *s = *ptr; if (*s == NULL) statement_list.tail = s; *ptr = first; - s = &lang_output_section_statement.head; + s = start; + continue; } + s = &(*s)->header.next; } /* Undo constraint twiddling. */ @@ -3882,12 +4324,12 @@ strip_excluded_output_sections (void) if (expld.phase != lang_mark_phase_enum) { expld.phase = lang_mark_phase_enum; - expld.dataseg.phase = exp_dataseg_none; + expld.dataseg.phase = exp_seg_none; one_lang_size_sections_pass (NULL, FALSE); lang_reset_memory_regions (); } - for (os = &lang_output_section_statement.head->output_section_statement; + for (os = (void *) lang_os_list.head; os != NULL; os = os->next) { @@ -3938,9 +4380,7 @@ strip_excluded_output_sections (void) } /* 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. */ + asection.map_tail for use as link_orders in ldwrite. */ void lang_clear_os_map (void) @@ -3950,7 +4390,7 @@ lang_clear_os_map (void) if (map_head_is_link_order) return; - for (os = &lang_output_section_statement.head->output_section_statement; + for (os = (void *) lang_os_list.head; os != NULL; os = os->next) { @@ -4039,9 +4479,7 @@ print_assignment (lang_assignment_statement_type *assignment, 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; + tree = assignment->exp; } osec = output_section->bfd_section; @@ -4076,7 +4514,9 @@ print_assignment (lang_assignment_statement_type *assignment, h = bfd_link_hash_lookup (link_info.hash, assignment->exp->assign.dst, FALSE, FALSE, TRUE); - if (h) + if (h != NULL + && (h->type == bfd_link_hash_defined + || h->type == bfd_link_hash_defweak)) { value = h->u.def.value; value += h->u.def.section->output_section->vma; @@ -4091,9 +4531,9 @@ print_assignment (lang_assignment_statement_type *assignment, else { if (assignment->exp->type.node_class == etree_provide) - minfo ("[!provide]"); + minfo ("[!provide]"); else - minfo ("*undef* "); + minfo ("*undef* "); #ifdef BFD64 minfo (" "); #endif @@ -4108,9 +4548,7 @@ print_assignment (lang_assignment_statement_type *assignment, static void print_input_statement (lang_input_statement_type *statm) { - if (statm->filename != NULL - && (statm->the_bfd == NULL - || (statm->the_bfd->flags & BFD_LINKER_CREATED) == 0)) + if (statm->filename != NULL) fprintf (config.map_file, "LOAD %s\n", statm->filename); } @@ -4135,7 +4573,7 @@ print_one_symbol (struct bfd_link_hash_entry *hash_entry, void *ptr) + hash_entry->u.def.section->output_offset + hash_entry->u.def.section->output_section->vma)); - minfo (" %T\n", hash_entry->root.string); + minfo (" %pT\n", hash_entry->root.string); } return TRUE; @@ -4158,8 +4596,7 @@ hash_entry_addr_cmp (const void *a, const void *b) static void print_all_symbols (asection *sec) { - input_section_userdata_type *ud - = (input_section_userdata_type *) get_userdata (sec); + input_section_userdata_type *ud = bfd_section_userdata (sec); struct map_symbol_def *def; struct bfd_link_hash_entry **entries; unsigned int i; @@ -4171,7 +4608,8 @@ print_all_symbols (asection *sec) /* Sort the symbols by address. */ entries = (struct bfd_link_hash_entry **) - obstack_alloc (&map_obstack, ud->map_symbol_def_count * sizeof (*entries)); + obstack_alloc (&map_obstack, + ud->map_symbol_def_count * sizeof (*entries)); for (i = 0, def = ud->map_symbol_def_head; def; def = def->next, i++) entries[i] = def->entry; @@ -4195,7 +4633,7 @@ print_input_section (asection *i, bfd_boolean is_discarded) int len; bfd_vma addr; - init_opb (); + init_opb (i); print_space (); minfo ("%s", i->name); @@ -4222,7 +4660,7 @@ print_input_section (asection *i, bfd_boolean is_discarded) size = 0; } - minfo ("0x%V %W %B\n", addr, size, i->owner); + minfo ("0x%V %W %pB\n", addr, TO_ADDR (size), i->owner); if (size != i->rawsize && i->rawsize != 0) { @@ -4238,7 +4676,7 @@ print_input_section (asection *i, bfd_boolean is_discarded) --len; } - minfo (_("%W (size before relaxing)\n"), i->rawsize); + minfo (_("%W (size before relaxing)\n"), TO_ADDR (i->rawsize)); } if (i->output_section != NULL @@ -4276,7 +4714,7 @@ print_data_statement (lang_data_statement_type *data) bfd_size_type size; const char *name; - init_opb (); + init_opb (data->output_section); for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++) print_space (); @@ -4345,7 +4783,7 @@ print_reloc_statement (lang_reloc_statement_type *reloc) bfd_vma addr; bfd_size_type size; - init_opb (); + init_opb (reloc->output_section); for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++) print_space (); @@ -4375,7 +4813,7 @@ print_padding_statement (lang_padding_statement_type *s) int len; bfd_vma addr; - init_opb (); + init_opb (s->output_section); minfo (" *fill*"); len = sizeof " *fill*" - 1; @@ -4411,8 +4849,17 @@ print_wild_statement (lang_wild_statement_type *w, print_space (); + if (w->exclude_name_list) + { + name_list *tmp; + minfo ("EXCLUDE_FILE(%s", w->exclude_name_list->name); + for (tmp = w->exclude_name_list->next; tmp; tmp = tmp->next) + minfo (" %s", tmp->name); + minfo (") "); + } + if (w->filenames_sorted) - minfo ("SORT("); + minfo ("SORT_BY_NAME("); if (w->filename != NULL) minfo ("%s", w->filename); else @@ -4423,8 +4870,44 @@ print_wild_statement (lang_wild_statement_type *w, minfo ("("); for (sec = w->section_list; sec; sec = sec->next) { - if (sec->spec.sorted) - minfo ("SORT("); + int closing_paren = 0; + + switch (sec->spec.sorted) + { + case none: + break; + + case by_name: + minfo ("SORT_BY_NAME("); + closing_paren = 1; + break; + + case by_alignment: + minfo ("SORT_BY_ALIGNMENT("); + closing_paren = 1; + break; + + case by_name_alignment: + minfo ("SORT_BY_NAME(SORT_BY_ALIGNMENT("); + closing_paren = 2; + break; + + case by_alignment_name: + minfo ("SORT_BY_ALIGNMENT(SORT_BY_NAME("); + closing_paren = 2; + break; + + case by_none: + minfo ("SORT_NONE("); + closing_paren = 1; + break; + + case by_init_priority: + minfo ("SORT_BY_INIT_PRIORITY("); + closing_paren = 1; + break; + } + if (sec->spec.exclude_name_list != NULL) { name_list *tmp; @@ -4437,7 +4920,7 @@ print_wild_statement (lang_wild_statement_type *w, minfo ("%s", sec->spec.name); else minfo ("*"); - if (sec->spec.sorted) + for (;closing_paren > 0; closing_paren--) minfo (")"); if (sec->next) minfo (" "); @@ -4610,8 +5093,7 @@ insert_pad (lang_statement_union_type **ptr, else { /* Make a new padding statement, linked into existing chain. */ - pad = (lang_statement_union_type *) - stat_alloc (sizeof (lang_padding_statement_type)); + pad = stat_alloc (sizeof (lang_padding_statement_type)); pad->header.next = *ptr; *ptr = pad; pad->header.type = lang_padding_statement_enum; @@ -4622,8 +5104,9 @@ 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 = TO_SIZE (dot + TO_ADDR (alignment_needed) - - output_section->vma); + if (!(output_section->flags & SEC_FIXED_SIZE)) + output_section->size = TO_SIZE (dot + TO_ADDR (alignment_needed) + - output_section->vma); } /* Work out how much this section will move the dot point. */ @@ -4641,7 +5124,8 @@ size_input_section if (i->sec_info_type == SEC_INFO_TYPE_JUST_SYMS) i->output_offset = i->vma - o->vma; - else if ((i->flags & SEC_EXCLUDE) != 0) + else if (((i->flags & SEC_EXCLUDE) != 0) + || output_section_statement->ignored) i->output_offset = dot - o->vma; else { @@ -4652,8 +5136,10 @@ size_input_section is greater than any seen before, then record it too. Perform the alignment by inserting a magic 'padding' statement. */ - if (output_section_statement->subsection_alignment != -1) - i->alignment_power = output_section_statement->subsection_alignment; + if (output_section_statement->subsection_alignment != NULL) + i->alignment_power + = exp_get_power (output_section_statement->subsection_alignment, + "subsection alignment"); if (o->alignment_power < i->alignment_power) o->alignment_power = i->alignment_power; @@ -4671,7 +5157,8 @@ size_input_section /* Mark how big the output section must be to contain this now. */ dot += TO_ADDR (i->size); - o->size = TO_SIZE (dot - o->vma); + if (!(o->flags & SEC_FIXED_SIZE)) + o->size = TO_SIZE (dot - o->vma); } return dot; @@ -4736,6 +5223,7 @@ lang_check_section_addresses (void) asection *s, *p; struct check_sec *sections; size_t i, count; + bfd_vma addr_mask; bfd_vma s_start; bfd_vma s_end; bfd_vma p_start = 0; @@ -4743,6 +5231,26 @@ lang_check_section_addresses (void) lang_memory_region_type *m; bfd_boolean overlays; + /* Detect address space overflow on allocated sections. */ + addr_mask = ((bfd_vma) 1 << + (bfd_arch_bits_per_address (link_info.output_bfd) - 1)) - 1; + addr_mask = (addr_mask << 1) + 1; + for (s = link_info.output_bfd->sections; s != NULL; s = s->next) + if ((s->flags & SEC_ALLOC) != 0) + { + s_end = (s->vma + s->size) & addr_mask; + if (s_end != 0 && s_end < (s->vma & addr_mask)) + einfo (_("%X%P: section %s VMA wraps around address space\n"), + s->name); + else + { + s_end = (s->lma + s->size) & addr_mask; + if (s_end != 0 && s_end < (s->lma & addr_mask)) + einfo (_("%X%P: section %s LMA wraps around address space\n"), + s->name); + } + } + if (bfd_count_sections (link_info.output_bfd) <= 1) return; @@ -4775,6 +5283,7 @@ lang_check_section_addresses (void) for (p = NULL, i = 0; i < count; i++) { s = sections[i].sec; + init_opb (s); if ((s->flags & SEC_LOAD) != 0) { s_start = s->lma; @@ -4825,6 +5334,7 @@ lang_check_section_addresses (void) for (p = NULL, i = 0; i < count; i++) { s = sections[i].sec; + init_opb (s); s_start = s->vma; s_end = s_start + TO_ADDR (s->size) - 1; @@ -4853,8 +5363,13 @@ lang_check_section_addresses (void) a bfd_vma quantity in decimal. */ for (m = lang_memory_region_list; m; m = m->next) if (m->had_full_message) - einfo (_("%X%P: region `%s' overflowed by %ld bytes\n"), - m->name_list.name, (long)(m->current - (m->origin + m->length))); + { + unsigned long over = m->current - (m->origin + m->length); + einfo (ngettext ("%X%P: region `%s' overflowed by %lu byte\n", + "%X%P: region `%s' overflowed by %lu bytes\n", + over), + m->name_list.name, over); + } } /* Make sure the new address is within the region. We explicitly permit the @@ -4875,7 +5390,7 @@ os_region_check (lang_output_section_statement_type *os, { if (tree != NULL) { - einfo (_("%X%P: address 0x%v of %B section `%s'" + einfo (_("%X%P: address 0x%v of %pB section `%s'" " is not within region `%s'\n"), region->current, os->bfd_section->owner, @@ -4886,7 +5401,7 @@ os_region_check (lang_output_section_statement_type *os, { region->had_full_message = TRUE; - einfo (_("%X%P: %B section `%s' will not fit in region `%s'\n"), + einfo (_("%X%P: %pB section `%s' will not fit in region `%s'\n"), os->bfd_section->owner, os->bfd_section->name, region->name_list.name); @@ -4894,6 +5409,30 @@ os_region_check (lang_output_section_statement_type *os, } } +static void +ldlang_check_relro_region (lang_statement_union_type *s, + seg_align_type *seg) +{ + if (seg->relro == exp_seg_relro_start) + { + if (!seg->relro_start_stat) + seg->relro_start_stat = s; + else + { + ASSERT (seg->relro_start_stat == s); + } + } + else if (seg->relro == exp_seg_relro_end) + { + if (!seg->relro_end_stat) + seg->relro_end_stat = s; + else + { + ASSERT (seg->relro_end_stat == s); + } + } +} + /* Set the sizes for all the output sections. */ static bfd_vma @@ -4920,6 +5459,7 @@ lang_size_sections_1 int section_alignment = 0; os = &s->output_section_statement; + init_opb (os->bfd_section); if (os->constraint == -1) break; @@ -4943,7 +5483,7 @@ lang_size_sections_1 dot += expld.result.section->vma; } else if (expld.phase != lang_mark_phase_enum) - einfo (_("%F%S: non constant or forward reference" + einfo (_("%F%P:%pS: non constant or forward reference" " address expression for section %s\n"), os->addr_tree, os->name); } @@ -4968,14 +5508,14 @@ lang_size_sections_1 || os->children.head->header.next != NULL || (os->children.head->header.type != lang_input_section_enum)) - einfo (_("%P%X: Internal error on COFF shared library" + einfo (_("%X%P: internal error on COFF shared library" " section %s\n"), os->name); input = os->children.head->input_section.section; - bfd_set_section_vma (os->bfd_section->owner, - os->bfd_section, - bfd_section_vma (input->owner, input)); - os->bfd_section->size = input->size; + bfd_set_section_vma (os->bfd_section, + bfd_section_vma (input)); + if (!(os->bfd_section->flags & SEC_FIXED_SIZE)) + os->bfd_section->size = input->size; break; } @@ -5026,22 +5566,21 @@ lang_size_sections_1 overridden by the using the --no-check-sections switch. */ if (command_line.check_section_addresses) - einfo (_("%P%F: error: no memory region specified" + einfo (_("%F%P: error: no memory region specified" " for loadable section `%s'\n"), - bfd_get_section_name (link_info.output_bfd, - os->bfd_section)); + bfd_section_name (os->bfd_section)); else einfo (_("%P: warning: no memory region specified" " for loadable section `%s'\n"), - bfd_get_section_name (link_info.output_bfd, - os->bfd_section)); + bfd_section_name (os->bfd_section)); } newdot = os->region->current; section_alignment = os->bfd_section->alignment_power; } else - section_alignment = os->section_alignment; + section_alignment = exp_get_power (os->section_alignment, + "section alignment"); /* Align to what the section needs. */ if (section_alignment > 0) @@ -5054,12 +5593,15 @@ lang_size_sections_1 && (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"), + einfo (ngettext ("%P: warning: changing start of " + "section %s by %lu byte\n", + "%P: warning: changing start of " + "section %s by %lu bytes\n", + (unsigned long) dotdelta), os->name, (unsigned long) dotdelta); } - bfd_set_section_vma (0, os->bfd_section, newdot); + bfd_set_section_vma (os->bfd_section, newdot); os->bfd_section->output_offset = 0; } @@ -5087,7 +5629,9 @@ lang_size_sections_1 + os->block_value - 1) & - (bfd_vma) os->block_value); - os->bfd_section->size = TO_SIZE (after - os->bfd_section->vma); + if (!(os->bfd_section->flags & SEC_FIXED_SIZE)) + os->bfd_section->size = TO_SIZE (after + - os->bfd_section->vma); } /* Set section lma. */ @@ -5114,7 +5658,8 @@ lang_size_sections_1 only align according to the value in the output statement. */ if (os->lma_region != os->region) - section_alignment = os->section_alignment; + section_alignment = exp_get_power (os->section_alignment, + "section alignment"); if (section_alignment > 0) lma = align_power (lma, section_alignment); } @@ -5143,8 +5688,8 @@ lang_size_sections_1 so people can fix their linker scripts. */ if (last->vma != last->lma) - einfo (_("%P: warning: dot moved backwards before `%s'\n"), - os->name); + einfo (_("%P: warning: dot moved backwards " + "before `%s'\n"), os->name); } else { @@ -5156,7 +5701,7 @@ lang_size_sections_1 /* Otherwise, keep the same lma to vma relationship as the previous section. */ else - lma = dot + last->lma - last->vma; + lma = os->bfd_section->vma + last->lma - last->vma; if (section_alignment > 0) lma = align_power (lma, section_alignment); @@ -5165,9 +5710,6 @@ lang_size_sections_1 } os->processed_lma = TRUE; - if (bfd_is_abs_section (os->bfd_section) || os->ignored) - break; - /* Keep track of normal sections using the default lma region. We use this to set the lma for following sections. Overlays or other linker @@ -5175,18 +5717,28 @@ lang_size_sections_1 default lma == vma is incorrect. To avoid warnings about dot moving backwards when using -Ttext, don't start tracking sections until we find one - of non-zero size or with lma set differently to vma. */ - if (!IGNORE_SECTION (os->bfd_section) - && (os->bfd_section->size != 0 - || (r->last_os == NULL - && os->bfd_section->vma != os->bfd_section->lma) - || (r->last_os != NULL - && dot >= (r->last_os->output_section_statement - .bfd_section->vma))) + of non-zero size or with lma set differently to vma. + Do this tracking before we short-cut the loop so that we + track changes for the case where the section size is zero, + but the lma is set differently to the vma. This is + important, if an orphan section is placed after an + otherwise empty output section that has an explicit lma + set, we want that lma reflected in the orphans lma. */ + if (((!IGNORE_SECTION (os->bfd_section) + && (os->bfd_section->size != 0 + || (r->last_os == NULL + && os->bfd_section->vma != os->bfd_section->lma) + || (r->last_os != NULL + && dot >= (r->last_os->output_section_statement + .bfd_section->vma)))) + || os->sectype == first_overlay_section) && os->lma_region == NULL && !bfd_link_relocatable (&link_info)) r->last_os = s; + if (bfd_is_abs_section (os->bfd_section) || os->ignored) + break; + /* .tbss sections effectively have zero size. */ if (!IS_TBSS (os->bfd_section) || bfd_link_relocatable (&link_info)) @@ -5266,8 +5818,10 @@ 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 - = TO_SIZE (dot - output_section_statement->bfd_section->vma); + if (!(output_section_statement->bfd_section->flags + & SEC_FIXED_SIZE)) + output_section_statement->bfd_section->size + = TO_SIZE (dot - output_section_statement->bfd_section->vma); } break; @@ -5282,8 +5836,10 @@ 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 - = TO_SIZE (dot - output_section_statement->bfd_section->vma); + if (!(output_section_statement->bfd_section->flags + & SEC_FIXED_SIZE)) + output_section_statement->bfd_section->size + = TO_SIZE (dot - output_section_statement->bfd_section->vma); } break; @@ -5294,8 +5850,9 @@ lang_size_sections_1 break; case lang_object_symbols_statement_enum: - link_info.create_object_symbols_section = - output_section_statement->bfd_section; + link_info.create_object_symbols_section + = output_section_statement->bfd_section; + output_section_statement->bfd_section->flags |= SEC_KEEP; break; case lang_output_statement_enum: @@ -5311,8 +5868,8 @@ lang_size_sections_1 { bfd_boolean again; - if (! bfd_relax_section (i->owner, i, &link_info, &again)) - einfo (_("%P%F: can't relax section: %E\n")); + if (!bfd_relax_section (i->owner, i, &link_info, &again)) + einfo (_("%F%P: can't relax section: %E\n")); if (again) *relax = TRUE; } @@ -5336,31 +5893,15 @@ lang_size_sections_1 bfd_vma newdot = dot; etree_type *tree = s->assignment_statement.exp; - expld.dataseg.relro = exp_dataseg_relro_none; + expld.dataseg.relro = exp_seg_relro_none; exp_fold_tree (tree, output_section_statement->bfd_section, &newdot); - if (expld.dataseg.relro == exp_dataseg_relro_start) - { - if (!expld.dataseg.relro_start_stat) - expld.dataseg.relro_start_stat = s; - else - { - ASSERT (expld.dataseg.relro_start_stat == s); - } - } - else if (expld.dataseg.relro == exp_dataseg_relro_end) - { - if (!expld.dataseg.relro_end_stat) - expld.dataseg.relro_end_stat = s; - else - { - ASSERT (expld.dataseg.relro_end_stat == s); - } - } - expld.dataseg.relro = exp_dataseg_relro_none; + ldlang_check_relro_region (s, &expld.dataseg); + + expld.dataseg.relro = exp_seg_relro_none; /* This symbol may be relative to this section. */ if ((tree->type.node_class == etree_provided @@ -5449,14 +5990,14 @@ lang_size_sections_1 segments. We are allowed an opportunity to override this decision. */ bfd_boolean -ldlang_override_segment_assignment (struct bfd_link_info * info ATTRIBUTE_UNUSED, - bfd * abfd ATTRIBUTE_UNUSED, - asection * current_section, - asection * previous_section, +ldlang_override_segment_assignment (struct bfd_link_info *info ATTRIBUTE_UNUSED, + bfd *abfd ATTRIBUTE_UNUSED, + asection *current_section, + asection *previous_section, bfd_boolean new_segment) { - lang_output_section_statement_type * cur; - lang_output_section_statement_type * prev; + lang_output_section_statement_type *cur; + lang_output_section_statement_type *prev; /* The checks below are only necessary when the BFD library has decided that the two sections ought to be placed into the same segment. */ @@ -5499,90 +6040,136 @@ one_lang_size_sections_pass (bfd_boolean *relax, bfd_boolean check_regions) 0, 0, relax, check_regions); } -void -lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions) +static bfd_boolean +lang_size_segment (seg_align_type *seg) { - expld.phase = lang_allocating_phase_enum; - expld.dataseg.phase = exp_dataseg_none; + /* If XXX_SEGMENT_ALIGN XXX_SEGMENT_END pair was seen, check whether + a page could be saved in the data segment. */ + bfd_vma first, last; - one_lang_size_sections_pass (relax, check_regions); - if (expld.dataseg.phase == exp_dataseg_end_seen - && link_info.relro && expld.dataseg.relro_end) + first = -seg->base & (seg->pagesize - 1); + last = seg->end & (seg->pagesize - 1); + if (first && last + && ((seg->base & ~(seg->pagesize - 1)) + != (seg->end & ~(seg->pagesize - 1))) + && first + last <= seg->pagesize) { - bfd_vma initial_base, relro_end, desired_end; - asection *sec; + seg->phase = exp_seg_adjust; + return TRUE; + } - /* Compute the expected PT_GNU_RELRO segment end. */ - relro_end = ((expld.dataseg.relro_end + expld.dataseg.pagesize - 1) - & ~(expld.dataseg.pagesize - 1)); + seg->phase = exp_seg_done; + return FALSE; +} - /* Adjust by the offset arg of DATA_SEGMENT_RELRO_END. */ - desired_end = relro_end - expld.dataseg.relro_offset; +static bfd_vma +lang_size_relro_segment_1 (seg_align_type *seg) +{ + bfd_vma relro_end, desired_end; + asection *sec; - /* For sections in the relro segment.. */ - for (sec = link_info.output_bfd->section_last; sec; sec = sec->prev) - if ((sec->flags & SEC_ALLOC) != 0 - && 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, end, bump; - - end = start = sec->vma; - if (!IS_TBSS (sec)) - end += TO_ADDR (sec->size); - 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; - start &= ~(((bfd_vma) 1 << sec->alignment_power) - 1); - /* This is now the desired end for the previous section. */ - desired_end = start; - } + /* Compute the expected PT_GNU_RELRO/PT_LOAD segment end. */ + relro_end = ((seg->relro_end + seg->pagesize - 1) + & ~(seg->pagesize - 1)); + + /* Adjust by the offset arg of XXX_SEGMENT_RELRO_END. */ + desired_end = relro_end - seg->relro_offset; + + /* For sections in the relro segment.. */ + for (sec = link_info.output_bfd->section_last; sec; sec = sec->prev) + if ((sec->flags & SEC_ALLOC) != 0 + && sec->vma >= seg->base + && sec->vma < seg->relro_end - seg->relro_offset) + { + /* Where do we want to put this section so that it ends as + desired? */ + bfd_vma start, end, bump; + + end = start = sec->vma; + if (!IS_TBSS (sec)) + end += TO_ADDR (sec->size); + 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; + start &= ~(((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; + seg->phase = exp_seg_relro_adjust; + ASSERT (desired_end >= seg->base); + seg->base = desired_end; + return relro_end; +} + +static bfd_boolean +lang_size_relro_segment (bfd_boolean *relax, bfd_boolean check_regions) +{ + bfd_boolean do_reset = FALSE; + bfd_boolean do_data_relro; + bfd_vma data_initial_base, data_relro_end; + + if (link_info.relro && expld.dataseg.relro_end) + { + do_data_relro = TRUE; + data_initial_base = expld.dataseg.base; + data_relro_end = lang_size_relro_segment_1 (&expld.dataseg); + } + else + { + do_data_relro = FALSE; + data_initial_base = data_relro_end = 0; + } + + if (do_data_relro) + { lang_reset_memory_regions (); one_lang_size_sections_pass (relax, check_regions); - if (expld.dataseg.relro_end > relro_end) + /* Assignments to dot, or to output section address in a user + script have increased padding over the original. Revert. */ + if (do_data_relro && expld.dataseg.relro_end > data_relro_end) { - /* 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); + expld.dataseg.base = data_initial_base;; + do_reset = TRUE; } - - link_info.relro_start = expld.dataseg.base; - link_info.relro_end = expld.dataseg.relro_end; } - else if (expld.dataseg.phase == exp_dataseg_end_seen) + + if (!do_data_relro && lang_size_segment (&expld.dataseg)) + do_reset = TRUE; + + return do_reset; +} + +void +lang_size_sections (bfd_boolean *relax, bfd_boolean check_regions) +{ + expld.phase = lang_allocating_phase_enum; + expld.dataseg.phase = exp_seg_none; + + one_lang_size_sections_pass (relax, check_regions); + + if (expld.dataseg.phase != exp_seg_end_seen) + expld.dataseg.phase = exp_seg_done; + + if (expld.dataseg.phase == exp_seg_end_seen) { - /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_END pair was seen, check whether - a page could be saved in the data segment. */ - bfd_vma first, last; + bfd_boolean do_reset + = lang_size_relro_segment (relax, check_regions); - first = -expld.dataseg.base & (expld.dataseg.pagesize - 1); - last = expld.dataseg.end & (expld.dataseg.pagesize - 1); - if (first && last - && ((expld.dataseg.base & ~(expld.dataseg.pagesize - 1)) - != (expld.dataseg.end & ~(expld.dataseg.pagesize - 1))) - && first + last <= expld.dataseg.pagesize) + if (do_reset) { - expld.dataseg.phase = exp_dataseg_adjust; lang_reset_memory_regions (); one_lang_size_sections_pass (relax, check_regions); } - else - expld.dataseg.phase = exp_dataseg_done; + + if (link_info.relro && expld.dataseg.relro_end) + { + link_info.relro_start = expld.dataseg.base; + link_info.relro_end = expld.dataseg.relro_end; + } } - else - expld.dataseg.phase = exp_dataseg_done; } static lang_output_section_statement_type *current_section; @@ -5610,9 +6197,11 @@ lang_do_assignments_1 (lang_statement_union_type *s, case lang_output_section_statement_enum: { lang_output_section_statement_type *os; + bfd_vma newdot; os = &(s->output_section_statement); os->after_end = *found_end; + init_opb (os->bfd_section); if (os->bfd_section != NULL && !os->ignored) { if ((os->bfd_section->flags & SEC_ALLOC) != 0) @@ -5621,17 +6210,24 @@ lang_do_assignments_1 (lang_statement_union_type *s, prefer_next_section = FALSE; } dot = os->bfd_section->vma; - - lang_do_assignments_1 (os->children.head, - os, os->fill, dot, found_end); - - /* .tbss sections effectively have zero size. */ - if (!IS_TBSS (os->bfd_section) - || bfd_link_relocatable (&link_info)) - dot += TO_ADDR (os->bfd_section->size); - - if (os->update_dot_tree != NULL) - exp_fold_tree (os->update_dot_tree, bfd_abs_section_ptr, &dot); + } + newdot = lang_do_assignments_1 (os->children.head, + os, os->fill, dot, found_end); + if (!os->ignored) + { + if (os->bfd_section != NULL) + { + /* .tbss sections effectively have zero size. */ + if (!IS_TBSS (os->bfd_section) + || bfd_link_relocatable (&link_info)) + dot += TO_ADDR (os->bfd_section->size); + + if (os->update_dot_tree != NULL) + exp_fold_tree (os->update_dot_tree, + bfd_abs_section_ptr, &dot); + } + else + dot = newdot; } } break; @@ -5655,7 +6251,7 @@ lang_do_assignments_1 (lang_statement_union_type *s, if (expld.result.section != NULL) s->data_statement.value += expld.result.section->vma; } - else + else if (expld.phase == lang_final_phase_enum) einfo (_("%F%P: invalid data statement\n")); { unsigned int size; @@ -5688,7 +6284,7 @@ lang_do_assignments_1 (lang_statement_union_type *s, bfd_abs_section_ptr, &dot); if (expld.result.valid_p) s->reloc_statement.addend_value = expld.result.value; - else + else if (expld.phase == lang_final_phase_enum) einfo (_("%F%P: invalid reloc statement\n")); dot += TO_ADDR (bfd_get_reloc_size (s->reloc_statement.howto)); break; @@ -5724,7 +6320,8 @@ lang_do_assignments_1 (lang_statement_union_type *s, *found_end = TRUE; } exp_fold_tree (s->assignment_statement.exp, - current_os->bfd_section, + (current_os->bfd_section != NULL + ? current_os->bfd_section : bfd_und_section_ptr), &dot); break; @@ -5839,52 +6436,191 @@ section_for_dot (void) return bfd_abs_section_ptr; } -/* Fix any .startof. or .sizeof. symbols. When the assemblers see the - operator .startof. (section_name), it produces an undefined symbol - .startof.section_name. Similarly, when it sees - .sizeof. (section_name), it produces an undefined symbol - .sizeof.section_name. For all the output sections, we look for - such symbols, and set them to the correct value. */ +/* Array of __start/__stop/.startof./.sizeof/ symbols. */ + +static struct bfd_link_hash_entry **start_stop_syms; +static size_t start_stop_count = 0; +static size_t start_stop_alloc = 0; + +/* Give start/stop SYMBOL for SEC a preliminary definition, and add it + to start_stop_syms. */ static void -lang_set_startof (void) +lang_define_start_stop (const char *symbol, asection *sec) { + struct bfd_link_hash_entry *h; + + h = bfd_define_start_stop (link_info.output_bfd, &link_info, symbol, sec); + if (h != NULL) + { + if (start_stop_count == start_stop_alloc) + { + start_stop_alloc = 2 * start_stop_alloc + 10; + start_stop_syms + = xrealloc (start_stop_syms, + start_stop_alloc * sizeof (*start_stop_syms)); + } + start_stop_syms[start_stop_count++] = h; + } +} + +/* Check for input sections whose names match references to + __start_SECNAME or __stop_SECNAME symbols. Give the symbols + preliminary definitions. */ + +static void +lang_init_start_stop (void) +{ + bfd *abfd; asection *s; + char leading_char = bfd_get_symbol_leading_char (link_info.output_bfd); - if (bfd_link_relocatable (&link_info)) + for (abfd = link_info.input_bfds; abfd != NULL; abfd = abfd->link.next) + for (s = abfd->sections; s != NULL; s = s->next) + { + const char *ps; + const char *secname = s->name; + + for (ps = secname; *ps != '\0'; ps++) + if (!ISALNUM ((unsigned char) *ps) && *ps != '_') + break; + if (*ps == '\0') + { + char *symbol = (char *) xmalloc (10 + strlen (secname)); + + symbol[0] = leading_char; + sprintf (symbol + (leading_char != 0), "__start_%s", secname); + lang_define_start_stop (symbol, s); + + symbol[1] = leading_char; + memcpy (symbol + 1 + (leading_char != 0), "__stop", 6); + lang_define_start_stop (symbol + 1, s); + + free (symbol); + } + } +} + +/* Iterate over start_stop_syms. */ + +static void +foreach_start_stop (void (*func) (struct bfd_link_hash_entry *)) +{ + size_t i; + + for (i = 0; i < start_stop_count; ++i) + func (start_stop_syms[i]); +} + +/* __start and __stop symbols are only supposed to be defined by the + linker for orphan sections, but we now extend that to sections that + map to an output section of the same name. The symbols were + defined early for --gc-sections, before we mapped input to output + sections, so undo those that don't satisfy this rule. */ + +static void +undef_start_stop (struct bfd_link_hash_entry *h) +{ + if (h->ldscript_def) return; + if (h->u.def.section->output_section == NULL + || h->u.def.section->output_section->owner != link_info.output_bfd + || strcmp (h->u.def.section->name, + h->u.def.section->output_section->name) != 0) + { + asection *sec = bfd_get_section_by_name (link_info.output_bfd, + h->u.def.section->name); + if (sec != NULL) + { + /* When there are more than one input sections with the same + section name, SECNAME, linker picks the first one to define + __start_SECNAME and __stop_SECNAME symbols. When the first + input section is removed by comdat group, we need to check + if there is still an output section with section name + SECNAME. */ + asection *i; + for (i = sec->map_head.s; i != NULL; i = i->map_head.s) + if (strcmp (h->u.def.section->name, i->name) == 0) + { + h->u.def.section = i; + return; + } + } + h->type = bfd_link_hash_undefined; + h->u.undef.abfd = NULL; + } +} + +static void +lang_undef_start_stop (void) +{ + foreach_start_stop (undef_start_stop); +} + +/* Check for output sections whose names match references to + .startof.SECNAME or .sizeof.SECNAME symbols. Give the symbols + preliminary definitions. */ + +static void +lang_init_startof_sizeof (void) +{ + asection *s; + for (s = link_info.output_bfd->sections; s != NULL; s = s->next) { - const char *secname; - char *buf; - struct bfd_link_hash_entry *h; + const char *secname = s->name; + char *symbol = (char *) xmalloc (10 + strlen (secname)); - secname = bfd_get_section_name (link_info.output_bfd, s); - buf = (char *) xmalloc (10 + strlen (secname)); + sprintf (symbol, ".startof.%s", secname); + lang_define_start_stop (symbol, s); - sprintf (buf, ".startof.%s", secname); - h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE, TRUE); - if (h != NULL && h->type == bfd_link_hash_undefined) - { - h->type = bfd_link_hash_defined; - h->u.def.value = 0; - h->u.def.section = s; - } + memcpy (symbol + 1, ".size", 5); + lang_define_start_stop (symbol + 1, s); + free (symbol); + } +} - sprintf (buf, ".sizeof.%s", secname); - h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE, TRUE); - if (h != NULL && h->type == bfd_link_hash_undefined) +/* Set .startof., .sizeof., __start and __stop symbols final values. */ + +static void +set_start_stop (struct bfd_link_hash_entry *h) +{ + if (h->ldscript_def + || h->type != bfd_link_hash_defined) + return; + + if (h->root.string[0] == '.') + { + /* .startof. or .sizeof. symbol. + .startof. already has final value. */ + if (h->root.string[2] == 'i') { - h->type = bfd_link_hash_defined; - h->u.def.value = TO_ADDR (s->size); + /* .sizeof. */ + h->u.def.value = TO_ADDR (h->u.def.section->size); h->u.def.section = bfd_abs_section_ptr; } + } + else + { + /* __start or __stop symbol. */ + int has_lead = bfd_get_symbol_leading_char (link_info.output_bfd) != 0; - free (buf); + h->u.def.section = h->u.def.section->output_section; + if (h->root.string[4 + has_lead] == 'o') + { + /* __stop_ */ + h->u.def.value = TO_ADDR (h->u.def.section->size); + } } } +static void +lang_finalize_start_stop (void) +{ + foreach_start_stop (set_start_stop); +} + static void lang_end (void) { @@ -5898,10 +6634,12 @@ lang_end (void) warn = TRUE; /* Force the user to specify a root when generating a relocatable with - --gc-sections. */ - if (link_info.gc_sections && bfd_link_relocatable (&link_info) + --gc-sections, unless --gc-keep-exported was also given. */ + if (bfd_link_relocatable (&link_info) + && link_info.gc_sections + && !link_info.gc_keep_exported && !(entry_from_cmdline || undef_from_cmdline)) - einfo (_("%P%F: gc-sections requires either an entry or " + einfo (_("%F%P: gc-sections requires either an entry or " "an undefined symbol\n")); if (entry_symbol.name == NULL) @@ -5922,11 +6660,10 @@ lang_end (void) bfd_vma val; val = (h->u.def.value - + bfd_get_section_vma (link_info.output_bfd, - h->u.def.section->output_section) + + bfd_section_vma (h->u.def.section->output_section) + h->u.def.section->output_offset); - if (! bfd_set_start_address (link_info.output_bfd, val)) - einfo (_("%P%F:%s: can't set start address\n"), entry_symbol.name); + if (!bfd_set_start_address (link_info.output_bfd, val)) + einfo (_("%F%P: %s: can't set start address\n"), entry_symbol.name); } else { @@ -5938,8 +6675,8 @@ lang_end (void) val = bfd_scan_vma (entry_symbol.name, &send, 0); if (*send == '\0') { - if (! bfd_set_start_address (link_info.output_bfd, val)) - einfo (_("%P%F: can't set start address\n")); + if (!bfd_set_start_address (link_info.output_bfd, val)) + einfo (_("%F%P: can't set start address\n")); } else { @@ -5954,11 +6691,10 @@ lang_end (void) einfo (_("%P: warning: cannot find entry symbol %s;" " defaulting to %V\n"), entry_symbol.name, - bfd_get_section_vma (link_info.output_bfd, ts)); - if (!(bfd_set_start_address - (link_info.output_bfd, - bfd_get_section_vma (link_info.output_bfd, ts)))) - einfo (_("%P%F: can't set start address\n")); + bfd_section_vma (ts)); + if (!bfd_set_start_address (link_info.output_bfd, + bfd_section_vma (ts))) + einfo (_("%F%P: can't set start address\n")); } else { @@ -5975,7 +6711,8 @@ lang_end (void) BFD. */ static void -ignore_bfd_errors (const char *s ATTRIBUTE_UNUSED, ...) +ignore_bfd_errors (const char *fmt ATTRIBUTE_UNUSED, + va_list ap ATTRIBUTE_UNUSED) { /* Don't do anything. */ } @@ -5987,18 +6724,20 @@ ignore_bfd_errors (const char *s ATTRIBUTE_UNUSED, ...) static void lang_check (void) { - lang_statement_union_type *file; + lang_input_statement_type *file; bfd *input_bfd; const bfd_arch_info_type *compatible; - for (file = file_chain.head; file != NULL; file = file->input_statement.next) + for (file = (void *) file_chain.head; + file != NULL; + file = file->next) { #ifdef ENABLE_PLUGINS /* Don't check format of files claimed by plugin. */ - if (file->input_statement.flags.claimed) + if (file->flags.claimed) continue; #endif /* ENABLE_PLUGINS */ - input_bfd = file->input_statement.the_bfd; + input_bfd = file->the_bfd; compatible = bfd_arch_get_compatible (input_bfd, link_info.output_bfd, command_line.accept_unknown_input_arch); @@ -6016,8 +6755,8 @@ lang_check (void) != bfd_get_flavour (link_info.output_bfd))) && (bfd_get_file_flags (input_bfd) & HAS_RELOC) != 0) { - einfo (_("%P%F: Relocatable linking with relocations from" - " format %s (%B) to format %s (%B) is not supported\n"), + einfo (_("%F%P: relocatable linking with relocations from" + " format %s (%pB) to format %s (%pB) is not supported\n"), bfd_get_target (input_bfd), input_bfd, bfd_get_target (link_info.output_bfd), link_info.output_bfd); /* einfo with %F exits. */ @@ -6026,7 +6765,7 @@ lang_check (void) if (compatible == NULL) { if (command_line.warn_mismatch) - einfo (_("%P%X: %s architecture of input file `%B'" + einfo (_("%X%P: %s architecture of input file `%pB'" " is incompatible with %s output\n"), bfd_printable_name (input_bfd), input_bfd, bfd_printable_name (link_info.output_bfd)); @@ -6043,15 +6782,15 @@ lang_check (void) function which will do nothing. We still want to call bfd_merge_private_bfd_data, since it may set up information which is needed in the output file. */ - if (! command_line.warn_mismatch) + if (!command_line.warn_mismatch) pfn = bfd_set_error_handler (ignore_bfd_errors); - if (! bfd_merge_private_bfd_data (input_bfd, link_info.output_bfd)) + if (!bfd_merge_private_bfd_data (input_bfd, &link_info)) { if (command_line.warn_mismatch) - einfo (_("%P%X: failed to merge target specific data" - " of file %B\n"), input_bfd); + einfo (_("%X%P: failed to merge target specific data" + " of file %pB\n"), input_bfd); } - if (! command_line.warn_mismatch) + if (!command_line.warn_mismatch) bfd_set_error_handler (pfn); } } @@ -6064,13 +6803,13 @@ lang_check (void) static void lang_common (void) { - if (command_line.inhibit_common_definition) + if (link_info.inhibit_common_definition) return; if (bfd_link_relocatable (&link_info) - && ! command_line.force_common_definition) + && !command_line.force_common_definition) return; - if (! config.sort_common) + if (!config.sort_common) bfd_link_hash_traverse (link_info.hash, lang_one_common, NULL); else { @@ -6119,7 +6858,7 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info) section = h->u.c.p->section; if (!bfd_define_common_symbol (link_info.output_bfd, &link_info, h)) - einfo (_("%P%F: Could not define common symbol `%T': %E\n"), + einfo (_("%F%P: could not define common symbol `%pT': %E\n"), h->root.string); if (config.map_file != NULL) @@ -6129,7 +6868,7 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info) char *name; char buf[50]; - if (! header_printed) + if (!header_printed) { minfo (_("\nAllocating common symbols\n")); minfo (_("Common symbol size file\n\n")); @@ -6175,7 +6914,7 @@ lang_one_common (struct bfd_link_hash_entry *h, void *info) ++len; } - minfo ("%B\n", section->owner); + minfo ("%pB\n", section->owner); } return TRUE; @@ -6206,7 +6945,7 @@ ldlang_place_orphan (asection *s) int constraint = 0; if (config.orphan_handling == orphan_handling_error) - einfo ("%X%P: error: unplaced orphan section `%A' from `%B'.\n", + einfo (_("%X%P: error: unplaced orphan section `%pA' from `%pB'\n"), s, s->owner); if (config.unique_orphan_sections || unique_section_p (s, NULL)) @@ -6224,8 +6963,8 @@ ldlang_place_orphan (asection *s) } if (config.orphan_handling == orphan_handling_warn) - einfo ("%P: warning: orphan section `%A' from `%B' being " - "placed in section `%s'.\n", + einfo (_("%P: warning: orphan section `%pA' from `%pB' being " + "placed in section `%s'\n"), s, s->owner, os->name); } } @@ -6250,7 +6989,7 @@ lang_place_orphans (void) if (file->flags.just_syms) bfd_link_just_syms (file->the_bfd, s, &link_info); - else if ((s->flags & SEC_EXCLUDE) != 0) + else if (lang_discard_section_p (s)) s->output_section = bfd_abs_section_ptr; else if (strcmp (s->name, "COMMON") == 0) { @@ -6289,7 +7028,7 @@ lang_set_flags (lang_memory_region_type *ptr, const char *flags, int invert) /* PR 17900: An exclamation mark in the attributes reverses the sense of any of the attributes that follow. */ case '!': - invert = ! invert; + invert = !invert; ptr_flags = invert ? &ptr->not_flags : &ptr->flags; break; @@ -6315,46 +7054,47 @@ lang_set_flags (lang_memory_region_type *ptr, const char *flags, int invert) break; default: - einfo (_("%P%F: invalid character %c (%d) in flags\n"), * flags, * flags); + einfo (_("%F%P: invalid character %c (%d) in flags\n"), + *flags, *flags); break; } flags++; } } -/* Call a function on each input file. This function will be called - on an archive, but not on the elements. */ +/* Call a function on each real input file. This function will be + called on an archive, but not on the elements. */ void lang_for_each_input_file (void (*func) (lang_input_statement_type *)) { lang_input_statement_type *f; - for (f = (lang_input_statement_type *) input_file_chain.head; + for (f = (void *) input_file_chain.head; f != NULL; - f = (lang_input_statement_type *) f->next_real_file) - func (f); + f = f->next_real_file) + if (f->flags.real) + func (f); } -/* Call a function on each file. The function will be called on all - the elements of an archive which are included in the link, but will - not be called on the archive file itself. */ +/* Call a function on each real file. The function will be called on + all the elements of an archive which are included in the link, but + will not be called on the archive file itself. */ void lang_for_each_file (void (*func) (lang_input_statement_type *)) { LANG_FOR_EACH_INPUT_STATEMENT (f) { - func (f); + if (f->flags.real) + func (f); } } void ldlang_add_file (lang_input_statement_type *entry) { - lang_statement_append (&file_chain, - (lang_statement_union_type *) entry, - &entry->next); + lang_statement_append (&file_chain, entry, &entry->next); /* The BFD linker needs to have a list of all input BFDs involved in a link. */ @@ -6363,7 +7103,7 @@ ldlang_add_file (lang_input_statement_type *entry) *link_info.input_bfds_tail = entry->the_bfd; link_info.input_bfds_tail = &entry->the_bfd->link.next; - entry->the_bfd->usrdata = entry; + bfd_set_usrdata (entry->the_bfd, entry); bfd_set_gp_size (entry->the_bfd, g_switch_value); /* Look through the sections and check for any which should not be @@ -6390,25 +7130,6 @@ lang_add_output (const char *name, int from_script) } } -static int -topower (int x) -{ - unsigned int i = 1; - int l; - - if (x < 0) - return -1; - - for (l = 0; l < 32; l++) - { - if (i >= (unsigned int) x) - return l; - i <<= 1; - } - - return 0; -} - lang_output_section_statement_type * lang_enter_output_section_statement (const char *output_section_statement_name, etree_type *address_exp, @@ -6441,12 +7162,11 @@ lang_enter_output_section_statement (const char *output_section_statement_name, 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); + einfo (_("%F%P:%pS: 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 = - topower (exp_get_value_int (align, -1, "section alignment")); + os->subsection_alignment = subalign; + os->section_alignment = align; os->load_base = ebase; return os; @@ -6476,7 +7196,7 @@ lang_reset_memory_regions (void) p->last_os = NULL; } - for (os = &lang_output_section_statement.head->output_section_statement; + for (os = (void *) lang_os_list.head; os != NULL; os = os->next) { @@ -6488,7 +7208,8 @@ lang_reset_memory_regions (void) { /* Save the last size for possible use by bfd_relax_section. */ o->rawsize = o->size; - o->size = 0; + if (!(o->flags & SEC_FIXED_SIZE)) + o->size = 0; } } @@ -6590,6 +7311,7 @@ find_relro_section_callback (lang_wild_statement_type *ptr ATTRIBUTE_UNUSED, static void lang_find_relro_sections_1 (lang_statement_union_type *s, + seg_align_type *seg, bfd_boolean *has_relro_section) { if (*has_relro_section) @@ -6597,7 +7319,7 @@ lang_find_relro_sections_1 (lang_statement_union_type *s, for (; s != NULL; s = s->header.next) { - if (s == expld.dataseg.relro_end_stat) + if (s == seg->relro_end_stat) break; switch (s->header.type) @@ -6609,15 +7331,15 @@ lang_find_relro_sections_1 (lang_statement_union_type *s, break; case lang_constructors_statement_enum: lang_find_relro_sections_1 (constructor_list.head, - has_relro_section); + seg, has_relro_section); break; case lang_output_section_statement_enum: lang_find_relro_sections_1 (s->output_section_statement.children.head, - has_relro_section); + seg, has_relro_section); break; case lang_group_statement_enum: lang_find_relro_sections_1 (s->group_statement.children.head, - has_relro_section); + seg, has_relro_section); break; default: break; @@ -6633,7 +7355,7 @@ lang_find_relro_sections (void) /* Check all sections in the link script. */ lang_find_relro_sections_1 (expld.dataseg.relro_start_stat, - &has_relro_section); + &expld.dataseg, &has_relro_section); if (!has_relro_section) link_info.relro = FALSE; @@ -6708,26 +7430,76 @@ lang_relax_sections (bfd_boolean need_layout) inserted at the head of the file_chain. */ static lang_input_statement_type * -find_replacements_insert_point (void) +find_replacements_insert_point (bfd_boolean *before) { lang_input_statement_type *claim1, *lastobject; - lastobject = &input_file_chain.head->input_statement; - for (claim1 = &file_chain.head->input_statement; + lastobject = (void *) input_file_chain.head; + for (claim1 = (void *) file_chain.head; claim1 != NULL; - claim1 = &claim1->next->input_statement) + claim1 = claim1->next) { if (claim1->flags.claimed) - return claim1->flags.claim_archive ? lastobject : claim1; + { + *before = claim1->flags.claim_archive; + 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)) + if (claim1->the_bfd != NULL && claim1->the_bfd->my_archive == NULL) lastobject = claim1; } /* No files were claimed by the plugin. Choose the last object file found on the list (maybe the first, dummy entry) as the insert point. */ + *before = FALSE; return lastobject; } +/* Find where to insert ADD, an archive element or shared library + added during a rescan. */ + +static lang_input_statement_type ** +find_rescan_insertion (lang_input_statement_type *add) +{ + bfd *add_bfd = add->the_bfd; + lang_input_statement_type *f; + lang_input_statement_type *last_loaded = NULL; + lang_input_statement_type *before = NULL; + lang_input_statement_type **iter = NULL; + + if (add_bfd->my_archive != NULL) + add_bfd = add_bfd->my_archive; + + /* First look through the input file chain, to find an object file + before the one we've rescanned. Normal object files always + appear on both the input file chain and the file chain, so this + lets us get quickly to somewhere near the correct place on the + file chain if it is full of archive elements. Archives don't + appear on the file chain, but if an element has been extracted + then their input_statement->next points at it. */ + for (f = (void *) input_file_chain.head; + f != NULL; + f = f->next_real_file) + { + if (f->the_bfd == add_bfd) + { + before = last_loaded; + if (f->next != NULL) + return &f->next->next; + } + if (f->the_bfd != NULL && f->next != NULL) + last_loaded = f; + } + + for (iter = before ? &before->next : &file_chain.head->input_statement.next; + *iter != NULL; + iter = &(*iter)->next) + if (!(*iter)->flags.claim_archive + && (*iter)->the_bfd->my_archive == NULL) + break; + + return iter; +} + /* Insert SRCLIST into DESTLIST after given element by chaining on FIELD as the next-pointer. (Counterintuitively does not need a pointer to the actual after-node itself, just its chain field.) */ @@ -6759,19 +7531,48 @@ lang_list_remove_tail (lang_statement_list_type *destlist, destlist->tail = savetail; *savetail = NULL; } + +static lang_statement_union_type ** +find_next_input_statement (lang_statement_union_type **s) +{ + for ( ; *s; s = &(*s)->header.next) + { + lang_statement_union_type **t; + switch ((*s)->header.type) + { + case lang_input_statement_enum: + return s; + case lang_wild_statement_enum: + t = &(*s)->wild_statement.children.head; + break; + case lang_group_statement_enum: + t = &(*s)->group_statement.children.head; + break; + case lang_output_section_statement_enum: + t = &(*s)->output_section_statement.children.head; + break; + default: + continue; + } + t = find_next_input_statement (t); + if (*t) + return t; + } + return s; +} #endif /* ENABLE_PLUGINS */ /* Add NAME to the list of garbage collection entry points. */ void -lang_add_gc_name (const char * name) +lang_add_gc_name (const char *name) { struct bfd_sym_chain *sym; if (name == NULL) return; - sym = (struct bfd_sym_chain *) stat_alloc (sizeof (*sym)); + sym = stat_alloc (sizeof (*sym)); sym->next = link_info.gc_sym_list; sym->name = name; @@ -6800,6 +7601,27 @@ lang_check_relocs (void) } } +/* Look through all output sections looking for places where we can + propagate forward the lma region. */ + +static void +lang_propagate_lma_regions (void) +{ + lang_output_section_statement_type *os; + + for (os = (void *) lang_os_list.head; + os != NULL; + os = os->next) + { + if (os->prev != NULL + && os->lma_region == NULL + && os->load_base == NULL + && os->addr_tree == NULL + && os->region == os->prev->region) + os->lma_region = os->prev->lma_region; + } +} + void lang_process (void) { @@ -6811,7 +7633,7 @@ lang_process (void) /* Open the output file. */ lang_for_each_statement (ldlang_open_output); - init_opb (); + init_opb (NULL); ldemul_create_output_section_statements (); @@ -6819,11 +7641,15 @@ lang_process (void) lang_place_undefineds (); if (!bfd_section_already_linked_table_init ()) - einfo (_("%P%F: Failed to create hash table\n")); + einfo (_("%F%P: can not create hash table: %E\n")); /* Create a bfd for each input file. */ current_target = default_target; + lang_statement_iteration++; open_input_bfds (statement_list.head, OPEN_BFD_NORMAL); + /* open_input_bfds also handles assignments, so we can give values + to symbolic origin/length now. */ + lang_do_memory_regions (); #ifdef ENABLE_PLUGINS if (link_info.lto_plugin_active) @@ -6835,17 +7661,20 @@ lang_process (void) are any more to be added to the link before we call the emulation's after_open hook. We create a private list of input statements for this purpose, which we will eventually - insert into the global statment list after the first claimed + insert into the global statement list after the first claimed file. */ added = *stat_ptr; /* We need to manipulate all three chains in synchrony. */ files = file_chain; inputfiles = input_file_chain; if (plugin_call_all_symbols_read ()) - einfo (_("%P%F: %s: plugin reported error after all symbols read\n"), + einfo (_("%F%P: %s: plugin reported error after all symbols read\n"), plugin_error_plugin ()); /* Open any newly added files, updating the file chains. */ + plugin_undefs = link_info.hash->undefs_tail; open_input_bfds (*added.tail, OPEN_BFD_NORMAL); + if (plugin_undefs == link_info.hash->undefs_tail) + plugin_undefs = NULL; /* Restore the global list pointer now they have all been added. */ lang_list_remove_tail (stat_ptr, &added); /* And detach the fresh ends of the file lists. */ @@ -6855,34 +7684,80 @@ lang_process (void) if (added.head != NULL) { /* If so, we will insert them into the statement list immediately - after the first input file that was claimed by the plugin. */ - plugin_insert = find_replacements_insert_point (); + after the first input file that was claimed by the plugin, + unless that file was an archive in which case it is inserted + immediately before. */ + bfd_boolean before; + lang_statement_union_type **prev; + plugin_insert = find_replacements_insert_point (&before); /* If a plugin adds input files without having claimed any, we don't really have a good idea where to place them. Just putting them at the start or end of the list is liable to leave them outside the crtbegin...crtend range. */ ASSERT (plugin_insert != NULL); /* Splice the new statement list into the old one. */ - lang_list_insert_after (stat_ptr, &added, - &plugin_insert->header.next); + prev = &plugin_insert->header.next; + if (before) + { + prev = find_next_input_statement (prev); + if (*prev != (void *) plugin_insert->next_real_file) + { + /* We didn't find the expected input statement. + Fall back to adding after plugin_insert. */ + prev = &plugin_insert->header.next; + } + } + lang_list_insert_after (stat_ptr, &added, prev); /* Likewise for the file chains. */ lang_list_insert_after (&input_file_chain, &inputfiles, - &plugin_insert->next_real_file); + (void *) &plugin_insert->next_real_file); /* We must be careful when relinking file_chain; we may need to insert the new files at the head of the list if the insert point chosen is the dummy first input file. */ if (plugin_insert->filename) - lang_list_insert_after (&file_chain, &files, &plugin_insert->next); + lang_list_insert_after (&file_chain, &files, + (void *) &plugin_insert->next); else lang_list_insert_after (&file_chain, &files, &file_chain.head); /* Rescan archives in case new undefined symbols have appeared. */ + files = file_chain; + lang_statement_iteration++; open_input_bfds (statement_list.head, OPEN_BFD_RESCAN); + lang_list_remove_tail (&file_chain, &files); + while (files.head != NULL) + { + lang_input_statement_type **insert; + lang_input_statement_type **iter, *temp; + bfd *my_arch; + + insert = find_rescan_insertion (&files.head->input_statement); + /* All elements from an archive can be added at once. */ + iter = &files.head->input_statement.next; + my_arch = files.head->input_statement.the_bfd->my_archive; + if (my_arch != NULL) + for (; *iter != NULL; iter = &(*iter)->next) + if ((*iter)->the_bfd->my_archive != my_arch) + break; + temp = *insert; + *insert = &files.head->input_statement; + files.head = (lang_statement_union_type *) *iter; + *iter = temp; + if (my_arch != NULL) + { + lang_input_statement_type *parent = bfd_usrdata (my_arch); + if (parent != NULL) + parent->next = (lang_input_statement_type *) + ((char *) iter + - offsetof (lang_input_statement_type, next)); + } + } } } #endif /* ENABLE_PLUGINS */ - /* Make sure that nobody has tried to add a symbol to this list before now. */ + /* Make sure that nobody has tried to add a symbol to this list + before now. */ ASSERT (link_info.gc_sym_list == NULL); link_info.gc_sym_list = &entry_symbol; @@ -6909,6 +7784,8 @@ lang_process (void) if (config.map_file != NULL) lang_print_asneeded (); + ldlang_open_ctf (); + bfd_section_already_linked_table_free (); /* Make sure that we're not mixing architectures. We call this @@ -6926,11 +7803,15 @@ lang_process (void) files. */ ldctor_build_sets (); + /* Give initial values for __start and __stop symbols, so that ELF + gc_sections will keep sections referenced by these symbols. Must + be done before lang_do_assignments below. */ + if (config.build_constructors) + lang_init_start_stop (); + /* 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); - - lang_do_memory_regions(); expld.phase = lang_first_phase_enum; /* Size up the common data. */ @@ -6942,6 +7823,8 @@ lang_process (void) /* Check relocations. */ lang_check_relocs (); + ldemul_after_check_relocs (); + /* Update wild statements. */ update_wild_statements (statement_list.head); @@ -6950,7 +7833,11 @@ lang_process (void) lang_statement_iteration++; map_input_to_output_sections (statement_list.head, NULL, NULL); - process_insert_statements (); + /* Start at the statement immediately after the special abs_section + output statement, so that it isn't reordered. */ + process_insert_statements (&lang_os_list.head->header.next); + + ldemul_before_place_orphans (); /* Find any sections not attached explicitly and handle them. */ lang_place_orphans (); @@ -6977,6 +7864,28 @@ lang_process (void) } } + /* Merge together CTF sections. After this, only the symtab-dependent + function and data object sections need adjustment. */ + lang_merge_ctf (); + + /* Emit the CTF, iff the emulation doesn't need to do late emission after + examining things laid out late, like the strtab. */ + lang_write_ctf (0); + + /* Copy forward lma regions for output sections in same lma region. */ + lang_propagate_lma_regions (); + + /* Defining __start/__stop symbols early for --gc-sections to work + around a glibc build problem can result in these symbols being + defined when they should not be. Fix them now. */ + if (config.build_constructors) + lang_undef_start_stop (); + + /* Define .startof./.sizeof. symbols with preliminary values before + dynamic symbols are created. */ + if (!bfd_link_relocatable (&link_info)) + lang_init_startof_sizeof (); + /* Do anything special before sizing sections. This is where ELF and other back-ends size dynamic sections. */ ldemul_before_allocation (); @@ -6990,17 +7899,20 @@ lang_process (void) lang_find_relro_sections (); /* Size up the sections. */ - lang_size_sections (NULL, ! RELAXATION_ENABLED); + lang_size_sections (NULL, !RELAXATION_ENABLED); /* See if anything special should be done now we know how big everything is. This is where relaxation is done. */ ldemul_after_allocation (); - /* Fix any .startof. or .sizeof. symbols. */ - lang_set_startof (); + /* Fix any __start, __stop, .startof. or .sizeof. symbols. */ + lang_finalize_start_stop (); - /* Do all the assignments, now that we know the final resting places - of all the symbols. */ + /* Do all the assignments again, to report errors. Assignment + statements are processed multiple times, updating symbols; In + open_input_bfds, lang_do_assignments, and lang_size_sections. + Since lang_relax_sections calls lang_do_assignments, symbols are + also updated in ldemul_after_allocation. */ lang_do_assignments (lang_final_phase_enum); ldemul_finish (); @@ -7033,9 +7945,6 @@ lang_add_wild (struct wildcard_spec *filespec, curr != NULL; section_list = curr, curr = next) { - if (curr->spec.name != NULL && strcmp (curr->spec.name, "COMMON") == 0) - placed_commons = TRUE; - next = curr->next; curr->next = section_list; } @@ -7044,7 +7953,7 @@ lang_add_wild (struct wildcard_spec *filespec, { if (strcmp (filespec->name, "*") == 0) filespec->name = NULL; - else if (! wildcardp (filespec->name)) + else if (!wildcardp (filespec->name)) lang_has_input_file = TRUE; } @@ -7052,11 +7961,13 @@ lang_add_wild (struct wildcard_spec *filespec, new_stmt->filename = NULL; new_stmt->filenames_sorted = FALSE; new_stmt->section_flag_list = NULL; + new_stmt->exclude_name_list = NULL; if (filespec != NULL) { new_stmt->filename = filespec->name; new_stmt->filenames_sorted = filespec->sorted == by_name; new_stmt->section_flag_list = filespec->section_flag_list; + new_stmt->exclude_name_list = filespec->exclude_name_list; } new_stmt->section_list = section_list; new_stmt->keep_sections = keep_sections; @@ -7086,7 +7997,7 @@ lang_add_entry (const char *name, bfd_boolean cmdline) { if (entry_symbol.name == NULL || cmdline - || ! entry_from_cmdline) + || !entry_from_cmdline) { entry_symbol.name = name; entry_from_cmdline = cmdline; @@ -7194,7 +8105,7 @@ lang_startup (const char *name) { if (first_file->filename != NULL) { - einfo (_("%P%F: multiple STARTUP files\n")); + einfo (_("%F%P: multiple STARTUP files\n")); } first_file->filename = name; first_file->local_sym_name = name; @@ -7233,14 +8144,14 @@ lang_get_regions (lang_memory_region_type **region, has been specified, then use the load region for the runtime region as well. */ if (lma_memspec != NULL - && ! have_vma + && !have_vma && strcmp (memspec, DEFAULT_MEMORY_REGION) == 0) *region = *lma_region; else *region = lang_memory_region_lookup (memspec, FALSE); if (have_lma && lma_memspec != 0) - einfo (_("%X%P:%S: section has both a load address and a load region\n"), + einfo (_("%X%P:%pS: section has both a load address and a load region\n"), NULL); } @@ -7255,30 +8166,11 @@ lang_leave_output_section_statement (fill_type *fill, const char *memspec, current_section->load_base != NULL, current_section->addr_tree != NULL); - /* If this section has no load region or base, but uses the same - region as the previous section, then propagate the previous - section's load region. */ - - if (current_section->lma_region == NULL - && current_section->load_base == NULL - && current_section->addr_tree == NULL - && current_section->region == current_section->prev->region) - current_section->lma_region = current_section->prev->lma_region; - current_section->fill = fill; current_section->phdrs = phdrs; pop_stat_ptr (); } -void -lang_statement_append (lang_statement_list_type *list, - lang_statement_union_type *element, - lang_statement_union_type **field) -{ - *(list->tail) = element; - list->tail = field; -} - /* Set the output format type. -oformat overrides scripts. */ void @@ -7349,10 +8241,10 @@ lang_new_phdr (const char *name, struct lang_phdr *n, **pp; bfd_boolean hdrs; - n = (struct lang_phdr *) stat_alloc (sizeof (struct lang_phdr)); + n = stat_alloc (sizeof (struct lang_phdr)); n->next = NULL; n->name = name; - n->type = exp_get_value_int (type, 0, "program header type"); + n->type = exp_get_vma (type, 0, "program header type"); n->filehdr = filehdr; n->phdrs = phdrs; n->at = at; @@ -7365,7 +8257,7 @@ lang_new_phdr (const char *name, && (*pp)->type == 1 && !((*pp)->filehdr || (*pp)->phdrs)) { - einfo (_("%X%P:%S: PHDRS and FILEHDR are not supported" + einfo (_("%X%P:%pS: PHDRS and FILEHDR are not supported" " when prior PT_LOAD headers lack them\n"), NULL); hdrs = FALSE; } @@ -7396,7 +8288,7 @@ lang_record_phdrs (void) bfd_vma at; c = 0; - for (os = &lang_output_section_statement.head->output_section_statement; + for (os = (void *) lang_os_list.head; os != NULL; os = os->next) { @@ -7421,7 +8313,7 @@ lang_record_phdrs (void) if (last == NULL) { - lang_output_section_statement_type * tmp_os; + lang_output_section_statement_type *tmp_os; /* If we have not run across a section with a program header assigned to it yet, then scan forwards to find @@ -7473,16 +8365,16 @@ lang_record_phdrs (void) else at = exp_get_vma (l->at, 0, "phdr load address"); - if (! bfd_record_phdr (link_info.output_bfd, l->type, - l->flags != NULL, flags, l->at != NULL, - at, l->filehdr, l->phdrs, c, secs)) + if (!bfd_record_phdr (link_info.output_bfd, l->type, + l->flags != NULL, flags, l->at != NULL, + at, l->filehdr, l->phdrs, c, secs)) einfo (_("%F%P: bfd_record_phdr failed: %E\n")); } free (secs); /* Make sure all the phdr assignments succeeded. */ - for (os = &lang_output_section_statement.head->output_section_statement; + for (os = (void *) lang_os_list.head; os != NULL; os = os->next) { @@ -7495,7 +8387,7 @@ lang_record_phdrs (void) for (pl = os->phdrs; pl != NULL; pl = pl->next) - if (! pl->used && strcmp (pl->name, "NONE") != 0) + if (!pl->used && strcmp (pl->name, "NONE") != 0) einfo (_("%X%P: section `%s' assigned to non-existent phdr `%s'\n"), os->name, pl->name); } @@ -7689,7 +8581,7 @@ lang_leave_overlay (etree_type *lma_expr, if (l->next == 0) { l->os->load_base = lma_expr; - l->os->sectype = normal_section; + l->os->sectype = first_overlay_section; } if (phdrs != NULL && l->os->phdrs == NULL) l->os->phdrs = phdrs; @@ -7715,6 +8607,7 @@ lang_leave_overlay (etree_type *lma_expr, overlay_vma = NULL; overlay_list = NULL; overlay_max = NULL; + overlay_subalign = NULL; } /* Version handling. This is only useful for ELF. */ @@ -8223,24 +9116,26 @@ lang_do_memory_regions (void) 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); - } + { + 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); - } + { + 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); + } } } @@ -8289,7 +9184,7 @@ lang_append_dynamic_list (struct bfd_elf_version_expr *dynamic) void lang_append_dynamic_list_cpp_typeinfo (void) { - const char * symbols [] = + const char *symbols[] = { "typeinfo name for*", "typeinfo for*" @@ -8310,7 +9205,7 @@ lang_append_dynamic_list_cpp_typeinfo (void) void lang_append_dynamic_list_cpp_new (void) { - const char * symbols [] = + const char *symbols[] = { "operator new*", "operator delete*" @@ -8380,14 +9275,16 @@ lang_print_memory_usage (void) 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); + if (r->length != 0) + { + double percent = used_length * 100.0 / r->length; + printf (" %6.2f%%", percent); + } + printf ("\n"); } }