/* Linker command language support.
- Copyright (C) 1991-2015 Free Software Foundation, Inc.
+ Copyright (C) 1991-2017 Free Software Foundation, Inc.
This file is part of the GNU Binutils.
#include "fnmatch.h"
#include "demangle.h"
#include "hashtab.h"
-#include "libbfd.h"
#include "elf-bfd.h"
#ifdef ENABLE_PLUGINS
#include "plugin.h"
#define offsetof(TYPE, MEMBER) ((size_t) & (((TYPE*) 0)->MEMBER))
#endif
-/* Locals variables. */
+/* Convert between addresses in bytes and sizes in octets.
+ For currently supported targets, octets_per_byte is always a power
+ of two, so we can use shifts. */
+#define TO_ADDR(X) ((X) >> opb_shift)
+#define TO_SIZE(X) ((X) << opb_shift)
+
+/* Local variables. */
static struct obstack stat_obstack;
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 lang_statement_list_type **stat_save_ptr = &stat_save[0];
static struct unique_sections *unique_section_list;
static struct asneeded_minfo *asneeded_list_head;
+static unsigned int opb_shift = 0;
/* Forward declarations. */
static void exp_init_os (etree_type *);
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))
+ || !bfd_check_format (f->the_bfd, bfd_archive))
walk_wild_section (s, f, callback, data);
else
{
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;
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
}
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
}
static lang_memory_region_type *
-lang_memory_default (asection * section)
+lang_memory_default (asection *section)
{
lang_memory_region_type *p;
lang_output_section_statement_type *
lang_output_section_find_by_flags (const asection *sec,
+ flagword sec_flags,
lang_output_section_statement_type **exact,
lang_match_sec_type_func match_type)
{
lang_output_section_statement_type *first, *look, *found;
- flagword look_flags, sec_flags, differ;
+ flagword look_flags, differ;
/* We know the first statement on this list is *ABS*. May as well
skip it. */
first = first->next;
/* First try for an exact match. */
- sec_flags = sec->flags;
found = NULL;
for (look = first; look; look = look->next)
{
if (found || !match_type)
return found;
- return lang_output_section_find_by_flags (sec, NULL, NULL);
+ return lang_output_section_find_by_flags (sec, sec_flags, NULL, NULL);
}
/* Find the last output section before given output statement.
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 += 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)
{
|| s->output_section->owner != link_info.output_bfd)
&& (s->flags & (SEC_LINKER_CREATED | SEC_KEEP)) == 0)
{
- if (! dis_header_printed)
+ if (!dis_header_printed)
{
fprintf (config.map_file, _("\nDiscarded input sections\n\n"));
dis_header_printed = TRUE;
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);
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
s->name, flags);
if (s->bfd_section == NULL)
{
- einfo (_("%P%F: output format %s cannot represent section called %s\n"),
+ einfo (_("%P%F: 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;
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);
}
\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)
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
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
if (search->flags.loaded || !search->flags.real)
return search;
- if (! load_symbols (search, NULL))
+ if (!load_symbols (search, NULL))
return NULL;
return search;
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 (!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;
case bfd_archive:
check_excluded_libs (entry->the_bfd);
+ entry->the_bfd->usrdata = entry;
if (entry->flags.whole_archive)
{
bfd *member = NULL;
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"),
entry->the_bfd, member);
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
/* 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. */
delete_output_file_on_failure = TRUE;
- if (! bfd_set_format (link_info.output_bfd, bfd_object))
+ 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_arch_mach (link_info.output_bfd,
ldfile_output_architecture,
ldfile_output_machine))
einfo (_("%P%F:%s: can not set architecture: %E\n"), name);
}
}
-/* Convert between addresses in bytes and sizes in octets.
- For currently supported targets, octets_per_byte is always a power
- of two, so we can use shifts. */
-#define TO_ADDR(X) ((X) >> opb_shift)
-#define TO_SIZE(X) ((X) << opb_shift)
-
-/* Support the above. */
-static unsigned int opb_shift = 0;
-
static void
init_opb (void)
{
os_tail = lang_output_section_statement.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)
#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);
}
}
defined. */
void
-ldlang_add_require_defined (const char * const name)
+ldlang_add_require_defined (const char *const name)
{
struct require_defined_symbol *ptr;
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(_("%P%X: required symbol `%s' not defined\n"), ptr->name);
}
}
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:
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
++len;
}
- minfo ("0x%V %W", section->vma, section->size);
+ minfo ("0x%V %W", section->vma, TO_ADDR (section->size));
if (section->vma != section->lma)
minfo (_(" load address 0x%V"), section->lma);
else
{
if (assignment->exp->type.node_class == etree_provide)
- minfo ("[!provide]");
+ minfo ("[!provide]");
else
- minfo ("*undef* ");
+ minfo ("*undef* ");
#ifdef BFD64
minfo (" ");
#endif
/* 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;
size = 0;
}
- minfo ("0x%V %W %B\n", addr, TO_ADDR (size), i->owner);
+ minfo ("0x%V %W %B\n", addr, size, i->owner);
if (size != i->rawsize && i->rawsize != 0)
{
break;
}
- minfo ("0x%V %W %s 0x%v", addr, size, name, data->value);
+ if (size < TO_SIZE ((unsigned) 1))
+ size = TO_SIZE ((unsigned) 1);
+ minfo ("0x%V %W %s 0x%v", addr, TO_ADDR (size), name, data->value);
if (data->exp->type.node_class != etree_value)
{
size = bfd_get_reloc_size (reloc->howto);
- minfo ("0x%V %W RELOC %s ", addr, size, reloc->howto->name);
+ minfo ("0x%V %W RELOC %s ", addr, TO_ADDR (size), reloc->howto->name);
if (reloc->name != NULL)
minfo ("%s+", reloc->name);
addr = s->output_offset;
if (s->output_section != NULL)
addr += s->output_section->vma;
- minfo ("0x%V %W ", addr, (bfd_vma) s->size);
+ minfo ("0x%V %W ", addr, TO_ADDR (s->size));
if (s->fill->size != 0)
{
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
{
return dot;
}
+struct check_sec
+{
+ asection *sec;
+ bfd_boolean warned;
+};
+
static int
sort_sections_by_lma (const void *arg1, const void *arg2)
{
- const asection *sec1 = *(const asection **) arg1;
- const asection *sec2 = *(const asection **) arg2;
+ const asection *sec1 = ((const struct check_sec *) arg1)->sec;
+ const asection *sec2 = ((const struct check_sec *) arg2)->sec;
- if (bfd_section_lma (sec1->owner, sec1)
- < bfd_section_lma (sec2->owner, sec2))
+ if (sec1->lma < sec2->lma)
return -1;
- else if (bfd_section_lma (sec1->owner, sec1)
- > bfd_section_lma (sec2->owner, sec2))
+ else if (sec1->lma > sec2->lma)
return 1;
else if (sec1->id < sec2->id)
return -1;
return 0;
}
+static int
+sort_sections_by_vma (const void *arg1, const void *arg2)
+{
+ const asection *sec1 = ((const struct check_sec *) arg1)->sec;
+ const asection *sec2 = ((const struct check_sec *) arg2)->sec;
+
+ if (sec1->vma < sec2->vma)
+ return -1;
+ else if (sec1->vma > sec2->vma)
+ return 1;
+ else if (sec1->id < sec2->id)
+ return -1;
+ else if (sec1->id > sec2->id)
+ return 1;
+
+ return 0;
+}
+
+#define IS_TBSS(s) \
+ ((s->flags & (SEC_LOAD | SEC_THREAD_LOCAL)) == SEC_THREAD_LOCAL)
+
#define IGNORE_SECTION(s) \
- ((s->flags & SEC_ALLOC) == 0 \
- || ((s->flags & SEC_THREAD_LOCAL) != 0 \
- && (s->flags & SEC_LOAD) == 0))
+ ((s->flags & SEC_ALLOC) == 0 || IS_TBSS (s))
/* Check to see if any allocated sections overlap with other allocated
sections. This can happen if a linker script specifies the output
lang_check_section_addresses (void)
{
asection *s, *p;
- asection **sections, **spp;
- unsigned int count;
+ struct check_sec *sections;
+ size_t i, count;
+ bfd_vma addr_mask;
bfd_vma s_start;
bfd_vma s_end;
- bfd_vma p_start;
- bfd_vma p_end;
- bfd_size_type amt;
+ bfd_vma p_start = 0;
+ bfd_vma p_end = 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;
- amt = bfd_count_sections (link_info.output_bfd) * sizeof (asection *);
- sections = (asection **) xmalloc (amt);
+ count = bfd_count_sections (link_info.output_bfd);
+ sections = XNEWVEC (struct check_sec, count);
/* Scan all sections in the output list. */
count = 0;
for (s = link_info.output_bfd->sections; s != NULL; s = s->next)
{
- /* Only consider loadable sections with real contents. */
- if (!(s->flags & SEC_LOAD)
- || !(s->flags & SEC_ALLOC)
+ if (IGNORE_SECTION (s)
|| s->size == 0)
continue;
- sections[count] = s;
+ sections[count].sec = s;
+ sections[count].warned = FALSE;
count++;
}
if (count <= 1)
- return;
+ {
+ free (sections);
+ return;
+ }
- qsort (sections, (size_t) count, sizeof (asection *),
- sort_sections_by_lma);
+ qsort (sections, count, sizeof (*sections), sort_sections_by_lma);
- spp = sections;
- s = *spp++;
- s_start = s->lma;
- s_end = s_start + TO_ADDR (s->size) - 1;
- for (count--; count; count--)
+ /* First check section LMAs. There should be no overlap of LMAs on
+ loadable sections, even with overlays. */
+ for (p = NULL, i = 0; i < count; i++)
{
- /* We must check the sections' LMA addresses not their VMA
- addresses because overlay sections can have overlapping VMAs
- but they must have distinct LMAs. */
- p = s;
+ s = sections[i].sec;
+ if ((s->flags & SEC_LOAD) != 0)
+ {
+ s_start = s->lma;
+ s_end = s_start + TO_ADDR (s->size) - 1;
+
+ /* Look for an overlap. We have sorted sections by lma, so
+ we know that s_start >= p_start. Besides the obvious
+ case of overlap when the current section starts before
+ the previous one ends, we also must have overlap if the
+ previous section wraps around the address space. */
+ if (p != NULL
+ && (s_start <= p_end
+ || p_end < p_start))
+ {
+ einfo (_("%X%P: section %s LMA [%V,%V]"
+ " overlaps section %s LMA [%V,%V]\n"),
+ s->name, s_start, s_end, p->name, p_start, p_end);
+ sections[i].warned = TRUE;
+ }
+ p = s;
+ p_start = s_start;
+ p_end = s_end;
+ }
+ }
+
+ /* If any non-zero size allocated section (excluding tbss) starts at
+ exactly the same VMA as another such section, then we have
+ overlays. Overlays generated by the OVERLAY keyword will have
+ this property. It is possible to intentionally generate overlays
+ that fail this test, but it would be unusual. */
+ qsort (sections, count, sizeof (*sections), sort_sections_by_vma);
+ overlays = FALSE;
+ p_start = sections[0].sec->vma;
+ for (i = 1; i < count; i++)
+ {
+ s_start = sections[i].sec->vma;
+ if (p_start == s_start)
+ {
+ overlays = TRUE;
+ break;
+ }
p_start = s_start;
- p_end = s_end;
- s = *spp++;
- s_start = s->lma;
- s_end = s_start + TO_ADDR (s->size) - 1;
-
- /* Look for an overlap. We have sorted sections by lma, so we
- know that s_start >= p_start. Besides the obvious case of
- overlap when the current section starts before the previous
- one ends, we also must have overlap if the previous section
- wraps around the address space. */
- if (s_start <= p_end
- || p_end < p_start)
- einfo (_("%X%P: section %s loaded at [%V,%V] overlaps section %s loaded at [%V,%V]\n"),
- s->name, s_start, s_end, p->name, p_start, p_end);
+ }
+
+ /* Now check section VMAs if no overlays were detected. */
+ if (!overlays)
+ {
+ for (p = NULL, i = 0; i < count; i++)
+ {
+ s = sections[i].sec;
+ s_start = s->vma;
+ s_end = s_start + TO_ADDR (s->size) - 1;
+
+ if (p != NULL
+ && !sections[i].warned
+ && (s_start <= p_end
+ || p_end < p_start))
+ einfo (_("%X%P: section %s VMA [%V,%V]"
+ " overlaps section %s VMA [%V,%V]\n"),
+ s->name, s_start, s_end, p->name, p_start, p_end);
+ p = s;
+ p_start = s_start;
+ p_end = s_end;
+ }
}
free (sections);
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)));
-
}
/* Make sure the new address is within the region. We explicitly permit the
create overlapping LMAs. */
if (dot < last->vma
&& os->bfd_section->size != 0
- && dot + os->bfd_section->size <= last->vma)
+ && dot + TO_ADDR (os->bfd_section->size) <= last->vma)
{
/* If dot moved backwards then leave lma equal to
vma. This is the old default lma, which might
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
{
/* If this is an overlay, set the current lma to that
at the end of the previous section. */
if (os->sectype == overlay_section)
- lma = last->lma + last->size;
+ lma = last->lma + TO_ADDR (last->size);
/* Otherwise, keep the same lma to vma relationship
as the previous section. */
}
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. */
- if (((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0
- || (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0)
- && (os->bfd_section->flags & SEC_ALLOC) != 0
+ 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)
&& !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 ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0
- || (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0
+ if (!IS_TBSS (os->bfd_section)
|| bfd_link_relocatable (&link_info))
dotdelta = TO_ADDR (os->bfd_section->size);
else
{
bfd_boolean again;
- if (! bfd_relax_section (i->owner, i, &link_info, &again))
+ if (!bfd_relax_section (i->owner, i, &link_info, &again))
einfo (_("%P%F: can't relax section: %E\n"));
if (again)
*relax = TRUE;
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. */
/* For sections in the relro segment.. */
for (sec = link_info.output_bfd->section_last; sec; sec = sec->prev)
- if (!IGNORE_SECTION (sec)
+ 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 = sec->vma;
- bfd_vma end = start + sec->size;
- bfd_vma bump = desired_end - end;
+ 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 & ~(((bfd_vma) 1 << sec->alignment_power) - 1);
+ start += bump;
+ start &= ~(((bfd_vma) 1 << sec->alignment_power) - 1);
/* This is now the desired end for the previous section. */
desired_end = start;
}
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 ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0
- || (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0
- || 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_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)
+ {
+ 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);
+ }
+}
+
+/* Set .startof., .sizeof., __start and __stop symbols final values. */
- 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)
+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_get_section_vma (link_info.output_bfd,
h->u.def.section->output_section)
+ h->u.def.section->output_offset);
- if (! bfd_set_start_address (link_info.output_bfd, val))
+ if (!bfd_set_start_address (link_info.output_bfd, val))
einfo (_("%P%F:%s: can't set start address\n"), entry_symbol.name);
}
else
val = bfd_scan_vma (entry_symbol.name, &send, 0);
if (*send == '\0')
{
- if (! bfd_set_start_address (link_info.output_bfd, val))
+ if (!bfd_set_start_address (link_info.output_bfd, val))
einfo (_("%P%F: can't set start address\n"));
}
else
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. */
}
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);
}
- if (! command_line.warn_mismatch)
+ if (!command_line.warn_mismatch)
bfd_set_error_handler (pfn);
}
}
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
{
char *name;
char buf[50];
- if (! header_printed)
+ if (!header_printed)
{
minfo (_("\nAllocating common symbols\n"));
minfo (_("Common symbol size file\n\n"));
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)
{
/* 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;
break;
default:
- einfo (_("%P%F: invalid character %c (%d) in flags\n"), * flags, * flags);
+ einfo (_("%P%F: invalid character %c (%d) in flags\n"),
+ *flags, *flags);
break;
}
flags++;
{
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);
}
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:%S: error: align with input and explicit align specified\n"),
+ NULL);
os->subsection_alignment =
topower (exp_get_value_int (subalign, -1, "subsection alignment"));
lang_gc_sections (void)
{
/* Keep all sections so marked in the link script. */
-
lang_gc_sections_1 (statement_list.head);
/* SEC_EXCLUDE is ignored when doing a relocatable link, except in
if (claim1->flags.claimed)
return claim1->flags.claim_archive ? lastobject : claim1;
/* Update lastobject if this is a real object file. */
- if (claim1->the_bfd && (claim1->the_bfd->my_archive == NULL))
+ if (claim1->the_bfd != NULL && claim1->the_bfd->my_archive == NULL)
lastobject = claim1;
}
/* No files were claimed by the plugin. Choose the last object
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.) */
}
#endif /* ENABLE_PLUGINS */
+/* Add NAME to the list of garbage collection entry points. */
+
+void
+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->next = link_info.gc_sym_list;
+ sym->name = name;
+ link_info.gc_sym_list = sym;
+}
+
+/* Check relocations. */
+
+static void
+lang_check_relocs (void)
+{
+ if (link_info.check_relocs_after_open_input)
+ {
+ bfd *abfd;
+
+ for (abfd = link_info.input_bfds;
+ abfd != (bfd *) NULL; abfd = abfd->link.next)
+ if (!bfd_link_check_relocs (abfd, &link_info))
+ {
+ /* No object output, fail return. */
+ config.make_executable = FALSE;
+ /* Note: we do not abort the loop, but rather
+ continue the scan in case there are other
+ bad relocations to report. */
+ }
+ }
+}
+
+/* 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 */
+ /* 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;
+
if (entry_symbol.name == NULL)
- link_info.gc_sym_list = ldlang_undef_chain_list_head;
- if (link_info.init_function != NULL)
{
- struct bfd_sym_chain *sym
- = (struct bfd_sym_chain *) stat_alloc (sizeof (*sym));
- sym->next = link_info.gc_sym_list;
- sym->name = link_info.init_function;
- link_info.gc_sym_list = sym;
- }
- if (link_info.fini_function != NULL)
- {
- struct bfd_sym_chain *sym
- = (struct bfd_sym_chain *) stat_alloc (sizeof (*sym));
- sym->next = link_info.gc_sym_list;
- sym->name = link_info.fini_function;
- link_info.gc_sym_list = sym;
+ link_info.gc_sym_list = ldlang_undef_chain_list_head;
+
+ /* entry_symbol is normally initialied by a ENTRY definition in the
+ linker script or the -e command line option. But if neither of
+ these have been used, the target specific backend may still have
+ provided an entry symbol via a call to lang_default_entry().
+ Unfortunately this value will not be processed until lang_end()
+ is called, long after this function has finished. So detect this
+ case here and add the target's entry symbol to the list of starting
+ points for garbage collection resolution. */
+ lang_add_gc_name (entry_symbol_default);
}
+ lang_add_gc_name (link_info.init_function);
+ lang_add_gc_name (link_info.fini_function);
+
ldemul_after_open ();
if (config.map_file != NULL)
lang_print_asneeded ();
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);
/* Remove unreferenced sections if asked to. */
lang_gc_sections ();
+ /* Check relocations. */
+ lang_check_relocs ();
+
/* Update wild statements. */
update_wild_statements (statement_list.head);
}
}
+ /* 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 ();
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. */
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;
}
{
if (strcmp (filespec->name, "*") == 0)
filespec->name = NULL;
- else if (! wildcardp (filespec->name))
+ else if (!wildcardp (filespec->name))
lang_has_input_file = TRUE;
}
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;
{
if (entry_symbol.name == NULL
|| cmdline
- || ! entry_from_cmdline)
+ || !entry_from_cmdline)
{
entry_symbol.name = name;
entry_from_cmdline = cmdline;
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
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 ();
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
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"));
}
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);
}
n = (struct lang_nocrossrefs *) xmalloc (sizeof *n);
n->next = nocrossref_list;
n->list = l;
+ n->onlyfirst = FALSE;
nocrossref_list = n;
/* Set notice_all so that we get informed about all symbols. */
link_info.notice_all = TRUE;
}
+
+/* Record a section that cannot be referenced from a list of sections. */
+
+void
+lang_add_nocrossref_to (lang_nocrossref_type *l)
+{
+ lang_add_nocrossref (l);
+ nocrossref_list->onlyfirst = TRUE;
+}
\f
/* Overlay handling. We handle overlays with some static variables. */
overlay_vma = NULL;
overlay_list = NULL;
overlay_max = NULL;
+ overlay_subalign = NULL;
}
\f
/* Version handling. This is only useful for ELF. */
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);
+ }
}
}
void
lang_append_dynamic_list_cpp_typeinfo (void)
{
- const char * symbols [] =
+ const char *symbols[] =
{
"typeinfo name for*",
"typeinfo for*"
void
lang_append_dynamic_list_cpp_new (void)
{
- const char * symbols [] =
+ const char *symbols[] =
{
"operator new*",
"operator delete*"