/* 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.
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;
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)
{
{
/* 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);
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
{
an explicit assignment to the section LMA (ie.
os->load_base set) because backwards moves normally
create overlapping LMAs. */
- if (dot < last->vma)
+ if (dot < last->vma
+ && os->bfd_section->size != 0)
{
einfo (_("%P: warning: dot moved backwards before `%s'\n"),
os->name);
|| (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0)
&& (os->bfd_section->flags & SEC_ALLOC) != 0
&& (os->bfd_section->size != 0
- || os->bfd_section->vma != os->bfd_section->lma
- || r->last_os != NULL)
+ || (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;
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);
+ /* 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)
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);
+}