/* Linker command language support.
- Copyright (C) 1991, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1991, 92, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
#include "bfd.h"
#include "sysdep.h"
#include "libiberty.h"
+#include "obstack.h"
#include "bfdlink.h"
#include "ld.h"
PARAMS ((lang_assignment_statement_type *assignment,
lang_output_section_statement_type *output_section));
static void print_input_statement PARAMS ((lang_input_statement_type *statm));
+static boolean print_one_symbol PARAMS ((struct bfd_link_hash_entry *, PTR));
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));
lang_output_section_statement_type *output_section_statement,
fill_type fill, bfd_vma dot, boolean relax));
static void lang_finish PARAMS ((void));
+static void ignore_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));
lang_memory_region_lookup (name)
CONST char *CONST name;
{
-
- lang_memory_region_type *p = lang_memory_region_list;
+ lang_memory_region_type *p;
for (p = lang_memory_region_list;
p != (lang_memory_region_type *) NULL;
*lang_memory_region_list_tail = new;
lang_memory_region_list_tail = &new->next;
new->origin = 0;
+ new->flags = 0;
+ new->not_flags = 0;
new->length = ~(bfd_size_type)0;
new->current = 0;
new->had_full_message = false;
}
+lang_memory_region_type *
+lang_memory_default (section)
+ asection *section;
+{
+ lang_memory_region_type *p;
+
+ flagword sec_flags = section->flags;
+
+ /* Override SEC_DATA to mean a writable section. */
+ if (sec_flags & (SEC_ALLOC | SEC_READONLY | SEC_CODE) == SEC_ALLOC)
+ sec_flags |= SEC_DATA;
+
+ for (p = lang_memory_region_list;
+ p != (lang_memory_region_type *) NULL;
+ p = p->next)
+ {
+ if ((p->flags & sec_flags) != 0
+ && (p->not_flags & sec_flags) == 0)
+ {
+ return p;
+ }
+ }
+ return lang_memory_region_lookup ("*default*");
+}
+
lang_output_section_statement_type *
lang_output_section_find (name)
CONST char *CONST name;
return lookup;
}
+static void
+lang_map_flags (flag)
+ flagword flag;
+{
+ if (flag & SEC_ALLOC)
+ minfo ("a");
+
+ if (flag & SEC_CODE)
+ minfo ("x");
+
+ if (flag & SEC_READONLY)
+ minfo ("r");
+
+ if (flag & SEC_DATA)
+ minfo ("w");
+
+ if (flag & SEC_LOAD)
+ minfo ("l");
+}
+
void
lang_map ()
{
lang_memory_region_type *m;
minfo ("\nMemory Configuration\n\n");
- fprintf (config.map_file, "%-16s %-18s %-18s\n",
- "Name", "Origin", "Length");
+ fprintf (config.map_file, "%-16s %-18s %-18s %s\n",
+ "Name", "Origin", "Length", "Attributes");
for (m = lang_memory_region_list;
m != (lang_memory_region_type *) NULL;
++len;
}
- minfo ("0x%V\n", m->length);
+ minfo ("0x%V", m->length);
+ if (m->flags || m->not_flags)
+ {
+#ifndef BFD64
+ minfo (" ");
+#endif
+ if (m->flags)
+ {
+ print_space ();
+ lang_map_flags (m->flags);
+ }
+
+ if (m->not_flags)
+ {
+ minfo (" !");
+ lang_map_flags (m->not_flags);
+ }
+ }
+
+ print_nl ();
}
fprintf (config.map_file, "\nLinker script and memory map\n\n");
/*ARGSUSED*/
static void
-section_already_linked (abfd, sec, ignore)
+section_already_linked (abfd, sec, data)
bfd *abfd;
asection *sec;
- PTR ignore;
+ PTR data;
{
+ lang_input_statement_type *entry = (lang_input_statement_type *) data;
struct sec_link_once
{
struct sec_link_once *next;
const char *name;
struct sec_link_once *l;
+ /* If we are only reading symbols from this object, then we want to
+ discard all sections. */
+ if (entry->just_syms_flag)
+ {
+ sec->output_section = bfd_abs_section_ptr;
+ sec->output_offset = sec->vma;
+ return;
+ }
+
flags = bfd_get_section_flags (abfd, sec);
if ((flags & SEC_LINK_ONCE) == 0)
explicit actions, like foo.o(.text), bar.o(.text) and
foo.o(.text, .data). */
-/* Return true if the PATTERN argument is a wildcard pattern. */
+/* Return true if the PATTERN argument is a wildcard pattern.
+ Although backslashes are treated specially if a pattern contains
+ wildcards, we do not consider the mere presence of a backslash to
+ be enough to cause the the pattern to be treated as a wildcard.
+ That lets us handle DOS filenames more naturally. */
static boolean
wildcardp (pattern)
for (s = pattern; *s != '\0'; ++s)
if (*s == '?'
- || *s == '\\'
|| *s == '*'
|| *s == '[')
return true;
if (section->output_section == NULL)
{
+ boolean first;
lang_input_section_type *new;
+ flagword flags;
if (output->bfd_section == NULL)
- init_os (output);
+ {
+ init_os (output);
+ first = true;
+ }
+ else
+ first = false;
/* Add a section reference to the list */
new = new_stat (lang_input_section, ptr);
new->ifile = file;
section->output_section = output->bfd_section;
+ flags = section->flags;
+
/* 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.
+ the embedded SEC_NEVER_LOAD section into a fill. */
+
+ flags &= ~ SEC_NEVER_LOAD;
- 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. */
+ /* 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)));
+ if (! link_info.relocateable)
+ flags &= ~ (SEC_LINK_ONCE | SEC_LINK_DUPLICATES);
+
+ /* If this is not the first input section, and the SEC_READONLY
+ flag is not currently set, then don't set it just because the
+ input section has it set. */
+
+ if (! first && (section->output_section->flags & SEC_READONLY) == 0)
+ flags &= ~ SEC_READONLY;
+
+ section->output_section->flags |= flags;
+
+ /* If SEC_READONLY is not set in the input section, then clear
+ it from the output section. */
+ if ((section->flags & SEC_READONLY) == 0)
+ section->output_section->flags &= ~SEC_READONLY;
switch (output->sectype)
{
h = bfd_link_hash_lookup (link_info.hash, ptr->name, true, false, true);
if (h == (struct bfd_link_hash_entry *) NULL)
- einfo ("%P%F: bfd_link_hash_lookup failed: %E");
+ einfo ("%P%F: bfd_link_hash_lookup failed: %E\n");
if (h->type == bfd_link_hash_new)
{
h->type = bfd_link_hash_undefined;
size = QUAD_SIZE;
name = "QUAD";
break;
+ case SQUAD:
+ size = QUAD_SIZE;
+ name = "SQUAD";
+ break;
}
minfo ("0x%V %W %s 0x%v", addr, size, name, data->value);
if (os->children.head == NULL
|| os->children.head->next != NULL
|| os->children.head->header.type != lang_input_section_enum)
- einfo ("%P%X: Internal error on COFF shared library section %s",
+ einfo ("%P%X: Internal error on COFF shared library section %s\n",
os->name);
input = os->children.head->input_section.section;
*/
if (os->region == (lang_memory_region_type *) NULL)
{
- os->region = lang_memory_region_lookup ("*default*");
+ os->region = lang_memory_default (os->bfd_section);
}
dot = os->region->current;
if (os->section_alignment == -1)
- dot = align_power (dot, os->bfd_section->alignment_power);
+ {
+ bfd_vma olddot;
+
+ olddot = dot;
+ dot = align_power (dot, os->bfd_section->alignment_power);
+ if (dot != olddot && config.warn_section_align)
+ einfo ("%P: warning: changing start of section %s by %u bytes\n",
+ os->name, (unsigned int) (dot - olddot));
+ }
}
else
{
output_section_statement->bfd_section;
switch (s->data_statement.type)
- {
- case QUAD:
- size = QUAD_SIZE;
- break;
- case LONG:
- size = LONG_SIZE;
- break;
- case SHORT:
- size = SHORT_SIZE;
- break;
- case BYTE:
- size = BYTE_SIZE;
- break;
+ {
+ case QUAD:
+ case SQUAD:
+ size = QUAD_SIZE;
+ break;
+ case LONG:
+ size = LONG_SIZE;
+ break;
+ case SHORT:
+ size = SHORT_SIZE;
+ break;
+ case BYTE:
+ size = BYTE_SIZE;
+ break;
+ }
- }
dot += size;
output_section_statement->bfd_section->_raw_size += size;
/* The output section gets contents, and then we inspect for
switch (s->data_statement.type)
{
case QUAD:
+ case SQUAD:
dot += QUAD_SIZE;
break;
case LONG:
}
}
+/* This is a small function used when we want to ignore errors from
+ BFD. */
+
+static void
+#ifdef ANSI_PROTOTYPES
+ignore_bfd_errors (const char *s, ...)
+#else
+ignore_bfd_errors (s)
+ const char *s;
+#endif
+{
+ /* Don't do anything. */
+}
+
/* Check that the architecture of all the input files is compatible
with the output file. Also call the backend to let it do any
other checking that is needed. */
compatible = bfd_arch_get_compatible (input_bfd,
output_bfd);
if (compatible == NULL)
- einfo ("%P: warning: %s architecture of input file `%B' is incompatible with %s output\n",
- bfd_printable_name (input_bfd), input_bfd,
- bfd_printable_name (output_bfd));
-
+ {
+ if (command_line.warn_mismatch)
+ einfo ("%P: warning: %s architecture of input file `%B' is incompatible with %s output\n",
+ bfd_printable_name (input_bfd), input_bfd,
+ bfd_printable_name (output_bfd));
+ }
else
- bfd_merge_private_bfd_data (input_bfd, output_bfd);
+ {
+ bfd_error_handler_type pfn;
+
+ /* If we aren't supposed to warn about mismatched input
+ files, temporarily set the BFD error handler to a
+ function which will do nothing. We still want to call
+ bfd_merge_private_bfd_data, since it may set up
+ information which is needed in the output file. */
+ if (! command_line.warn_mismatch)
+ pfn = bfd_set_error_handler (ignore_bfd_errors);
+ if (! bfd_merge_private_bfd_data (input_bfd, output_bfd))
+ {
+ if (command_line.warn_mismatch)
+ einfo ("%E%X: failed to merge target specific data of file %B\n",
+ input_bfd);
+ }
+ if (! command_line.warn_mismatch)
+ bfd_set_error_handler (pfn);
+ }
}
}
/* Increase the size of the section. */
section->_raw_size += size;
- /* Make sure the section is allocated in memory. */
+ /* Make sure the section is allocated in memory, and make sure that
+ it is no longer a common section. */
section->flags |= SEC_ALLOC;
+ section->flags &= ~ SEC_IS_COMMON;
if (config.map_file != NULL)
{
void
lang_set_flags (ptr, flags)
- int *ptr;
+ lang_memory_region_type *ptr;
CONST char *flags;
{
- boolean state = false;
+ flagword *ptr_flags = &ptr->flags;
- *ptr = 0;
+ ptr->flags = ptr->not_flags = 0;
while (*flags)
{
- if (*flags == '!')
- {
- state = false;
- flags++;
- }
- else
- state = true;
switch (*flags)
{
- case 'R':
- /* ptr->flag_read = state; */
+ case '!':
+ ptr_flags = (ptr_flags == &ptr->flags) ? &ptr->not_flags : &ptr->flags;
break;
- case 'W':
- /* ptr->flag_write = state; */
+
+ case 'A': case 'a':
+ *ptr_flags |= SEC_ALLOC;
break;
- case 'X':
- /* ptr->flag_executable= state;*/
+
+ case 'R': case 'r':
+ *ptr_flags |= SEC_READONLY;
break;
- case 'L':
- case 'I':
- /* ptr->flag_loadable= state;*/
+
+ case 'W': case 'w':
+ *ptr_flags |= SEC_DATA;
break;
+
+ case 'X': case 'x':
+ *ptr_flags |= SEC_CODE;
+ break;
+
+ case 'L': case 'l':
+ case 'I': case 'i':
+ *ptr_flags |= SEC_LOAD;
+ break;
+
default:
einfo ("%P%F: invalid syntax in flags\n");
break;
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);
+ bfd_map_over_sections (entry->the_bfd, section_already_linked, (PTR) entry);
}
void
ldemul_after_open ();
+ /* Make sure that we're not mixing architectures. We call this
+ after all the input files have been opened, but before we do any
+ other processing, so that any operations merge_private_bfd_data
+ does on the output file will be known during the rest of the
+ link. */
+ lang_check ();
+
/* Build all sets based on the information gathered from the input
files. */
ldctor_build_sets ();
/* Size up the common data */
lang_common ();
- /* Run through the contours of the script and attatch input sections
+ /* Run through the contours of the script and attach input sections
to the correct output sections
*/
map_input_to_output_sections (statement_list.head, (char *) NULL,
(lang_output_section_statement_type *) NULL);
- /* Find any sections not attatched explicitly and handle them */
+ /* Find any sections not attached explicitly and handle them */
lang_place_orphans ();
ldemul_before_allocation ();
abs_output_section,
(fill_type) 0, (bfd_vma) 0);
- /* Make sure that we're not mixing architectures */
-
- lang_check ();
-
/* Final stuffs */
ldemul_finish ();
lang_statement_union_type *u;
alc = 10;
- secs = xmalloc (alc * sizeof (asection *));
+ secs = (asection **) xmalloc (alc * sizeof (asection *));
last = NULL;
for (l = lang_phdr_list; l != NULL; l = l->next)
{
if (c >= alc)
{
alc *= 2;
- secs = xrealloc (secs, alc * sizeof (asection *));
+ secs = ((asection **)
+ xrealloc (secs, alc * sizeof (asection *)));
}
secs[c] = os->bfd_section;
++c;
/* The overlay load address. */
static etree_type *overlay_lma;
+/* Whether nocrossrefs is set for this overlay. */
+static int overlay_nocrossrefs;
+
/* An expression for the maximum section size seen so far. */
static etree_type *overlay_max;
/* Start handling an overlay. */
void
-lang_enter_overlay (vma_expr, lma_expr)
+lang_enter_overlay (vma_expr, lma_expr, nocrossrefs)
etree_type *vma_expr;
etree_type *lma_expr;
+ int nocrossrefs;
{
/* The grammar should prevent nested overlays from occurring. */
ASSERT (overlay_vma == NULL
overlay_vma = vma_expr;
overlay_lma = lma_expr;
+ overlay_nocrossrefs = nocrossrefs;
}
/* Start a section in an overlay. We handle this by calling
l = overlay_list;
while (l != NULL)
{
- struct lang_nocrossref *nc;
struct overlay_list *next;
if (fill != 0 && l->os->fill == 0)
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;
+ if (overlay_nocrossrefs)
+ {
+ struct lang_nocrossref *nc;
+
+ nc = (struct lang_nocrossref *) xmalloc (sizeof *nc);
+ nc->name = l->os->name;
+ nc->next = nocrossref;
+ nocrossref = nc;
+ }
next = l->next;
free (l);
overlay_vma = NULL;
overlay_lma = NULL;
+ overlay_nocrossrefs = 0;
overlay_list = NULL;
overlay_max = NULL;
}
+\f
+/* Version handling. This is only useful for ELF. */
+
+/* This global variable holds the version tree that we build. */
+
+struct bfd_elf_version_tree *lang_elf_version_info;
+
+/* This is called for each variable name or match expression. */
+
+struct bfd_elf_version_expr *
+lang_new_vers_regex (orig, new)
+ struct bfd_elf_version_expr *orig;
+ const char *new;
+{
+ struct bfd_elf_version_expr *ret;
+
+ ret = (struct bfd_elf_version_expr *) xmalloc (sizeof *ret);
+ ret->next = orig;
+ ret->match = new;
+ return ret;
+}
+
+/* This is called for each set of variable names and match
+ expressions. */
+
+struct bfd_elf_version_tree *
+lang_new_vers_node (globals, locals)
+ struct bfd_elf_version_expr *globals;
+ struct bfd_elf_version_expr *locals;
+{
+ struct bfd_elf_version_tree *ret;
+
+ ret = (struct bfd_elf_version_tree *) xmalloc (sizeof *ret);
+ ret->next = NULL;
+ ret->name = NULL;
+ ret->vernum = 0;
+ ret->globals = globals;
+ ret->locals = locals;
+ ret->deps = NULL;
+ ret->name_indx = (unsigned int) -1;
+ ret->used = 0;
+ return ret;
+}
+
+/* This static variable keeps track of version indices. */
+
+static int version_index;
+
+/* This is called when we know the name and dependencies of the
+ version. */
+
+void
+lang_register_vers_node (name, version, deps)
+ const char *name;
+ struct bfd_elf_version_tree *version;
+ struct bfd_elf_version_deps *deps;
+{
+ struct bfd_elf_version_tree *t, **pp;
+ struct bfd_elf_version_expr *e1;
+
+ /* Make sure this node has a unique name. */
+ for (t = lang_elf_version_info; t != NULL; t = t->next)
+ if (strcmp (t->name, name) == 0)
+ einfo ("%X%P: duplicate version tag `%s'\n", name);
+
+ /* Check the global and local match names, and make sure there
+ aren't any duplicates. */
+
+ for (e1 = version->globals; e1 != NULL; e1 = e1->next)
+ {
+ for (t = lang_elf_version_info; t != NULL; t = t->next)
+ {
+ struct bfd_elf_version_expr *e2;
+
+ for (e2 = t->locals; e2 != NULL; e2 = e2->next)
+ if (strcmp (e1->match, e2->match) == 0)
+ einfo ("%X%P: duplicate expression `%s' in version information\n",
+ e1->match);
+ }
+ }
+
+ for (e1 = version->locals; e1 != NULL; e1 = e1->next)
+ {
+ for (t = lang_elf_version_info; t != NULL; t = t->next)
+ {
+ struct bfd_elf_version_expr *e2;
+
+ for (e2 = t->globals; e2 != NULL; e2 = e2->next)
+ if (strcmp (e1->match, e2->match) == 0)
+ einfo ("%X%P: duplicate expression `%s' in version information\n",
+ e1->match);
+ }
+ }
+
+ version->deps = deps;
+ version->name = name;
+ ++version_index;
+ version->vernum = version_index;
+
+ for (pp = &lang_elf_version_info; *pp != NULL; pp = &(*pp)->next)
+ ;
+ *pp = version;
+}
+
+/* This is called when we see a version dependency. */
+
+struct bfd_elf_version_deps *
+lang_add_vers_depend (list, name)
+ struct bfd_elf_version_deps *list;
+ const char *name;
+{
+ struct bfd_elf_version_deps *ret;
+ struct bfd_elf_version_tree *t;
+
+ ret = (struct bfd_elf_version_deps *) xmalloc (sizeof *ret);
+ ret->next = list;
+
+ for (t = lang_elf_version_info; t != NULL; t = t->next)
+ {
+ if (strcmp (t->name, name) == 0)
+ {
+ ret->version_needed = t;
+ return ret;
+ }
+ }
+
+ einfo ("%X%P: unable to find version dependency `%s'\n", name);
+
+ return ret;
+}