/* Linker command language support.
- Copyright (C) 1991-2016 Free Software Foundation, Inc.
+ Copyright (C) 1991-2017 Free Software Foundation, Inc.
This file is part of the GNU Binutils.
#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;
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
/* 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)
{
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
&& 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);
}
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))
walk_wild_section (s, f, callback, data);
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
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;
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);
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 ();
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)
{
bfd_section_already_linked (abfd, sec, &link_info);
}
\f
+
+/* 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
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)
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 bfd_archive:
check_excluded_libs (entry->the_bfd);
+ entry->the_bfd->usrdata = entry;
if (entry->flags.whole_archive)
{
bfd *member = NULL;
#endif
break;
case lang_assignment_statement_enum:
- if (s->assignment_statement.exp->assign.defsym)
+ if (s->assignment_statement.exp->type.node_class != etree_assert
+ && s->assignment_statement.exp->assign.defsym)
/* This is from a --defsym on the command line. */
exp_fold_tree_no_dot (s->assignment_statement.exp);
break;
{
h->type = bfd_link_hash_undefined;
h->u.undef.abfd = NULL;
+ if (is_elf_hash_table (link_info.hash))
+ ((struct elf_link_hash_entry *) h)->mark = 1;
bfd_link_add_undef (link_info.hash, h);
}
}
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
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
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;
minfo ("%s", sec->spec.name);
else
minfo ("*");
- if (sec->spec.sorted)
+ for (;closing_paren > 0; closing_paren--)
minfo (")");
if (sec->next)
minfo (" ");
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
{
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;
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;
}
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
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. */
+ 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
&& !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))
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;
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;
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;
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;
*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;
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_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_set_startof (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)
+ {
+ 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)
{
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. */
}
information which is needed in the output file. */
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"
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)
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 `%A' from `%B'.\n"),
s, s->owner);
if (config.unique_orphan_sections || unique_section_p (s, NULL))
}
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 `%A' from `%B' being "
+ "placed in section `%s'.\n"),
s, s->owner, os->name);
}
}
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)
{
{
lang_input_statement_type *f;
- for (f = (lang_input_statement_type *) input_file_chain.head;
+ for (f = &input_file_chain.head->input_statement;
f != NULL;
- f = (lang_input_statement_type *) f->next_real_file)
+ f = &f->next_real_file->input_statement)
func (f);
}
return lastobject;
}
+/* Find where to insert ADD, an archive element or shared library
+ added during a rescan. */
+
+static lang_statement_union_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_statement_union_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 = &input_file_chain.head->input_statement;
+ f != NULL;
+ f = &f->next_real_file->input_statement)
+ {
+ if (f->the_bfd == add_bfd)
+ {
+ before = last_loaded;
+ if (f->next != NULL)
+ return &f->next->input_statement.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)->input_statement.next)
+ if ((*iter)->input_statement.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.) */
}
}
+/* 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 = &lang_output_section_statement.head->output_section_statement;
+ 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)
{
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. */
lang_list_insert_after (&file_chain, &files, &file_chain.head);
/* Rescan archives in case new undefined symbols have appeared. */
+ files = file_chain;
open_input_bfds (statement_list.head, OPEN_BFD_RESCAN);
+ lang_list_remove_tail (&file_chain, &files);
+ while (files.head != NULL)
+ {
+ lang_statement_union_type **insert;
+ lang_statement_union_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)->input_statement.next)
+ if ((*iter)->input_statement.the_bfd->my_archive != my_arch)
+ break;
+ temp = *insert;
+ *insert = files.head;
+ files.head = *iter;
+ *iter = temp;
+ if (my_arch != NULL)
+ {
+ lang_input_statement_type *parent = my_arch->usrdata;
+ if (parent != NULL)
+ parent->next = (lang_statement_union_type *)
+ ((char *) iter
+ - offsetof (lang_input_statement_type, next));
+ }
+ }
}
}
#endif /* ENABLE_PLUGINS */
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);
}
}
+ /* 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 ();
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. */
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;
}
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;
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 ();
overlay_vma = NULL;
overlay_list = NULL;
overlay_max = NULL;
+ overlay_subalign = NULL;
}
\f
/* Version handling. This is only useful for ELF. */