#include "obstack.h"
#include "bfdlink.h"
#include "ctf-api.h"
-
#include "ld.h"
#include "ldmain.h"
#include "ldexp.h"
#include "demangle.h"
#include "hashtab.h"
#include "elf-bfd.h"
+#include "bfdver.h"
+
#if BFD_SUPPORTS_PLUGINS
#include "plugin.h"
-#endif /* BFD_SUPPORTS_PLUGINS */
+#endif
#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) & (((TYPE*) 0)->MEMBER))
/* Forward declarations. */
static void exp_init_os (etree_type *);
static lang_input_statement_type *lookup_name (const char *);
+static bool wont_add_section_p (asection *,
+ lang_output_section_statement_type *);
static void insert_undefined (const char *);
static bool sort_def_symbol (struct bfd_link_hash_entry *, void *);
static lang_statement_union_type *new_statement (enum statement_enum type,
bool had_output_filename = false;
bool lang_float_flag = false;
bool delete_output_file_on_failure = false;
+bool enable_linker_version = false;
struct lang_phdr *lang_phdr_list;
struct lang_nocrossrefs *nocrossref_list;
struct asneeded_minfo **asneeded_list_tail;
}
else
{
- lang_input_statement_type *f;
- /* Perform the iteration over a single file. */
- f = lookup_name (file_spec);
- if (f != file)
+ /* XXX Matching against non-wildcard filename in wild statements
+ was done by going through lookup_name, which uses
+ ->local_sym_name to compare against, not ->filename. We retain
+ this behaviour even though the above code paths use filename.
+ It would be more logical to use it here as well, in which
+ case the above wildcard() arm could be folded into this by using
+ name_match. This would also solve the worry of what to do
+ about unset local_sym_name (in which case lookup_name simply adds
+ the input file again). */
+ const char *filename = file->local_sym_name;
+ lang_input_statement_type *arch_is;
+ if (filename && filename_cmp (filename, file_spec) == 0)
+ ;
+ /* FIXME: see also walk_wild_file_in_exclude_list for why we
+ also check parents BFD (local_sym_)name to match input statements
+ with unadorned archive names. */
+ else if (file->the_bfd
+ && file->the_bfd->my_archive
+ && (arch_is = bfd_usrdata (file->the_bfd->my_archive))
+ && arch_is->local_sym_name
+ && filename_cmp (arch_is->local_sym_name, file_spec) == 0)
+ ;
+ else
return;
}
if (unique_section_p (section, os))
return;
+ /* Don't add sections to the tree when we already know that
+ lang_add_section won't do anything with it. */
+ if (wont_add_section_p (section, os))
+ return;
+
node = (lang_section_bst_type *) xmalloc (sizeof (lang_section_bst_type));
node->left = 0;
node->right = 0;
lang_has_input_file = true;
+ /* PR 30632: It is OK for name to be NULL. For example
+ see the initialization of first_file in lang_init(). */
+ if (name != NULL)
+ {
+ name = ldfile_possibly_remap_input (name);
+ /* But if a name is remapped to NULL, it should be ignored. */
+ if (name == NULL)
+ return NULL;
+ }
+
p = new_stat (lang_input_statement, stat_ptr);
memset (&p->the_bfd, 0,
sizeof (*p) - offsetof (lang_input_statement_type, the_bfd));
lang_finish (void)
{
output_section_statement_table_free ();
+ ldfile_remap_input_free ();
}
/*----------------------------------------------------------------------
if (lookup->constraint < 0)
continue;
- if (lookup->bfd_section != NULL && lookup->bfd_section->owner != NULL)
+ if (lookup->bfd_section != NULL)
return lookup->bfd_section;
}
image symbols. */
static lang_statement_union_type **
-insert_os_after (lang_output_section_statement_type *after)
+insert_os_after (lang_statement_union_type *after)
{
lang_statement_union_type **where;
lang_statement_union_type **assign = NULL;
bool ignore_first;
- ignore_first = after == (void *) lang_os_list.head;
+ ignore_first = after == lang_os_list.head;
for (where = &after->header.next;
*where != NULL;
if (bfd_section == NULL)
bfd_section = output_prev_sec_find (after);
- if (bfd_section != NULL && bfd_section != snew)
+ if (bfd_section != NULL
+ && bfd_section->owner != NULL
+ && bfd_section != snew)
place->section = &bfd_section->next;
}
/* Place OS after AFTER if AFTER_NOTE is TRUE. */
if (place_after)
{
- lang_statement_union_type **where = insert_os_after (after);
+ lang_statement_union_type **where;
+ where = insert_os_after ((lang_statement_union_type *) after);
*add.tail = *where;
*where = add.head;
lang_memory_region_type *m;
bool dis_header_printed = false;
+ ldfile_print_input_remaps ();
+
LANG_FOR_EACH_INPUT_STATEMENT (file)
{
asection *s;
{
if (! dis_header_printed)
{
- fprintf (config.map_file, _("\nDiscarded input sections\n\n"));
+ minfo (_("\nDiscarded input sections\n\n"));
dis_header_printed = true;
}
print_input_section (s, true);
}
}
+ if (config.print_map_discarded && ! dis_header_printed)
+ minfo (_("\nThere are no discarded input sections\n"));
minfo (_("\nMemory Configuration\n\n"));
fprintf (config.map_file, "%-16s %-18s %-18s %s\n",
print_nl ();
}
- fprintf (config.map_file, _("\nLinker script and memory map\n\n"));
+ minfo (_("\nLinker script and memory map\n\n"));
if (!link_info.reduce_memory_overheads)
{
/* If supplied an alignment, set it. */
if (s->section_alignment != NULL)
- s->bfd_section->alignment_power = exp_get_power (s->section_alignment,
+ s->bfd_section->alignment_power = exp_get_power (s->section_alignment, s,
"section alignment");
}
&& (flags & SEC_DEBUGGING) != 0)
discard = true;
+ /* Discard non-alloc sections if we are stripping section headers. */
+ else if (config.no_section_header && (flags & SEC_ALLOC) == 0)
+ discard = true;
+
return discard;
}
-/* The wild routines.
+/* Return TRUE if SECTION is never going to be added to output statement
+ OUTPUT. lang_add_section() definitely won't do anything with SECTION
+ if this returns TRUE. It may do something (or not) if this returns FALSE.
- These expand statements like *(.text) and foo.o to a list of
- explicit actions, like foo.o(.text), bar.o(.text) and
- 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. */
+ Can be used as early-out to filter matches. This may set
+ output_section of SECTION, if it was unset, to the abs section in case
+ we discover SECTION to be always discarded. This may also give
+ warning messages. */
-void
-lang_add_section (lang_statement_list_type *ptr,
- asection *section,
- struct wildcard_list *pattern,
- struct flag_info *sflag_info,
- lang_output_section_statement_type *output)
+static bool
+wont_add_section_p (asection *section,
+ lang_output_section_statement_type *output)
{
- flagword flags = section->flags;
-
bool discard;
- lang_input_section_type *new_section;
- bfd *abfd = link_info.output_bfd;
/* Is this section one we know should be discarded? */
discard = lang_discard_section_p (section);
{
if (section->output_section == NULL)
{
- /* This prevents future calls from assigning this section. */
+ /* This prevents future calls from assigning this section or
+ warning about it again. */
section->output_section = bfd_abs_section_ptr;
}
+ else if (bfd_is_abs_section (section->output_section))
+ ;
else if (link_info.non_contiguous_regions_warnings)
einfo (_("%P:%pS: warning: --enable-non-contiguous-regions makes "
"section `%pA' from `%pB' match /DISCARD/ clause.\n"),
NULL, section, section->owner);
- return;
- }
-
- if (sflag_info)
- {
- bool keep;
-
- keep = bfd_lookup_section_flags (&link_info, sflag_info, section);
- if (!keep)
- return;
+ return true;
}
if (section->output_section != NULL)
{
if (!link_info.non_contiguous_regions)
- return;
+ return true;
/* SECTION has already been handled in a special way
(eg. LINK_ONCE): skip it. */
if (bfd_is_abs_section (section->output_section))
- return;
+ return true;
/* Already assigned to the same output section, do not process
it again, to avoid creating loops between duplicate sections
later. */
if (section->output_section == output->bfd_section)
- return;
+ return true;
if (link_info.non_contiguous_regions_warnings && output->bfd_section)
einfo (_("%P:%pS: warning: --enable-non-contiguous-regions may "
size_input_section as appropriate. */
}
+ return false;
+}
+
+/* The wild routines.
+
+ These expand statements like *(.text) and foo.o to a list of
+ explicit actions, like foo.o(.text), bar.o(.text) and
+ 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. */
+
+void
+lang_add_section (lang_statement_list_type *ptr,
+ asection *section,
+ struct wildcard_list *pattern,
+ struct flag_info *sflag_info,
+ lang_output_section_statement_type *output)
+{
+ flagword flags = section->flags;
+
+ lang_input_section_type *new_section;
+ bfd *abfd = link_info.output_bfd;
+
+ if (wont_add_section_p (section, output))
+ return;
+
+ if (sflag_info)
+ {
+ bool keep;
+
+ keep = bfd_lookup_section_flags (&link_info, sflag_info, section);
+ if (!keep)
+ return;
+ }
+
/* We don't copy the SEC_NEVER_LOAD flag from an input section
to an output section, because we want to be able to include a
SEC_NEVER_LOAD section in the middle of an otherwise loaded
link_info.output_bfd->flags |= BFD_TRADITIONAL_FORMAT;
else
link_info.output_bfd->flags &= ~BFD_TRADITIONAL_FORMAT;
+ if (config.no_section_header)
+ link_info.output_bfd->flags |= BFD_NO_SECTION_HEADER;
+ else
+ link_info.output_bfd->flags &= ~BFD_NO_SECTION_HEADER;
break;
case lang_target_statement_enum:
#endif
static void
-open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
+open_input_bfds (lang_statement_union_type *s,
+ lang_output_section_statement_type *os,
+ enum open_bfd_mode mode)
{
for (; s != NULL; s = s->header.next)
{
switch (s->header.type)
{
case lang_constructors_statement_enum:
- open_input_bfds (constructor_list.head, mode);
+ open_input_bfds (constructor_list.head, os, mode);
break;
case lang_output_section_statement_enum:
- open_input_bfds (s->output_section_statement.children.head, mode);
+ os = &s->output_section_statement;
+ open_input_bfds (os->children.head, os, mode);
break;
case lang_wild_statement_enum:
/* Maybe we should load the file's symbols. */
&& !wildcardp (s->wild_statement.filename)
&& !archive_path (s->wild_statement.filename))
lookup_name (s->wild_statement.filename);
- open_input_bfds (s->wild_statement.children.head, mode);
+ open_input_bfds (s->wild_statement.children.head, os, mode);
break;
case lang_group_statement_enum:
{
plugin_insert_save = plugin_insert;
#endif
undefs = link_info.hash->undefs_tail;
- open_input_bfds (s->group_statement.children.head,
+ open_input_bfds (s->group_statement.children.head, os,
mode | OPEN_BFD_FORCE);
}
while (undefs != link_info.hash->undefs_tail
break;
case lang_assignment_statement_enum:
if (s->assignment_statement.exp->type.node_class != etree_assert)
- exp_fold_tree_no_dot (s->assignment_statement.exp);
+ exp_fold_tree_no_dot (s->assignment_statement.exp, os);
break;
default:
break;
}
else
{
- exp_fold_tree_no_dot (os->sectype_value);
+ exp_fold_tree_no_dot (os->sectype_value, os);
if (expld.result.valid_p)
type = expld.result.value;
else
else
link_info.output_bfd->section_last = first_sec->prev;
/* Add back. */
- last_sec->next = sec->next;
- if (sec->next != NULL)
- sec->next->prev = last_sec;
+ if (sec->owner == NULL)
+ /* SEC is the absolute section, from the
+ first dummy output section statement. Add
+ back the sections we trimmed off to the
+ start of the bfd sections. */
+ sec = NULL;
+ if (sec != NULL)
+ last_sec->next = sec->next;
+ else
+ last_sec->next = link_info.output_bfd->sections;
+ if (last_sec->next != NULL)
+ last_sec->next->prev = last_sec;
else
link_info.output_bfd->section_last = last_sec;
first_sec->prev = sec;
- sec->next = first_sec;
+ if (first_sec->prev != NULL)
+ first_sec->prev->next = first_sec;
+ else
+ link_info.output_bfd->sections = first_sec;
}
}
-
- first_os = NULL;
- last_os = NULL;
}
- ptr = insert_os_after (where);
+ lang_statement_union_type *after = (void *) where;
+ if (where == &lang_os_list.head->output_section_statement
+ && where->next == first_os)
+ {
+ /* PR30155. Handle a corner case where the statement
+ list is something like the following:
+ . LOAD t.o
+ . .data 0x0000000000000000 0x0
+ . [0x0000000000000000] b = .
+ . *(.data)
+ . .data 0x0000000000000000 0x0 t.o
+ . 0x0000000000000000 0x4 LONG 0x0
+ . INSERT BEFORE .text.start
+ . [0x0000000000000004] a = .
+ . .text.start 0x0000000000000000 0x0
+ . [0x0000000000000000] c = .
+ . OUTPUT(a.out elf64-x86-64)
+ Here we do not want to allow insert_os_after to
+ choose a point inside the list we are moving.
+ That would lose the list. Instead, let
+ insert_os_after work from the INSERT, which in this
+ particular example will result in inserting after
+ the assignment "a = .". */
+ after = *s;
+ }
+ ptr = insert_os_after (after);
/* Snip everything from the start of the list, up to and
including the insert statement we are currently processing. */
first = *start;
statement_list.tail = s;
*ptr = first;
s = start;
+ first_os = NULL;
+ last_os = NULL;
continue;
}
s = &(*s)->header.next;
if (output_section_statement->update_dot_tree != NULL)
exp_fold_tree (output_section_statement->update_dot_tree,
+ output_section_statement,
bfd_abs_section_ptr, &print_dot);
}
osec = bfd_abs_section_ptr;
if (assignment->exp->type.node_class != etree_provide)
- exp_fold_tree (tree, osec, &print_dot);
+ exp_fold_tree (tree, output_section, osec, &print_dot);
else
expld.result.valid_p = false;
obstack_free (&map_obstack, entries);
}
+/* Returns TRUE if SYM is a symbol suitable for printing
+ in a linker map as a local symbol. */
+
+static bool
+ld_is_local_symbol (asymbol * sym)
+{
+ const char * name = bfd_asymbol_name (sym);
+
+ if (name == NULL || *name == 0)
+ return false;
+
+ if (strcmp (name, "(null)") == 0)
+ return false;
+
+ /* Skip .Lxxx and such like. */
+ if (bfd_is_local_label (link_info.output_bfd, sym))
+ return false;
+
+ /* FIXME: This is intended to skip ARM mapping symbols,
+ which for some reason are not excluded by bfd_is_local_label,
+ but maybe it is wrong for other architectures.
+ It would be better to fix bfd_is_local_label. */
+ if (*name == '$')
+ return false;
+
+ /* Some local symbols, eg _GLOBAL_OFFSET_TABLE_, are present
+ in the hash table, so do not print duplicates here. */
+ struct bfd_link_hash_entry * h;
+ h = bfd_link_hash_lookup (link_info.hash, name, false /* create */,
+ false /* copy */, true /* follow */);
+ if (h == NULL)
+ return true;
+
+ /* Symbols from the plugin owned BFD will not get their own
+ iteration of this function, but can be on the link_info
+ list. So include them here. */
+ if (h->u.def.section->owner != NULL
+ && ((bfd_get_file_flags (h->u.def.section->owner) & (BFD_LINKER_CREATED | BFD_PLUGIN))
+ == (BFD_LINKER_CREATED | BFD_PLUGIN)))
+ return true;
+
+ return false;
+}
+
/* Print information about an input section to the map file. */
static void
later overlay is shorter than an earier one. */
if (addr + TO_ADDR (size) > print_dot)
print_dot = addr + TO_ADDR (size);
+
+ if (config.print_map_locals)
+ {
+ long storage_needed;
+
+ /* FIXME: It would be better to cache this table, rather
+ than recreating it for each output section. */
+ /* FIXME: This call is not working for non-ELF based targets.
+ Find out why. */
+ storage_needed = bfd_get_symtab_upper_bound (link_info.output_bfd);
+ if (storage_needed > 0)
+ {
+ asymbol ** symbol_table;
+ long number_of_symbols;
+ long j;
+
+ symbol_table = xmalloc (storage_needed);
+ number_of_symbols = bfd_canonicalize_symtab (link_info.output_bfd, symbol_table);
+
+ for (j = 0; j < number_of_symbols; j++)
+ {
+ asymbol * sym = symbol_table[j];
+ bfd_vma sym_addr = sym->value + i->output_section->vma;
+
+ if (sym->section == i->output_section
+ && (sym->flags & BSF_LOCAL) != 0
+ && sym_addr >= addr
+ && sym_addr < print_dot
+ && ld_is_local_symbol (sym))
+ {
+ print_spaces (SECTION_NAME_MAP_LENGTH);
+ minfo ("0x%V (local) %s\n", sym_addr, bfd_asymbol_name (sym));
+ }
+ }
+
+ free (symbol_table);
+ }
+ }
}
}
if (output_section_statement->subsection_alignment != NULL)
i->alignment_power
= exp_get_power (output_section_statement->subsection_alignment,
+ output_section_statement,
"subsection alignment");
if (o->alignment_power < i->alignment_power)
static bfd_vma
lang_size_sections_1
(lang_statement_union_type **prev,
- lang_output_section_statement_type *output_section_statement,
+ lang_output_section_statement_type *current_os,
fill_type *fill,
bfd_vma dot,
bool *relax,
lang_statement_union_type *s;
lang_statement_union_type *prev_s = NULL;
bool removed_prev_s = false;
+ lang_output_section_statement_type *os = current_os;
/* Size up the sections from their constituent parts. */
for (s = *prev; s != NULL; prev_s = s, s = s->header.next)
case lang_output_section_statement_enum:
{
bfd_vma newdot, after, dotdelta;
- lang_output_section_statement_type *os;
lang_memory_region_type *r;
int section_alignment = 0;
os->addr_tree = exp_intop (0);
if (os->addr_tree != NULL)
{
- exp_fold_tree (os->addr_tree, bfd_abs_section_ptr, &dot);
+ exp_fold_tree (os->addr_tree, os, bfd_abs_section_ptr, &dot);
if (expld.result.valid_p)
{
section_alignment = os->bfd_section->alignment_power;
}
else
- section_alignment = exp_get_power (os->section_alignment,
+ section_alignment = exp_get_power (os->section_alignment, os,
"section alignment");
/* Align to what the section needs. */
statement. */
if (os->lma_region != os->region)
section_alignment = exp_get_power (os->section_alignment,
+ os,
"section alignment");
if (section_alignment > 0)
lma = align_power (lma, section_alignment);
dot += dotdelta;
if (os->update_dot_tree != 0)
- exp_fold_tree (os->update_dot_tree, bfd_abs_section_ptr, &dot);
+ exp_fold_tree (os->update_dot_tree, os, bfd_abs_section_ptr, &dot);
/* Update dot in the region ?
We only do this if the section is going to be allocated,
break;
case lang_constructors_statement_enum:
- dot = lang_size_sections_1 (&constructor_list.head,
- output_section_statement,
+ dot = lang_size_sections_1 (&constructor_list.head, current_os,
fill, dot, relax, check_regions);
break;
{
unsigned int size = 0;
- s->data_statement.output_offset =
- dot - output_section_statement->bfd_section->vma;
- s->data_statement.output_section =
- output_section_statement->bfd_section;
+ s->data_statement.output_offset = dot - current_os->bfd_section->vma;
+ s->data_statement.output_section = current_os->bfd_section;
/* We might refer to provided symbols in the expression, and
need to mark them as needed. */
- exp_fold_tree (s->data_statement.exp, bfd_abs_section_ptr, &dot);
+ exp_fold_tree (s->data_statement.exp, os,
+ bfd_abs_section_ptr, &dot);
switch (s->data_statement.type)
{
if (size < TO_SIZE ((unsigned) 1))
size = TO_SIZE ((unsigned) 1);
dot += TO_ADDR (size);
- if (!(output_section_statement->bfd_section->flags
- & SEC_FIXED_SIZE))
- output_section_statement->bfd_section->size
- = TO_SIZE (dot - output_section_statement->bfd_section->vma);
+ if (!(current_os->bfd_section->flags & SEC_FIXED_SIZE))
+ current_os->bfd_section->size
+ = TO_SIZE (dot - current_os->bfd_section->vma);
}
break;
{
int size;
- s->reloc_statement.output_offset =
- dot - output_section_statement->bfd_section->vma;
- s->reloc_statement.output_section =
- output_section_statement->bfd_section;
+ s->reloc_statement.output_offset
+ = dot - current_os->bfd_section->vma;
+ s->reloc_statement.output_section
+ = current_os->bfd_section;
size = bfd_get_reloc_size (s->reloc_statement.howto);
dot += TO_ADDR (size);
- if (!(output_section_statement->bfd_section->flags
- & SEC_FIXED_SIZE))
- output_section_statement->bfd_section->size
- = TO_SIZE (dot - output_section_statement->bfd_section->vma);
+ if (!(current_os->bfd_section->flags & SEC_FIXED_SIZE))
+ current_os->bfd_section->size
+ = TO_SIZE (dot - current_os->bfd_section->vma);
}
break;
case lang_wild_statement_enum:
dot = lang_size_sections_1 (&s->wild_statement.children.head,
- output_section_statement,
- fill, dot, relax, check_regions);
+ current_os, fill, dot, relax,
+ check_regions);
break;
case lang_object_symbols_statement_enum:
- link_info.create_object_symbols_section
- = output_section_statement->bfd_section;
- output_section_statement->bfd_section->flags |= SEC_KEEP;
+ link_info.create_object_symbols_section = current_os->bfd_section;
+ current_os->bfd_section->flags |= SEC_KEEP;
break;
case lang_output_statement_enum:
if (again)
*relax = true;
}
- dot = size_input_section (prev, output_section_statement,
- fill, &removed, dot);
+ dot = size_input_section (prev, current_os, fill, &removed, dot);
}
break;
break;
case lang_fill_statement_enum:
- s->fill_statement.output_section =
- output_section_statement->bfd_section;
+ s->fill_statement.output_section = current_os->bfd_section;
fill = s->fill_statement.fill;
break;
expld.dataseg.relro = exp_seg_relro_none;
- exp_fold_tree (tree,
- output_section_statement->bfd_section,
- &newdot);
+ exp_fold_tree (tree, os, current_os->bfd_section, &newdot);
ldlang_check_relro_region (s);
|| tree->type.node_class == etree_assign)
&& (tree->assign.dst [0] != '.'
|| tree->assign.dst [1] != '\0'))
- output_section_statement->update_dot = 1;
+ current_os->update_dot = 1;
- if (!output_section_statement->ignored)
+ if (!current_os->ignored)
{
- if (output_section_statement == abs_output_section)
+ if (current_os == abs_output_section)
{
/* If we don't have an output section, then just adjust
the default memory address. */
put the pad before when relaxing, in case the
assignment references dot. */
insert_pad (&s->header.next, fill, TO_SIZE (newdot - dot),
- output_section_statement->bfd_section, dot);
+ current_os->bfd_section, dot);
/* Don't neuter the pad below when relaxing. */
s = s->header.next;
should have space allocated to it, unless the
user has explicitly stated that the section
should not be allocated. */
- if (output_section_statement->sectype != noalloc_section
- && (output_section_statement->sectype != noload_section
+ if (current_os->sectype != noalloc_section
+ && (current_os->sectype != noload_section
|| (bfd_get_flavour (link_info.output_bfd)
== bfd_target_elf_flavour)))
- output_section_statement->bfd_section->flags |= SEC_ALLOC;
+ current_os->bfd_section->flags |= SEC_ALLOC;
}
dot = newdot;
}
section. bfd_set_section_contents will complain even for
a pad size of zero. */
s->padding_statement.output_offset
- = dot - output_section_statement->bfd_section->vma;
+ = dot - current_os->bfd_section->vma;
break;
case lang_group_statement_enum:
dot = lang_size_sections_1 (&s->group_statement.children.head,
- output_section_statement,
- fill, dot, relax, check_regions);
+ current_os, fill, dot, relax,
+ check_regions);
break;
case lang_insert_statement_enum:
bfd_vma dot,
bool *found_end)
{
+ lang_output_section_statement_type *os = current_os;
+
for (; s != NULL; s = s->header.next)
{
switch (s->header.type)
case lang_output_section_statement_enum:
{
- lang_output_section_statement_type *os;
bfd_vma newdot;
- os = &(s->output_section_statement);
+ os = &s->output_section_statement;
os->after_end = *found_end;
init_opb (os->bfd_section);
newdot = dot;
newdot += TO_ADDR (os->bfd_section->size);
if (os->update_dot_tree != NULL)
- exp_fold_tree (os->update_dot_tree,
+ exp_fold_tree (os->update_dot_tree, os,
bfd_abs_section_ptr, &newdot);
}
dot = newdot;
break;
case lang_data_statement_enum:
- exp_fold_tree (s->data_statement.exp, bfd_abs_section_ptr, &dot);
+ exp_fold_tree (s->data_statement.exp, os, bfd_abs_section_ptr, &dot);
if (expld.result.valid_p)
{
s->data_statement.value = expld.result.value;
break;
case lang_reloc_statement_enum:
- exp_fold_tree (s->reloc_statement.addend_exp,
+ exp_fold_tree (s->reloc_statement.addend_exp, os,
bfd_abs_section_ptr, &dot);
if (expld.result.valid_p)
s->reloc_statement.addend_value = expld.result.value;
if (strcmp (p, "end") == 0)
*found_end = true;
}
- exp_fold_tree (s->assignment_statement.exp,
+ exp_fold_tree (s->assignment_statement.exp, os,
(current_os->bfd_section != NULL
? current_os->bfd_section : bfd_und_section_ptr),
&dot);
/* Create a bfd for each input file. */
current_target = default_target;
lang_statement_iteration++;
- open_input_bfds (statement_list.head, OPEN_BFD_NORMAL);
+ open_input_bfds (statement_list.head, NULL, OPEN_BFD_NORMAL);
/* Now that open_input_bfds has processed assignments and provide
statements we can give values to symbolic origin/length now. */
lang_do_memory_regions (true);
+ ldemul_before_plugin_all_symbols_read ();
+
#if BFD_SUPPORTS_PLUGINS
if (link_info.lto_plugin_active)
{
lang_statement_list_type added;
lang_statement_list_type files, inputfiles;
- ldemul_before_plugin_all_symbols_read ();
-
/* Now all files are read, let the plugin(s) decide if there
are any more to be added to the link before we call the
emulation's after_open hook. We create a private list of
link_info.lto_all_symbols_read = true;
/* Open any newly added files, updating the file chains. */
plugin_undefs = link_info.hash->undefs_tail;
- open_input_bfds (*added.tail, OPEN_BFD_NORMAL);
+ lang_output_section_statement_type *last_os = NULL;
+ if (lang_os_list.head != NULL)
+ last_os = ((lang_output_section_statement_type *)
+ ((char *) lang_os_list.tail
+ - offsetof (lang_output_section_statement_type, next)));
+ open_input_bfds (*added.tail, last_os, OPEN_BFD_NORMAL);
if (plugin_undefs == link_info.hash->undefs_tail)
plugin_undefs = NULL;
/* Restore the global list pointer now they have all been added. */
/* Rescan archives in case new undefined symbols have appeared. */
files = file_chain;
lang_statement_iteration++;
- open_input_bfds (statement_list.head, OPEN_BFD_RESCAN);
+ open_input_bfds (statement_list.head, NULL, OPEN_BFD_RESCAN);
lang_list_remove_tail (&file_chain, &files);
while (files.head != NULL)
{
}
#endif /* BFD_SUPPORTS_PLUGINS */
- /* Make sure that nobody has tried to add a symbol to this list
- before now. */
- ASSERT (link_info.gc_sym_list == NULL);
+ struct bfd_sym_chain **sym = &link_info.gc_sym_list;
+ while (*sym)
+ sym = &(*sym)->next;
- link_info.gc_sym_list = &entry_symbol;
+ *sym = &entry_symbol;
if (entry_symbol.name == NULL)
{
- link_info.gc_sym_list = ldlang_undef_chain_list_head;
+ *sym = ldlang_undef_chain_list_head;
- /* entry_symbol is normally initialied by a ENTRY definition in the
+ /* entry_symbol is normally initialised by an 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().
lang_end ();
}
+void
+lang_add_version_string (void)
+{
+ if (! enable_linker_version)
+ return;
+
+ const char * str = "GNU ld ";
+ int len = strlen (str);
+ int i;
+
+ for (i = 0 ; i < len ; i++)
+ lang_add_data (BYTE, exp_intop (str[i]));
+
+ str = BFD_VERSION_STRING;
+ len = strlen (str);
+
+ for (i = 0 ; i < len ; i++)
+ lang_add_data (BYTE, exp_intop (str[i]));
+
+ lang_add_data (BYTE, exp_intop ('\0'));
+}
+
/* EXPORTED TO YACC */
void
new_stmt->type = type;
}
+void
+lang_add_string (const char *s)
+{
+ bfd_vma len = strlen (s);
+ bfd_vma i;
+ bool escape = false;
+
+ /* Add byte expressions until end of string. */
+ for (i = 0 ; i < len; i++)
+ {
+ char c = *s++;
+
+ if (escape)
+ {
+ switch (c)
+ {
+ default:
+ /* Ignore the escape. */
+ break;
+
+ case 'n': c = '\n'; break;
+ case 'r': c = '\r'; break;
+ case 't': c = '\t'; break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ /* We have an octal number. */
+ {
+ unsigned int value = c - '0';
+
+ c = *s;
+ if ((c >= '0') && (c <= '7'))
+ {
+ value <<= 3;
+ value += (c - '0');
+ i++;
+ s++;
+
+ c = *s;
+ if ((c >= '0') && (c <= '7'))
+ {
+ value <<= 3;
+ value += (c - '0');
+ i++;
+ s++;
+ }
+ }
+
+ if (value > 0xff)
+ {
+ /* octal: \777 is treated as '\077' + '7' */
+ value >>= 3;
+ i--;
+ s--;
+ }
+
+ c = value;
+ }
+ break;
+ }
+
+ lang_add_data (BYTE, exp_intop (c));
+ escape = false;
+ }
+ else
+ {
+ if (c == '\\')
+ escape = true;
+ else
+ lang_add_data (BYTE, exp_intop (c));
+ }
+ }
+
+ /* Remeber to terminate the string. */
+ lang_add_data (BYTE, exp_intop (0));
+}
+
/* Create a new reloc statement. RELOC is the BFD relocation type to
generate. HOWTO is the corresponding howto structure (we could
look this up, but the caller has already done so). SECTION is the
n = stat_alloc (sizeof (struct lang_phdr));
n->next = NULL;
n->name = name;
- n->type = exp_get_vma (type, 0, "program header type");
+ n->type = exp_get_vma (type, NULL, 0, "program header type");
n->filehdr = filehdr;
n->phdrs = phdrs;
n->at = at;
if (l->flags == NULL)
flags = 0;
else
- flags = exp_get_vma (l->flags, 0, "phdr flags");
+ flags = exp_get_vma (l->flags, NULL, 0, "phdr flags");
if (l->at == NULL)
at = 0;
else
- at = exp_get_vma (l->at, 0, "phdr load address");
+ at = exp_get_vma (l->at, NULL, 0, "phdr load address");
if (!bfd_record_phdr (link_info.output_bfd, l->type,
l->flags != NULL, flags, l->at != NULL,
{
if (r->origin_exp)
{
- exp_fold_tree_no_dot (r->origin_exp);
+ exp_fold_tree_no_dot (r->origin_exp, NULL);
if (update_regions_p)
{
if (expld.result.valid_p)
}
if (r->length_exp)
{
- exp_fold_tree_no_dot (r->length_exp);
+ exp_fold_tree_no_dot (r->length_exp, NULL);
if (update_regions_p)
{
if (expld.result.valid_p)