/* Linker command language support.
- Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
- Free Software Foundation, Inc.
+ Copyright (C) 1991-2014 Free Software Foundation, Inc.
This file is part of the GNU Binutils.
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;
/* 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 *);
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 */
{
struct name_list *list_tmp;
- /* Propagate the section_flag_info from the wild statement to the section. */
- s->section_flag_info = ptr->section_flag_list;
-
/* Don't process sections from files which were excluded. */
for (list_tmp = sec->spec.exclude_name_list;
list_tmp;
return;
}
- (*callback) (ptr, sec, s, file, data);
+ (*callback) (ptr, sec, s, ptr->section_flag_list, file, data);
}
/* Lowest common denominator routine that can handle everything correctly,
{
sec = ptr->section_list;
if (sec == NULL)
- (*callback) (ptr, sec, s, file, data);
+ (*callback) (ptr, sec, s, ptr->section_flag_list, file, data);
while (sec != NULL)
{
decimal numerical value of the init_priority attribute.
The order of execution in .init_array is forward and
.fini_array is backward.
- 2: .ctors.NNNN/.ctors.NNNN: Where NNNN is 65535 minus the
+ 2: .ctors.NNNN/.dtors.NNNN: Where NNNN is 65535 minus the
decimal numerical value of the init_priority attribute.
The order of execution in .ctors is backward and .dtors
is forward.
output_section_callback_fast (lang_wild_statement_type *ptr,
struct wildcard_list *sec,
asection *section,
+ struct flag_info *sflag_list ATTRIBUTE_UNUSED,
lang_input_statement_type *file,
void *output)
{
if (tree->left)
output_section_callback_tree_to_list (ptr, tree->left, output);
- lang_add_section (&ptr->children, tree->section,
+ lang_add_section (&ptr->children, tree->section, NULL,
(lang_output_section_statement_type *) output);
if (tree->right)
if (member->usrdata != NULL)
{
walk_wild_section (s,
- (lang_input_statement_type *) member->usrdata,
- callback, data);
+ (lang_input_statement_type *) member->usrdata,
+ callback, data);
}
member = bfd_openr_next_archived_file (f->the_bfd, member);
else
{
p = (lang_input_statement_type *)
- stat_alloc (sizeof (lang_input_statement_type));
+ stat_alloc (sizeof (lang_input_statement_type));
p->header.type = lang_input_statement_enum;
p->header.next = NULL;
}
p->flags.add_DT_NEEDED_for_dynamic = input_flags.add_DT_NEEDED_for_dynamic;
p->flags.add_DT_NEEDED_for_regular = input_flags.add_DT_NEEDED_for_regular;
p->flags.whole_archive = input_flags.whole_archive;
-
- 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;
- }
+ p->flags.sysrooted = input_flags.sysrooted;
switch (file_type)
{
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;
p->local_sym_name = name;
p->flags.real = TRUE;
p->flags.search_dirs = TRUE;
- p->flags.sysrooted = input_flags.sysrooted;
break;
case lang_input_file_is_file_enum:
p->filename = name;
if (entry == NULL)
{
entry = (struct bfd_hash_entry *) bfd_hash_allocate (table,
- sizeof (*ret));
+ sizeof (*ret));
if (entry == NULL)
return entry;
}
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. */
+ /* The value "13" is ad-hoc, somewhat related to the expected number of
+ assignments in a linker script. */
if (!bfd_hash_table_init_n (&lang_definedness_table,
lang_definedness_newfunc,
sizeof (struct lang_definedness_hash_entry),
- 3))
+ 13))
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 ();
}
for (r = lang_memory_region_list; r != NULL; r = r->next)
for (n = &r->name_list; n != NULL; n = n->next)
if (strcmp (n->name, name) == 0)
- {
- if (create)
- einfo (_("%P:%S: warning: redeclaration of memory region `%s'\n"),
- NULL, name);
- return r;
- }
+ {
+ if (create)
+ einfo (_("%P:%S: warning: redeclaration of memory region `%s'\n"),
+ NULL, name);
+ return r;
+ }
if (!create && strcmp (name, DEFAULT_MEMORY_REGION))
einfo (_("%P:%S: warning: memory region `%s' not declared\n"),
for (r = lang_memory_region_list; r != NULL; r = r->next)
for (n = &r->name_list; n != NULL; n = n->next)
{
- if (region == NULL && strcmp (n->name, region_name) == 0)
- region = r;
- if (strcmp (n->name, alias) == 0)
- einfo (_("%F%P:%S: error: redefinition of memory region "
- "alias `%s'\n"),
- NULL, alias);
+ if (region == NULL && strcmp (n->name, region_name) == 0)
+ region = r;
+ if (strcmp (n->name, alias) == 0)
+ einfo (_("%F%P:%S: error: redefinition of memory region "
+ "alias `%s'\n"),
+ NULL, alias);
}
/* Check if the target region exists. */
if (region == NULL)
einfo (_("%F%P:%S: error: memory region `%s' "
- "for alias `%s' does not exist\n"),
- NULL, region_name, alias);
+ "for alias `%s' does not exist\n"),
+ NULL, region_name, alias);
/* Add alias to region name list. */
n = (lang_memory_region_name *) stat_alloc (sizeof (lang_memory_region_name));
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_match_sec_type_func match_type)
{
lang_output_section_statement_type *first, *look, *found;
- flagword flags;
+ flagword look_flags, sec_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)
{
- 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;
os_tail = ((lang_output_section_statement_type **)
lang_output_section_statement.tail);
os = lang_enter_output_section_statement (secname, address, normal_section,
- NULL, NULL, NULL, constraint);
+ NULL, NULL, NULL, constraint, 0);
ps = NULL;
if (config.build_constructors && *os_tail == os)
if (*ps == '\0')
{
char *symname;
- etree_type *e_align;
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);
- e_align = exp_unop (ALIGN_K,
- exp_intop ((bfd_vma) 1 << s->alignment_power));
- lang_add_assignment (exp_assign (".", e_align));
lang_add_assignment (exp_provide (symname,
- exp_unop (ABSOLUTE,
- exp_nameop (NAME, ".")),
+ exp_nameop (NAME, "."),
FALSE));
}
}
if (add_child == NULL)
add_child = &os->children;
- lang_add_section (add_child, s, os);
+ lang_add_section (add_child, s, NULL, os);
if (after && (s->flags & (SEC_LOAD | SEC_ALLOC)) != 0)
{
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)
{
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;
-}
-
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->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. */
foo.o(.text, .data). */
/* Add SECTION to the output section OUTPUT. Do this by creating a
- lang_input_section statement which is placed at PTR. FILE is the
- input file which holds SECTION. */
+ lang_input_section statement which is placed at PTR. */
void
lang_add_section (lang_statement_list_type *ptr,
asection *section,
+ struct flag_info *sflag_info,
lang_output_section_statement_type *output)
{
flagword flags = section->flags;
- struct flag_info *sflag_info = section->section_flag_info;
bfd_boolean discard;
lang_input_section_type *new_section;
if (sflag_info)
{
- if (sflag_info->flags_initialized == FALSE)
- bfd_lookup_section_flags (&link_info, sflag_info);
-
- if (sflag_info->only_with_flags != 0
- && sflag_info->not_with_flags != 0
- && ((sflag_info->not_with_flags & flags) != 0
- || (sflag_info->only_with_flags & flags)
- != sflag_info->only_with_flags))
- return;
-
- if (sflag_info->only_with_flags != 0
- && (sflag_info->only_with_flags & flags)
- != sflag_info->only_with_flags)
- return;
+ bfd_boolean keep;
- if (sflag_info->not_with_flags != 0
- && (sflag_info->not_with_flags & flags) != 0)
+ keep = bfd_lookup_section_flags (&link_info, sflag_info, section);
+ if (!keep)
return;
}
/* Here either the files are not sorted by name, or we are
looking at the sections for this file. */
- if (sec != NULL && sec->spec.sorted != none)
+ if (sec != NULL
+ && sec->spec.sorted != none
+ && sec->spec.sorted != by_none)
if (compare_section (sec->spec.sorted, section, ls->section) < 0)
break;
}
output_section_callback (lang_wild_statement_type *ptr,
struct wildcard_list *sec,
asection *section,
+ struct flag_info *sflag_info,
lang_input_statement_type *file,
void *output)
{
of the current list. */
if (before == NULL)
- lang_add_section (&ptr->children, section, os);
+ lang_add_section (&ptr->children, section, sflag_info, os);
else
{
lang_statement_list_type list;
lang_statement_union_type **pp;
lang_list_init (&list);
- lang_add_section (&list, section, os);
+ lang_add_section (&list, section, sflag_info, os);
/* If we are discarding the section, LIST.HEAD will
be NULL. */
check_section_callback (lang_wild_statement_type *ptr ATTRIBUTE_UNUSED,
struct wildcard_list *sec ATTRIBUTE_UNUSED,
asection *section,
+ struct flag_info *sflag_info ATTRIBUTE_UNUSED,
lang_input_statement_type *file ATTRIBUTE_UNUSED,
void *output)
{
{
bfd_error_type err;
struct lang_input_statement_flags save_flags;
+ extern FILE *yyin;
err = bfd_get_error ();
ldfile_open_command_file (entry->filename);
push_stat_ptr (place);
- input_flags.sysrooted = entry->flags.sysrooted;
input_flags.add_DT_NEEDED_for_regular
= entry->flags.add_DT_NEEDED_for_regular;
input_flags.add_DT_NEEDED_for_dynamic
yyparse ();
ldfile_assumed_script = FALSE;
- /* missing_file is sticky. */
+ /* missing_file is sticky. sysrooted will already have been
+ restored when seeing EOF in yyparse, but no harm to restore
+ again. */
save_flags.missing_file |= input_flags.missing_file;
input_flags = save_flags;
pop_stat_ptr ();
+ fclose (yyin);
+ yyin = NULL;
+ entry->flags.loaded = TRUE;
return TRUE;
}
if (!entry->flags.reload)
#endif
ldlang_add_file (entry);
- if (trace_files || trace_file_tries)
+ if (trace_files || verbose)
info_msg ("%I\n", entry);
break;
substitute BFD for us. */
if (!bfd_link_add_symbols (subsbfd, &link_info))
{
- einfo (_("%F%B: could not read symbols: %E\n"), member);
+ einfo (_("%F%B: error adding symbols: %E\n"), member);
loaded = FALSE;
}
}
if (bfd_link_add_symbols (entry->the_bfd, &link_info))
entry->flags.loaded = TRUE;
else
- einfo (_("%F%B: could not read symbols: %E\n"), entry->the_bfd);
+ einfo (_("%F%B: error adding symbols: %E\n"), entry->the_bfd);
return entry->flags.loaded;
}
#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;
&& 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))
{
#endif
break;
case lang_assignment_statement_enum:
- if (s->assignment_statement.exp->assign.hidden)
+ if (s->assignment_statement.exp->assign.defsym)
/* This is from a --defsym on the command line. */
exp_fold_tree_no_dot (s->assignment_statement.exp);
break;
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 *
if (ret == NULL)
einfo (_("%P%F: bfd_hash_allocate failed creating symbol %s\n"), name);
- ret->iteration = -1;
+ ret->by_object = 0;
+ ret->by_script = 0;
+ ret->iteration = 0;
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. */
+/* Called during processing of linker script script expressions.
+ For symbols assigned in a linker script, return a struct describing
+ where the symbol is defined relative to the current expression,
+ otherwise return NULL. */
-int
-lang_symbol_definition_iteration (const char *name)
+struct lang_definedness_hash_entry *
+lang_symbol_defined (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;
+ return ((struct lang_definedness_hash_entry *)
+ bfd_hash_lookup (&lang_definedness_table, name, FALSE, FALSE));
}
/* Update the definedness state of NAME. */
{
struct lang_definedness_hash_entry *defentry
= (struct lang_definedness_hash_entry *)
- bfd_hash_lookup (&lang_definedness_table, name, FALSE, FALSE);
+ bfd_hash_lookup (&lang_definedness_table, name, TRUE, FALSE);
- /* We don't keep track of symbols not tested with DEFINED. */
if (defentry == NULL)
- return;
+ einfo (_("%P%F: bfd_hash_lookup failed creating symbol %s\n"), name);
- /* 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
+ /* If the symbol was already defined, and not by a script, then it
+ must be defined by an object file. */
+ if (!defentry->by_script
+ && h->type != bfd_link_hash_undefined
&& h->type != bfd_link_hash_common
- && h->type != bfd_link_hash_new
- && defentry->iteration == -1)
- return;
+ && h->type != bfd_link_hash_new)
+ defentry->by_object = 1;
+ defentry->by_script = 1;
defentry->iteration = lang_statement_iteration;
}
break;
case lang_wild_statement_enum:
- sec = s->wild_statement.section_list;
for (sec = s->wild_statement.section_list; sec != NULL;
sec = sec->next)
{
break;
case lang_output_section_statement_enum:
- update_wild_statements
- (s->output_section_statement.children.head);
+ /* Don't sort .init/.fini sections. */
+ if (strcmp (s->output_section_statement.name, ".init") != 0
+ && strcmp (s->output_section_statement.name, ".fini") != 0)
+ update_wild_statements
+ (s->output_section_statement.children.head);
break;
case lang_group_statement_enum:
asection *s;
for (s = output_section->map_head.s; s != NULL; s = s->map_head.s)
- if ((s->flags & SEC_LINKER_CREATED) != 0
- && (s->flags & SEC_EXCLUDE) == 0)
+ if ((s->flags & SEC_EXCLUDE) == 0
+ && ((s->flags & SEC_LINKER_CREATED) != 0
+ || link_info.emitrelocations))
{
exclude = FALSE;
break;
{
/* We don't set bfd_section to NULL since bfd_section of the
removed output section statement may still be used. */
- if (!os->section_relative_symbol
- && !os->update_dot_tree)
+ if (!os->update_dot)
os->ignored = TRUE;
output_section->flags |= SEC_EXCLUDE;
bfd_section_list_remove (link_info.output_bfd, output_section);
output_section_statement);
}
-/* Scan for the use of the destination in the right hand side
- of an expression. In such cases we will not compute the
- correct expression, since the value of DST that is used on
- the right hand side will be its final value, not its value
- just before this expression is evaluated. */
-
-static bfd_boolean
-scan_for_self_assignment (const char * dst, etree_type * rhs)
-{
- if (rhs == NULL || dst == NULL)
- return FALSE;
-
- switch (rhs->type.node_class)
- {
- case etree_binary:
- return (scan_for_self_assignment (dst, rhs->binary.lhs)
- || scan_for_self_assignment (dst, rhs->binary.rhs));
-
- case etree_trinary:
- return (scan_for_self_assignment (dst, rhs->trinary.lhs)
- || scan_for_self_assignment (dst, rhs->trinary.rhs));
-
- case etree_assign:
- case etree_provided:
- case etree_provide:
- if (strcmp (dst, rhs->assign.dst) == 0)
- return TRUE;
- return scan_for_self_assignment (dst, rhs->assign.src);
-
- case etree_unary:
- return scan_for_self_assignment (dst, rhs->unary.child);
-
- case etree_value:
- if (rhs->value.str)
- return strcmp (dst, rhs->value.str) == 0;
- return FALSE;
-
- case etree_name:
- if (rhs->name.name)
- return strcmp (dst, rhs->name.name) == 0;
- return FALSE;
-
- default:
- break;
- }
-
- return FALSE;
-}
-
-
static void
print_assignment (lang_assignment_statement_type *assignment,
lang_output_section_statement_type *output_section)
{
unsigned int i;
bfd_boolean is_dot;
- bfd_boolean computation_is_valid = TRUE;
etree_type *tree;
asection *osec;
{
is_dot = FALSE;
tree = assignment->exp->assert_s.child;
- computation_is_valid = TRUE;
}
else
{
const char *dst = assignment->exp->assign.dst;
is_dot = (dst[0] == '.' && dst[1] == 0);
+ if (!is_dot)
+ expld.assign_name = dst;
tree = assignment->exp->assign.src;
- computation_is_valid = is_dot || !scan_for_self_assignment (dst, tree);
}
osec = output_section->bfd_section;
{
bfd_vma value;
- if (computation_is_valid)
+ if (assignment->exp->type.node_class == etree_assert
+ || is_dot
+ || expld.assign_name != NULL)
{
value = expld.result.value;
minfo (" ");
#endif
}
+ expld.assign_name = NULL;
minfo (" ");
exp_print_tree (assignment->exp);
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;
entries[i] = def->entry;
qsort (entries, ud->map_symbol_def_count, sizeof (*entries),
- hash_entry_addr_cmp);
+ hash_entry_addr_cmp);
/* Print the symbols. */
for (i = 0; i < ud->map_symbol_def_count; i++)
{
/* Make a new padding statement, linked into existing chain. */
pad = (lang_statement_union_type *)
- stat_alloc (sizeof (lang_padding_statement_type));
+ stat_alloc (sizeof (lang_padding_statement_type));
pad->header.next = *ptr;
*ptr = pad;
pad->header.type = lang_padding_statement_enum;
}
pad->padding_statement.output_offset = dot - output_section->vma;
pad->padding_statement.size = alignment_needed;
- output_section->size += alignment_needed;
+ output_section->size = TO_SIZE (dot + TO_ADDR (alignment_needed)
+ - output_section->vma);
}
/* Work out how much this section will move the dot point. */
lang_input_section_type *is = &((*this_ptr)->input_section);
asection *i = is->section;
- if (!((lang_input_statement_type *) i->owner->usrdata)->flags.just_syms
+ if (i->sec_info_type != SEC_INFO_TYPE_JUST_SYMS
&& (i->flags & SEC_EXCLUDE) == 0)
{
bfd_size_type alignment_needed;
{
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;
}
newdot = dot;
+ dotdelta = 0;
if (bfd_is_abs_section (os->bfd_section))
{
/* No matter what happens, an abs section starts at zero. */
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;
- 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
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);
+ 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,
if (size < TO_SIZE ((unsigned) 1))
size = TO_SIZE ((unsigned) 1);
dot += TO_ADDR (size);
- output_section_statement->bfd_section->size += size;
+ output_section_statement->bfd_section->size
+ = TO_SIZE (dot - output_section_statement->bfd_section->vma);
+
}
break;
output_section_statement->bfd_section;
size = bfd_get_reloc_size (s->reloc_statement.howto);
dot += TO_ADDR (size);
- output_section_statement->bfd_section->size += size;
+ output_section_statement->bfd_section->size
+ = TO_SIZE (dot - output_section_statement->bfd_section->vma);
}
break;
*relax = TRUE;
}
dot = size_input_section (prev, output_section_statement,
- output_section_statement->fill, dot);
+ fill, dot);
}
break;
}
expld.dataseg.relro = exp_dataseg_relro_none;
- /* This symbol is relative to this section. */
+ /* This symbol may be relative to this section. */
if ((tree->type.node_class == etree_provided
|| tree->type.node_class == etree_assign)
&& (tree->assign.dst [0] != '.'
|| tree->assign.dst [1] != '\0'))
- output_section_statement->section_relative_symbol = 1;
+ output_section_statement->update_dot = 1;
if (!output_section_statement->ignored)
{
if (current_section == NULL || previous_section == NULL)
return new_segment;
+ /* If this flag is set, the target never wants code and non-code
+ sections comingled in the same segment. */
+ if (config.separate_code
+ && ((current_section->flags ^ previous_section->flags) & SEC_CODE))
+ return TRUE;
+
/* Find the memory regions associated with the two sections.
We call lang_output_section_find() here rather than scanning the list
of output sections looking for a matching section pointer because if
&& 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;
+ to put expld.dataseg.relro_end on a (common) page boundary. */
+ bfd_vma min_base, relro_end, maxpage;
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. */
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. */
+ 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;
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;
- expld.dataseg.base -= (1 << max_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);
lang_reset_memory_regions ();
one_lang_size_sections_pass (relax, check_regions);
}
expld.dataseg.phase = exp_dataseg_done;
}
+static lang_output_section_statement_type *current_section;
+static lang_assignment_statement_type *current_assign;
+static bfd_boolean prefer_next_section;
+
/* Worker function for lang_do_assignments. Recursiveness goes here. */
static bfd_vma
lang_do_assignments_1 (lang_statement_union_type *s,
lang_output_section_statement_type *current_os,
fill_type *fill,
- bfd_vma dot)
+ bfd_vma dot,
+ bfd_boolean *found_end)
{
for (; s != NULL; s = s->header.next)
{
{
case lang_constructors_statement_enum:
dot = lang_do_assignments_1 (constructor_list.head,
- current_os, fill, dot);
+ current_os, fill, dot, found_end);
break;
case lang_output_section_statement_enum:
lang_output_section_statement_type *os;
os = &(s->output_section_statement);
+ os->after_end = *found_end;
if (os->bfd_section != NULL && !os->ignored)
{
+ if ((os->bfd_section->flags & SEC_ALLOC) != 0)
+ {
+ current_section = os;
+ prefer_next_section = FALSE;
+ }
dot = os->bfd_section->vma;
- lang_do_assignments_1 (os->children.head, os, os->fill, dot);
+ 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
case lang_wild_statement_enum:
dot = lang_do_assignments_1 (s->wild_statement.children.head,
- current_os, fill, dot);
+ current_os, fill, dot, found_end);
break;
case lang_object_symbols_statement_enum:
break;
case lang_assignment_statement_enum:
+ current_assign = &s->assignment_statement;
+ if (current_assign->exp->type.node_class != etree_assert)
+ {
+ const char *p = current_assign->exp->assign.dst;
+
+ if (current_os == abs_output_section && p[0] == '.' && p[1] == 0)
+ prefer_next_section = TRUE;
+
+ while (*p == '_')
+ ++p;
+ if (strcmp (p, "end") == 0)
+ *found_end = TRUE;
+ }
exp_fold_tree (s->assignment_statement.exp,
current_os->bfd_section,
&dot);
case lang_group_statement_enum:
dot = lang_do_assignments_1 (s->group_statement.children.head,
- current_os, fill, dot);
+ current_os, fill, dot, found_end);
break;
case lang_insert_statement_enum:
void
lang_do_assignments (lang_phase_type phase)
{
+ bfd_boolean found_end = FALSE;
+
+ current_section = NULL;
+ prefer_next_section = FALSE;
expld.phase = phase;
lang_statement_iteration++;
- lang_do_assignments_1 (statement_list.head, abs_output_section, NULL, 0);
+ lang_do_assignments_1 (statement_list.head,
+ abs_output_section, NULL, 0, &found_end);
+}
+
+/* For an assignment statement outside of an output section statement,
+ choose the best of neighbouring output sections to use for values
+ of "dot". */
+
+asection *
+section_for_dot (void)
+{
+ asection *s;
+
+ /* Assignments belong to the previous output section, unless there
+ has been an assignment to "dot", in which case following
+ assignments belong to the next output section. (The assumption
+ is that an assignment to "dot" is setting up the address for the
+ next output section.) Except that past the assignment to "_end"
+ we always associate with the previous section. This exception is
+ for targets like SH that define an alloc .stack or other
+ weirdness after non-alloc sections. */
+ if (current_section == NULL || prefer_next_section)
+ {
+ lang_statement_union_type *stmt;
+ lang_output_section_statement_type *os;
+
+ for (stmt = (lang_statement_union_type *) current_assign;
+ stmt != NULL;
+ stmt = stmt->header.next)
+ if (stmt->header.type == lang_output_section_statement_enum)
+ break;
+
+ os = &stmt->output_section_statement;
+ while (os != NULL
+ && !os->after_end
+ && (os->bfd_section == NULL
+ || (os->bfd_section->flags & SEC_EXCLUDE) != 0
+ || bfd_section_removed_from_list (link_info.output_bfd,
+ os->bfd_section)))
+ os = os->next;
+
+ if (current_section == NULL || os == NULL || !os->after_end)
+ {
+ if (os != NULL)
+ s = os->bfd_section;
+ else
+ s = link_info.output_bfd->section_last;
+ while (s != NULL
+ && ((s->flags & SEC_ALLOC) == 0
+ || (s->flags & SEC_THREAD_LOCAL) != 0))
+ s = s->prev;
+ if (s != NULL)
+ return s;
+
+ return bfd_abs_section_ptr;
+ }
+ }
+
+ s = current_section->bfd_section;
+
+ /* The section may have been stripped. */
+ while (s != NULL
+ && ((s->flags & SEC_EXCLUDE) != 0
+ || (s->flags & SEC_ALLOC) == 0
+ || (s->flags & SEC_THREAD_LOCAL) != 0
+ || bfd_section_removed_from_list (link_info.output_bfd, s)))
+ s = s->prev;
+ if (s == NULL)
+ s = link_info.output_bfd->sections;
+ while (s != NULL
+ && ((s->flags & SEC_ALLOC) == 0
+ || (s->flags & SEC_THREAD_LOCAL) != 0))
+ s = s->next;
+ if (s != NULL)
+ return s;
+
+ return bfd_abs_section_ptr;
}
/* Fix any .startof. or .sizeof. symbols. When the assemblers see the
if (h != NULL && h->type == bfd_link_hash_undefined)
{
h->type = bfd_link_hash_defined;
- h->u.def.value = bfd_get_section_vma (link_info.output_bfd, s);
- h->u.def.section = bfd_abs_section_ptr;
+ h->u.def.value = 0;
+ h->u.def.section = s;
}
sprintf (buf, ".sizeof.%s", secname);
}
}
}
-
- /* Don't bfd_hash_table_free (&lang_definedness_table);
- map file output may result in a call of lang_track_definedness. */
}
/* This is a small function used when we want to ignore errors from
= lang_output_section_statement_lookup (".bss", 0,
TRUE);
lang_add_section (&default_common_section->children, s,
- default_common_section);
+ NULL, default_common_section);
}
}
else
&& (link_info.relocatable
|| (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0))
os->addr_tree = exp_intop (0);
- lang_add_section (&os->children, s, os);
+ lang_add_section (&os->children, s, NULL, os);
}
}
}
}
}
-static lang_output_section_statement_type *current_section;
-
static int
topower (int x)
{
etree_type *align,
etree_type *subalign,
etree_type *ebase,
- int constraint)
+ int constraint,
+ int align_with_input)
{
lang_output_section_statement_type *os;
/* Make next things chain into subchain of this. */
push_stat_ptr (&os->children);
+ 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);
+
os->subsection_alignment =
topower (exp_get_value_int (subalign, -1, "subsection alignment"));
os->section_alignment =
gc_section_callback (lang_wild_statement_type *ptr,
struct wildcard_list *sec ATTRIBUTE_UNUSED,
asection *section,
+ struct flag_info *sflag_info ATTRIBUTE_UNUSED,
lang_input_statement_type *file ATTRIBUTE_UNUSED,
void *data ATTRIBUTE_UNUSED)
{
find_relro_section_callback (lang_wild_statement_type *ptr ATTRIBUTE_UNUSED,
struct wildcard_list *sec ATTRIBUTE_UNUSED,
asection *section,
+ struct flag_info *sflag_info ATTRIBUTE_UNUSED,
lang_input_statement_type *file ATTRIBUTE_UNUSED,
void *data)
{
link_info.gc_sym_list = ldlang_undef_chain_list_head;
ldemul_after_open ();
+ if (config.map_file != NULL)
+ lang_print_asneeded ();
bfd_section_already_linked_table_free ();
pop_stat_ptr ();
}
-/* Create an absolute symbol with the given name with the value of the
- address of first byte of the section named.
-
- If the symbol already exists, then do nothing. */
-
-void
-lang_abs_symbol_at_beginning_of (const char *secname, const char *name)
-{
- struct bfd_link_hash_entry *h;
-
- h = bfd_link_hash_lookup (link_info.hash, name, TRUE, TRUE, TRUE);
- if (h == NULL)
- einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n"));
-
- if (h->type == bfd_link_hash_new
- || h->type == bfd_link_hash_undefined)
- {
- asection *sec;
-
- h->type = bfd_link_hash_defined;
-
- sec = bfd_get_section_by_name (link_info.output_bfd, secname);
- if (sec == NULL)
- h->u.def.value = 0;
- else
- h->u.def.value = bfd_get_section_vma (link_info.output_bfd, sec);
-
- h->u.def.section = bfd_abs_section_ptr;
- }
-}
-
-/* Create an absolute symbol with the given name with the value of the
- address of the first byte after the end of the section named.
-
- If the symbol already exists, then do nothing. */
-
-void
-lang_abs_symbol_at_end_of (const char *secname, const char *name)
-{
- struct bfd_link_hash_entry *h;
-
- h = bfd_link_hash_lookup (link_info.hash, name, TRUE, TRUE, TRUE);
- if (h == NULL)
- einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n"));
-
- if (h->type == bfd_link_hash_new
- || h->type == bfd_link_hash_undefined)
- {
- asection *sec;
-
- h->type = bfd_link_hash_defined;
-
- sec = bfd_get_section_by_name (link_info.output_bfd, secname);
- if (sec == NULL)
- h->u.def.value = 0;
- else
- h->u.def.value = (bfd_get_section_vma (link_info.output_bfd, sec)
- + TO_ADDR (sec->size));
-
- h->u.def.section = bfd_abs_section_ptr;
- }
-}
-
void
lang_statement_append (lang_statement_list_type *list,
lang_statement_union_type *element,
{
alc *= 2;
secs = (asection **) xrealloc (secs,
- alc * sizeof (asection *));
+ alc * sizeof (asection *));
}
secs[c] = os->bfd_section;
++c;
etree_type *size;
lang_enter_output_section_statement (name, overlay_vma, overlay_section,
- 0, overlay_subalign, 0, 0);
+ 0, overlay_subalign, 0, 0, 0);
/* If this is the first section, then base the VMA of future
sections on this one. This will work correctly even if `.' is
/* After setting the size of the last section, set '.' to end of the
overlay region. */
if (overlay_list != NULL)
- overlay_list->os->update_dot_tree
- = exp_assign (".", exp_binop ('+', overlay_vma, overlay_max));
+ {
+ overlay_list->os->update_dot = 1;
+ overlay_list->os->update_dot_tree
+ = exp_assign (".", exp_binop ('+', overlay_vma, overlay_max), FALSE);
+ }
l = overlay_list;
while (l != NULL)
{
e.pattern = c_sym;
expr = (struct bfd_elf_version_expr *)
- htab_find ((htab_t) head->htab, &e);
+ htab_find ((htab_t) head->htab, &e);
while (expr && strcmp (expr->pattern, c_sym) == 0)
if (expr->mask == BFD_ELF_VERSION_C_TYPE)
goto out_ret;
{
e.pattern = cxx_sym;
expr = (struct bfd_elf_version_expr *)
- htab_find ((htab_t) head->htab, &e);
+ htab_find ((htab_t) head->htab, &e);
while (expr && strcmp (expr->pattern, cxx_sym) == 0)
if (expr->mask == BFD_ELF_VERSION_CXX_TYPE)
goto out_ret;
{
e.pattern = java_sym;
expr = (struct bfd_elf_version_expr *)
- htab_find ((htab_t) head->htab, &e);
+ htab_find ((htab_t) head->htab, &e);
while (expr && strcmp (expr->pattern, java_sym) == 0)
if (expr->mask == BFD_ELF_VERSION_JAVA_TYPE)
goto out_ret;
if (t->locals.htab && e1->literal)
{
e2 = (struct bfd_elf_version_expr *)
- htab_find ((htab_t) t->locals.htab, e1);
+ htab_find ((htab_t) t->locals.htab, e1);
while (e2 && strcmp (e1->pattern, e2->pattern) == 0)
{
if (e1->mask == e2->mask)
if (t->globals.htab && e1->literal)
{
e2 = (struct bfd_elf_version_expr *)
- htab_find ((htab_t) t->globals.htab, e1);
+ htab_find ((htab_t) t->globals.htab, e1);
while (e2 && strcmp (e1->pattern, e2->pattern) == 0)
{
if (e1->mask == e2->mask)