/* Linker command language support.
- Copyright (C) 1991-2015 Free Software Foundation, Inc.
+ Copyright (C) 1991-2016 Free Software Foundation, Inc.
This file is part of the GNU Binutils.
#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 *);
struct unique_sections *unam;
const char *secnam;
- if (link_info.relocatable
+ if (bfd_link_relocatable (&link_info)
&& sec->owner != NULL
&& bfd_is_group_section (sec->owner, sec))
return !(os != NULL
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;
push_stat_ptr (&add);
}
- if (link_info.relocatable || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)
+ if (bfd_link_relocatable (&link_info)
+ || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0)
address = exp_intop (0);
os_tail = ((lang_output_section_statement_type **)
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
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. */
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;
format targets, .text$foo sections go into .text and it's odd
to see .text with SEC_LINK_ONCE set. */
- if (!link_info.relocatable)
+ if (!bfd_link_relocatable (&link_info))
flags &= ~(SEC_LINK_ONCE | SEC_LINK_DUPLICATES | SEC_RELOC);
switch (output->sectype)
ASSERT (link_info.output_bfd == NULL);
open_output (statement->output_statement.name);
ldemul_set_output_arch ();
- if (config.magic_demand_paged && !link_info.relocatable)
+ if (config.magic_demand_paged
+ && !bfd_link_relocatable (&link_info))
link_info.output_bfd->flags |= D_PAGED;
else
link_info.output_bfd->flags &= ~D_PAGED;
}
}
-/* 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)
{
insert_undefined (ptr->name);
}
+/* Structure used to build the list of symbols that the user has required
+ be defined. */
+
+struct require_defined_symbol
+{
+ const char *name;
+ struct require_defined_symbol *next;
+};
+
+/* The list of symbols that the user has required be defined. */
+
+static struct require_defined_symbol *require_defined_symbol_list;
+
+/* Add a new symbol NAME to the list of symbols that are required to be
+ defined. */
+
+void
+ldlang_add_require_defined (const char * const name)
+{
+ struct require_defined_symbol *ptr;
+
+ ldlang_add_undef (name, TRUE);
+ ptr = (struct require_defined_symbol *) stat_alloc (sizeof (*ptr));
+ ptr->next = require_defined_symbol_list;
+ ptr->name = strdup (name);
+ require_defined_symbol_list = ptr;
+}
+
+/* Check that all symbols the user required to be defined, are defined,
+ raise an error if we find a symbol that is not defined. */
+
+static void
+ldlang_check_require_defined_symbols (void)
+{
+ struct require_defined_symbol *ptr;
+
+ for (ptr = require_defined_symbol_list; ptr != NULL; ptr = ptr->next)
+ {
+ struct bfd_link_hash_entry *h;
+
+ h = bfd_link_hash_lookup (link_info.hash, ptr->name,
+ FALSE, FALSE, TRUE);
+ if (h == NULL
+ || (h->type != bfd_link_hash_defined
+ && h->type != bfd_link_hash_defweak))
+ einfo(_("%P%X: required symbol `%s' not defined\n"), ptr->name);
+ }
+}
+
/* Check for all readonly or some readwrite sections. */
static void
++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);
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)
{
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, count, sizeof (*sections), sort_sections_by_lma);
- qsort (sections, (size_t) count, sizeof (asection *),
- sort_sections_by_lma);
+ /* 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++)
+ {
+ 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;
+ }
+ }
- spp = sections;
- s = *spp++;
- s_start = s->lma;
- s_end = s_start + TO_ADDR (s->size) - 1;
- for (count--; count; count--)
+ /* 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++)
{
- /* 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_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
here, in lang_insert_orphan, or in the default linker scripts.
This is covering for coff backend linker bugs. See PR6945. */
if (os->addr_tree == NULL
- && link_info.relocatable
+ && bfd_link_relocatable (&link_info)
&& (bfd_get_flavour (link_info.output_bfd)
== bfd_target_coff_flavour))
os->addr_tree = exp_intop (0);
defined, issue an error message. */
if (!os->ignored
&& !IGNORE_SECTION (os->bfd_section)
- && ! link_info.relocatable
+ && !bfd_link_relocatable (&link_info)
&& check_regions
&& strcmp (os->region->name_list.name,
DEFAULT_MEMORY_REGION) == 0
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
/* 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)
&& dot >= (r->last_os->output_section_statement
.bfd_section->vma)))
&& os->lma_region == NULL
- && !link_info.relocatable)
+ && !bfd_link_relocatable (&link_info))
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
- || link_info.relocatable)
+ if (!IS_TBSS (os->bfd_section)
+ || bfd_link_relocatable (&link_info))
dotdelta = TO_ADDR (os->bfd_section->size);
else
dotdelta = 0;
if (expld.dataseg.phase == exp_dataseg_end_seen
&& link_info.relro && expld.dataseg.relro_end)
{
- bfd_vma initial_base, min_base, relro_end, maxpage;
+ bfd_vma initial_base, relro_end, desired_end;
+ asection *sec;
- expld.dataseg.phase = exp_dataseg_relro_adjust;
- maxpage = expld.dataseg.maxpagesize;
- initial_base = expld.dataseg.base;
- /* Try to put expld.dataseg.relro_end on a (common) page boundary. */
- expld.dataseg.base += (-expld.dataseg.relro_end
- & (expld.dataseg.pagesize - 1));
/* Compute the expected PT_GNU_RELRO segment end. */
relro_end = ((expld.dataseg.relro_end + expld.dataseg.pagesize - 1)
& ~(expld.dataseg.pagesize - 1));
- /* MIN_BASE is the absolute minimum address we are allowed to start the
- read-write segment (byte before will be mapped read-only). */
- min_base = (expld.dataseg.min_base + maxpage - 1) & ~(maxpage - 1);
- if (min_base + maxpage < expld.dataseg.base)
- {
- expld.dataseg.base -= maxpage;
- relro_end -= maxpage;
- }
+
+ /* Adjust by the offset arg of DATA_SEGMENT_RELRO_END. */
+ desired_end = relro_end - expld.dataseg.relro_offset;
+
+ /* For sections in the relro segment.. */
+ for (sec = link_info.output_bfd->section_last; sec; sec = sec->prev)
+ if ((sec->flags & SEC_ALLOC) != 0
+ && sec->vma >= expld.dataseg.base
+ && sec->vma < expld.dataseg.relro_end - expld.dataseg.relro_offset)
+ {
+ /* Where do we want to put this section so that it ends as
+ desired? */
+ bfd_vma start, end, bump;
+
+ end = start = sec->vma;
+ if (!IS_TBSS (sec))
+ end += TO_ADDR (sec->size);
+ bump = desired_end - end;
+ /* We'd like to increase START by BUMP, but we must heed
+ alignment so the increase might be less than optimum. */
+ start += bump;
+ start &= ~(((bfd_vma) 1 << sec->alignment_power) - 1);
+ /* This is now the desired end for the previous section. */
+ desired_end = start;
+ }
+
+ expld.dataseg.phase = exp_dataseg_relro_adjust;
+ ASSERT (desired_end >= expld.dataseg.base);
+ initial_base = expld.dataseg.base;
+ expld.dataseg.base = desired_end;
lang_reset_memory_regions ();
one_lang_size_sections_pass (relax, check_regions);
+
if (expld.dataseg.relro_end > relro_end)
{
- /* The alignment of sections between DATA_SEGMENT_ALIGN
- and DATA_SEGMENT_RELRO_END can cause excessive padding to
- be inserted at DATA_SEGMENT_RELRO_END. Try to start a
- bit lower so that the section alignments will fit in. */
- asection *sec;
- unsigned int max_alignment_power = 0;
-
- /* Find maximum alignment power of sections between
- DATA_SEGMENT_ALIGN and DATA_SEGMENT_RELRO_END. */
- for (sec = link_info.output_bfd->sections; sec; sec = sec->next)
- if (sec->vma >= expld.dataseg.base
- && sec->vma < expld.dataseg.relro_end
- && sec->alignment_power > max_alignment_power)
- max_alignment_power = sec->alignment_power;
-
- /* Aligning the adjusted base guarantees the padding
- between sections won't change. This is better than
- simply subtracting 1 << max_alignment_power which is
- what we used to do here. */
- expld.dataseg.base &= ~((1 << max_alignment_power) - 1);
- /* It doesn't make much sense to go lower than the initial
- base. That can only increase padding. */
- if (expld.dataseg.base < initial_base)
- expld.dataseg.base = initial_base;
+ /* Assignments to dot, or to output section address in a
+ user script have increased padding over the original.
+ Revert. */
+ expld.dataseg.base = initial_base;
lang_reset_memory_regions ();
one_lang_size_sections_pass (relax, check_regions);
}
+
link_info.relro_start = expld.dataseg.base;
link_info.relro_end = expld.dataseg.relro_end;
}
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
- || link_info.relocatable)
+ if (!IS_TBSS (os->bfd_section)
+ || bfd_link_relocatable (&link_info))
dot += TO_ADDR (os->bfd_section->size);
if (os->update_dot_tree != NULL)
{
asection *s;
- if (link_info.relocatable)
+ if (bfd_link_relocatable (&link_info))
return;
for (s = link_info.output_bfd->sections; s != NULL; s = s->next)
struct bfd_link_hash_entry *h;
bfd_boolean warn;
- if ((link_info.relocatable && !link_info.gc_sections)
- || (link_info.shared && !link_info.executable))
+ if ((bfd_link_relocatable (&link_info) && !link_info.gc_sections)
+ || bfd_link_dll (&link_info))
warn = entry_from_cmdline;
else
warn = TRUE;
/* Force the user to specify a root when generating a relocatable with
--gc-sections. */
- if (link_info.gc_sections && link_info.relocatable
+ if (link_info.gc_sections && bfd_link_relocatable (&link_info)
&& !(entry_from_cmdline || undef_from_cmdline))
einfo (_("%P%F: gc-sections requires either an entry or "
"an undefined symbol\n"));
input format may not have equivalent representations in
the output format (and besides BFD does not translate
relocs for other link purposes than a final link). */
- if ((link_info.relocatable || link_info.emitrelocations)
+ if ((bfd_link_relocatable (&link_info)
+ || link_info.emitrelocations)
&& (compatible == NULL
|| (bfd_get_flavour (input_bfd)
!= bfd_get_flavour (link_info.output_bfd)))
{
if (command_line.inhibit_common_definition)
return;
- if (link_info.relocatable
+ if (bfd_link_relocatable (&link_info)
&& ! command_line.force_common_definition)
return;
return TRUE;
}
+/* Handle a single orphan section S, placing the orphan into an appropriate
+ output section. The effects of the --orphan-handling command line
+ option are handled here. */
+
+static void
+ldlang_place_orphan (asection *s)
+{
+ if (config.orphan_handling == orphan_handling_discard)
+ {
+ lang_output_section_statement_type *os;
+ os = lang_output_section_statement_lookup (DISCARD_SECTION_NAME, 0,
+ TRUE);
+ if (os->addr_tree == NULL
+ && (bfd_link_relocatable (&link_info)
+ || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0))
+ os->addr_tree = exp_intop (0);
+ lang_add_section (&os->children, s, NULL, os);
+ }
+ else
+ {
+ lang_output_section_statement_type *os;
+ const char *name = s->name;
+ int constraint = 0;
+
+ if (config.orphan_handling == orphan_handling_error)
+ einfo ("%X%P: error: unplaced orphan section `%A' from `%B'.\n",
+ s, s->owner);
+
+ if (config.unique_orphan_sections || unique_section_p (s, NULL))
+ constraint = SPECIAL;
+
+ os = ldemul_place_orphan (s, name, constraint);
+ if (os == NULL)
+ {
+ os = lang_output_section_statement_lookup (name, constraint, TRUE);
+ if (os->addr_tree == NULL
+ && (bfd_link_relocatable (&link_info)
+ || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0))
+ os->addr_tree = exp_intop (0);
+ lang_add_section (&os->children, s, NULL, os);
+ }
+
+ if (config.orphan_handling == orphan_handling_warn)
+ einfo ("%P: warning: orphan section `%A' from `%B' being "
+ "placed in section `%s'.\n",
+ s, s->owner, os->name);
+ }
+}
+
/* Run through the input files and ensure that every input section has
somewhere to go. If one is found without a destination then create
an input request and place it into the statement tree. */
/* This is a lonely common section which must have
come from an archive. We attach to the section
with the wildcard. */
- if (! link_info.relocatable
+ if (!bfd_link_relocatable (&link_info)
|| command_line.force_common_definition)
{
if (default_common_section == NULL)
}
}
else
- {
- const char *name = s->name;
- int constraint = 0;
-
- if (config.unique_orphan_sections
- || unique_section_p (s, NULL))
- constraint = SPECIAL;
-
- if (!ldemul_place_orphan (s, name, constraint))
- {
- lang_output_section_statement_type *os;
- os = lang_output_section_statement_lookup (name,
- constraint,
- TRUE);
- if (os->addr_tree == NULL
- && (link_info.relocatable
- || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0))
- os->addr_tree = exp_intop (0);
- lang_add_section (&os->children, s, NULL, os);
- }
- }
+ ldlang_place_orphan (s);
}
}
}
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
the special case of debug info. (See bfd/stabs.c)
Twiddle the flag here, to simplify later linker code. */
- if (link_info.relocatable)
+ if (bfd_link_relocatable (&link_info))
{
LANG_FOR_EACH_INPUT_STATEMENT (f)
{
}
#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)
{
}
#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;
+ {
+ 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)
/* Remove unreferenced sections if asked to. */
lang_gc_sections ();
+ /* Check relocations. */
+ lang_check_relocs ();
+
/* Update wild statements. */
update_wild_statements (statement_list.head);
/* Find any sections not attached explicitly and handle them. */
lang_place_orphans ();
- if (! link_info.relocatable)
+ if (!bfd_link_relocatable (&link_info))
{
asection *found;
lang_record_phdrs ();
/* Check relro sections. */
- if (link_info.relro && ! link_info.relocatable)
+ if (link_info.relro && !bfd_link_relocatable (&link_info))
lang_find_relro_sections ();
/* Size up the sections. */
ldemul_finish ();
+ /* Convert absolute symbols to section relative. */
+ ldexp_finalize_syms ();
+
/* Make sure that the section addresses make sense. */
if (command_line.check_section_addresses)
lang_check_section_addresses ();
+ /* Check any required symbols are known. */
+ ldlang_check_require_defined_symbols ();
+
lang_end ();
}
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. */
p = q;
}
}
+
+/* Pretty print memory amount. */
+
+static void
+lang_print_memory_size (bfd_vma sz)
+{
+ if ((sz & 0x3fffffff) == 0)
+ printf ("%10" BFD_VMA_FMT "u GB", sz >> 30);
+ else if ((sz & 0xfffff) == 0)
+ printf ("%10" BFD_VMA_FMT "u MB", sz >> 20);
+ else if ((sz & 0x3ff) == 0)
+ printf ("%10" BFD_VMA_FMT "u KB", sz >> 10);
+ else
+ printf (" %10" BFD_VMA_FMT "u B", sz);
+}
+
+/* Implement --print-memory-usage: disply per region memory usage. */
+
+void
+lang_print_memory_usage (void)
+{
+ lang_memory_region_type *r;
+
+ printf ("Memory region Used Size Region Size %%age Used\n");
+ for (r = lang_memory_region_list; r->next != NULL; r = r->next)
+ {
+ bfd_vma used_length = r->current - r->origin;
+ double percent;
+
+ printf ("%16s: ",r->name_list.name);
+ lang_print_memory_size (used_length);
+ lang_print_memory_size ((bfd_vma) r->length);
+
+ percent = used_length * 100.0 / r->length;
+
+ printf (" %6.2f%%\n", percent);
+ }
+}