/* 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
+ 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
Free Software Foundation, Inc.
This file is part of the GNU Binutils.
#include "fnmatch.h"
#include "demangle.h"
#include "hashtab.h"
+#include "libbfd.h"
+#ifdef ENABLE_PLUGINS
+#include "plugin.h"
+#endif /* ENABLE_PLUGINS */
#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) & (((TYPE*) 0)->MEMBER))
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
-static const char *startup_file;
static const char *entry_symbol_default = "start";
static bfd_boolean placed_commons = FALSE;
static bfd_boolean stripped_excluded_sections = FALSE;
struct bfd_sym_chain entry_symbol = { NULL, NULL };
const char *entry_section = ".text";
bfd_boolean entry_from_cmdline;
+bfd_boolean undef_from_cmdline;
bfd_boolean lang_has_input_file = FALSE;
bfd_boolean had_output_filename = FALSE;
bfd_boolean lang_float_flag = FALSE;
return TRUE;
}
+/* Return the numerical value of the init_priority attribute from
+ section name NAME. */
+
+static unsigned long
+get_init_priority (const char *name)
+{
+ char *end;
+ unsigned long init_priority;
+
+ /* GCC uses the following section names for the init_priority
+ attribute with numerical values 101 and 65535 inclusive. A
+ lower value means a higher priority.
+
+ 1: .init_array.NNNN/.fini_array.NNNN: Where NNNN is the
+ 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
+ decimal numerical value of the init_priority attribute.
+ The order of execution in .ctors is backward and .dtors
+ is forward.
+ */
+ if (strncmp (name, ".init_array.", 12) == 0
+ || strncmp (name, ".fini_array.", 12) == 0)
+ {
+ init_priority = strtoul (name + 12, &end, 10);
+ return *end ? 0 : init_priority;
+ }
+ else if (strncmp (name, ".ctors.", 7) == 0
+ || strncmp (name, ".dtors.", 7) == 0)
+ {
+ init_priority = strtoul (name + 7, &end, 10);
+ return *end ? 0 : 65535 - init_priority;
+ }
+
+ return 0;
+}
+
/* Compare sections ASEC and BSEC according to SORT. */
static int
compare_section (sort_type sort, asection *asec, asection *bsec)
{
int ret;
+ unsigned long ainit_priority, binit_priority;
switch (sort)
{
default:
abort ();
+ case by_init_priority:
+ ainit_priority
+ = get_init_priority (bfd_get_section_name (asec->owner, asec));
+ binit_priority
+ = get_init_priority (bfd_get_section_name (bsec->owner, bsec));
+ if (ainit_priority == 0 || binit_priority == 0)
+ goto sort_by_name;
+ ret = ainit_priority - binit_priority;
+ if (ret)
+ break;
+ else
+ goto sort_by_name;
+
case by_alignment_name:
ret = (bfd_section_alignment (bsec->owner, bsec)
- bfd_section_alignment (asec->owner, asec));
/* Fall through. */
case by_name:
+sort_by_name:
ret = strcmp (bfd_get_section_name (asec->owner, asec),
bfd_get_section_name (bsec->owner, bsec));
break;
{
case lang_input_file_is_symbols_only_enum:
p->filename = name;
- p->is_archive = FALSE;
+ p->maybe_archive = FALSE;
p->real = TRUE;
p->local_sym_name = name;
p->just_syms_flag = TRUE;
break;
case lang_input_file_is_fake_enum:
p->filename = name;
- p->is_archive = FALSE;
+ p->maybe_archive = FALSE;
p->real = FALSE;
p->local_sym_name = name;
p->just_syms_flag = FALSE;
p->search_dirs_flag = FALSE;
break;
case lang_input_file_is_l_enum:
- p->is_archive = TRUE;
+ p->maybe_archive = TRUE;
p->filename = name;
p->real = TRUE;
p->local_sym_name = concat ("-l", name, (const char *) NULL);
break;
case lang_input_file_is_marker_enum:
p->filename = name;
- p->is_archive = FALSE;
+ p->maybe_archive = FALSE;
p->real = FALSE;
p->local_sym_name = name;
p->just_syms_flag = FALSE;
case lang_input_file_is_search_file_enum:
p->sysrooted = ldlang_sysrooted_script;
p->filename = name;
- p->is_archive = FALSE;
+ p->maybe_archive = FALSE;
p->real = TRUE;
p->local_sym_name = name;
p->just_syms_flag = FALSE;
break;
case lang_input_file_is_file_enum:
p->filename = name;
- p->is_archive = FALSE;
+ p->maybe_archive = FALSE;
p->real = TRUE;
p->local_sym_name = name;
p->just_syms_flag = FALSE;
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_assop ('=', ".", e_align));
+ lang_add_assignment (exp_assign (".", e_align));
lang_add_assignment (exp_provide (symname,
exp_unop (ABSOLUTE,
exp_nameop (NAME, ".")),
sort_def_symbol (struct bfd_link_hash_entry *hash_entry,
void *info ATTRIBUTE_UNUSED)
{
+ if (hash_entry->type == bfd_link_hash_warning)
+ hash_entry = (struct bfd_link_hash_entry *) hash_entry->u.i.link;
+
if (hash_entry->type == bfd_link_hash_defined
|| hash_entry->type == bfd_link_hash_defweak)
{
case noload_section:
flags &= ~SEC_LOAD;
flags |= SEC_NEVER_LOAD;
- if (((bfd_get_flavour (section->owner)
- == bfd_target_ecoff_flavour)
- || (bfd_get_flavour (section->owner)
- == bfd_target_coff_flavour)))
- {
- if ((flags & (SEC_COFF_SHARED_LIBRARY | SEC_DEBUGGING)) == 0)
- flags &= ~SEC_HAS_CONTENTS;
- }
- else
+ /* Unfortunately GNU ld has managed to evolve two different
+ meanings to NOLOAD in scripts. ELF gets a .bss style noload,
+ alloc, no contents section. All others get a noload, noalloc
+ section. */
+ if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour)
flags &= ~SEC_HAS_CONTENTS;
+ else
+ flags &= ~SEC_ALLOC;
break;
}
for (;;)
{
+ bfd *subsbfd;
member = bfd_openr_next_archived_file (entry->the_bfd, member);
if (member == NULL)
loaded = FALSE;
}
- if (! ((*link_info.callbacks->add_archive_element)
- (&link_info, member, "--whole-archive")))
+ subsbfd = member;
+ if (!(*link_info.callbacks
+ ->add_archive_element) (&link_info, member,
+ "--whole-archive", &subsbfd))
abort ();
- if (! bfd_link_add_symbols (member, &link_info))
+ /* Potentially, the add_archive_element hook may have set a
+ substitute BFD for us. */
+ if (!bfd_link_add_symbols (subsbfd, &link_info))
{
einfo (_("%F%B: could not read symbols: %E\n"), member);
loaded = FALSE;
}
}
break;
+ case lang_assignment_statement_enum:
+ if (s->assignment_statement.exp->assign.hidden)
+ /* This is from a --defsym on the command line. */
+ exp_fold_tree_no_dot (s->assignment_statement.exp);
+ break;
default:
break;
}
#define ldlang_undef_chain_list_head entry_symbol.next
void
-ldlang_add_undef (const char *const name)
+ldlang_add_undef (const char *const name, bfd_boolean cmdline)
{
- ldlang_undef_chain_list_type *new_undef = (ldlang_undef_chain_list_type *)
- stat_alloc (sizeof (ldlang_undef_chain_list_type));
+ ldlang_undef_chain_list_type *new_undef;
+ undef_from_cmdline = undef_from_cmdline || cmdline;
+ new_undef = (ldlang_undef_chain_list_type *) stat_alloc (sizeof (*new_undef));
new_undef->next = ldlang_undef_chain_list_head;
ldlang_undef_chain_list_head = new_undef;
flags = SEC_HAS_CONTENTS;
break;
case noload_section:
- flags = SEC_NEVER_LOAD;
+ if (bfd_get_flavour (link_info.output_bfd)
+ == bfd_target_elf_flavour)
+ flags = SEC_NEVER_LOAD | SEC_ALLOC;
+ else
+ flags = SEC_NEVER_LOAD | SEC_HAS_CONTENTS;
break;
}
if (os->bfd_section == NULL)
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);
+ 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);
+ return (scan_for_self_assignment (dst, rhs->trinary.lhs)
+ || scan_for_self_assignment (dst, rhs->trinary.rhs));
case etree_assign:
case etree_provided:
is_dot = (dst[0] == '.' && dst[1] == 0);
tree = assignment->exp->assign.src;
- computation_is_valid = is_dot || (scan_for_self_assignment (dst, tree) == FALSE);
+ computation_is_valid = is_dot || !scan_for_self_assignment (dst, tree);
}
osec = output_section->bfd_section;
return 0;
}
-/* On ELF, a debugging section must never set SEC_NEVER_LOAD, as no output
- would be written for it. So the combination of debugging and never-load
- is something which can only happen for pe-coff and must not be ignored. */
#define IGNORE_SECTION(s) \
- ((s->flags & (SEC_NEVER_LOAD | SEC_DEBUGGING)) == SEC_NEVER_LOAD \
- || (s->flags & SEC_ALLOC) == 0 \
- || ((s->flags & SEC_THREAD_LOCAL) != 0 \
+ ((s->flags & SEC_ALLOC) == 0 \
+ || ((s->flags & SEC_THREAD_LOCAL) != 0 \
&& (s->flags & SEC_LOAD) == 0))
/* Check to see if any allocated sections overlap with other allocated
for (s = link_info.output_bfd->sections; s != NULL; s = s->next)
{
/* Only consider loadable sections with real contents. */
- if ((s->flags & (SEC_NEVER_LOAD | SEC_DEBUGGING)) == SEC_NEVER_LOAD
- || !(s->flags & SEC_LOAD)
+ if (!(s->flags & SEC_LOAD)
|| !(s->flags & SEC_ALLOC)
|| s->size == 0)
continue;
bfd_vma newdot, after;
lang_output_section_statement_type *os;
lang_memory_region_type *r;
+ int section_alignment = 0;
os = &s->output_section_statement;
if (os->constraint == -1)
}
else
{
- int align;
-
if (os->addr_tree == NULL)
{
/* No address specified for this section, get one
}
newdot = os->region->current;
- align = os->bfd_section->alignment_power;
+ section_alignment = os->bfd_section->alignment_power;
}
else
- align = os->section_alignment;
+ section_alignment = os->section_alignment;
/* Align to what the section needs. */
- if (align > 0)
+ if (section_alignment > 0)
{
bfd_vma savedot = newdot;
- newdot = align_power (newdot, align);
+ newdot = align_power (newdot, section_alignment);
if (newdot != savedot
&& (config.warn_section_align
{
bfd_vma lma = os->lma_region->current;
- if (os->section_alignment != -1)
- lma = align_power (lma, os->section_alignment);
+ if (section_alignment > 0)
+ lma = align_power (lma, section_alignment);
os->bfd_section->lma = lma;
}
else if (r->last_os != NULL
else
lma = dot + last->lma - last->vma;
- if (os->section_alignment != -1)
- lma = align_power (lma, os->section_alignment);
+ if (section_alignment > 0)
+ lma = align_power (lma, section_alignment);
os->bfd_section->lma = lma;
}
}
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)
+ if (output_section_statement->sectype != noalloc_section
+ && (output_section_statement->sectype != noload_section
+ || (bfd_get_flavour (link_info.output_bfd)
+ == bfd_target_elf_flavour)))
output_section_statement->bfd_section->flags |= SEC_ALLOC;
}
dot = newdot;
lang_reset_memory_regions ();
one_lang_size_sections_pass (relax, check_regions);
}
+ else
+ expld.dataseg.phase = exp_dataseg_done;
}
-
- expld.phase = lang_final_phase_enum;
+ else
+ expld.dataseg.phase = exp_dataseg_done;
}
/* Worker function for lang_do_assignments. Recursiveness goes here. */
/* Force the user to specify a root when generating a relocatable with
--gc-sections. */
if (link_info.gc_sections && link_info.relocatable
- && (entry_symbol.name == NULL
- && ldlang_undef_chain_list_head == NULL))
+ && !(entry_from_cmdline || undef_from_cmdline))
einfo (_("%P%F: gc-sections requires either an entry or "
"an undefined symbol\n"));
os = lang_output_section_statement_lookup (name,
constraint,
TRUE);
+ if (os->addr_tree == NULL
+ && (link_info.relocatable
+ || (s->flags & (SEC_LOAD | SEC_ALLOC)) == 0))
+ os->addr_tree = exp_intop (0);
lang_add_section (&os->children, s, os);
}
}
current_target = default_target;
open_input_bfds (statement_list.head, FALSE);
+#ifdef ENABLE_PLUGINS
+ {
+ union lang_statement_union **listend;
+ /* 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. */
+ listend = statement_list.tail;
+ ASSERT (!*listend);
+ if (plugin_call_all_symbols_read ())
+ einfo (_("%P%F: %s: plugin reported error after all symbols read\n"),
+ plugin_error_plugin ());
+ /* If any new files were added, they will be on the end of the
+ statement list, and we can open them now by getting open_input_bfds
+ to carry on from where it ended last time. */
+ if (*listend)
+ open_input_bfds (*listend, FALSE);
+ }
+#endif /* ENABLE_PLUGINS */
+
link_info.gc_sym_list = &entry_symbol;
if (entry_symbol.name == NULL)
link_info.gc_sym_list = ldlang_undef_chain_list_head;
/* Run through the contours of the script and attach input sections
to the correct output sections. */
+ lang_statement_iteration++;
map_input_to_output_sections (statement_list.head, NULL, NULL);
process_insert_statements ();
/* Do all the assignments, now that we know the final resting places
of all the symbols. */
-
+ expld.phase = lang_final_phase_enum;
lang_do_assignments ();
ldemul_finish ();
void
lang_startup (const char *name)
{
- if (startup_file != NULL)
+ if (first_file->filename != NULL)
{
einfo (_("%P%F: multiple STARTUP files\n"));
}
first_file->filename = name;
first_file->local_sym_name = name;
first_file->real = TRUE;
-
- startup_file = name;
}
void
overlay region. */
if (overlay_list != NULL)
overlay_list->os->update_dot_tree
- = exp_assop ('=', ".", exp_binop ('+', overlay_vma, overlay_max));
+ = exp_assign (".", exp_binop ('+', overlay_vma, overlay_max));
l = overlay_list;
while (l != NULL)
struct bfd_elf_version_expr *prev,
const char *sym)
{
+ const char *c_sym;
const char *cxx_sym = sym;
const char *java_sym = sym;
struct bfd_elf_version_expr *expr = NULL;
+ enum demangling_styles curr_style;
+
+ curr_style = CURRENT_DEMANGLING_STYLE;
+ cplus_demangle_set_style (no_demangling);
+ c_sym = bfd_demangle (link_info.output_bfd, sym, DMGL_NO_OPTS);
+ if (!c_sym)
+ c_sym = sym;
+ cplus_demangle_set_style (curr_style);
if (head->mask & BFD_ELF_VERSION_CXX_TYPE)
{
- cxx_sym = cplus_demangle (sym, DMGL_PARAMS | DMGL_ANSI);
+ cxx_sym = bfd_demangle (link_info.output_bfd, sym,
+ DMGL_PARAMS | DMGL_ANSI);
if (!cxx_sym)
cxx_sym = sym;
}
if (head->mask & BFD_ELF_VERSION_JAVA_TYPE)
{
- java_sym = cplus_demangle (sym, DMGL_JAVA);
+ java_sym = bfd_demangle (link_info.output_bfd, sym, DMGL_JAVA);
if (!java_sym)
java_sym = sym;
}
case 0:
if (head->mask & BFD_ELF_VERSION_C_TYPE)
{
- e.pattern = sym;
+ e.pattern = c_sym;
expr = (struct bfd_elf_version_expr *)
htab_find ((htab_t) head->htab, &e);
- while (expr && strcmp (expr->pattern, sym) == 0)
+ while (expr && strcmp (expr->pattern, c_sym) == 0)
if (expr->mask == BFD_ELF_VERSION_C_TYPE)
goto out_ret;
else
else if (expr->mask == BFD_ELF_VERSION_CXX_TYPE)
s = cxx_sym;
else
- s = sym;
+ s = c_sym;
if (fnmatch (expr->pattern, s, 0) == 0)
break;
}
out_ret:
+ if (c_sym != sym)
+ free ((char *) c_sym);
if (cxx_sym != sym)
free ((char *) cxx_sym);
if (java_sym != sym)
lang_append_dynamic_list (dynamic);
}
+
+/* Scan a space and/or comma separated string of features. */
+
+void
+lang_ld_feature (char *str)
+{
+ char *p, *q;
+
+ p = str;
+ while (*p)
+ {
+ char sep;
+ while (*p == ',' || ISSPACE (*p))
+ ++p;
+ if (!*p)
+ break;
+ q = p + 1;
+ while (*q && *q != ',' && !ISSPACE (*q))
+ ++q;
+ sep = *q;
+ *q = 0;
+ if (strcasecmp (p, "SANE_EXPR") == 0)
+ config.sane_expr = TRUE;
+ else
+ einfo (_("%X%P: unknown feature `%s'\n"), p);
+ *q = sep;
+ p = q;
+ }
+}