/* 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;
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 *);
/* 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;
}
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;
const char *ps;
+ lang_assignment_statement_type *start_assign;
lang_output_section_statement_type *os;
lang_output_section_statement_type **os_tail;
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 != '_')
+ if (!ISALNUM ((unsigned char) *ps) && *ps != '_')
break;
if (*ps == '\0')
{
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);
- lang_add_assignment (exp_provide (symname,
- exp_nameop (NAME, "."),
- FALSE));
+ start_assign
+ = lang_add_assignment (exp_provide (symname,
+ exp_nameop (NAME, "."),
+ FALSE));
}
}
lang_leave_output_section_statement (NULL, DEFAULT_MEMORY_REGION, NULL,
NULL);
- if (ps != NULL && *ps == '\0')
+ 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);
- lang_add_assignment (exp_provide (symname,
- exp_nameop (NAME, "."),
- FALSE));
+ 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. */
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);
}
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;
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;
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(");
if (w->filename != NULL)
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 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;
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. */
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
+ 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 = s;
/* .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;
+ 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);
}
}
if (command_line.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"));
/* 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++;
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
}
#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. */
+ }
+ }
+}
+
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. */
}
#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 ();
/* Remove unreferenced sections if asked to. */
lang_gc_sections ();
+ /* Check relocations. */
+ lang_check_relocs ();
+
/* Update wild statements. */
update_wild_statements (statement_list.head);
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. */
{
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
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. */
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*"