/* Linker command language support.
Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004, 2005, 2006
+ 2001, 2002, 2003, 2004, 2005, 2006, 2007
Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
#define offsetof(TYPE, MEMBER) ((size_t) & (((TYPE*) 0)->MEMBER))
#endif
-/* Binary search tree structure to
- efficiently sort sections by name. */
-typedef struct lang_section_bst
-{
- asection *section;
- struct lang_section_bst *left;
- struct lang_section_bst *right;
-} lang_section_bst_type;
-
/* Locals variables. */
static struct obstack stat_obstack;
static struct obstack map_obstack;
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 bfd_boolean load_symbols (lang_input_statement_type *,
- lang_statement_list_type *);
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 lang_one_common (struct bfd_link_hash_entry *, void *);
static void lang_record_phdrs (void);
static void lang_do_version_exports_section (void);
+static void lang_finalize_version_expr_head
+ (struct bfd_elf_version_expr_head *);
/* Exported variables. */
lang_output_section_statement_type *abs_output_section;
{
lang_section_bst_type **tree;
- tree = (lang_section_bst_type **) &wild->handler_data[1];
+ tree = &wild->tree;
if (!wild->filenames_sorted
&& (sec == NULL || sec->spec.sorted == none))
{
ptr->handler_data[1] = NULL;
ptr->handler_data[2] = NULL;
ptr->handler_data[3] = NULL;
+ ptr->tree = NULL;
/* Count how many wildcard_specs there are, and how many of those
actually use wildcards in the name. Also, bail out if any of the
{
LANG_FOR_EACH_INPUT_STATEMENT (f)
{
- if (fnmatch (file_spec, f->filename, FNM_FILE_NAME) == 0)
+ if (fnmatch (file_spec, f->filename, 0) == 0)
walk_wild_file (s, f, callback, data);
}
}
continue;
for (s = file->the_bfd->sections; s != NULL; s = s->next)
- if (s->output_section == NULL
- || s->output_section->owner != output_bfd)
+ if ((s->output_section == NULL
+ || s->output_section->owner != output_bfd)
+ && (s->flags & (SEC_LINKER_CREATED | SEC_KEEP)) == 0)
{
if (! dis_header_printed)
{
fprintf (config.map_file, _("\nLinker script and memory map\n\n"));
- if (! command_line.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)
s->bfd_section->output_section = s->bfd_section;
s->bfd_section->output_offset = 0;
- if (!command_line.reduce_memory_overheads)
+ if (!link_info.reduce_memory_overheads)
{
fat_section_userdata_type *new
= stat_alloc (sizeof (fat_section_userdata_type));
}
if (!(abfd->flags & DYNAMIC))
- bfd_section_already_linked (abfd, sec);
+ bfd_section_already_linked (abfd, sec, &link_info);
}
\f
/* The wild routines.
/* Get the symbols for an input file. */
-static bfd_boolean
+bfd_boolean
load_symbols (lang_input_statement_type *entry,
lang_statement_list_type *place)
{
walk_wild (s, output_section_callback_fast, output);
- tree = (lang_section_bst_type *) s->handler_data[1];
+ tree = s->tree;
if (tree)
- output_section_callback_tree_to_list (s, tree, output);
- s->handler_data[1] = NULL;
+ {
+ output_section_callback_tree_to_list (s, tree, output);
+ s->tree = NULL;
+ }
}
else
walk_wild (s, output_section_callback, output);
case lang_wild_statement_enum:
sec = s->wild_statement.section_list;
- if (sec != NULL)
+ for (sec = s->wild_statement.section_list; sec != NULL;
+ sec = sec->next)
{
switch (sec->spec.sorted)
{
{
/* We don't set bfd_section to NULL since bfd_section of the
removed output section statement may still be used. */
- os->ignored = TRUE;
+ if (!os->section_relative_symbol)
+ os->ignored = TRUE;
output_section->flags |= SEC_EXCLUDE;
bfd_section_list_remove (output_bfd, output_section);
output_bfd->section_count--;
minfo ("0x%V %W", section->vma, section->size);
- if (output_section_statement->load_base != NULL)
- {
- bfd_vma addr;
-
- addr = exp_get_abs_int (output_section_statement->load_base, 0,
- "load base");
- minfo (_(" load address 0x%V"), addr);
- }
+ if (section->vma != section->lma)
+ minfo (_(" load address 0x%V"), section->lma);
}
print_nl ();
if (i->output_section != NULL && i->output_section->owner == output_bfd)
{
- if (command_line.reduce_memory_overheads)
+ if (link_info.reduce_memory_overheads)
bfd_link_hash_traverse (link_info.hash, print_one_symbol, i);
else
print_all_symbols (i);
{
bfd_vma newdot, after;
lang_output_section_statement_type *os;
+ lang_memory_region_type *r;
os = &s->output_section_statement;
if (os->addr_tree != NULL)
{
- os->processed = FALSE;
+ os->processed_vma = FALSE;
exp_fold_tree (os->addr_tree, bfd_abs_section_ptr, &dot);
if (!expld.result.valid_p
lang_size_sections_1 (os->children.head, os, &os->children.head,
os->fill, newdot, relax, check_regions);
- os->processed = TRUE;
+ os->processed_vma = TRUE;
if (bfd_is_abs_section (os->bfd_section) || os->ignored)
+ /* Except for some special linker created sections,
+ no output section should change from zero size
+ after strip_excluded_output_sections. A non-zero
+ size on an ignored section indicates that some
+ input section was not sized early enough. */
+ ASSERT (os->bfd_section->size == 0);
+ else
{
- ASSERT (os->bfd_section->size == 0);
- break;
+ dot = os->bfd_section->vma;
+
+ /* Put the section within the requested block size, or
+ align at the block boundary. */
+ after = ((dot
+ + TO_ADDR (os->bfd_section->size)
+ + os->block_value - 1)
+ & - (bfd_vma) os->block_value);
+
+ os->bfd_section->size = TO_SIZE (after - os->bfd_section->vma);
}
- dot = os->bfd_section->vma;
+ /* Set section lma. */
+ r = os->region;
+ if (r == NULL)
+ r = lang_memory_region_lookup (DEFAULT_MEMORY_REGION, FALSE);
- /* Put the section within the requested block size, or
- align at the block boundary. */
- after = ((dot
- + TO_ADDR (os->bfd_section->size)
- + os->block_value - 1)
- & - (bfd_vma) os->block_value);
+ if (os->load_base)
+ {
+ bfd_vma lma = exp_get_abs_int (os->load_base, 0, "load base");
+ os->bfd_section->lma = lma;
+ }
+ else if (os->region != NULL
+ && os->lma_region != NULL
+ && os->lma_region != os->region)
+ {
+ bfd_vma lma = os->lma_region->current;
+
+ if (os->section_alignment != -1)
+ lma = align_power (lma, os->section_alignment);
+ os->bfd_section->lma = lma;
+ }
+ else if (r->last_os != NULL
+ && (os->bfd_section->flags & SEC_ALLOC) != 0)
+ {
+ bfd_vma lma;
+ asection *last;
- os->bfd_section->size = TO_SIZE (after - os->bfd_section->vma);
+ last = r->last_os->output_section_statement.bfd_section;
+
+ /* A backwards move of dot should be accompanied by
+ an explicit assignment to the section LMA (ie.
+ os->load_base set) because backwards moves normally
+ create overlapping LMAs. */
+ if (dot < last->vma
+ && os->bfd_section->size != 0)
+ {
+ einfo (_("%P: warning: dot moved backwards before `%s'\n"),
+ os->name);
+
+ /* If dot moved backwards then leave lma equal to
+ vma. This is the old default lma, which might
+ just happen to work when the backwards move is
+ sufficiently large. Nag anyway, so people fix
+ their linker scripts. */
+ }
+ else
+ {
+ /* If the current vma overlaps the previous section,
+ then set the current lma to that at the end of
+ the previous section. The previous section was
+ probably an overlay. */
+ if ((dot >= last->vma
+ && dot < last->vma + last->size)
+ || (last->vma >= dot
+ && last->vma < dot + os->bfd_section->size))
+ lma = last->lma + last->size;
+
+ /* Otherwise, keep the same lma to vma relationship
+ as the previous section. */
+ else
+ lma = dot + last->lma - last->vma;
+
+ if (os->section_alignment != -1)
+ lma = align_power (lma, os->section_alignment);
+ os->bfd_section->lma = lma;
+ }
+ }
+ os->processed_lma = TRUE;
+
+ if (bfd_is_abs_section (os->bfd_section) || os->ignored)
+ break;
+
+ /* Keep track of normal sections using the default
+ lma region. We use this to set the lma for
+ following sections. Overlays or other linker
+ script assignment to lma might mean that the
+ default lma == vma is incorrect.
+ 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
+ && (os->bfd_section->size != 0
+ || (r->last_os == NULL
+ && os->bfd_section->vma != os->bfd_section->lma)
+ || (r->last_os != NULL
+ && dot >= (r->last_os->output_section_statement
+ .bfd_section->vma)))
+ && os->lma_region == NULL
+ && !link_info.relocatable)
+ r->last_os = s;
/* .tbss sections effectively have zero size. */
if ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0
if (os->lma_region != NULL && os->lma_region != os->region)
{
- /* Set load_base, which will be handled later. */
- os->load_base = exp_intop (os->lma_region->current);
- os->lma_region->current +=
- TO_ADDR (os->bfd_section->size);
+ os->lma_region->current
+ = os->bfd_section->lma + TO_ADDR (os->bfd_section->size);
if (check_regions)
os_region_check (os, os->lma_region, NULL,
- os->lma_region->current);
+ os->bfd_section->lma);
}
}
}
case lang_assignment_statement_enum:
{
bfd_vma newdot = dot;
+ etree_type *tree = s->assignment_statement.exp;
- exp_fold_tree (s->assignment_statement.exp,
+ exp_fold_tree (tree,
output_section_statement->bfd_section,
&newdot);
- if (newdot != dot && !output_section_statement->ignored)
+ /* This symbol is 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;
+
+ if (!output_section_statement->ignored)
{
if (output_section_statement == abs_output_section)
{
lang_memory_region_lookup (DEFAULT_MEMORY_REGION,
FALSE)->current = newdot;
}
- else
+ else if (newdot != dot)
{
/* Insert a pad after this statement. We can't
put the pad before when relaxing, in case the
os = &(s->output_section_statement);
if (os->bfd_section != NULL && !os->ignored)
{
- lang_memory_region_type *r;
-
dot = os->bfd_section->vma;
- r = os->region;
- if (r == NULL)
- r = lang_memory_region_lookup (DEFAULT_MEMORY_REGION, FALSE);
-
- if (os->load_base)
- os->bfd_section->lma
- = exp_get_abs_int (os->load_base, 0, "load base");
- else if (r->last_os != NULL)
- {
- asection *last;
- bfd_vma lma;
- last = r->last_os->output_section_statement.bfd_section;
-
- /* If the current vma overlaps the previous section,
- then set the current lma to that at the end of
- the previous section. The previous section was
- probably an overlay. */
- if ((dot >= last->vma
- && dot < last->vma + last->size)
- || (last->vma >= dot
- && last->vma < dot + os->bfd_section->size))
- lma = last->lma + last->size;
-
- /* Otherwise, keep the same lma to vma relationship
- as the previous section. */
- else
- lma = dot + last->lma - last->vma;
-
- if (os->section_alignment != -1)
- lma = align_power (lma, os->section_alignment);
- os->bfd_section->lma = lma;
- }
-
- lang_do_assignments_1 (os->children.head,
- os, os->fill, dot);
+ lang_do_assignments_1 (os->children.head, os, os->fill, dot);
/* .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);
-
- /* Keep track of normal sections using the default
- lma region. We use this to set the lma for
- following sections. Overlays or other linker
- script assignment to lma might mean that the
- default lma == vma is incorrect. */
- if (!link_info.relocatable
- && os->lma_region == NULL)
- r->last_os = s;
- }
+ dot += TO_ADDR (os->bfd_section->size);
}
}
break;
for (os = &lang_output_section_statement.head->output_section_statement;
os != NULL;
os = os->next)
- os->processed = FALSE;
+ {
+ os->processed_vma = FALSE;
+ os->processed_lma = FALSE;
+ }
for (o = output_bfd->sections; o != NULL; o = o->next)
{
void
lang_process (void)
{
+ /* Finalize dynamic list. */
+ if (link_info.dynamic_list)
+ lang_finalize_version_expr_head (&link_info.dynamic_list->head);
+
current_target = default_target;
/* Open the output file. */
/* Do not free the contents, as we used them creating the regex. */
/* Do not include this section in the link. */
- sec->flags |= SEC_EXCLUDE;
+ sec->flags |= SEC_EXCLUDE | SEC_KEEP;
}
lreg = lang_new_vers_pattern (NULL, "*", NULL, FALSE);
ent->next = unique_section_list;
unique_section_list = ent;
}
+
+/* Append the list of dynamic symbols to the existing one. */
+
+void
+lang_append_dynamic_list (struct bfd_elf_version_expr *dynamic)
+{
+ if (link_info.dynamic_list)
+ {
+ struct bfd_elf_version_expr *tail;
+ for (tail = dynamic; tail->next != NULL; tail = tail->next)
+ ;
+ tail->next = link_info.dynamic_list->head.list;
+ link_info.dynamic_list->head.list = dynamic;
+ }
+ else
+ {
+ struct bfd_elf_dynamic_list *d;
+
+ d = xcalloc (1, sizeof *d);
+ d->head.list = dynamic;
+ d->match = lang_vers_match;
+ link_info.dynamic_list = d;
+ }
+}
+
+/* Append the list of C++ typeinfo dynamic symbols to the existing
+ one. */
+
+void
+lang_append_dynamic_list_cpp_typeinfo (void)
+{
+ const char * symbols [] =
+ {
+ "typeinfo name for*",
+ "typeinfo for*"
+ };
+ struct bfd_elf_version_expr *dynamic = NULL;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE (symbols); i++)
+ dynamic = lang_new_vers_pattern (dynamic, symbols [i], "C++",
+ FALSE);
+
+ lang_append_dynamic_list (dynamic);
+}
+
+/* Append the list of C++ operator new and delete dynamic symbols to the
+ existing one. */
+
+void
+lang_append_dynamic_list_cpp_new (void)
+{
+ const char * symbols [] =
+ {
+ "operator new*",
+ "operator delete*"
+ };
+ struct bfd_elf_version_expr *dynamic = NULL;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE (symbols); i++)
+ dynamic = lang_new_vers_pattern (dynamic, symbols [i], "C++",
+ FALSE);
+
+ lang_append_dynamic_list (dynamic);
+}