/* Linker command language support.
- Copyright 1991-2013 Free Software Foundation, Inc.
+ Copyright (C) 1991-2016 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"
#endif /* ENABLE_PLUGINS */
#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_free free
static const char *entry_symbol_default = "start";
static bfd_boolean placed_commons = FALSE;
-static bfd_boolean stripped_excluded_sections = FALSE;
+static bfd_boolean map_head_is_link_order = FALSE;
static lang_output_section_statement_type *default_common_section;
static bfd_boolean map_option_f;
static bfd_vma print_dot;
static lang_input_statement_type *first_file;
static const char *current_target;
static lang_statement_list_type statement_list;
-static struct bfd_hash_table lang_definedness_table;
static lang_statement_list_type *stat_save[10];
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 *);
-static void init_map_userdata (bfd *, asection *, void *);
static lang_input_statement_type *lookup_name (const char *);
-static struct bfd_hash_entry *lang_definedness_newfunc
- (struct bfd_hash_entry *, struct bfd_hash_table *, const char *);
static void insert_undefined (const char *);
static bfd_boolean sort_def_symbol (struct bfd_link_hash_entry *, void *);
static void print_statement (lang_statement_union_type *,
static void lang_do_version_exports_section (void);
static void lang_finalize_version_expr_head
(struct bfd_elf_version_expr_head *);
+static void lang_do_memory_regions (void);
/* Exported variables. */
const char *output_target;
bfd_boolean delete_output_file_on_failure = FALSE;
struct lang_phdr *lang_phdr_list;
struct lang_nocrossrefs *nocrossref_list;
+struct asneeded_minfo **asneeded_list_tail;
/* Functions that traverse the linker script and might evaluate
- DEFINED() need to increment this. */
+ DEFINED() need to increment this at the start of the traversal. */
int lang_statement_iteration = 0;
-etree_type *base; /* Relocation base - or null */
-
/* Return TRUE if the PATTERN argument is a wildcard pattern.
Although backslashes are treated specially if a pattern contains
wildcards, we do not consider the mere presence of a backslash to
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
void *data)
{
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
{
p->flags.whole_archive = input_flags.whole_archive;
p->flags.sysrooted = input_flags.sysrooted;
- if (file_type == lang_input_file_is_l_enum
- && name[0] == ':' && name[1] != '\0')
- {
- file_type = lang_input_file_is_search_file_enum;
- name = name + 1;
- }
-
switch (file_type)
{
case lang_input_file_is_symbols_only_enum:
p->local_sym_name = name;
break;
case lang_input_file_is_l_enum:
- p->filename = name;
+ if (name[0] == ':' && name[1] != '\0')
+ {
+ p->filename = name + 1;
+ p->flags.full_name_provided = TRUE;
+ }
+ else
+ 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 == '=')
+ {
+ lang_input_statement_type *ret;
+ char *sysrooted_name
+ = concat (ld_sysroot, name + 1, (const char *) NULL);
+
+ /* We've now forcibly prepended the sysroot, making the input
+ file independent of the context. Therefore, temporarily
+ force a non-sysrooted context for this statement, so it won't
+ get the sysroot prepended again when opened. (N.B. if it's a
+ script, any child nodes with input files starting with "/"
+ will be handled as "sysrooted" as they'll be found to be
+ within the sysroot subdirectory.) */
+ unsigned int outer_sysrooted = input_flags.sysrooted;
+ input_flags.sysrooted = 0;
+ ret = new_afile (sysrooted_name, file_type, target, TRUE);
+ input_flags.sysrooted = outer_sysrooted;
+ return ret;
+ }
+
return new_afile (name, file_type, target, TRUE);
}
abs_output_section->bfd_section = bfd_abs_section_ptr;
- /* The value "3" is ad-hoc, somewhat related to the expected number of
- DEFINED expressions in a linker script. For most default linker
- scripts, there are none. Why a hash table then? Well, it's somewhat
- simpler to re-use working machinery than using a linked list in terms
- of code-complexity here in ld, besides the initialization which just
- looks like other code here. */
- if (!bfd_hash_table_init_n (&lang_definedness_table,
- lang_definedness_newfunc,
- sizeof (struct lang_definedness_hash_entry),
- 3))
- einfo (_("%P%F: can not create hash table: %E\n"));
+ asneeded_list_head = NULL;
+ asneeded_list_tail = &asneeded_list_head;
}
void
lang_finish (void)
{
- bfd_link_hash_table_free (link_info.output_bfd, link_info.hash);
- bfd_hash_table_free (&lang_definedness_table);
output_section_statement_table_free ();
}
new_region->name_list.name = xstrdup (name);
new_region->name_list.next = NULL;
new_region->next = NULL;
+ new_region->origin_exp = NULL;
new_region->origin = 0;
+ new_region->length_exp = NULL;
new_region->length = ~(bfd_size_type) 0;
new_region->current = 0;
new_region->last_os = NULL;
}
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;
return lang_memory_region_lookup (DEFAULT_MEMORY_REGION, FALSE);
}
+/* Get the output section statement directly from the userdata. */
+
+lang_output_section_statement_type *
+lang_output_section_get (const asection *output_section)
+{
+ return get_userdata (output_section);
+}
+
/* Find or create an output_section_statement with the given NAME.
If CONSTRAINT is non-zero match one with that constraint, otherwise
match any non-negative constraint. If CREATE, always make a
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 flags;
+ flagword look_flags, differ;
/* We know the first statement on this list is *ABS*. May as well
skip it. */
found = NULL;
for (look = first; look; look = look->next)
{
- flags = look->flags;
+ look_flags = look->flags;
if (look->bfd_section != NULL)
{
- flags = look->bfd_section->flags;
+ look_flags = look->bfd_section->flags;
if (match_type && !match_type (link_info.output_bfd,
look->bfd_section,
sec->owner, sec))
continue;
}
- flags ^= sec->flags;
- if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY
- | SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
+ differ = look_flags ^ sec_flags;
+ if (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY
+ | SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
found = look;
}
if (found != NULL)
return found;
}
- if ((sec->flags & SEC_CODE) != 0
- && (sec->flags & SEC_ALLOC) != 0)
+ if ((sec_flags & SEC_CODE) != 0
+ && (sec_flags & SEC_ALLOC) != 0)
{
/* Try for a rw code section. */
for (look = first; look; look = look->next)
{
- flags = look->flags;
+ look_flags = look->flags;
if (look->bfd_section != NULL)
{
- flags = look->bfd_section->flags;
+ look_flags = look->bfd_section->flags;
if (match_type && !match_type (link_info.output_bfd,
look->bfd_section,
sec->owner, sec))
continue;
}
- flags ^= sec->flags;
- if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
- | SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
+ differ = look_flags ^ sec_flags;
+ if (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
+ | SEC_CODE | SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
found = look;
}
}
- else if ((sec->flags & (SEC_READONLY | SEC_THREAD_LOCAL)) != 0
- && (sec->flags & SEC_ALLOC) != 0)
+ else if ((sec_flags & SEC_READONLY) != 0
+ && (sec_flags & SEC_ALLOC) != 0)
{
/* .rodata can go after .text, .sdata2 after .rodata. */
for (look = first; look; look = look->next)
{
- flags = look->flags;
+ look_flags = look->flags;
if (look->bfd_section != NULL)
{
- flags = look->bfd_section->flags;
+ look_flags = look->bfd_section->flags;
if (match_type && !match_type (link_info.output_bfd,
look->bfd_section,
sec->owner, sec))
continue;
}
- flags ^= sec->flags;
- if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
- | SEC_READONLY | SEC_SMALL_DATA))
- || (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
- | SEC_READONLY))
- && !(look->flags & SEC_SMALL_DATA))
- || (!(flags & (SEC_THREAD_LOCAL | SEC_ALLOC))
- && (look->flags & SEC_THREAD_LOCAL)
- && (!(flags & SEC_LOAD)
- || (look->flags & SEC_LOAD))))
+ differ = look_flags ^ sec_flags;
+ if (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
+ | SEC_READONLY | SEC_SMALL_DATA))
+ || (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
+ | SEC_READONLY))
+ && !(look_flags & SEC_SMALL_DATA)))
found = look;
}
}
- else if ((sec->flags & SEC_SMALL_DATA) != 0
- && (sec->flags & SEC_ALLOC) != 0)
+ else if ((sec_flags & SEC_THREAD_LOCAL) != 0
+ && (sec_flags & SEC_ALLOC) != 0)
+ {
+ /* .tdata can go after .data, .tbss after .tdata. Treat .tbss
+ as if it were a loaded section, and don't use match_type. */
+ bfd_boolean seen_thread_local = FALSE;
+
+ match_type = NULL;
+ for (look = first; look; look = look->next)
+ {
+ look_flags = look->flags;
+ if (look->bfd_section != NULL)
+ look_flags = look->bfd_section->flags;
+
+ differ = look_flags ^ (sec_flags | SEC_LOAD | SEC_HAS_CONTENTS);
+ if (!(differ & (SEC_THREAD_LOCAL | SEC_ALLOC)))
+ {
+ /* .tdata and .tbss must be adjacent and in that order. */
+ if (!(look_flags & SEC_LOAD)
+ && (sec_flags & SEC_LOAD))
+ /* ..so if we're at a .tbss section and we're placing
+ a .tdata section stop looking and return the
+ previous section. */
+ break;
+ found = look;
+ seen_thread_local = TRUE;
+ }
+ else if (seen_thread_local)
+ break;
+ else if (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD)))
+ found = look;
+ }
+ }
+ else if ((sec_flags & SEC_SMALL_DATA) != 0
+ && (sec_flags & SEC_ALLOC) != 0)
{
/* .sdata goes after .data, .sbss after .sdata. */
for (look = first; look; look = look->next)
{
- flags = look->flags;
+ look_flags = look->flags;
if (look->bfd_section != NULL)
{
- flags = look->bfd_section->flags;
+ look_flags = look->bfd_section->flags;
if (match_type && !match_type (link_info.output_bfd,
look->bfd_section,
sec->owner, sec))
continue;
}
- flags ^= sec->flags;
- if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
- | SEC_THREAD_LOCAL))
- || ((look->flags & SEC_SMALL_DATA)
- && !(sec->flags & SEC_HAS_CONTENTS)))
+ differ = look_flags ^ sec_flags;
+ if (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
+ | SEC_THREAD_LOCAL))
+ || ((look_flags & SEC_SMALL_DATA)
+ && !(sec_flags & SEC_HAS_CONTENTS)))
found = look;
}
}
- else if ((sec->flags & SEC_HAS_CONTENTS) != 0
- && (sec->flags & SEC_ALLOC) != 0)
+ else if ((sec_flags & SEC_HAS_CONTENTS) != 0
+ && (sec_flags & SEC_ALLOC) != 0)
{
/* .data goes after .rodata. */
for (look = first; look; look = look->next)
{
- flags = look->flags;
+ look_flags = look->flags;
if (look->bfd_section != NULL)
{
- flags = look->bfd_section->flags;
+ look_flags = look->bfd_section->flags;
if (match_type && !match_type (link_info.output_bfd,
look->bfd_section,
sec->owner, sec))
continue;
}
- flags ^= sec->flags;
- if (!(flags & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
- | SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
+ differ = look_flags ^ sec_flags;
+ if (!(differ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD
+ | SEC_SMALL_DATA | SEC_THREAD_LOCAL)))
found = look;
}
}
- else if ((sec->flags & SEC_ALLOC) != 0)
+ else if ((sec_flags & SEC_ALLOC) != 0)
{
/* .bss goes after any other alloc section. */
for (look = first; look; look = look->next)
{
- flags = look->flags;
+ look_flags = look->flags;
if (look->bfd_section != NULL)
{
- flags = look->bfd_section->flags;
+ look_flags = look->bfd_section->flags;
if (match_type && !match_type (link_info.output_bfd,
look->bfd_section,
sec->owner, sec))
continue;
}
- flags ^= sec->flags;
- if (!(flags & SEC_ALLOC))
+ differ = look_flags ^ sec_flags;
+ if (!(differ & SEC_ALLOC))
found = look;
}
}
/* non-alloc go last. */
for (look = first; look; look = look->next)
{
- flags = look->flags;
+ look_flags = look->flags;
if (look->bfd_section != NULL)
- flags = look->bfd_section->flags;
- flags ^= sec->flags;
- if (!(flags & SEC_DEBUGGING))
+ look_flags = look->bfd_section->flags;
+ differ = look_flags ^ sec_flags;
+ if (!(differ & SEC_DEBUGGING))
found = look;
}
return found;
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
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. */
return os;
}
+static void
+lang_print_asneeded (void)
+{
+ struct asneeded_minfo *m;
+ char buf[100];
+
+ if (asneeded_list_head == NULL)
+ return;
+
+ sprintf (buf, _("\nAs-needed library included "
+ "to satisfy reference by file (symbol)\n\n"));
+ minfo ("%s", buf);
+
+ for (m = asneeded_list_head; m != NULL; m = m->next)
+ {
+ size_t len;
+
+ minfo ("%s", m->soname);
+ len = strlen (m->soname);
+
+ if (len >= 29)
+ {
+ print_nl ();
+ len = 0;
+ }
+ while (len < 30)
+ {
+ print_space ();
+ ++len;
+ }
+
+ if (m->ref != NULL)
+ minfo ("%B ", m->ref);
+ minfo ("(%T)\n", m->name);
+ }
+}
+
static void
lang_map_flags (flagword flag)
{
{
lang_memory_region_type *m;
bfd_boolean dis_header_printed = FALSE;
- bfd *p;
LANG_FOR_EACH_INPUT_STATEMENT (file)
{
|| 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);
- for (p = link_info.input_bfds; p != (bfd *) NULL; p = p->link_next)
- bfd_map_over_sections (p, init_map_userdata, 0);
bfd_link_hash_traverse (link_info.hash, sort_def_symbol, 0);
}
- lang_statement_iteration ++;
+ lang_statement_iteration++;
print_statements ();
-}
-static void
-init_map_userdata (bfd *abfd ATTRIBUTE_UNUSED,
- asection *sec,
- void *data ATTRIBUTE_UNUSED)
-{
- fat_section_userdata_type *new_data
- = ((fat_section_userdata_type *) (stat_alloc
- (sizeof (fat_section_userdata_type))));
-
- ASSERT (get_userdata (sec) == NULL);
- get_userdata (sec) = new_data;
- new_data->map_symbol_def_tail = &new_data->map_symbol_def_head;
- new_data->map_symbol_def_count = 0;
+ ldemul_extra_map_file_text (link_info.output_bfd, &link_info,
+ config.map_file);
}
static bfd_boolean
sort_def_symbol (struct bfd_link_hash_entry *hash_entry,
void *info ATTRIBUTE_UNUSED)
{
- if (hash_entry->type == bfd_link_hash_defined
- || hash_entry->type == bfd_link_hash_defweak)
+ if ((hash_entry->type == bfd_link_hash_defined
+ || hash_entry->type == bfd_link_hash_defweak)
+ && hash_entry->u.def.section->owner != link_info.output_bfd
+ && hash_entry->u.def.section->owner != NULL)
{
- struct fat_user_section_struct *ud;
+ input_section_userdata_type *ud;
struct map_symbol_def *def;
- ud = (struct fat_user_section_struct *)
- get_userdata (hash_entry->u.def.section);
- if (! ud)
+ ud = ((input_section_userdata_type *)
+ get_userdata (hash_entry->u.def.section));
+ if (!ud)
{
- /* ??? What do we have to do to initialize this beforehand? */
- /* The first time we get here is bfd_abs_section... */
- init_map_userdata (0, hash_entry->u.def.section, 0);
- ud = (struct fat_user_section_struct *)
- get_userdata (hash_entry->u.def.section);
+ ud = (input_section_userdata_type *) stat_alloc (sizeof (*ud));
+ get_userdata (hash_entry->u.def.section) = ud;
+ ud->map_symbol_def_tail = &ud->map_symbol_def_head;
+ ud->map_symbol_def_count = 0;
}
- else if (!ud->map_symbol_def_tail)
+ else if (!ud->map_symbol_def_tail)
ud->map_symbol_def_tail = &ud->map_symbol_def_head;
def = (struct map_symbol_def *) obstack_alloc (&map_obstack, sizeof *def);
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;
s->bfd_section->output_offset = 0;
- if (!link_info.reduce_memory_overheads)
- {
- fat_section_userdata_type *new_userdata = (fat_section_userdata_type *)
- stat_alloc (sizeof (fat_section_userdata_type));
- memset (new_userdata, 0, sizeof (fat_section_userdata_type));
- get_userdata (s->bfd_section) = new_userdata;
- }
+ /* Set the userdata of the output section to the output section
+ statement to avoid lookup. */
+ get_userdata (s->bfd_section) = s;
/* If there is a base address, make sure that any sections it might
mention are initialized. */
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);
}
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)
section->output_section = output->bfd_section;
- if (!link_info.relocatable
- && !stripped_excluded_sections)
+ if (!map_head_is_link_order)
{
asection *s = output->bfd_section->map_tail.s;
output->bfd_section->map_tail.s = section;
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;
break;
case bfd_object:
-#ifdef ENABLE_PLUGINS
if (!entry->flags.reload)
-#endif
ldlang_add_file (entry);
if (trace_files || verbose)
info_msg ("%I\n", entry);
if (member == NULL)
break;
- if (! bfd_check_format (member, bfd_object))
+ if (!bfd_check_format (member, bfd_object))
{
einfo (_("%F%B: member %B in archive is not an object\n"),
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);
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)
{
{
lang_statement_union_type **os_tail;
lang_statement_list_type add;
+ bfd *abfd;
s->input_statement.target = current_target;
/* If we are being called from within a group, and this
is an archive which has already been searched, then
force it to be researched unless the whole archive
- has been loaded already. Do the same for a rescan. */
+ has been loaded already. Do the same for a rescan.
+ Likewise reload --as-needed shared libs. */
if (mode != OPEN_BFD_NORMAL
#ifdef ENABLE_PLUGINS
&& ((mode & OPEN_BFD_RESCAN) == 0
|| plugin_insert == NULL)
#endif
- && !s->input_statement.flags.whole_archive
&& s->input_statement.flags.loaded
- && s->input_statement.the_bfd != NULL
- && bfd_check_format (s->input_statement.the_bfd,
- bfd_archive))
- s->input_statement.flags.loaded = FALSE;
-#ifdef ENABLE_PLUGINS
- /* When rescanning, reload --as-needed shared libs. */
- else if ((mode & OPEN_BFD_RESCAN) != 0
- && plugin_insert == NULL
- && s->input_statement.flags.loaded
- && s->input_statement.flags.add_DT_NEEDED_for_regular
- && s->input_statement.the_bfd != NULL
- && ((s->input_statement.the_bfd->flags) & DYNAMIC) != 0
- && plugin_should_reload (s->input_statement.the_bfd))
+ && (abfd = s->input_statement.the_bfd) != NULL
+ && ((bfd_get_format (abfd) == bfd_archive
+ && !s->input_statement.flags.whole_archive)
+ || (bfd_get_format (abfd) == bfd_object
+ && ((abfd->flags) & DYNAMIC) != 0
+ && s->input_statement.flags.add_DT_NEEDED_for_regular
+ && bfd_get_flavour (abfd) == bfd_target_elf_flavour
+ && (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0)))
{
s->input_statement.flags.loaded = FALSE;
s->input_statement.flags.reload = TRUE;
}
-#endif
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)
einfo ("%F");
}
-/* Add a symbol to a hash of symbols used in DEFINED (NAME) expressions. */
-
-void
-lang_track_definedness (const char *name)
-{
- if (bfd_hash_lookup (&lang_definedness_table, name, TRUE, FALSE) == NULL)
- einfo (_("%P%F: bfd_hash_lookup failed creating symbol %s\n"), name);
-}
-
-/* New-function for the definedness hash table. */
-
-static struct bfd_hash_entry *
-lang_definedness_newfunc (struct bfd_hash_entry *entry,
- struct bfd_hash_table *table ATTRIBUTE_UNUSED,
- const char *name ATTRIBUTE_UNUSED)
-{
- struct lang_definedness_hash_entry *ret
- = (struct lang_definedness_hash_entry *) entry;
-
- if (ret == NULL)
- ret = (struct lang_definedness_hash_entry *)
- bfd_hash_allocate (table, sizeof (struct lang_definedness_hash_entry));
-
- if (ret == NULL)
- einfo (_("%P%F: bfd_hash_allocate failed creating symbol %s\n"), name);
-
- ret->iteration = -1;
- return &ret->root;
-}
-
-/* Return the iteration when the definition of NAME was last updated. A
- value of -1 means that the symbol is not defined in the linker script
- or the command line, but may be defined in the linker symbol table. */
-
-int
-lang_symbol_definition_iteration (const char *name)
-{
- struct lang_definedness_hash_entry *defentry
- = (struct lang_definedness_hash_entry *)
- bfd_hash_lookup (&lang_definedness_table, name, FALSE, FALSE);
-
- /* We've already created this one on the presence of DEFINED in the
- script, so it can't be NULL unless something is borked elsewhere in
- the code. */
- if (defentry == NULL)
- FAIL ();
-
- return defentry->iteration;
-}
-
-/* Update the definedness state of NAME. */
-
-void
-lang_update_definedness (const char *name, struct bfd_link_hash_entry *h)
-{
- struct lang_definedness_hash_entry *defentry
- = (struct lang_definedness_hash_entry *)
- bfd_hash_lookup (&lang_definedness_table, name, FALSE, FALSE);
-
- /* We don't keep track of symbols not tested with DEFINED. */
- if (defentry == NULL)
- return;
-
- /* If the symbol was already defined, and not from an earlier statement
- iteration, don't update the definedness iteration, because that'd
- make the symbol seem defined in the linker script at this point, and
- it wasn't; it was defined in some object. If we do anyway, DEFINED
- would start to yield false before this point and the construct "sym =
- DEFINED (sym) ? sym : X;" would change sym to X despite being defined
- in an object. */
- if (h->type != bfd_link_hash_undefined
- && h->type != bfd_link_hash_common
- && h->type != bfd_link_hash_new
- && defentry->iteration == -1)
- return;
-
- defentry->iteration = lang_statement_iteration;
-}
-
/* Add the supplied name to the symbol table as an undefined reference.
This is a two step process as the symbol table doesn't even exist at
the time the ld command line is processed. First we put the name
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
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:
}
}
- /* TODO: Don't just junk map_head.s, turn them into link_orders. */
- output_section->map_head.link_order = NULL;
- output_section->map_tail.link_order = NULL;
-
if (exclude)
{
/* We don't set bfd_section to NULL since bfd_section of the
link_info.output_bfd->section_count--;
}
}
+}
+
+/* Called from ldwrite to clear out asection.map_head and
+ asection.map_tail for use as link_orders in ldwrite.
+ FIXME: Except for sh64elf.em which starts creating link_orders in
+ its after_allocation routine so needs to call it early. */
+
+void
+lang_clear_os_map (void)
+{
+ lang_output_section_statement_type *os;
+
+ if (map_head_is_link_order)
+ return;
+
+ for (os = &lang_output_section_statement.head->output_section_statement;
+ os != NULL;
+ os = os->next)
+ {
+ asection *output_section;
+
+ if (os->constraint < 0)
+ continue;
+
+ output_section = os->bfd_section;
+ if (output_section == NULL)
+ continue;
+
+ /* TODO: Don't just junk map_head.s, turn them into link_orders. */
+ output_section->map_head.link_order = NULL;
+ output_section->map_tail.link_order = NULL;
+ }
/* Stop future calls to lang_add_section from messing with map_head
and map_tail link_order fields. */
- stripped_excluded_sections = TRUE;
+ map_head_is_link_order = TRUE;
}
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);
const char *dst = assignment->exp->assign.dst;
is_dot = (dst[0] == '.' && dst[1] == 0);
- expld.assign_name = dst;
+ if (!is_dot)
+ expld.assign_name = dst;
tree = assignment->exp->assign.src;
}
osec = output_section->bfd_section;
if (osec == NULL)
osec = bfd_abs_section_ptr;
- exp_fold_tree (tree, osec, &print_dot);
+
+ if (assignment->exp->type.node_class != etree_provide)
+ exp_fold_tree (tree, osec, &print_dot);
+ else
+ expld.result.valid_p = FALSE;
+
if (expld.result.valid_p)
{
bfd_vma value;
}
else
{
- minfo ("*undef* ");
+ if (assignment->exp->type.node_class == etree_provide)
+ minfo ("[!provide]");
+ else
+ minfo ("*undef* ");
#ifdef BFD64
minfo (" ");
#endif
static void
print_all_symbols (asection *sec)
{
- struct fat_user_section_struct *ud =
- (struct fat_user_section_struct *) get_userdata (sec);
+ input_section_userdata_type *ud
+ = (input_section_userdata_type *) get_userdata (sec);
struct map_symbol_def *def;
struct bfd_link_hash_entry **entries;
unsigned int i;
/* 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)
{
{
lang_input_section_type *is = &((*this_ptr)->input_section);
asection *i = is->section;
+ asection *o = output_section_statement->bfd_section;
- if (i->sec_info_type != SEC_INFO_TYPE_JUST_SYMS
- && (i->flags & SEC_EXCLUDE) == 0)
+ if (i->sec_info_type == SEC_INFO_TYPE_JUST_SYMS)
+ i->output_offset = i->vma - o->vma;
+ else if ((i->flags & SEC_EXCLUDE) != 0)
+ i->output_offset = dot - o->vma;
+ else
{
bfd_size_type alignment_needed;
- asection *o;
/* Align this section first to the input sections requirement,
then to the output section's requirement. If this alignment
if (output_section_statement->subsection_alignment != -1)
i->alignment_power = output_section_statement->subsection_alignment;
- o = output_section_statement->bfd_section;
if (o->alignment_power < i->alignment_power)
o->alignment_power = i->alignment_power;
}
/* Remember where in the output section this input section goes. */
-
i->output_offset = dot - o->vma;
/* Mark how big the output section must be to contain this now. */
dot += TO_ADDR (i->size);
o->size = TO_SIZE (dot - o->vma);
}
- else
- {
- i->output_offset = i->vma - output_section_statement->bfd_section->vma;
- }
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
{
case lang_output_section_statement_enum:
{
- bfd_vma newdot, after;
+ bfd_vma newdot, after, dotdelta;
lang_output_section_statement_type *os;
lang_memory_region_type *r;
int section_alignment = 0;
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);
}
newdot = dot;
+ dotdelta = 0;
if (bfd_is_abs_section (os->bfd_section))
{
/* No matter what happens, an abs section starts at zero. */
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
bfd_vma savedot = newdot;
newdot = align_power (newdot, section_alignment);
- if (newdot != savedot
+ dotdelta = newdot - savedot;
+ if (dotdelta != 0
&& (config.warn_section_align
|| os->addr_tree != NULL)
&& expld.phase != lang_mark_phase_enum)
einfo (_("%P: warning: changing start of section"
" %s by %lu bytes\n"),
- os->name, (unsigned long) (newdot - savedot));
+ os->name, (unsigned long) dotdelta);
}
bfd_set_section_vma (0, os->bfd_section, newdot);
{
bfd_vma lma = os->lma_region->current;
- /* When LMA_REGION is the same as REGION, align the LMA
- as we did for the VMA, possibly including alignment
- from the bfd section. If a different region, then
- only align according to the value in the output
- statement unless specified otherwise. */
- if (os->lma_region != os->region && !os->align_lma_with_input)
- section_alignment = os->section_alignment;
- if (section_alignment > 0)
- lma = align_power (lma, section_alignment);
+ if (os->align_lma_with_input)
+ lma += dotdelta;
+ else
+ {
+ /* When LMA_REGION is the same as REGION, align the LMA
+ as we did for the VMA, possibly including alignment
+ from the bfd section. If a different region, then
+ only align according to the value in the output
+ statement. */
+ if (os->lma_region != os->region)
+ section_alignment = os->section_alignment;
+ if (section_alignment > 0)
+ lma = align_power (lma, section_alignment);
+ }
os->bfd_section->lma = lma;
}
else if (r->last_os != NULL
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)
&& 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)
- dot += TO_ADDR (os->bfd_section->size);
+ if (!IS_TBSS (os->bfd_section)
+ || bfd_link_relocatable (&link_info))
+ dotdelta = TO_ADDR (os->bfd_section->size);
+ else
+ dotdelta = 0;
+ dot += dotdelta;
if (os->update_dot_tree != 0)
exp_fold_tree (os->update_dot_tree, bfd_abs_section_ptr, &dot);
os->bfd_section->vma);
if (os->lma_region != NULL && os->lma_region != os->region
- && (os->bfd_section->flags & SEC_LOAD))
+ && ((os->bfd_section->flags & SEC_LOAD)
+ || os->align_lma_with_input))
{
- os->lma_region->current
- = os->bfd_section->lma + TO_ADDR (os->bfd_section->size);
+ os->lma_region->current = os->bfd_section->lma + dotdelta;
if (check_regions)
os_region_check (os, os->lma_region, NULL,
{
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;
}
dot = size_input_section (prev, output_section_statement,
- output_section_statement->fill, dot);
+ fill, dot);
}
break;
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. */
if (expld.dataseg.phase == exp_dataseg_end_seen
&& link_info.relro && expld.dataseg.relro_end)
{
- /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_RELRO_END pair was seen, try
- to put expld.dataseg.relro on a (common) page boundary. */
- bfd_vma min_base, old_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;
- /* 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);
- /* OLD_BASE is the address for a feasible minimum address which will
- still not cause a data overlap inside MAXPAGE causing file offset skip
- by MAXPAGE. */
- old_base = expld.dataseg.base;
- 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));
- 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 caused huge 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;
-
- if (((bfd_vma) 1 << max_alignment_power) < expld.dataseg.pagesize)
- {
- if (expld.dataseg.base - (1 << max_alignment_power) < old_base)
- expld.dataseg.base += expld.dataseg.pagesize;
- /* Properly align base to max_alignment_power. */
- expld.dataseg.base &= ~((1 << max_alignment_power) - 1);
- lang_reset_memory_regions ();
- one_lang_size_sections_pass (relax, check_regions);
- }
+ /* 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;
}
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
- || link_info.relocatable)
- 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;
{
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"));
+ 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. */
}
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)))
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 (link_info.relocatable
- && ! command_line.force_common_definition)
+ if (bfd_link_relocatable (&link_info)
+ && !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
{
for (power = 0; power <= 4; power++)
bfd_link_hash_traverse (link_info.hash, lang_one_common, &power);
- power = UINT_MAX;
+ power = (unsigned int) -1;
bfd_link_hash_traverse (link_info.hash, lang_one_common, &power);
}
}
char *name;
char buf[50];
- if (! header_printed)
+ if (!header_printed)
{
minfo (_("\nAllocating common symbols\n"));
minfo (_("Common symbol size file\n\n"));
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);
}
}
}
flagword *ptr_flags;
ptr_flags = invert ? &ptr->not_flags : &ptr->flags;
+
while (*flags)
{
switch (*flags)
{
+ /* PR 17900: An exclamation mark in the attributes reverses
+ the sense of any of the attributes that follow. */
+ case '!':
+ invert = !invert;
+ ptr_flags = invert ? &ptr->not_flags : &ptr->flags;
+ break;
+
case 'A': case 'a':
*ptr_flags |= SEC_ALLOC;
break;
break;
default:
- einfo (_("%P%F: invalid syntax in flags\n"));
+ einfo (_("%P%F: invalid character %c (%d) in flags\n"),
+ *flags, *flags);
break;
}
flags++;
/* The BFD linker needs to have a list of all input BFDs involved in
a link. */
- ASSERT (entry->the_bfd->link_next == NULL);
+ ASSERT (entry->the_bfd->link.next == NULL);
ASSERT (entry->the_bfd != link_info.output_bfd);
*link_info.input_bfds_tail = entry->the_bfd;
- link_info.input_bfds_tail = &entry->the_bfd->link_next;
+ link_info.input_bfds_tail = &entry->the_bfd->link.next;
entry->the_bfd->usrdata = entry;
bfd_set_gp_size (entry->the_bfd, g_switch_value);
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"));
new_stmt = new_stat (lang_output_statement, stat_ptr);
new_stmt->name = output_filename;
-
}
/* Reset the current counters in the regions. */
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)
{
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)
{
open_input_bfds (statement_list.head, OPEN_BFD_NORMAL);
#ifdef ENABLE_PLUGINS
- if (plugin_active_plugins_p ())
+ if (link_info.lto_plugin_active)
{
lang_statement_list_type added;
lang_statement_list_type files, inputfiles;
einfo (_("%P%F: %s: plugin reported error after all symbols read\n"),
plugin_error_plugin ());
/* Open any newly added files, updating the file chains. */
- link_info.loading_lto_outputs = TRUE;
open_input_bfds (*added.tail, OPEN_BFD_NORMAL);
/* Restore the global list pointer now they have all been added. */
lang_list_remove_tail (stat_ptr, &added);
}
#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)
+ lang_print_asneeded ();
bfd_section_already_linked_table_free ();
/* PR 13683: We must rerun the assignments prior to running garbage
collection in order to make sure that all symbol aliases are resolved. */
lang_do_assignments (lang_mark_phase_enum);
+
+ lang_do_memory_regions();
expld.phase = lang_first_phase_enum;
+ /* Size up the common data. */
+ lang_common ();
+
/* Remove unreferenced sections if asked to. */
lang_gc_sections ();
- /* Size up the common data. */
- lang_common ();
+ /* 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. */
- 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_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 ();
}
{
if (strcmp (filespec->name, "*") == 0)
filespec->name = NULL;
- else if (! wildcardp (filespec->name))
+ else if (!wildcardp (filespec->name))
lang_has_input_file = TRUE;
}
{
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. */
lang_new_vers_node (greg, lreg), NULL);
}
+/* Evaluate LENGTH and ORIGIN parts of MEMORY spec */
+
+static void
+lang_do_memory_regions (void)
+{
+ lang_memory_region_type *r = lang_memory_region_list;
+
+ 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);
+ }
+ 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);
+ }
+ }
+}
+
void
lang_add_unique (const char *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*"
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);
+ }
+}