GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GLD; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+along with GLD; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
#include "bfd.h"
#include "sysdep.h"
#include "ldmisc.h"
#include "ldctor.h"
#include "ldfile.h"
+#include "fnmatch.h"
+
+#include <ctype.h>
/* FORWARDS */
static lang_statement_union_type *new_statement PARAMS ((enum statement_enum,
static lang_statement_list_type lang_output_section_statement;
static CONST char *current_target;
static CONST char *output_target;
-static int longest_section_name = 8;
static lang_statement_list_type statement_list;
static struct lang_phdr *lang_phdr_list;
-static void print_size PARAMS ((size_t value));
-static void print_alignment PARAMS ((unsigned int value));
-static void print_fill PARAMS ((fill_type value));
-static void print_section PARAMS ((const char *name));
static void lang_for_each_statement_worker
PARAMS ((void (*func) (lang_statement_union_type *),
lang_statement_union_type *s));
static lang_input_statement_type *new_afile
PARAMS ((const char *name, lang_input_file_enum_type file_type,
const char *target, boolean add_to_list));
-static void print_flags PARAMS ((int *ignore_flags));
static void init_os PARAMS ((lang_output_section_statement_type *s));
+static void exp_init_os PARAMS ((etree_type *));
+static void section_already_linked PARAMS ((bfd *, asection *, PTR));
+static boolean wildcardp PARAMS ((const char *));
static void wild_section PARAMS ((lang_wild_statement_type *ptr,
const char *section,
lang_input_statement_type *file,
static lang_input_statement_type *lookup_name PARAMS ((const char *name));
static void load_symbols PARAMS ((lang_input_statement_type *entry,
lang_statement_list_type *));
+static void wild_file PARAMS ((lang_wild_statement_type *, const char *,
+ lang_input_statement_type *,
+ lang_output_section_statement_type *));
static void wild PARAMS ((lang_wild_statement_type *s,
const char *section, const char *file,
const char *target,
static void print_input_section PARAMS ((lang_input_section_type *in));
static void print_fill_statement PARAMS ((lang_fill_statement_type *fill));
static void print_data_statement PARAMS ((lang_data_statement_type *data));
+static void print_address_statement PARAMS ((lang_address_statement_type *));
static void print_reloc_statement PARAMS ((lang_reloc_statement_type *reloc));
static void print_padding_statement PARAMS ((lang_padding_statement_type *s));
static void print_wild_statement
boolean had_output_filename = false;
boolean lang_float_flag = false;
boolean delete_output_file_on_failure = false;
+struct lang_nocrossrefs *nocrossref_list;
etree_type *base; /* Relocation base - or null */
#define outside_symbol_address(q) ((q)->value + outside_section_address(q->section))
+#define SECTION_NAME_MAP_LENGTH (16)
+
PTR
stat_alloc (size)
size_t size;
return obstack_alloc (&stat_obstack, size);
}
-static void
-print_size (value)
- size_t value;
-{
- fprintf (config.map_file, "%5x", (unsigned) value);
-}
-
-static void
-print_alignment (value)
- unsigned int value;
-{
- fprintf (config.map_file, "2**%1u", value);
-}
-
-static void
-print_fill (value)
- fill_type value;
-{
- fprintf (config.map_file, "%04x", (unsigned) value);
-}
-
-static void
-print_section (name)
- CONST char *name;
-{
- fprintf (config.map_file, "%*s", -longest_section_name, name);
-}
-
/*----------------------------------------------------------------------
lang_for_each_statement walks the parse tree and calls the provided
function for each node
case lang_assignment_statement_enum:
case lang_padding_statement_enum:
case lang_address_statement_enum:
+ case lang_fill_statement_enum:
break;
default:
FAIL ();
lang_has_input_file = true;
p->target = target;
- p->complained = false;
switch (file_type)
{
case lang_input_file_is_symbols_only_enum:
p->next_real_file = (lang_statement_union_type *) NULL;
p->next = (lang_statement_union_type *) NULL;
p->symbol_count = 0;
- p->common_output_section = (asection *) NULL;
p->dynamic = config.dynamic_link;
p->whole_archive = whole_archive;
p->loaded = false;
lookup->next = (lang_statement_union_type *) NULL;
lookup->bfd_section = (asection *) NULL;
lookup->processed = false;
- lookup->loadable = 1;
+ lookup->sectype = normal_section;
lookup->addr_tree = (etree_type *) NULL;
lang_list_init (&lookup->children);
return lookup;
}
-/*ARGSUSED*/
-static void
-print_flags (ignore_flags)
- int *ignore_flags;
-{
- fprintf (config.map_file, "(");
-#if 0
- if (flags->flag_read)
- fprintf (outfile, "R");
- if (flags->flag_write)
- fprintf (outfile, "W");
- if (flags->flag_executable)
- fprintf (outfile, "X");
- if (flags->flag_loadable)
- fprintf (outfile, "L");
-#endif
- fprintf (config.map_file, ")");
-}
-
void
lang_map ()
{
lang_memory_region_type *m;
- fprintf (config.map_file, "**MEMORY CONFIGURATION**\n\n");
-#ifdef BFD64
- fprintf (config.map_file, "name\t\torigin\t\tlength\t\tattributes\n");
-#else
- fprintf (config.map_file,
- "name\t\torigin length r_size c_size is attributes\n");
+ minfo ("\nMemory Configuration\n\n");
+ fprintf (config.map_file, "%-16s %-18s %-18s\n",
+ "Name", "Origin", "Length");
-#endif
for (m = lang_memory_region_list;
m != (lang_memory_region_type *) NULL;
m = m->next)
{
- fprintf (config.map_file, "%-16s", m->name);
- print_address (m->origin);
- print_space ();
- print_address ((bfd_vma)m->length);
- print_space ();
- print_address ((bfd_vma)m->old_length);
- print_space();
- print_address (m->current - m->origin);
- print_space();
- if (m->old_length)
- fprintf (config.map_file, " %2d%% ",
- (int) ((m->current - m->origin) * 100 / m->old_length));
- print_flags (&m->flags);
- fprintf (config.map_file, "\n");
- }
- fprintf (config.map_file, "\n\n**LINK EDITOR MEMORY MAP**\n\n");
- fprintf (config.map_file, "output input virtual\n");
- fprintf (config.map_file, "section section address tsize\n\n");
+ char buf[100];
+ int len;
- print_statements ();
+ fprintf (config.map_file, "%-16s ", m->name);
+
+ sprintf_vma (buf, m->origin);
+ minfo ("0x%s ", buf);
+ len = strlen (buf);
+ while (len < 16)
+ {
+ print_space ();
+ ++len;
+ }
+ minfo ("0x%V\n", m->length);
+ }
+
+ fprintf (config.map_file, "\nLinker script and memory map\n\n");
+
+ print_statements ();
}
-/*
- *
- */
+/* Initialize an output section. */
+
static void
init_os (s)
- lang_output_section_statement_type * s;
+ lang_output_section_statement_type *s;
{
-/* asection *section = bfd_get_section_by_name(output_bfd, s->name);*/
- section_userdata_type *new =
- (section_userdata_type *)
- stat_alloc (sizeof (section_userdata_type));
+ section_userdata_type *new;
+
+ if (s->bfd_section != NULL)
+ return;
+
+ if (strcmp (s->name, DISCARD_SECTION_NAME) == 0)
+ einfo ("%P%F: Illegal use of `%s' section", DISCARD_SECTION_NAME);
+
+ new = ((section_userdata_type *)
+ stat_alloc (sizeof (section_userdata_type)));
s->bfd_section = bfd_get_section_by_name (output_bfd, s->name);
if (s->bfd_section == (asection *) NULL)
s->bfd_section->output_offset = 0;
get_userdata (s->bfd_section) = (PTR) new;
+ /* If there is a base address, make sure that any sections it might
+ mention are initialized. */
+ if (s->addr_tree != NULL)
+ exp_init_os (s->addr_tree);
}
-/***********************************************************************
- The wild routines.
+/* Make sure that all output sections mentioned in an expression are
+ initialized. */
- 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) .
+static void
+exp_init_os (exp)
+ etree_type *exp;
+{
+ switch (exp->type.node_class)
+ {
+ case etree_assign:
+ exp_init_os (exp->assign.src);
+ break;
- The toplevel routine, wild, takes a statement, section, file and
- target. If either the section or file is null it is taken to be the
- wildcard. Seperate lang_input_section statements are created for
- each part of the expanstion, and placed after the statement provided.
+ case etree_binary:
+ exp_init_os (exp->binary.lhs);
+ exp_init_os (exp->binary.rhs);
+ break;
-*/
+ case etree_trinary:
+ exp_init_os (exp->trinary.cond);
+ exp_init_os (exp->trinary.lhs);
+ exp_init_os (exp->trinary.rhs);
+ break;
-void
-wild_doit (ptr, section, output, file)
- lang_statement_list_type * ptr;
- asection * section;
- lang_output_section_statement_type * output;
- lang_input_statement_type * file;
+ case etree_unary:
+ exp_init_os (exp->unary.child);
+ break;
+
+ case etree_name:
+ switch (exp->type.node_code)
+ {
+ case ADDR:
+ case LOADADDR:
+ case SIZEOF:
+ {
+ lang_output_section_statement_type *os;
+
+ os = lang_output_section_find (exp->name.name);
+ if (os != NULL && os->bfd_section == NULL)
+ init_os (os);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* Sections marked with the SEC_LINK_ONCE flag should only be linked
+ once into the output. This routine checks each sections, and
+ arranges to discard it if a section of the same name has already
+ been linked. This code assumes that all relevant sections have the
+ SEC_LINK_ONCE flag set; that is, it does not depend solely upon the
+ section name. This is called via bfd_map_over_sections. */
+
+/*ARGSUSED*/
+static void
+section_already_linked (abfd, sec, ignore)
+ bfd *abfd;
+ asection *sec;
+ PTR ignore;
{
- if (output->bfd_section == (asection *) NULL)
- init_os (output);
+ struct sec_link_once
+ {
+ struct sec_link_once *next;
+ asection *sec;
+ };
+ static struct sec_link_once *sec_link_once_list;
+ flagword flags;
+ const char *name;
+ struct sec_link_once *l;
- if (section != (asection *) NULL
- && section->output_section == (asection *) NULL)
- {
- /* Add a section reference to the list */
- lang_input_section_type *new = new_stat (lang_input_section, ptr);
+ flags = bfd_get_section_flags (abfd, sec);
- new->section = section;
- new->ifile = file;
- section->output_section = output->bfd_section;
+ if ((flags & SEC_LINK_ONCE) == 0)
+ 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
- section (I don't know why we want to do this, but we do).
- build_link_order in ldwrite.c handles this case by turning the
- embedded SEC_NEVER_LOAD section into a fill. */
- section->output_section->flags |=
- section->flags & (flagword) (~ SEC_NEVER_LOAD);
+ name = bfd_get_section_name (abfd, sec);
- if (!output->loadable)
+ for (l = sec_link_once_list; l != NULL; l = l->next)
{
- /* Turn off load flag */
- output->bfd_section->flags &= ~SEC_LOAD;
- output->bfd_section->flags |= SEC_NEVER_LOAD;
+ if (strcmp (name, bfd_get_section_name (l->sec->owner, l->sec)) == 0)
+ {
+ /* The section has already been linked. See if we should
+ issue a warning. */
+ switch (flags & SEC_LINK_DUPLICATES)
+ {
+ default:
+ abort ();
+
+ case SEC_LINK_DUPLICATES_DISCARD:
+ break;
+
+ case SEC_LINK_DUPLICATES_ONE_ONLY:
+ einfo ("%P: %B: warning: ignoring duplicate section `%s'\n",
+ abfd, name);
+ break;
+
+ case SEC_LINK_DUPLICATES_SAME_CONTENTS:
+ /* FIXME: We should really dig out the contents of both
+ sections and memcmp them. The COFF/PE spec says that
+ the Microsoft linker does not implement this
+ correctly, so I'm not going to bother doing it
+ either. */
+ /* Fall through. */
+ case SEC_LINK_DUPLICATES_SAME_SIZE:
+ if (bfd_section_size (abfd, sec)
+ != bfd_section_size (l->sec->owner, l->sec))
+ einfo ("%P: %B: warning: duplicate section `%s' has different size\n",
+ abfd, name);
+ break;
+ }
+
+ /* Set the output_section field so that wild_doit does not
+ create a lang_input_section structure for this section. */
+ sec->output_section = bfd_abs_section_ptr;
+
+ return;
+ }
}
- if (section->alignment_power > output->bfd_section->alignment_power)
+
+ /* This is the first section with this name. Record it. */
+
+ l = (struct sec_link_once *) xmalloc (sizeof *l);
+ l->sec = sec;
+ l->next = sec_link_once_list;
+ sec_link_once_list = l;
+}
+\f
+/* 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). */
+
+/* Return true if the PATTERN argument is a wildcard pattern. */
+
+static boolean
+wildcardp (pattern)
+ const char *pattern;
+{
+ const char *s;
+
+ for (s = pattern; *s != '\0'; ++s)
+ if (*s == '?'
+ || *s == '\\'
+ || *s == '*'
+ || *s == '[')
+ return true;
+ return false;
+}
+
+/* Add SECTION to the output section OUTPUT. Do this by creating a
+ lang_input_section statement which is placed at PTR. FILE is the
+ input file which holds SECTION. */
+
+void
+wild_doit (ptr, section, output, file)
+ lang_statement_list_type *ptr;
+ asection *section;
+ lang_output_section_statement_type *output;
+ lang_input_statement_type *file;
+{
+ flagword flags;
+ boolean discard;
+
+ flags = bfd_get_section_flags (section->owner, section);
+
+ discard = false;
+
+ /* If we are doing a final link, discard sections marked with
+ SEC_EXCLUDE. */
+ if (! link_info.relocateable
+ && (flags & SEC_EXCLUDE) != 0)
+ discard = true;
+
+ /* Discard input sections which are assigned to a section named
+ DISCARD_SECTION_NAME. */
+ if (strcmp (output->name, DISCARD_SECTION_NAME) == 0)
+ discard = true;
+
+ /* Discard debugging sections if we are stripping debugging
+ information. */
+ if ((link_info.strip == strip_debugger || link_info.strip == strip_all)
+ && (flags & SEC_DEBUGGING) != 0)
+ discard = true;
+
+ if (discard)
{
- output->bfd_section->alignment_power = section->alignment_power;
+ if (section->output_section == NULL)
+ {
+ /* This prevents future calls from assigning this section. */
+ section->output_section = bfd_abs_section_ptr;
+ }
+ return;
}
- /* If supplied an aligmnet, then force it */
- if (output->section_alignment != -1)
+
+ if (section->output_section == NULL)
{
- output->bfd_section->alignment_power = output->section_alignment;
+ lang_input_section_type *new;
+
+ if (output->bfd_section == NULL)
+ init_os (output);
+
+ /* Add a section reference to the list */
+ new = new_stat (lang_input_section, ptr);
+
+ new->section = section;
+ new->ifile = file;
+ section->output_section = output->bfd_section;
+
+ /* 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
+ section (I don't know why we want to do this, but we do).
+ build_link_order in ldwrite.c handles this case by turning
+ the embedded SEC_NEVER_LOAD section into a fill.
+
+ If final link, don't copy the SEC_LINK_ONCE flags, they've already
+ been processed. One reason to do this is that on pe format targets,
+ .text$foo sections go into .text and it's odd to see .text with
+ SEC_LINK_ONCE set. */
+
+ section->output_section->flags |=
+ section->flags & (flagword) (~ (SEC_NEVER_LOAD
+ | (! link_info.relocateable
+ ? SEC_LINK_ONCE | SEC_LINK_DUPLICATES
+ : 0)));
+
+ switch (output->sectype)
+ {
+ case normal_section:
+ break;
+ case dsect_section:
+ case copy_section:
+ case info_section:
+ case overlay_section:
+ output->bfd_section->flags &= ~SEC_ALLOC;
+ break;
+ case noload_section:
+ output->bfd_section->flags &= ~SEC_LOAD;
+ output->bfd_section->flags |= SEC_NEVER_LOAD;
+ break;
+ }
+
+ if (section->alignment_power > output->bfd_section->alignment_power)
+ output->bfd_section->alignment_power = section->alignment_power;
+
+ /* If supplied an aligment, then force it. */
+ if (output->section_alignment != -1)
+ output->bfd_section->alignment_power = output->section_alignment;
}
- }
}
+/* Expand a wild statement for a particular FILE. SECTION may be
+ NULL, in which case it is a wild card. */
+
static void
wild_section (ptr, section, file, output)
lang_wild_statement_type *ptr;
if (file->just_syms_flag == false)
{
register asection *s;
+ boolean wildcard;
+
+ if (section == NULL)
+ wildcard = false;
+ else
+ wildcard = wildcardp (section);
for (s = file->the_bfd->sections; s != NULL; s = s->next)
{
+ boolean match;
+
/* Attach all sections named SECTION. If SECTION is NULL,
then attach all sections.
section. I did not understand that, and I took it out.
--ian@cygnus.com. */
- if (section == NULL
- || strcmp (bfd_get_section_name (file->the_bfd, s),
- section) == 0)
+ if (section == NULL)
+ match = true;
+ 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;
+ }
+ if (match)
wild_doit (&ptr->children, s, output, file);
}
}
}
-/* passed a file name (which must have been seen already and added to
- the statement tree. We will see if it has been opened already and
- had its symbols read. If not then we'll read it.
+/* This is passed a file name which must have been seen already and
+ added to the statement tree. We will see if it has been opened
+ already and had its symbols read. If not then we'll read it. */
- Archives are pecuilar here. We may open them once, but if they do
- not define anything we need at the time, they won't have all their
- symbols read. If we need them later, we'll have to redo it. */
static lang_input_statement_type *
lookup_name (name)
- CONST char *name;
+ const char *name;
{
lang_input_statement_type *search;
|| place == NULL)
einfo ("%F%B: file not recognized: %E\n", entry->the_bfd);
- /* Try to interpret the file as a linker script. */
-
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;
einfo ("%F%B: object %B in archive is not object\n",
entry->the_bfd, member);
if (! ((*link_info.callbacks->add_archive_element)
- (&link_info, member, "-whole-archive")))
+ (&link_info, member, "--whole-archive")))
abort ();
if (! bfd_link_add_symbols (member, &link_info))
einfo ("%F%B: could not read symbols: %E\n", member);
entry->loaded = true;
}
+/* Handle a wild statement for a single file F. */
+
+static void
+wild_file (s, section, f, output)
+ lang_wild_statement_type *s;
+ const char *section;
+ lang_input_statement_type *f;
+ lang_output_section_statement_type *output;
+{
+ if (f->the_bfd == NULL
+ || ! bfd_check_format (f->the_bfd, bfd_archive))
+ wild_section (s, section, f, output);
+ else
+ {
+ bfd *member;
+
+ /* This is an archive file. We must map each member of the
+ archive separately. */
+ member = bfd_openr_next_archived_file (f->the_bfd, (bfd *) NULL);
+ while (member != NULL)
+ {
+ /* When lookup_name is called, it will call the add_symbols
+ entry point for the archive. For each element of the
+ archive which is included, BFD will call ldlang_add_file,
+ which will set the usrdata field of the member to the
+ lang_input_statement. */
+ if (member->usrdata != NULL)
+ {
+ wild_section (s, section,
+ (lang_input_statement_type *) member->usrdata,
+ output);
+ }
+
+ member = bfd_openr_next_archived_file (f->the_bfd, member);
+ }
+ }
+}
+
+/* Handle a wild statement. SECTION or FILE or both may be NULL,
+ indicating that it is a wildcard. Separate lang_input_section
+ statements are created for each part of the expansion; they are
+ added after the wild statement S. OUTPUT is the output section. */
+
static void
wild (s, section, file, target, output)
- lang_wild_statement_type * s;
- CONST char *section;
- CONST char *file;
- CONST char *target;
- lang_output_section_statement_type * output;
+ lang_wild_statement_type *s;
+ const char *section;
+ const char *file;
+ const char *target;
+ lang_output_section_statement_type *output;
{
lang_input_statement_type *f;
f != (lang_input_statement_type *) NULL;
f = (lang_input_statement_type *) f->next)
{
- wild_section (s, section, f, output);
+ wild_file (s, section, f, output);
+ }
+ }
+ else if (wildcardp (file))
+ {
+ for (f = (lang_input_statement_type *) file_chain.head;
+ f != (lang_input_statement_type *) NULL;
+ f = (lang_input_statement_type *) f->next)
+ {
+ if (fnmatch (file, f->filename, FNM_FILE_NAME) == 0)
+ wild_file (s, section, f, output);
}
}
else
{
/* Perform the iteration over a single file */
- wild_section (s, section, lookup_name (file), output);
+ f = lookup_name (file);
+ wild_file (s, section, f, output);
}
+
if (section != (char *) NULL
&& strcmp (section, "COMMON") == 0
- && default_common_section == (lang_output_section_statement_type *) NULL)
+ && default_common_section == NULL)
{
- /* Remember the section that common is going to incase we later
- get something which doesn't know where to put it */
+ /* Remember the section that common is going to in case we later
+ get something which doesn't know where to put it. */
default_common_section = output;
}
}
-/*
- read in all the files
- */
+/* Open the output file. */
static bfd *
open_output (name)
- CONST char *name;
+ const char *name;
{
bfd *output;
einfo ("%P%F: cannot open output file %s: %E\n", name);
}
- delete_output_file_on_failure = 1;
+ delete_output_file_on_failure = true;
/* output->flags |= D_PAGED;*/
output_bfd->flags |= WP_TEXT;
else
output_bfd->flags &= ~WP_TEXT;
- if (config.traditional_format)
+ if (link_info.traditional_format)
output_bfd->flags |= BFD_TRADITIONAL_FORMAT;
else
output_bfd->flags &= ~BFD_TRADITIONAL_FORMAT;
break;
case lang_wild_statement_enum:
/* Maybe we should load the file's symbols */
- if (s->wild_statement.filename)
+ if (s->wild_statement.filename
+ && ! wildcardp (s->wild_statement.filename))
(void) lookup_name (s->wild_statement.filename);
open_input_bfds (s->wild_statement.children.head, force);
break;
case lang_object_symbols_statement_enum:
case lang_data_statement_enum:
case lang_reloc_statement_enum:
- case lang_assignment_statement_enum:
case lang_padding_statement_enum:
case lang_input_statement_enum:
if (output_section_statement != NULL
&& output_section_statement->bfd_section == NULL)
init_os (output_section_statement);
break;
+ case lang_assignment_statement_enum:
+ if (output_section_statement != NULL
+ && output_section_statement->bfd_section == NULL)
+ init_os (output_section_statement);
+
+ /* Make sure that any sections mentioned in the assignment
+ are initialized. */
+ exp_init_os (s->assignment_statement.exp);
+ break;
case lang_afile_asection_pair_statement_enum:
FAIL ();
break;
lang_output_section_statement_type * output_section_statement;
{
asection *section = output_section_statement->bfd_section;
+ int len;
- print_nl ();
- print_section (output_section_statement->name);
+ if (output_section_statement != abs_output_section)
+ {
+ minfo ("\n%s", output_section_statement->name);
+ if (section != NULL)
+ {
+ print_dot = section->vma;
- if (section)
- {
- print_dot = section->vma;
- print_space ();
- print_section ("");
- print_space ();
- print_address (section->vma);
- print_space ();
- print_size (section->_raw_size);
- print_space ();
- print_size(section->_cooked_size);
- print_space ();
- print_alignment (section->alignment_power);
- print_space ();
-#if 0
- fprintf (config.map_file, "%s flags", output_section_statement->region->name);
- print_flags (stdout, &output_section_statement->flags);
-#endif
- if (section->flags & SEC_LOAD)
- fprintf (config.map_file, "load ");
- if (section->flags & SEC_ALLOC)
- fprintf (config.map_file, "alloc ");
- if (section->flags & SEC_RELOC)
- fprintf (config.map_file, "reloc ");
- if (section->flags & SEC_HAS_CONTENTS)
- fprintf (config.map_file, "contents ");
+ len = strlen (output_section_statement->name);
+ if (len >= SECTION_NAME_MAP_LENGTH - 1)
+ {
+ print_nl ();
+ len = 0;
+ }
+ while (len < SECTION_NAME_MAP_LENGTH)
+ {
+ print_space ();
+ ++len;
+ }
- }
- else
- {
- fprintf (config.map_file, " (no attached output section)");
- }
- print_nl ();
- if (output_section_statement->load_base)
- {
- bfd_vma b = exp_get_abs_int(output_section_statement->load_base,
- 0, "output base", lang_final_phase_enum);
- fprintf (config.map_file, "Output address ");
- fprintf_vma (config.map_file, b);
- fprintf (config.map_file, "\n");
- }
- if (output_section_statement->section_alignment >= 0
- || output_section_statement->subsection_alignment >= 0)
- {
- fprintf (config.map_file, "\t\t\t\t\tforced alignment ");
- if (output_section_statement->section_alignment >= 0)
- {
- fprintf (config.map_file, "section 2**%d ",output_section_statement->section_alignment );
- }
- if ( output_section_statement->subsection_alignment >= 0)
- {
- fprintf (config.map_file, "subsection 2**%d ",output_section_statement->subsection_alignment );
+ minfo ("0x%V %W", section->vma, section->_raw_size);
+
+ if (output_section_statement->load_base != NULL)
+ {
+ bfd_vma addr;
+
+ addr = exp_get_abs_int (output_section_statement->load_base, 0,
+ "load base", lang_final_phase_enum);
+ minfo (" load address 0x%V", addr);
+ }
+ }
+
+ print_nl ();
}
-
- print_nl ();
- }
+
print_statement_list (output_section_statement->children.head,
output_section_statement);
-
}
static void
lang_assignment_statement_type * assignment;
lang_output_section_statement_type * output_section;
{
+ int i;
etree_value_type result;
- print_section ("");
- print_space ();
- print_section ("");
- print_space ();
- print_address (print_dot);
- print_space ();
- result = exp_fold_tree (assignment->exp->assign.src,
- output_section,
- lang_final_phase_enum,
- print_dot,
- &print_dot);
+ for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
+ print_space ();
+ result = exp_fold_tree (assignment->exp->assign.src, output_section,
+ lang_final_phase_enum, print_dot, &print_dot);
if (result.valid)
- {
- print_address (result.value);
- }
+ minfo ("0x%V", result.value + result.section->bfd_section->vma);
else
{
- fprintf (config.map_file, "*undefined*");
+ minfo ("*undef* ");
+#ifdef BFD64
+ minfo (" ");
+#endif
}
- print_space ();
+
+ minfo (" ");
+
exp_print_tree (assignment->exp);
- fprintf (config.map_file, "\n");
+ print_nl ();
}
static void
}
}
-/* Print all the defined symbols for the abfd provided by in the supplied
- section.
-*/
+/* Print all symbols defined in a particular section. This is called
+ via bfd_link_hash_traverse. */
static boolean
print_one_symbol (hash_entry, ptr)
-struct bfd_link_hash_entry *hash_entry;
-PTR ptr;
-{
- asection * sec = (asection *)ptr;
-
- if (hash_entry->type == bfd_link_hash_defined
- || hash_entry->type == bfd_link_hash_defweak)
- {
- if (sec == hash_entry->u.def.section) {
- print_section ("");
- fprintf (config.map_file, " ");
- print_section ("");
- fprintf (config.map_file, " ");
- print_address (hash_entry->u.def.value + outside_section_address (sec));
- fprintf (config.map_file, " %s", hash_entry->root.string);
- print_nl ();
- }
+ struct bfd_link_hash_entry *hash_entry;
+ PTR ptr;
+{
+ asection *sec = (asection *) ptr;
+
+ if ((hash_entry->type == bfd_link_hash_defined
+ || hash_entry->type == bfd_link_hash_defweak)
+ && sec == hash_entry->u.def.section)
+ {
+ int i;
+
+ for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
+ print_space ();
+ minfo ("0x%V ",
+ (hash_entry->u.def.value
+ + hash_entry->u.def.section->output_offset
+ + hash_entry->u.def.section->output_section->vma));
+
+ minfo (" %T\n", hash_entry->root.string);
}
return true;
}
+/* Print information about an input section to the map file. */
+
static void
print_input_section (in)
lang_input_section_type * in;
if (size != 0)
{
- print_section ("");
- fprintf (config.map_file, " ");
- print_section (i->name);
- fprintf (config.map_file, " ");
- if (i->output_section)
+ print_space ();
+
+ minfo ("%s", i->name);
+
+ if (i->output_section != NULL)
{
- print_address (i->output_section->vma + i->output_offset);
- fprintf (config.map_file, " ");
- print_size (i->_raw_size);
- fprintf (config.map_file, " ");
- print_size(i->_cooked_size);
- fprintf (config.map_file, " ");
- print_alignment (i->alignment_power);
- fprintf (config.map_file, " ");
- if (in->ifile)
- {
+ int len;
- bfd *abfd = in->ifile->the_bfd;
+ len = 1 + strlen (i->name);
+ if (len >= SECTION_NAME_MAP_LENGTH - 1)
+ {
+ print_nl ();
+ len = 0;
+ }
+ while (len < SECTION_NAME_MAP_LENGTH)
+ {
+ print_space ();
+ ++len;
+ }
- if (in->ifile->just_syms_flag == true)
- {
- fprintf (config.map_file, "symbols only ");
- }
+ minfo ("0x%V %W %B\n",
+ i->output_section->vma + i->output_offset, size,
+ i->owner);
- fprintf (config.map_file, " %s ", abfd->xvec->name);
- if (abfd->my_archive != (bfd *) NULL)
- {
- fprintf (config.map_file, "[%s]%s", abfd->my_archive->filename,
- abfd->filename);
- }
- else
+ if (i->_cooked_size != 0 && i->_cooked_size != i->_raw_size)
+ {
+ len = SECTION_NAME_MAP_LENGTH + 3;
+#ifdef BFD64
+ len += 16;
+#else
+ len += 8;
+#endif
+ while (len > 0)
{
- fprintf (config.map_file, "%s", abfd->filename);
+ print_space ();
+ --len;
}
- fprintf (config.map_file, "(overhead %d bytes)", (int) bfd_alloc_size (abfd));
- print_nl ();
- /* Print all the symbols */
- bfd_link_hash_traverse (link_info.hash, print_one_symbol, (PTR) i);
- }
- else
- {
- print_nl ();
+ minfo ("%W (size before relaxing)\n", i->_raw_size);
}
+ bfd_link_hash_traverse (link_info.hash, print_one_symbol, (PTR) i);
- print_dot = outside_section_address (i) + size;
- }
- else
- {
- fprintf (config.map_file, "No output section allocated\n");
+ print_dot = i->output_section->vma + i->output_offset + size;
}
}
}
print_fill_statement (fill)
lang_fill_statement_type * fill;
{
- fprintf (config.map_file, "FILL mask ");
- print_fill (fill->fill);
+ fprintf (config.map_file, " FILL mask 0x%x\n", fill->fill);
}
static void
print_data_statement (data)
lang_data_statement_type * data;
{
-/* bfd_vma value; */
- print_section ("");
- print_space ();
- print_section ("");
- print_space ();
-/* ASSERT(print_dot == data->output_vma);*/
+ int i;
+ bfd_vma addr;
+ bfd_size_type size;
+ const char *name;
+
+ for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
+ print_space ();
+
+ addr = data->output_vma;
+ if (data->output_section != NULL)
+ addr += data->output_section->vma;
- /* data->output_section may be NULL if called from gdb. */
- if (data->output_section)
- print_address (data->output_vma + data->output_section->vma);
- else
- print_address (data->output_vma);
- print_space ();
- print_address (data->value);
- print_space ();
switch (data->type)
{
+ default:
+ abort ();
case BYTE:
- fprintf (config.map_file, "BYTE ");
- print_dot += BYTE_SIZE;
+ size = BYTE_SIZE;
+ name = "BYTE";
break;
case SHORT:
- fprintf (config.map_file, "SHORT ");
- print_dot += SHORT_SIZE;
+ size = SHORT_SIZE;
+ name = "SHORT";
break;
case LONG:
- fprintf (config.map_file, "LONG ");
- print_dot += LONG_SIZE;
+ size = LONG_SIZE;
+ name = "LONG";
break;
case QUAD:
- fprintf (config.map_file, "QUAD ");
- print_dot += QUAD_SIZE;
+ size = QUAD_SIZE;
+ name = "QUAD";
break;
}
- exp_print_tree (data->exp);
+ minfo ("0x%V %W %s 0x%v", addr, size, name, data->value);
- fprintf (config.map_file, "\n");
+ if (data->exp->type.node_class != etree_value)
+ {
+ print_space ();
+ exp_print_tree (data->exp);
+ }
+
+ print_nl ();
+
+ print_dot = addr + size;
+}
+
+/* Print an address statement. These are generated by options like
+ -Ttext. */
+
+static void
+print_address_statement (address)
+ lang_address_statement_type *address;
+{
+ minfo ("Address of section %s set to ", address->section_name);
+ exp_print_tree (address->address);
+ print_nl ();
}
/* Print a reloc statement. */
print_reloc_statement (reloc)
lang_reloc_statement_type *reloc;
{
- print_section ("");
- print_space ();
- print_section ("");
- print_space ();
+ int i;
+ bfd_vma addr;
+ bfd_size_type size;
+
+ for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
+ print_space ();
-/* ASSERT(print_dot == data->output_vma);*/
+ addr = reloc->output_vma;
+ if (reloc->output_section != NULL)
+ addr += reloc->output_section->vma;
- /* reloc->output_section may be NULL if called from gdb. */
- if (reloc->output_section)
- print_address (reloc->output_vma + reloc->output_section->vma);
- else
- print_address (reloc->output_vma);
- print_space ();
- print_address (reloc->addend_value);
- print_space ();
+ size = bfd_get_reloc_size (reloc->howto);
- fprintf (config.map_file, "RELOC %s ", reloc->howto->name);
+ minfo ("0x%V %W RELOC %s ", addr, size, reloc->howto->name);
- print_dot += bfd_get_reloc_size (reloc->howto);
+ if (reloc->name != NULL)
+ minfo ("%s+", reloc->name);
+ else
+ minfo ("%s+", reloc->section->name);
exp_print_tree (reloc->addend_exp);
- fprintf (config.map_file, "\n");
+ print_nl ();
+
+ print_dot = addr + size;
}
static void
print_padding_statement (s)
- lang_padding_statement_type * s;
+ lang_padding_statement_type *s;
{
- print_section ("");
- print_space ();
- print_section ("*fill*");
- print_space ();
- /* s->output_section may be NULL if called from gdb. */
- if (s->output_section)
- print_address (s->output_offset + s->output_section->vma);
- else
- print_address (s->output_offset);
- print_space ();
- print_size (s->size);
- print_space ();
- print_fill (s->fill);
+ int len;
+ bfd_vma addr;
+
+ minfo (" *fill*");
+
+ len = sizeof " *fill*" - 1;
+ while (len < SECTION_NAME_MAP_LENGTH)
+ {
+ print_space ();
+ ++len;
+ }
+
+ addr = s->output_offset;
+ if (s->output_section != NULL)
+ addr += s->output_section->vma;
+ minfo ("0x%V %W", addr, s->size);
+
+ if (s->fill != 0)
+ minfo (" %u", s->fill);
+
print_nl ();
- print_dot = s->output_offset + s->size;
- /* s->output_section may be NULL if called from gdb. */
- if (s->output_section)
- print_dot += s->output_section->vma;
+ print_dot = addr + s->size;
}
static void
lang_wild_statement_type * w;
lang_output_section_statement_type * os;
{
- fprintf (config.map_file, " from ");
- if (w->filename != (char *) NULL)
- {
- fprintf (config.map_file, "%s", w->filename);
- }
+ print_space ();
+
+ if (w->filename != NULL)
+ minfo ("%s", w->filename);
else
- {
- fprintf (config.map_file, "*");
- }
- if (w->section_name != (char *) NULL)
- {
- fprintf (config.map_file, "(%s)", w->section_name);
- }
+ minfo ("*");
+
+ if (w->section_name != NULL)
+ minfo ("(%s)", w->section_name);
else
- {
- fprintf (config.map_file, "(*)");
- }
+ minfo ("(*)");
+
print_nl ();
- print_statement_list (w->children.head, os);
+ print_statement_list (w->children.head, os);
}
/* Print a group statement. */
static void
print_statement_list (s, os)
- lang_statement_union_type * s;
- lang_output_section_statement_type * os;
+ lang_statement_union_type *s;
+ lang_output_section_statement_type *os;
{
- while (s)
+ while (s != NULL)
{
print_statement (s, os);
s = s->next;
static void
print_statement (s, os)
- lang_statement_union_type * s;
- lang_output_section_statement_type * os;
+ lang_statement_union_type *s;
+ lang_output_section_statement_type *os;
{
switch (s->header.type)
{
+ default:
+ fprintf (config.map_file, "Fail with %d\n", s->header.type);
+ FAIL ();
+ break;
case lang_constructors_statement_enum:
- fprintf (config.map_file, "constructors:\n");
- print_statement_list (constructor_list.head, os);
+ if (constructor_list.head != NULL)
+ {
+ minfo (" CONSTRUCTORS\n");
+ print_statement_list (constructor_list.head, os);
+ }
break;
case lang_wild_statement_enum:
print_wild_statement (&s->wild_statement, os);
break;
- default:
- fprintf (config.map_file, "Fail with %d\n", s->header.type);
- FAIL ();
- break;
case lang_address_statement_enum:
- fprintf (config.map_file, "address\n");
+ print_address_statement (&s->address_statement);
break;
case lang_object_symbols_statement_enum:
- fprintf (config.map_file, "object symbols\n");
+ minfo (" CREATE_OBJECT_SYMBOLS\n");
break;
case lang_fill_statement_enum:
print_fill_statement (&s->fill_statement);
print_output_section_statement (&s->output_section_statement);
break;
case lang_assignment_statement_enum:
- print_assignment (&s->assignment_statement,
- os);
+ print_assignment (&s->assignment_statement, os);
break;
case lang_target_statement_enum:
fprintf (config.map_file, "TARGET(%s)\n", s->target_statement.target);
break;
case lang_output_statement_enum:
- fprintf (config.map_file, "OUTPUT(%s %s)\n",
- s->output_statement.name,
- output_target ? output_target : "");
+ minfo ("OUTPUT(%s", s->output_statement.name);
+ if (output_target != NULL)
+ minfo (" %s", output_target);
+ minfo (")\n");
break;
case lang_input_statement_enum:
print_input_statement (&s->input_statement);
}
}
-
static void
print_statements ()
{
- print_statement_list (statement_list.head,
- abs_output_section);
-
+ print_statement_list (statement_list.head, abs_output_section);
}
/* Print the first N statements in statement list S to STDERR.
print_statement_list (s, abs_output_section);
else
{
- while (--n >= 0)
+ while (s && --n >= 0)
{
print_statement (s, abs_output_section);
s = s->next;
einfo ("%F%S: non constant address expression for section %s\n",
os->name);
}
- dot = r.value;
+ dot = r.value + r.section->bfd_section->vma;
}
/* The section starts here */
/* First, align to what the section needs */
{
os->region->current = dot;
/* Make sure this isn't silly. */
- if ((os->region->current < os->region->origin)
- || (os->region->current
- > os->region->origin + os->region->length))
+ if (os->region->current < os->region->origin
+ || (os->region->current - os->region->origin
+ > os->region->length))
{
if (os->addr_tree != (etree_type *) NULL)
{
i = (*prev)->input_section.section;
if (! relax)
- i->_cooked_size = i->_raw_size;
+ {
+ if (i->_cooked_size == 0)
+ i->_cooked_size = i->_raw_size;
+ }
else
{
boolean again;
section->flags |= SEC_ALLOC;
if (config.map_file != NULL)
- fprintf (config.map_file, "Allocating common %s: %lx at %lx %s\n",
- h->root.string, (unsigned long) size,
- (unsigned long) h->u.def.value, section->owner->filename);
+ {
+ static boolean header_printed;
+ int len;
+ char *name;
+ char buf[50];
+
+ if (! header_printed)
+ {
+ minfo ("\nAllocating common symbols\n");
+ minfo ("Common symbol size file\n\n");
+ header_printed = true;
+ }
+
+ name = demangle (h->root.string);
+ minfo ("%s", name);
+ len = strlen (name);
+ free (name);
+
+ if (len >= 19)
+ {
+ print_nl ();
+ len = 0;
+ }
+ while (len < 20)
+ {
+ print_space ();
+ ++len;
+ }
+
+ minfo ("0x");
+ if (size <= 0xffffffff)
+ sprintf (buf, "%lx", (unsigned long) size);
+ else
+ sprintf_vma (buf, size);
+ minfo ("%s", buf);
+ len = strlen (buf);
+
+ while (len < 16)
+ {
+ print_space ();
+ ++len;
+ }
+
+ minfo ("%B\n", section->owner);
+ }
return true;
}
s->output_section = bfd_abs_section_ptr;
s->output_offset = s->vma;
}
- else if (file->common_section == s)
+ else if (strcmp (s->name, "COMMON") == 0)
{
- /* This is a lonely common section which must
- have come from an archive. We attatch to the
- section with the wildcard */
+ /* This is a lonely common section which must have
+ come from an archive. We attach to the section
+ with the wildcard. */
if (! link_info.relocateable
- && ! command_line.force_common_definition)
+ || command_line.force_common_definition)
{
- if (default_common_section ==
- (lang_output_section_statement_type *) NULL)
+ if (default_common_section == NULL)
{
+#if 0
+ /* This message happens when using the
+ svr3.ifile linker script, so I have
+ disabled it. */
info_msg ("%P: no [COMMON] command, defaulting to .bss\n");
-
+#endif
default_common_section =
lang_output_section_statement_lookup (".bss");
*pp = entry->the_bfd;
entry->the_bfd->usrdata = (PTR) entry;
bfd_set_gp_size (entry->the_bfd, g_switch_value);
+
+ /* Look through the sections and check for any which should not be
+ included in the link. We need to do this now, so that we can
+ notice when the backend linker tries to report multiple
+ definition errors for symbols which are in sections we aren't
+ going to link. FIXME: It might be better to entirely ignore
+ symbols which are defined in sections which are going to be
+ discarded. This would require modifying the backend linker for
+ each backend which might set the SEC_LINK_ONCE flag. If we do
+ this, we should probably handle SEC_EXCLUDE in the same way. */
+
+ bfd_map_over_sections (entry->the_bfd, section_already_linked, (PTR) NULL);
}
void
return 0;
}
+
void
lang_enter_output_section_statement (output_section_statement_name,
- address_exp, flags, block_value,
+ address_exp, sectype, block_value,
align, subalign, ebase)
const char *output_section_statement_name;
etree_type * address_exp;
- int flags;
+ enum section_type sectype;
bfd_vma block_value;
etree_type *align;
etree_type *subalign;
os->addr_tree =
address_exp;
}
- os->flags = flags;
- if (flags & SEC_NEVER_LOAD)
- os->loadable = 0;
+ os->sectype = sectype;
+ if (sectype != noload_section)
+ os->flags = SEC_NO_FLAGS;
else
- os->loadable = 1;
+ os->flags = SEC_NEVER_LOAD;
os->block_value = block_value ? block_value : 1;
stat_ptr = &os->children;
}
void
-lang_leave_output_section_statement (fill, memspec)
+lang_leave_output_section_statement (fill, memspec, phdrs)
bfd_vma fill;
- CONST char *memspec;
+ const char *memspec;
+ struct lang_output_section_phdr_list *phdrs;
{
current_section->fill = fill;
current_section->region = lang_memory_region_lookup (memspec);
+ current_section->phdrs = phdrs;
stat_ptr = &statement_list;
}
*pp = n;
}
-/* Record that a section should be placed in a phdr. */
-
-void
-lang_section_in_phdr (name)
- const char *name;
-{
- struct lang_output_section_phdr_list *n;
-
- n = ((struct lang_output_section_phdr_list *)
- stat_alloc (sizeof (struct lang_output_section_phdr_list)));
- n->name = name;
- n->used = false;
- n->next = current_section->phdrs;
- current_section->phdrs = n;
-}
-
/* Record the program header information in the output BFD. FIXME: We
should not be calling an ELF specific function here. */
last = pl;
else
{
- if (! os->loadable
+ if (os->sectype == noload_section
|| os->bfd_section == NULL
|| (os->bfd_section->flags & SEC_ALLOC) == 0)
continue;
u->output_section_statement.name, pl->name);
}
}
+
+/* Record a list of sections which may not be cross referenced. */
+
+void
+lang_add_nocrossref (l)
+ struct lang_nocrossref *l;
+{
+ struct lang_nocrossrefs *n;
+
+ n = (struct lang_nocrossrefs *) xmalloc (sizeof *n);
+ n->next = nocrossref_list;
+ n->list = l;
+ nocrossref_list = n;
+
+ /* Set notice_all so that we get informed about all symbols. */
+ link_info.notice_all = true;
+}
+\f
+/* Overlay handling. We handle overlays with some static variables. */
+
+/* The overlay virtual address. */
+static etree_type *overlay_vma;
+
+/* The overlay load address. */
+static etree_type *overlay_lma;
+
+/* An expression for the maximum section size seen so far. */
+static etree_type *overlay_max;
+
+/* A list of all the sections in this overlay. */
+
+struct overlay_list
+{
+ struct overlay_list *next;
+ lang_output_section_statement_type *os;
+};
+
+static struct overlay_list *overlay_list;
+
+/* Start handling an overlay. */
+
+void
+lang_enter_overlay (vma_expr, lma_expr)
+ etree_type *vma_expr;
+ etree_type *lma_expr;
+{
+ /* The grammar should prevent nested overlays from occurring. */
+ ASSERT (overlay_vma == NULL
+ && overlay_lma == NULL
+ && overlay_list == NULL
+ && overlay_max == NULL);
+
+ overlay_vma = vma_expr;
+ overlay_lma = lma_expr;
+}
+
+/* Start a section in an overlay. We handle this by calling
+ lang_enter_output_section_statement with the correct VMA and LMA. */
+
+void
+lang_enter_overlay_section (name)
+ const char *name;
+{
+ struct overlay_list *n;
+ etree_type *size;
+
+ lang_enter_output_section_statement (name, overlay_vma, normal_section,
+ 0, 0, 0, overlay_lma);
+
+ /* If this is the first section, then base the VMA and LMA of future
+ sections on this one. This will work correctly even if `.' is
+ used in the addresses. */
+ if (overlay_list == NULL)
+ {
+ overlay_vma = exp_nameop (ADDR, name);
+ overlay_lma = exp_nameop (LOADADDR, name);
+ }
+
+ /* Remember the section. */
+ n = (struct overlay_list *) xmalloc (sizeof *n);
+ n->os = current_section;
+ n->next = overlay_list;
+ overlay_list = n;
+
+ size = exp_nameop (SIZEOF, name);
+
+ /* Adjust the LMA for the next section. */
+ overlay_lma = exp_binop ('+', overlay_lma, size);
+
+ /* Arrange to work out the maximum section end address. */
+ if (overlay_max == NULL)
+ overlay_max = size;
+ else
+ overlay_max = exp_binop (MAX, overlay_max, size);
+}
+
+/* Finish a section in an overlay. There isn't any special to do
+ here. */
+
+void
+lang_leave_overlay_section (fill, phdrs)
+ bfd_vma fill;
+ struct lang_output_section_phdr_list *phdrs;
+{
+ const char *name;
+ char *clean, *s2;
+ const char *s1;
+ char *buf;
+
+ name = current_section->name;
+
+ lang_leave_output_section_statement (fill, "*default*", phdrs);
+
+ /* Define the magic symbols. */
+
+ clean = xmalloc (strlen (name) + 1);
+ s2 = clean;
+ for (s1 = name; *s1 != '\0'; s1++)
+ if (isalnum (*s1) || *s1 == '_')
+ *s2++ = *s1;
+ *s2 = '\0';
+
+ buf = xmalloc (strlen (clean) + sizeof "__load_start_");
+ sprintf (buf, "__load_start_%s", clean);
+ lang_add_assignment (exp_assop ('=', buf,
+ exp_nameop (LOADADDR, name)));
+
+ buf = xmalloc (strlen (clean) + sizeof "__load_stop_");
+ sprintf (buf, "__load_stop_%s", clean);
+ lang_add_assignment (exp_assop ('=', buf,
+ exp_binop ('+',
+ exp_nameop (LOADADDR, name),
+ exp_nameop (SIZEOF, name))));
+
+ free (clean);
+}
+
+/* Finish an overlay. If there are any overlay wide settings, this
+ looks through all the sections in the overlay and sets them. */
+
+void
+lang_leave_overlay (fill, memspec, phdrs)
+ bfd_vma fill;
+ const char *memspec;
+ struct lang_output_section_phdr_list *phdrs;
+{
+ lang_memory_region_type *region;
+ struct overlay_list *l;
+ struct lang_nocrossref *nocrossref;
+
+ if (memspec == NULL)
+ region = NULL;
+ else
+ region = lang_memory_region_lookup (memspec);
+
+ nocrossref = NULL;
+
+ l = overlay_list;
+ while (l != NULL)
+ {
+ struct lang_nocrossref *nc;
+ struct overlay_list *next;
+
+ if (fill != 0 && l->os->fill == 0)
+ l->os->fill = fill;
+ if (region != NULL && l->os->region == NULL)
+ l->os->region = region;
+ if (phdrs != NULL && l->os->phdrs == NULL)
+ l->os->phdrs = phdrs;
+
+ nc = (struct lang_nocrossref *) xmalloc (sizeof *nc);
+ nc->name = l->os->name;
+ nc->next = nocrossref;
+ nocrossref = nc;
+
+ next = l->next;
+ free (l);
+ l = next;
+ }
+
+ if (nocrossref != NULL)
+ lang_add_nocrossref (nocrossref);
+
+ /* Update . for the end of the overlay. */
+ lang_add_assignment (exp_assop ('=', ".",
+ exp_binop ('+', overlay_vma, overlay_max)));
+
+ overlay_vma = NULL;
+ overlay_lma = NULL;
+ overlay_list = NULL;
+ overlay_max = NULL;
+}