/* Linker command language support.
- Copyright (C) 1991, 92, 93, 94, 95, 96, 97, 98, 99, 2000
+ Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+ 2001
Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
fill_type, bfd_vma, boolean));
static void lang_finish PARAMS ((void));
static void ignore_bfd_errors PARAMS ((const char *, ...));
+static void record_bfd_errors PARAMS ((const char *, ...));
static void lang_check PARAMS ((void));
static void lang_common PARAMS ((void));
static boolean lang_one_common PARAMS ((struct bfd_link_hash_entry *, PTR));
boolean lang_float_flag = false;
boolean delete_output_file_on_failure = false;
struct lang_nocrossrefs *nocrossref_list;
+struct unique_sections *unique_section_list;
etree_type *base; /* Relocation base - or null */
return obstack_alloc (&stat_obstack, size);
}
+boolean
+unique_section_p (secnam)
+ const char *secnam;
+{
+ struct unique_sections *unam;
+
+ for (unam = unique_section_list; unam; unam = unam->next)
+ if (wildcardp (unam->name)
+ ? fnmatch (unam->name, secnam, 0) == 0
+ : strcmp (unam->name, secnam) == 0)
+ {
+ return true;
+ }
+
+ return false;
+}
+
/* Generic traversal routines for finding matching sections. */
static void
if (file->just_syms_flag == false)
{
register asection *s;
- boolean wildcard;
+ boolean wildcard = false;
- if (section == NULL)
- wildcard = false;
- else
+ if (section != NULL)
wildcard = wildcardp (section);
for (s = file->the_bfd->sections; s != NULL; s = s->next)
{
boolean match;
+ const char *sname = bfd_get_section_name (file->the_bfd, s);
if (section == NULL)
match = true;
+ else if (wildcard)
+ match = fnmatch (section, sname, 0) == 0 ? true : false;
else
- {
- const char *name;
-
- name = bfd_get_section_name (file->the_bfd, s);
- if (wildcard)
- match = fnmatch (section, name, 0) == 0 ? true : false;
- else
- match = strcmp (section, name) == 0 ? true : false;
- }
+ match = strcmp (section, sname) == 0 ? true : false;
- if (match)
+ /* If this is a wild-card output section statement, exclude
+ sections that match UNIQUE_SECTION_LIST. */
+ if (match && (data == NULL || !unique_section_p (sname)))
(*callback) (ptr, s, file, data);
}
}
lang_memory_region_type *new =
(lang_memory_region_type *) stat_alloc (sizeof (lang_memory_region_type));
- new->name = buystring (name);
+ new->name = xstrdup (name);
new->next = (lang_memory_region_type *) NULL;
*lang_memory_region_list_tail = new;
if ((flags & SEC_LINK_ONCE) == 0)
return;
- /* FIXME: When doing a relocateable link, we may have trouble
+ /* FIXME: When doing a relocatable link, we may have trouble
copying relocations in other sections that refer to local symbols
in the section being discarded. Those relocations will have to
be converted somehow; as of this writing I'm not sure that any of
the backends handle that correctly.
It is tempting to instead not discard link once sections when
- doing a relocateable link (technically, they should be discarded
+ doing a relocatable link (technically, they should be discarded
whenever we are building constructors). However, that fails,
because the linker winds up combining all the link once sections
into a single large link once section, which defeats the purpose
of having link once sections in the first place.
- Also, not merging link once sections in a relocateable link
+ Also, not merging link once sections in a relocatable link
causes trouble for MIPS ELF, which relies in link once semantics
to handle the .reginfo section correctly. */
if (! first && (section->output_section->flags & SEC_READONLY) == 0)
flags &= ~ SEC_READONLY;
+ /* Keep SEC_MERGE and SEC_STRINGS only if they are the same. */
+ if (! first
+ && ((section->output_section->flags & (SEC_MERGE | SEC_STRINGS))
+ != (flags & (SEC_MERGE | SEC_STRINGS))
+ || ((flags & SEC_MERGE)
+ && section->output_section->entsize != section->entsize)))
+ {
+ section->output_section->flags &= ~ (SEC_MERGE | SEC_STRINGS);
+ flags &= ~ (SEC_MERGE | SEC_STRINGS);
+ }
+
section->output_section->flags |= flags;
+ if (flags & SEC_MERGE)
+ section->output_section->entsize = section->entsize;
+
/* If SEC_READONLY is not set in the input section, then clear
it from the output section. */
if ((section->flags & SEC_READONLY) == 0)
lang_statement_list_type *hold;
err = bfd_get_error ();
+
+ /* See if the emulation has some special knowledge. */
+ if (ldemul_unrecognized_file (entry))
+ return;
+
if (err == bfd_error_file_ambiguously_recognized)
{
char **p;
bfd_close (entry->the_bfd);
entry->the_bfd = NULL;
- /* See if the emulation has some special knowledge. */
-
- if (ldemul_unrecognized_file (entry))
- return;
-
/* Try to interpret the file as a linker script. */
-
ldfile_open_command_file (entry->filename);
hold = stat_ptr;
if (s->input_statement.real)
{
lang_statement_list_type add;
+ bfd_error_handler_type pfn;
s->input_statement.target = current_target;
bfd_archive))
s->input_statement.loaded = false;
- lang_list_init (&add);
+ lang_list_init (& add);
+
+ /* We need to know if an error occurs whilst loading the
+ symbols, since this means that a valid executable can
+ not be produced. */
+ pfn = bfd_set_error_handler (record_bfd_errors);
load_symbols (&s->input_statement, &add);
+ bfd_set_error_handler (pfn);
+
if (add.head != NULL)
{
*add.tail = s->next;
new->next = ldlang_undef_chain_list_head;
ldlang_undef_chain_list_head = new;
- new->name = buystring (name);
+ new->name = xstrdup (name);
}
/* Run through the list of undefineds created above and place them
#define IGNORE_SECTION(bfd, s) \
(((bfd_get_section_flags (bfd, s) & (SEC_ALLOC | SEC_LOAD)) != (SEC_ALLOC | SEC_LOAD)) \
|| bfd_section_size (bfd, s) == 0)
-
/* Check to see if any allocated sections overlap with other allocated
sections. This can happen when the linker script specifically specifies
the output section addresses of the two sections. */
asection *s;
unsigned opb = bfd_octets_per_byte (output_bfd);
+
/* Scan all sections in the output list. */
for (s = output_bfd->sections; s != NULL; s = s->next)
{
}
}
+
+/* This is the routine to handle BFD error messages. */
+
+#ifdef ANSI_PROTOTYPES
+
+static void
+record_bfd_errors (const char *s, ...)
+{
+ va_list p;
+
+ einfo ("%P: ");
+
+ va_start (p, s);
+
+ vfprintf (stderr, s, p);
+
+ va_end (p);
+
+ fprintf (stderr, "\n");
+
+ einfo ("%X");
+}
+
+#else /* ! defined (ANSI_PROTOTYPES) */
+
+static void
+record_bfd_errors (va_alist)
+ va_dcl
+{
+ va_list p;
+ const char *s;
+
+ einfo ("%P: ");
+
+ va_start (p);
+
+ s = va_arg (p, const char *);
+ vfprintf (stderr, s, p);
+
+ va_end (p);
+
+ fprintf (stderr, "\n");
+
+ einfo ("%X");
+}
+
+#endif /* ! defined (ANSI_PROTOTYPES) */
/* This is a small function used when we want to ignore errors from
BFD. */
bfd_printable_name (input_bfd), input_bfd,
bfd_printable_name (output_bfd));
}
- else
+ else if (bfd_count_sections (input_bfd))
{
+ /* If the input bfd has no contents, it shouldn't set the
+ private data of the output bfd. */
+
bfd_error_handler_type pfn = NULL;
/* If we aren't supposed to warn about mismatched input
l->os->fill = fill;
if (region != NULL && l->os->region == NULL)
l->os->region = region;
- if (lma_region != NULL && l->os->lma_region == NULL)
+ /* We only set lma_region for the first overlay section, as
+ subsequent overlay sections will have load_base set relative
+ to the first section. Also, don't set lma_region if
+ load_base is specified. FIXME: There should really be a test
+ that `AT ( LDADDR )' doesn't conflict with `AT >LMA_REGION'
+ rather than letting LDADDR simply override LMA_REGION. */
+ if (lma_region != NULL && l->os->lma_region == NULL
+ && l->next == NULL && l->os->load_base == NULL)
l->os->lma_region = lma_region;
if (phdrs != NULL && l->os->phdrs == NULL)
l->os->phdrs = phdrs;
lang_register_vers_node (command_line.version_exports_section,
lang_new_vers_node (greg, lreg), NULL);
}
+
+void
+lang_add_unique (name)
+ const char *name;
+{
+ struct unique_sections *ent;
+
+ for (ent = unique_section_list; ent; ent = ent->next)
+ if (strcmp (ent->name, name) == 0)
+ return;
+
+ ent = (struct unique_sections *) xmalloc (sizeof *ent);
+ ent->name = xstrdup (name);
+ ent->next = unique_section_list;
+ unique_section_list = ent;
+}