summaryrefslogtreecommitdiff
path: root/contrib/binutils/ld/ldlang.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/binutils/ld/ldlang.c')
-rw-r--r--contrib/binutils/ld/ldlang.c5470
1 files changed, 0 insertions, 5470 deletions
diff --git a/contrib/binutils/ld/ldlang.c b/contrib/binutils/ld/ldlang.c
deleted file mode 100644
index 0c086014e2a0..000000000000
--- a/contrib/binutils/ld/ldlang.c
+++ /dev/null
@@ -1,5470 +0,0 @@
-/* Linker command language support.
- Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004
- Free Software Foundation, Inc.
-
- This file is part of GLD, the Gnu Linker.
-
- GLD is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- GLD is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- 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. */
-
-#include "bfd.h"
-#include "sysdep.h"
-#include "libiberty.h"
-#include "safe-ctype.h"
-#include "obstack.h"
-#include "bfdlink.h"
-
-#include "ld.h"
-#include "ldmain.h"
-#include "ldexp.h"
-#include "ldlang.h"
-#include <ldgram.h>
-#include "ldlex.h"
-#include "ldmisc.h"
-#include "ldctor.h"
-#include "ldfile.h"
-#include "ldemul.h"
-#include "fnmatch.h"
-#include "demangle.h"
-#include "hashtab.h"
-
-#ifndef offsetof
-#define offsetof(TYPE, MEMBER) ((size_t) & (((TYPE*) 0)->MEMBER))
-#endif
-
-/* Locals variables. */
-static struct obstack stat_obstack;
-
-#define obstack_chunk_alloc xmalloc
-#define obstack_chunk_free free
-static const char *startup_file;
-static lang_statement_list_type input_file_chain;
-static bfd_boolean placed_commons = FALSE;
-static lang_output_section_statement_type *default_common_section;
-static bfd_boolean map_option_f;
-static bfd_vma print_dot;
-static lang_input_statement_type *first_file;
-static const char *current_target;
-static const char *output_target;
-static lang_statement_list_type statement_list;
-static struct lang_phdr *lang_phdr_list;
-static struct bfd_hash_table lang_definedness_table;
-
-/* Forward declarations. */
-static void exp_init_os (etree_type *);
-static bfd_boolean wildcardp (const char *);
-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 void print_statement (lang_statement_union_type *,
- lang_output_section_statement_type *);
-static void print_statement_list (lang_statement_union_type *,
- lang_output_section_statement_type *);
-static void print_statements (void);
-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);
-
-typedef void (*callback_t) (lang_wild_statement_type *, struct wildcard_list *,
- asection *, lang_input_statement_type *, void *);
-
-/* Exported variables. */
-lang_output_section_statement_type *abs_output_section;
-lang_statement_list_type lang_output_section_statement;
-lang_statement_list_type *stat_ptr = &statement_list;
-lang_statement_list_type file_chain = { NULL, NULL };
-struct bfd_sym_chain entry_symbol = { NULL, NULL };
-const char *entry_section = ".text";
-bfd_boolean entry_from_cmdline;
-bfd_boolean lang_has_input_file = FALSE;
-bfd_boolean had_output_filename = FALSE;
-bfd_boolean lang_float_flag = FALSE;
-bfd_boolean delete_output_file_on_failure = FALSE;
-struct lang_nocrossrefs *nocrossref_list;
-struct unique_sections *unique_section_list;
-static bfd_boolean ldlang_sysrooted_script = FALSE;
-int lang_statement_iteration = 0;
-
-etree_type *base; /* Relocation base - or null */
-
-#define new_stat(x, y) \
- (x##_type *) new_statement (x##_enum, sizeof (x##_type), y)
-
-#define outside_section_address(q) \
- ((q)->output_offset + (q)->output_section->vma)
-
-#define outside_symbol_address(q) \
- ((q)->value + outside_section_address (q->section))
-
-#define SECTION_NAME_MAP_LENGTH (16)
-
-void *
-stat_alloc (size_t size)
-{
- return obstack_alloc (&stat_obstack, size);
-}
-
-bfd_boolean
-unique_section_p (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
-walk_wild_section (lang_wild_statement_type *ptr,
- lang_input_statement_type *file,
- callback_t callback,
- void *data)
-{
- asection *s;
-
- if (file->just_syms_flag)
- return;
-
- for (s = file->the_bfd->sections; s != NULL; s = s->next)
- {
- struct wildcard_list *sec;
-
- sec = ptr->section_list;
- if (sec == NULL)
- (*callback) (ptr, sec, s, file, data);
-
- while (sec != NULL)
- {
- bfd_boolean skip = FALSE;
- struct name_list *list_tmp;
-
- /* Don't process sections from files which were
- excluded. */
- for (list_tmp = sec->spec.exclude_name_list;
- list_tmp;
- list_tmp = list_tmp->next)
- {
- if (wildcardp (list_tmp->name))
- skip = fnmatch (list_tmp->name, file->filename, 0) == 0;
- else
- skip = strcmp (list_tmp->name, file->filename) == 0;
-
- /* If this file is part of an archive, and the archive is
- excluded, exclude this file. */
- if (! skip && file->the_bfd != NULL
- && file->the_bfd->my_archive != NULL
- && file->the_bfd->my_archive->filename != NULL)
- {
- if (wildcardp (list_tmp->name))
- skip = fnmatch (list_tmp->name,
- file->the_bfd->my_archive->filename,
- 0) == 0;
- else
- skip = strcmp (list_tmp->name,
- file->the_bfd->my_archive->filename) == 0;
- }
-
- if (skip)
- break;
- }
-
- if (!skip && sec->spec.name != NULL)
- {
- const char *sname = bfd_get_section_name (file->the_bfd, s);
-
- if (wildcardp (sec->spec.name))
- skip = fnmatch (sec->spec.name, sname, 0) != 0;
- else
- skip = strcmp (sec->spec.name, sname) != 0;
- }
-
- if (!skip)
- (*callback) (ptr, sec, s, file, data);
-
- sec = sec->next;
- }
- }
-}
-
-/* Handle a wild statement for a single file F. */
-
-static void
-walk_wild_file (lang_wild_statement_type *s,
- lang_input_statement_type *f,
- callback_t callback,
- void *data)
-{
- if (f->the_bfd == NULL
- || ! bfd_check_format (f->the_bfd, bfd_archive))
- walk_wild_section (s, f, callback, data);
- 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, 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)
- {
- walk_wild_section (s, member->usrdata, callback, data);
- }
-
- member = bfd_openr_next_archived_file (f->the_bfd, member);
- }
- }
-}
-
-static void
-walk_wild (lang_wild_statement_type *s, callback_t callback, void *data)
-{
- const char *file_spec = s->filename;
-
- if (file_spec == NULL)
- {
- /* Perform the iteration over all files in the list. */
- LANG_FOR_EACH_INPUT_STATEMENT (f)
- {
- walk_wild_file (s, f, callback, data);
- }
- }
- else if (wildcardp (file_spec))
- {
- LANG_FOR_EACH_INPUT_STATEMENT (f)
- {
- if (fnmatch (file_spec, f->filename, FNM_FILE_NAME) == 0)
- walk_wild_file (s, f, callback, data);
- }
- }
- else
- {
- lang_input_statement_type *f;
-
- /* Perform the iteration over a single file. */
- f = lookup_name (file_spec);
- if (f)
- walk_wild_file (s, f, callback, data);
- }
-}
-
-/* lang_for_each_statement walks the parse tree and calls the provided
- function for each node. */
-
-static void
-lang_for_each_statement_worker (void (*func) (lang_statement_union_type *),
- lang_statement_union_type *s)
-{
- for (; s != NULL; s = s->header.next)
- {
- func (s);
-
- switch (s->header.type)
- {
- case lang_constructors_statement_enum:
- lang_for_each_statement_worker (func, constructor_list.head);
- break;
- case lang_output_section_statement_enum:
- lang_for_each_statement_worker
- (func,
- s->output_section_statement.children.head);
- break;
- case lang_wild_statement_enum:
- lang_for_each_statement_worker
- (func,
- s->wild_statement.children.head);
- break;
- case lang_group_statement_enum:
- lang_for_each_statement_worker (func,
- s->group_statement.children.head);
- break;
- case lang_data_statement_enum:
- case lang_reloc_statement_enum:
- case lang_object_symbols_statement_enum:
- case lang_output_statement_enum:
- case lang_target_statement_enum:
- case lang_input_section_enum:
- case lang_input_statement_enum:
- case lang_assignment_statement_enum:
- case lang_padding_statement_enum:
- case lang_address_statement_enum:
- case lang_fill_statement_enum:
- break;
- default:
- FAIL ();
- break;
- }
- }
-}
-
-void
-lang_for_each_statement (void (*func) (lang_statement_union_type *))
-{
- lang_for_each_statement_worker (func, statement_list.head);
-}
-
-/*----------------------------------------------------------------------*/
-
-void
-lang_list_init (lang_statement_list_type *list)
-{
- list->head = NULL;
- list->tail = &list->head;
-}
-
-/* Build a new statement node for the parse tree. */
-
-static lang_statement_union_type *
-new_statement (enum statement_enum type,
- size_t size,
- lang_statement_list_type *list)
-{
- lang_statement_union_type *new;
-
- new = stat_alloc (size);
- new->header.type = type;
- new->header.next = NULL;
- lang_statement_append (list, new, &new->header.next);
- return new;
-}
-
-/* Build a new input file node for the language. There are several
- ways in which we treat an input file, eg, we only look at symbols,
- or prefix it with a -l etc.
-
- We can be supplied with requests for input files more than once;
- they may, for example be split over several lines like foo.o(.text)
- foo.o(.data) etc, so when asked for a file we check that we haven't
- got it already so we don't duplicate the bfd. */
-
-static lang_input_statement_type *
-new_afile (const char *name,
- lang_input_file_enum_type file_type,
- const char *target,
- bfd_boolean add_to_list)
-{
- lang_input_statement_type *p;
-
- if (add_to_list)
- p = new_stat (lang_input_statement, stat_ptr);
- else
- {
- p = stat_alloc (sizeof (lang_input_statement_type));
- p->header.next = NULL;
- }
-
- lang_has_input_file = TRUE;
- p->target = target;
- p->sysrooted = FALSE;
- switch (file_type)
- {
- case lang_input_file_is_symbols_only_enum:
- p->filename = name;
- p->is_archive = FALSE;
- p->real = TRUE;
- p->local_sym_name = name;
- p->just_syms_flag = TRUE;
- p->search_dirs_flag = FALSE;
- break;
- case lang_input_file_is_fake_enum:
- p->filename = name;
- p->is_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->filename = name;
- p->real = TRUE;
- p->local_sym_name = concat ("-l", name, NULL);
- p->just_syms_flag = FALSE;
- p->search_dirs_flag = TRUE;
- break;
- case lang_input_file_is_marker_enum:
- p->filename = name;
- p->is_archive = FALSE;
- p->real = FALSE;
- p->local_sym_name = name;
- p->just_syms_flag = FALSE;
- p->search_dirs_flag = TRUE;
- break;
- case lang_input_file_is_search_file_enum:
- p->sysrooted = ldlang_sysrooted_script;
- p->filename = name;
- p->is_archive = FALSE;
- p->real = TRUE;
- p->local_sym_name = name;
- p->just_syms_flag = FALSE;
- p->search_dirs_flag = TRUE;
- break;
- case lang_input_file_is_file_enum:
- p->filename = name;
- p->is_archive = FALSE;
- p->real = TRUE;
- p->local_sym_name = name;
- p->just_syms_flag = FALSE;
- p->search_dirs_flag = FALSE;
- break;
- default:
- FAIL ();
- }
- p->the_bfd = NULL;
- p->asymbols = NULL;
- p->next_real_file = NULL;
- p->next = NULL;
- p->symbol_count = 0;
- p->dynamic = config.dynamic_link;
- p->as_needed = as_needed;
- p->whole_archive = whole_archive;
- p->loaded = FALSE;
- lang_statement_append (&input_file_chain,
- (lang_statement_union_type *) p,
- &p->next_real_file);
- return p;
-}
-
-lang_input_statement_type *
-lang_add_input_file (const char *name,
- lang_input_file_enum_type file_type,
- const char *target)
-{
- lang_has_input_file = TRUE;
- return new_afile (name, file_type, target, TRUE);
-}
-
-/* Build enough state so that the parser can build its tree. */
-
-void
-lang_init (void)
-{
- obstack_begin (&stat_obstack, 1000);
-
- stat_ptr = &statement_list;
-
- lang_list_init (stat_ptr);
-
- lang_list_init (&input_file_chain);
- lang_list_init (&lang_output_section_statement);
- lang_list_init (&file_chain);
- first_file = lang_add_input_file (NULL, lang_input_file_is_marker_enum,
- NULL);
- abs_output_section =
- lang_output_section_statement_lookup (BFD_ABS_SECTION_NAME);
-
- abs_output_section->bfd_section = bfd_abs_section_ptr;
-
- /* The value "3" is ad-hoc, somewhat related to the expected number of
- DEFINED expressions in a linker script. For most default linker
- scripts, there are none. Why a hash table then? Well, it's somewhat
- simpler to re-use working machinery than using a linked list in terms
- of code-complexity here in ld, besides the initialization which just
- looks like other code here. */
- if (bfd_hash_table_init_n (&lang_definedness_table,
- lang_definedness_newfunc, 3) != TRUE)
- einfo (_("%P%F: out of memory during initialization"));
-
- /* Callers of exp_fold_tree need to increment this. */
- lang_statement_iteration = 0;
-}
-
-/*----------------------------------------------------------------------
- A region is an area of memory declared with the
- MEMORY { name:org=exp, len=exp ... }
- syntax.
-
- We maintain a list of all the regions here.
-
- If no regions are specified in the script, then the default is used
- which is created when looked up to be the entire data space.
-
- If create is true we are creating a region inside a MEMORY block.
- In this case it is probably an error to create a region that has
- already been created. If we are not inside a MEMORY block it is
- dubious to use an undeclared region name (except DEFAULT_MEMORY_REGION)
- and so we issue a warning. */
-
-static lang_memory_region_type *lang_memory_region_list;
-static lang_memory_region_type **lang_memory_region_list_tail = &lang_memory_region_list;
-
-lang_memory_region_type *
-lang_memory_region_lookup (const char *const name, bfd_boolean create)
-{
- lang_memory_region_type *p;
- lang_memory_region_type *new;
-
- /* NAME is NULL for LMA memspecs if no region was specified. */
- if (name == NULL)
- return NULL;
-
- for (p = lang_memory_region_list; p != NULL; p = p->next)
- if (strcmp (p->name, name) == 0)
- {
- if (create)
- einfo (_("%P:%S: warning: redeclaration of memory region '%s'\n"), name);
- return p;
- }
-
-#if 0
- /* This code used to always use the first region in the list as the
- default region. I changed it to instead use a region
- encompassing all of memory as the default region. This permits
- NOLOAD sections to work reasonably without requiring a region.
- People should specify what region they mean, if they really want
- a region. */
- if (strcmp (name, DEFAULT_MEMORY_REGION) == 0)
- {
- if (lang_memory_region_list != NULL)
- return lang_memory_region_list;
- }
-#endif
-
- if (!create && strcmp (name, DEFAULT_MEMORY_REGION))
- einfo (_("%P:%S: warning: memory region %s not declared\n"), name);
-
- new = stat_alloc (sizeof (lang_memory_region_type));
-
- new->name = xstrdup (name);
- new->next = 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;
-
- return new;
-}
-
-static lang_memory_region_type *
-lang_memory_default (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 != NULL; p = p->next)
- {
- if ((p->flags & sec_flags) != 0
- && (p->not_flags & sec_flags) == 0)
- {
- return p;
- }
- }
- return lang_memory_region_lookup (DEFAULT_MEMORY_REGION, FALSE);
-}
-
-lang_output_section_statement_type *
-lang_output_section_find (const char *const name)
-{
- lang_statement_union_type *u;
- lang_output_section_statement_type *lookup;
-
- for (u = lang_output_section_statement.head; u != NULL; u = lookup->next)
- {
- lookup = &u->output_section_statement;
- if (strcmp (name, lookup->name) == 0)
- return lookup;
- }
- return NULL;
-}
-
-lang_output_section_statement_type *
-lang_output_section_statement_lookup (const char *const name)
-{
- lang_output_section_statement_type *lookup;
-
- lookup = lang_output_section_find (name);
- if (lookup == NULL)
- {
- lookup = new_stat (lang_output_section_statement, stat_ptr);
- lookup->region = NULL;
- lookup->lma_region = NULL;
- lookup->fill = 0;
- lookup->block_value = 1;
- lookup->name = name;
-
- lookup->next = NULL;
- lookup->bfd_section = NULL;
- lookup->processed = 0;
- lookup->sectype = normal_section;
- lookup->addr_tree = NULL;
- lang_list_init (&lookup->children);
-
- lookup->memspec = NULL;
- lookup->flags = 0;
- lookup->subsection_alignment = -1;
- lookup->section_alignment = -1;
- lookup->load_base = NULL;
- lookup->update_dot_tree = NULL;
- lookup->phdrs = NULL;
-
- lang_statement_append (&lang_output_section_statement,
- (lang_statement_union_type *) lookup,
- &lookup->next);
- }
- return lookup;
-}
-
-static void
-lang_map_flags (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 (void)
-{
- lang_memory_region_type *m;
-
- minfo (_("\nMemory Configuration\n\n"));
- fprintf (config.map_file, "%-16s %-18s %-18s %s\n",
- _("Name"), _("Origin"), _("Length"), _("Attributes"));
-
- for (m = lang_memory_region_list; m != NULL; m = m->next)
- {
- char buf[100];
- int len;
-
- 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", 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"));
-
- print_statements ();
-}
-
-/* Initialize an output section. */
-
-static void
-init_os (lang_output_section_statement_type *s)
-{
- 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\n"), DISCARD_SECTION_NAME);
-
- new = stat_alloc (sizeof (section_userdata_type));
-
- s->bfd_section = bfd_get_section_by_name (output_bfd, s->name);
- if (s->bfd_section == NULL)
- s->bfd_section = bfd_make_section (output_bfd, s->name);
- if (s->bfd_section == NULL)
- {
- einfo (_("%P%F: output format %s cannot represent section called %s\n"),
- output_bfd->xvec->name, s->name);
- }
- s->bfd_section->output_section = s->bfd_section;
-
- /* We initialize an output sections output offset to minus its own
- vma to allow us to output a section through itself. */
- s->bfd_section->output_offset = 0;
- get_userdata (s->bfd_section) = 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);
-
- if (s->load_base != NULL)
- exp_init_os (s->load_base);
-}
-
-/* Make sure that all output sections mentioned in an expression are
- initialized. */
-
-static void
-exp_init_os (etree_type *exp)
-{
- switch (exp->type.node_class)
- {
- case etree_assign:
- exp_init_os (exp->assign.src);
- break;
-
- 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;
-
- case etree_assert:
- exp_init_os (exp->assert_s.child);
- break;
-
- 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 section, and
- arrange to discard it if a section of the same name has already
- been linked. If the section has COMDAT information, then it uses
- that to decide whether the section should be included. 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.
- section_already_linked is called via bfd_map_over_sections. */
-
-/* This is the shape of the elements inside the already_linked hash
- table. It maps a name onto a list of already_linked elements with
- the same name. It's possible to get more than one element in a
- list if the COMDAT sections have different names. */
-
-struct already_linked_hash_entry
-{
- struct bfd_hash_entry root;
- struct already_linked *entry;
-};
-
-struct already_linked
-{
- struct already_linked *next;
- asection *sec;
-};
-
-/* The hash table. */
-
-static struct bfd_hash_table already_linked_table;
-
-static void
-section_already_linked (bfd *abfd, asection *sec, void *data)
-{
- lang_input_statement_type *entry = data;
- flagword flags;
- const char *name;
- struct already_linked *l;
- struct already_linked_hash_entry *already_linked_list;
-
- /* If we are only reading symbols from this object, then we want to
- discard all sections. */
- if (entry->just_syms_flag)
- {
- bfd_link_just_syms (sec, &link_info);
- return;
- }
-
- flags = bfd_get_section_flags (abfd, sec);
-
- if ((flags & SEC_LINK_ONCE) == 0)
- return;
-
- /* 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 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 relocatable link
- causes trouble for MIPS ELF, which relies on link once semantics
- to handle the .reginfo section correctly. */
-
- name = bfd_get_section_name (abfd, sec);
-
- already_linked_list =
- ((struct already_linked_hash_entry *)
- bfd_hash_lookup (&already_linked_table, name, TRUE, FALSE));
-
- for (l = already_linked_list->entry; l != NULL; l = l->next)
- {
- if (sec->comdat == NULL
- || l->sec->comdat == NULL
- || strcmp (sec->comdat->name, l->sec->comdat->name) == 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:
- if (sec->comdat == NULL)
- einfo (_("%P: %B: warning: ignoring duplicate section `%s'\n"),
- abfd, name);
- else
- einfo (_("%P: %B: warning: ignoring duplicate `%s' section symbol `%s'\n"),
- abfd, name, sec->comdat->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 lang_add_section
- does not create a lang_input_section structure for this
- section. Since there might be a symbol in the section
- being discarded, we must retain a pointer to the section
- which we are really going to use. */
- sec->output_section = bfd_abs_section_ptr;
- sec->kept_section = l->sec;
-
- if (flags & SEC_GROUP)
- bfd_discard_group (abfd, sec);
-
- return;
- }
- }
-
- /* This is the first section with this name. Record it. Allocate
- the memory from the same obstack as the hash table is kept in. */
-
- l = bfd_hash_allocate (&already_linked_table, sizeof *l);
-
- l->sec = sec;
- l->next = already_linked_list->entry;
- already_linked_list->entry = l;
-}
-
-/* Support routines for the hash table used by section_already_linked,
- initialize the table, fill in an entry and remove the table. */
-
-static struct bfd_hash_entry *
-already_linked_newfunc (struct bfd_hash_entry *entry ATTRIBUTE_UNUSED,
- struct bfd_hash_table *table,
- const char *string ATTRIBUTE_UNUSED)
-{
- struct already_linked_hash_entry *ret =
- bfd_hash_allocate (table, sizeof (struct already_linked_hash_entry));
-
- ret->entry = NULL;
-
- return &ret->root;
-}
-
-static void
-already_linked_table_init (void)
-{
- if (! bfd_hash_table_init_n (&already_linked_table,
- already_linked_newfunc,
- 42))
- einfo (_("%P%F: Failed to create hash table\n"));
-}
-
-static void
-already_linked_table_free (void)
-{
- bfd_hash_table_free (&already_linked_table);
-}
-
-/* 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.
- 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 pattern to be treated as a wildcard.
- That lets us handle DOS filenames more naturally. */
-
-static bfd_boolean
-wildcardp (const char *pattern)
-{
- const char *s;
-
- for (s = pattern; *s != '\0'; ++s)
- if (*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
-lang_add_section (lang_statement_list_type *ptr,
- asection *section,
- lang_output_section_statement_type *output,
- lang_input_statement_type *file)
-{
- flagword flags;
- bfd_boolean discard;
-
- flags = bfd_get_section_flags (section->owner, section);
-
- discard = FALSE;
-
- /* Discard sections marked with SEC_EXCLUDE if we are doing a final
- link. Discard debugging sections marked with SEC_EXCLUDE on a
- relocatable link too. */
- if ((flags & SEC_EXCLUDE) != 0
- && ((flags & SEC_DEBUGGING) != 0 || !link_info.relocatable))
- 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)
- {
- if (section->output_section == NULL)
- {
- /* This prevents future calls from assigning this section. */
- section->output_section = bfd_abs_section_ptr;
- }
- return;
- }
-
- if (section->output_section == NULL)
- {
- bfd_boolean first;
- lang_input_section_type *new;
- flagword flags;
-
- if (output->bfd_section == NULL)
- init_os (output);
-
- first = ! output->bfd_section->linker_has_input;
- output->bfd_section->linker_has_input = 1;
-
- /* 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;
-
- 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. */
-
- 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 (! link_info.relocatable)
- 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;
-
- /* 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)
- section->output_section->flags &= ~SEC_READONLY;
-
- 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;
- }
-
- /* Copy over SEC_SMALL_DATA. */
- if (section->flags & SEC_SMALL_DATA)
- section->output_section->flags |= SEC_SMALL_DATA;
-
- if (section->alignment_power > output->bfd_section->alignment_power)
- output->bfd_section->alignment_power = section->alignment_power;
-
- /* If supplied an alignment, then force it. */
- if (output->section_alignment != -1)
- output->bfd_section->alignment_power = output->section_alignment;
-
- if (section->flags & SEC_BLOCK)
- {
- section->output_section->flags |= SEC_BLOCK;
- /* FIXME: This value should really be obtained from the bfd... */
- output->block_value = 128;
- }
- }
-}
-
-/* Handle wildcard sorting. This returns the lang_input_section which
- should follow the one we are going to create for SECTION and FILE,
- based on the sorting requirements of WILD. It returns NULL if the
- new section should just go at the end of the current list. */
-
-static lang_statement_union_type *
-wild_sort (lang_wild_statement_type *wild,
- struct wildcard_list *sec,
- lang_input_statement_type *file,
- asection *section)
-{
- const char *section_name;
- lang_statement_union_type *l;
-
- if (!wild->filenames_sorted && (sec == NULL || !sec->spec.sorted))
- return NULL;
-
- section_name = bfd_get_section_name (file->the_bfd, section);
- for (l = wild->children.head; l != NULL; l = l->header.next)
- {
- lang_input_section_type *ls;
-
- if (l->header.type != lang_input_section_enum)
- continue;
- ls = &l->input_section;
-
- /* Sorting by filename takes precedence over sorting by section
- name. */
-
- if (wild->filenames_sorted)
- {
- const char *fn, *ln;
- bfd_boolean fa, la;
- int i;
-
- /* The PE support for the .idata section as generated by
- dlltool assumes that files will be sorted by the name of
- the archive and then the name of the file within the
- archive. */
-
- if (file->the_bfd != NULL
- && bfd_my_archive (file->the_bfd) != NULL)
- {
- fn = bfd_get_filename (bfd_my_archive (file->the_bfd));
- fa = TRUE;
- }
- else
- {
- fn = file->filename;
- fa = FALSE;
- }
-
- if (ls->ifile->the_bfd != NULL
- && bfd_my_archive (ls->ifile->the_bfd) != NULL)
- {
- ln = bfd_get_filename (bfd_my_archive (ls->ifile->the_bfd));
- la = TRUE;
- }
- else
- {
- ln = ls->ifile->filename;
- la = FALSE;
- }
-
- i = strcmp (fn, ln);
- if (i > 0)
- continue;
- else if (i < 0)
- break;
-
- if (fa || la)
- {
- if (fa)
- fn = file->filename;
- if (la)
- ln = ls->ifile->filename;
-
- i = strcmp (fn, ln);
- if (i > 0)
- continue;
- else if (i < 0)
- break;
- }
- }
-
- /* Here either the files are not sorted by name, or we are
- looking at the sections for this file. */
-
- if (sec != NULL && sec->spec.sorted)
- {
- if (strcmp (section_name,
- bfd_get_section_name (ls->ifile->the_bfd,
- ls->section))
- < 0)
- break;
- }
- }
-
- return l;
-}
-
-/* Expand a wild statement for a particular FILE. SECTION may be
- NULL, in which case it is a wild card. */
-
-static void
-output_section_callback (lang_wild_statement_type *ptr,
- struct wildcard_list *sec,
- asection *section,
- lang_input_statement_type *file,
- void *output)
-{
- lang_statement_union_type *before;
-
- /* Exclude sections that match UNIQUE_SECTION_LIST. */
- if (unique_section_p (bfd_get_section_name (file->the_bfd, section)))
- return;
-
- /* If the wild pattern was marked KEEP, the member sections
- should be as well. */
- if (ptr->keep_sections)
- section->flags |= SEC_KEEP;
-
- before = wild_sort (ptr, sec, file, section);
-
- /* Here BEFORE points to the lang_input_section which
- should follow the one we are about to add. If BEFORE
- is NULL, then the section should just go at the end
- of the current list. */
-
- if (before == NULL)
- lang_add_section (&ptr->children, section,
- (lang_output_section_statement_type *) output,
- file);
- else
- {
- lang_statement_list_type list;
- lang_statement_union_type **pp;
-
- lang_list_init (&list);
- lang_add_section (&list, section,
- (lang_output_section_statement_type *) output,
- file);
-
- /* If we are discarding the section, LIST.HEAD will
- be NULL. */
- if (list.head != NULL)
- {
- ASSERT (list.head->header.next == NULL);
-
- for (pp = &ptr->children.head;
- *pp != before;
- pp = &(*pp)->header.next)
- ASSERT (*pp != NULL);
-
- list.head->header.next = *pp;
- *pp = list.head;
- }
- }
-}
-
-/* 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. */
-
-static lang_input_statement_type *
-lookup_name (const char *name)
-{
- lang_input_statement_type *search;
-
- for (search = (lang_input_statement_type *) input_file_chain.head;
- search != NULL;
- search = (lang_input_statement_type *) search->next_real_file)
- {
- /* Use the local_sym_name as the name of the file that has
- already been loaded as filename might have been transformed
- via the search directory lookup mechanism. */
- const char * filename = search->local_sym_name;
-
- if (filename == NULL && name == NULL)
- return search;
- if (filename != NULL
- && name != NULL
- && strcmp (filename, name) == 0)
- break;
- }
-
- if (search == NULL)
- search = new_afile (name, lang_input_file_is_search_file_enum, default_target,
- FALSE);
-
- /* If we have already added this file, or this file is not real
- (FIXME: can that ever actually happen?) or the name is NULL
- (FIXME: can that ever actually happen?) don't add this file. */
- if (search->loaded
- || ! search->real
- || search->filename == NULL)
- return search;
-
- if (! load_symbols (search, NULL))
- return NULL;
-
- return search;
-}
-
-/* Get the symbols for an input file. */
-
-static bfd_boolean
-load_symbols (lang_input_statement_type *entry,
- lang_statement_list_type *place)
-{
- char **matching;
-
- if (entry->loaded)
- return TRUE;
-
- ldfile_open_file (entry);
-
- if (! bfd_check_format (entry->the_bfd, bfd_archive)
- && ! bfd_check_format_matches (entry->the_bfd, bfd_object, &matching))
- {
- bfd_error_type err;
- lang_statement_list_type *hold;
- bfd_boolean bad_load = TRUE;
- bfd_boolean save_ldlang_sysrooted_script;
-
- err = bfd_get_error ();
-
- /* See if the emulation has some special knowledge. */
- if (ldemul_unrecognized_file (entry))
- return TRUE;
-
- if (err == bfd_error_file_ambiguously_recognized)
- {
- char **p;
-
- einfo (_("%B: file not recognized: %E\n"), entry->the_bfd);
- einfo (_("%B: matching formats:"), entry->the_bfd);
- for (p = matching; *p != NULL; p++)
- einfo (" %s", *p);
- einfo ("%F\n");
- }
- else if (err != bfd_error_file_not_recognized
- || place == NULL)
- einfo (_("%F%B: file not recognized: %E\n"), entry->the_bfd);
- else
- bad_load = FALSE;
-
- bfd_close (entry->the_bfd);
- entry->the_bfd = NULL;
-
- /* Try to interpret the file as a linker script. */
- ldfile_open_command_file (entry->filename);
-
- hold = stat_ptr;
- stat_ptr = place;
- save_ldlang_sysrooted_script = ldlang_sysrooted_script;
- ldlang_sysrooted_script = entry->sysrooted;
-
- ldfile_assumed_script = TRUE;
- parser_input = input_script;
- yyparse ();
- ldfile_assumed_script = FALSE;
-
- ldlang_sysrooted_script = save_ldlang_sysrooted_script;
- stat_ptr = hold;
-
- return ! bad_load;
- }
-
- if (ldemul_recognized_file (entry))
- return TRUE;
-
- /* We don't call ldlang_add_file for an archive. Instead, the
- add_symbols entry point will call ldlang_add_file, via the
- add_archive_element callback, for each element of the archive
- which is used. */
- switch (bfd_get_format (entry->the_bfd))
- {
- default:
- break;
-
- case bfd_object:
- ldlang_add_file (entry);
- if (trace_files || trace_file_tries)
- info_msg ("%I\n", entry);
- break;
-
- case bfd_archive:
- if (entry->whole_archive)
- {
- bfd *member = NULL;
- bfd_boolean loaded = TRUE;
-
- for (;;)
- {
- member = bfd_openr_next_archived_file (entry->the_bfd, member);
-
- if (member == NULL)
- break;
-
- if (! bfd_check_format (member, bfd_object))
- {
- einfo (_("%F%B: member %B in archive is not an object\n"),
- entry->the_bfd, member);
- loaded = FALSE;
- }
-
- if (! ((*link_info.callbacks->add_archive_element)
- (&link_info, member, "--whole-archive")))
- abort ();
-
- if (! bfd_link_add_symbols (member, &link_info))
- {
- einfo (_("%F%B: could not read symbols: %E\n"), member);
- loaded = FALSE;
- }
- }
-
- entry->loaded = loaded;
- return loaded;
- }
- break;
- }
-
- if (bfd_link_add_symbols (entry->the_bfd, &link_info))
- entry->loaded = TRUE;
- else
- einfo (_("%F%B: could not read symbols: %E\n"), entry->the_bfd);
-
- return entry->loaded;
-}
-
-/* Handle a wild statement. S->FILENAME or S->SECTION_LIST 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 (lang_wild_statement_type *s,
- const char *target ATTRIBUTE_UNUSED,
- lang_output_section_statement_type *output)
-{
- struct wildcard_list *sec;
-
- walk_wild (s, output_section_callback, output);
-
- for (sec = s->section_list; sec != NULL; sec = sec->next)
- {
- if (default_common_section != NULL)
- break;
- if (sec->spec.name != NULL && strcmp (sec->spec.name, "COMMON") == 0)
- {
- /* 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;
- }
- }
-}
-
-/* Return TRUE iff target is the sought target. */
-
-static int
-get_target (const bfd_target *target, void *data)
-{
- const char *sought = data;
-
- return strcmp (target->name, sought) == 0;
-}
-
-/* Like strcpy() but convert to lower case as well. */
-
-static void
-stricpy (char *dest, char *src)
-{
- char c;
-
- while ((c = *src++) != 0)
- *dest++ = TOLOWER (c);
-
- *dest = 0;
-}
-
-/* Remove the first occurrence of needle (if any) in haystack
- from haystack. */
-
-static void
-strcut (char *haystack, char *needle)
-{
- haystack = strstr (haystack, needle);
-
- if (haystack)
- {
- char *src;
-
- for (src = haystack + strlen (needle); *src;)
- *haystack++ = *src++;
-
- *haystack = 0;
- }
-}
-
-/* Compare two target format name strings.
- Return a value indicating how "similar" they are. */
-
-static int
-name_compare (char *first, char *second)
-{
- char *copy1;
- char *copy2;
- int result;
-
- copy1 = xmalloc (strlen (first) + 1);
- copy2 = xmalloc (strlen (second) + 1);
-
- /* Convert the names to lower case. */
- stricpy (copy1, first);
- stricpy (copy2, second);
-
- /* Remove size and endian strings from the name. */
- strcut (copy1, "big");
- strcut (copy1, "little");
- strcut (copy2, "big");
- strcut (copy2, "little");
-
- /* Return a value based on how many characters match,
- starting from the beginning. If both strings are
- the same then return 10 * their length. */
- for (result = 0; copy1[result] == copy2[result]; result++)
- if (copy1[result] == 0)
- {
- result *= 10;
- break;
- }
-
- free (copy1);
- free (copy2);
-
- return result;
-}
-
-/* Set by closest_target_match() below. */
-static const bfd_target *winner;
-
-/* Scan all the valid bfd targets looking for one that has the endianness
- requirement that was specified on the command line, and is the nearest
- match to the original output target. */
-
-static int
-closest_target_match (const bfd_target *target, void *data)
-{
- const bfd_target *original = data;
-
- if (command_line.endian == ENDIAN_BIG
- && target->byteorder != BFD_ENDIAN_BIG)
- return 0;
-
- if (command_line.endian == ENDIAN_LITTLE
- && target->byteorder != BFD_ENDIAN_LITTLE)
- return 0;
-
- /* Must be the same flavour. */
- if (target->flavour != original->flavour)
- return 0;
-
- /* If we have not found a potential winner yet, then record this one. */
- if (winner == NULL)
- {
- winner = target;
- return 0;
- }
-
- /* Oh dear, we now have two potential candidates for a successful match.
- Compare their names and choose the better one. */
- if (name_compare (target->name, original->name)
- > name_compare (winner->name, original->name))
- winner = target;
-
- /* Keep on searching until wqe have checked them all. */
- return 0;
-}
-
-/* Return the BFD target format of the first input file. */
-
-static char *
-get_first_input_target (void)
-{
- char *target = NULL;
-
- LANG_FOR_EACH_INPUT_STATEMENT (s)
- {
- if (s->header.type == lang_input_statement_enum
- && s->real)
- {
- ldfile_open_file (s);
-
- if (s->the_bfd != NULL
- && bfd_check_format (s->the_bfd, bfd_object))
- {
- target = bfd_get_target (s->the_bfd);
-
- if (target != NULL)
- break;
- }
- }
- }
-
- return target;
-}
-
-const char *
-lang_get_output_target (void)
-{
- const char *target;
-
- /* Has the user told us which output format to use? */
- if (output_target != NULL)
- return output_target;
-
- /* No - has the current target been set to something other than
- the default? */
- if (current_target != default_target)
- return current_target;
-
- /* No - can we determine the format of the first input file? */
- target = get_first_input_target ();
- if (target != NULL)
- return target;
-
- /* Failed - use the default output target. */
- return default_target;
-}
-
-/* Open the output file. */
-
-static bfd *
-open_output (const char *name)
-{
- bfd *output;
-
- output_target = lang_get_output_target ();
-
- /* Has the user requested a particular endianness on the command
- line? */
- if (command_line.endian != ENDIAN_UNSET)
- {
- const bfd_target *target;
- enum bfd_endian desired_endian;
-
- /* Get the chosen target. */
- target = bfd_search_for_target (get_target, (void *) output_target);
-
- /* If the target is not supported, we cannot do anything. */
- if (target != NULL)
- {
- if (command_line.endian == ENDIAN_BIG)
- desired_endian = BFD_ENDIAN_BIG;
- else
- desired_endian = BFD_ENDIAN_LITTLE;
-
- /* See if the target has the wrong endianness. This should
- not happen if the linker script has provided big and
- little endian alternatives, but some scrips don't do
- this. */
- if (target->byteorder != desired_endian)
- {
- /* If it does, then see if the target provides
- an alternative with the correct endianness. */
- if (target->alternative_target != NULL
- && (target->alternative_target->byteorder == desired_endian))
- output_target = target->alternative_target->name;
- else
- {
- /* Try to find a target as similar as possible to
- the default target, but which has the desired
- endian characteristic. */
- bfd_search_for_target (closest_target_match,
- (void *) target);
-
- /* Oh dear - we could not find any targets that
- satisfy our requirements. */
- if (winner == NULL)
- einfo (_("%P: warning: could not find any targets that match endianness requirement\n"));
- else
- output_target = winner->name;
- }
- }
- }
- }
-
- output = bfd_openw (name, output_target);
-
- if (output == NULL)
- {
- if (bfd_get_error () == bfd_error_invalid_target)
- einfo (_("%P%F: target %s not found\n"), output_target);
-
- einfo (_("%P%F: cannot open output file %s: %E\n"), name);
- }
-
- delete_output_file_on_failure = TRUE;
-
-#if 0
- output->flags |= D_PAGED;
-#endif
-
- if (! bfd_set_format (output, bfd_object))
- einfo (_("%P%F:%s: can not make object file: %E\n"), name);
- if (! bfd_set_arch_mach (output,
- ldfile_output_architecture,
- ldfile_output_machine))
- einfo (_("%P%F:%s: can not set architecture: %E\n"), name);
-
- link_info.hash = bfd_link_hash_table_create (output);
- if (link_info.hash == NULL)
- einfo (_("%P%F: can not create link hash table: %E\n"));
-
- bfd_set_gp_size (output, g_switch_value);
- return output;
-}
-
-static void
-ldlang_open_output (lang_statement_union_type *statement)
-{
- switch (statement->header.type)
- {
- case lang_output_statement_enum:
- ASSERT (output_bfd == NULL);
- output_bfd = open_output (statement->output_statement.name);
- ldemul_set_output_arch ();
- if (config.magic_demand_paged && !link_info.relocatable)
- output_bfd->flags |= D_PAGED;
- else
- output_bfd->flags &= ~D_PAGED;
- if (config.text_read_only)
- output_bfd->flags |= WP_TEXT;
- else
- output_bfd->flags &= ~WP_TEXT;
- if (link_info.traditional_format)
- output_bfd->flags |= BFD_TRADITIONAL_FORMAT;
- else
- output_bfd->flags &= ~BFD_TRADITIONAL_FORMAT;
- break;
-
- case lang_target_statement_enum:
- current_target = statement->target_statement.target;
- break;
- default:
- break;
- }
-}
-
-/* Convert between addresses in bytes and sizes in octets.
- For currently supported targets, octets_per_byte is always a power
- of two, so we can use shifts. */
-#define TO_ADDR(X) ((X) >> opb_shift)
-#define TO_SIZE(X) ((X) << opb_shift)
-
-/* Support the above. */
-static unsigned int opb_shift = 0;
-
-static void
-init_opb (void)
-{
- unsigned x = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
- ldfile_output_machine);
- opb_shift = 0;
- if (x > 1)
- while ((x & 1) == 0)
- {
- x >>= 1;
- ++opb_shift;
- }
- ASSERT (x == 1);
-}
-
-/* Open all the input files. */
-
-static void
-open_input_bfds (lang_statement_union_type *s, bfd_boolean force)
-{
- for (; s != NULL; s = s->header.next)
- {
- switch (s->header.type)
- {
- case lang_constructors_statement_enum:
- open_input_bfds (constructor_list.head, force);
- break;
- case lang_output_section_statement_enum:
- open_input_bfds (s->output_section_statement.children.head, force);
- break;
- case lang_wild_statement_enum:
- /* Maybe we should load the file's symbols. */
- if (s->wild_statement.filename
- && ! wildcardp (s->wild_statement.filename))
- lookup_name (s->wild_statement.filename);
- open_input_bfds (s->wild_statement.children.head, force);
- break;
- case lang_group_statement_enum:
- {
- struct bfd_link_hash_entry *undefs;
-
- /* We must continually search the entries in the group
- until no new symbols are added to the list of undefined
- symbols. */
-
- do
- {
- undefs = link_info.hash->undefs_tail;
- open_input_bfds (s->group_statement.children.head, TRUE);
- }
- while (undefs != link_info.hash->undefs_tail);
- }
- break;
- case lang_target_statement_enum:
- current_target = s->target_statement.target;
- break;
- case lang_input_statement_enum:
- if (s->input_statement.real)
- {
- lang_statement_list_type add;
-
- s->input_statement.target = current_target;
-
- /* If we are being called from within a group, and this
- is an archive which has already been searched, then
- force it to be researched unless the whole archive
- has been loaded already. */
- if (force
- && !s->input_statement.whole_archive
- && s->input_statement.loaded
- && bfd_check_format (s->input_statement.the_bfd,
- bfd_archive))
- s->input_statement.loaded = FALSE;
-
- lang_list_init (&add);
-
- if (! load_symbols (&s->input_statement, &add))
- config.make_executable = FALSE;
-
- if (add.head != NULL)
- {
- *add.tail = s->header.next;
- s->header.next = add.head;
- }
- }
- break;
- default:
- break;
- }
- }
-}
-
-/* If there are [COMMONS] statements, put a wild one into the bss
- section. */
-
-static void
-lang_reasonable_defaults (void)
-{
-#if 0
- lang_output_section_statement_lookup (".text");
- lang_output_section_statement_lookup (".data");
-
- default_common_section = lang_output_section_statement_lookup (".bss");
-
- if (!placed_commons)
- {
- lang_wild_statement_type *new =
- new_stat (lang_wild_statement,
- &default_common_section->children);
-
- new->section_name = "COMMON";
- new->filename = NULL;
- lang_list_init (&new->children);
- }
-#endif
-}
-
-/* Add a symbol to a hash of symbols used in DEFINED (NAME) expressions. */
-
-void
-lang_track_definedness (const char *name)
-{
- if (bfd_hash_lookup (&lang_definedness_table, name, TRUE, FALSE) == NULL)
- einfo (_("%P%F: bfd_hash_lookup failed creating symbol %s\n"), name);
-}
-
-/* New-function for the definedness hash table. */
-
-static struct bfd_hash_entry *
-lang_definedness_newfunc (struct bfd_hash_entry *entry,
- struct bfd_hash_table *table ATTRIBUTE_UNUSED,
- const char *name ATTRIBUTE_UNUSED)
-{
- struct lang_definedness_hash_entry *ret
- = (struct lang_definedness_hash_entry *) entry;
-
- if (ret == NULL)
- ret = (struct lang_definedness_hash_entry *)
- bfd_hash_allocate (table, sizeof (struct lang_definedness_hash_entry));
-
- if (ret == NULL)
- einfo (_("%P%F: bfd_hash_allocate failed creating symbol %s\n"), name);
-
- ret->iteration = -1;
- return &ret->root;
-}
-
-/* Return the iteration when the definition of NAME was last updated. A
- value of -1 means that the symbol is not defined in the linker script
- or the command line, but may be defined in the linker symbol table. */
-
-int
-lang_symbol_definition_iteration (const char *name)
-{
- struct lang_definedness_hash_entry *defentry
- = (struct lang_definedness_hash_entry *)
- bfd_hash_lookup (&lang_definedness_table, name, FALSE, FALSE);
-
- /* We've already created this one on the presence of DEFINED in the
- script, so it can't be NULL unless something is borked elsewhere in
- the code. */
- if (defentry == NULL)
- FAIL ();
-
- return defentry->iteration;
-}
-
-/* Update the definedness state of NAME. */
-
-void
-lang_update_definedness (const char *name, struct bfd_link_hash_entry *h)
-{
- struct lang_definedness_hash_entry *defentry
- = (struct lang_definedness_hash_entry *)
- bfd_hash_lookup (&lang_definedness_table, name, FALSE, FALSE);
-
- /* We don't keep track of symbols not tested with DEFINED. */
- if (defentry == NULL)
- return;
-
- /* If the symbol was already defined, and not from an earlier statement
- iteration, don't update the definedness iteration, because that'd
- make the symbol seem defined in the linker script at this point, and
- it wasn't; it was defined in some object. If we do anyway, DEFINED
- would start to yield false before this point and the construct "sym =
- DEFINED (sym) ? sym : X;" would change sym to X despite being defined
- in an object. */
- if (h->type != bfd_link_hash_undefined
- && h->type != bfd_link_hash_common
- && h->type != bfd_link_hash_new
- && defentry->iteration == -1)
- return;
-
- defentry->iteration = lang_statement_iteration;
-}
-
-/* Add the supplied name to the symbol table as an undefined reference.
- This is a two step process as the symbol table doesn't even exist at
- the time the ld command line is processed. First we put the name
- on a list, then, once the output file has been opened, transfer the
- name to the symbol table. */
-
-typedef struct bfd_sym_chain ldlang_undef_chain_list_type;
-
-#define ldlang_undef_chain_list_head entry_symbol.next
-
-void
-ldlang_add_undef (const char *const name)
-{
- ldlang_undef_chain_list_type *new =
- stat_alloc (sizeof (ldlang_undef_chain_list_type));
-
- new->next = ldlang_undef_chain_list_head;
- ldlang_undef_chain_list_head = new;
-
- new->name = xstrdup (name);
-
- if (output_bfd != NULL)
- insert_undefined (new->name);
-}
-
-/* Insert NAME as undefined in the symbol table. */
-
-static void
-insert_undefined (const char *name)
-{
- struct bfd_link_hash_entry *h;
-
- h = bfd_link_hash_lookup (link_info.hash, name, TRUE, FALSE, TRUE);
- if (h == NULL)
- einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n"));
- if (h->type == bfd_link_hash_new)
- {
- h->type = bfd_link_hash_undefined;
- h->u.undef.abfd = NULL;
- bfd_link_add_undef (link_info.hash, h);
- }
-}
-
-/* Run through the list of undefineds created above and place them
- into the linker hash table as undefined symbols belonging to the
- script file. */
-
-static void
-lang_place_undefineds (void)
-{
- ldlang_undef_chain_list_type *ptr;
-
- for (ptr = ldlang_undef_chain_list_head; ptr != NULL; ptr = ptr->next)
- insert_undefined (ptr->name);
-}
-
-/* Open input files and attach to output sections. */
-
-static void
-map_input_to_output_sections
- (lang_statement_union_type *s, const char *target,
- lang_output_section_statement_type *output_section_statement)
-{
- for (; s != NULL; s = s->header.next)
- {
- switch (s->header.type)
- {
- case lang_wild_statement_enum:
- wild (&s->wild_statement, target, output_section_statement);
- break;
- case lang_constructors_statement_enum:
- map_input_to_output_sections (constructor_list.head,
- target,
- output_section_statement);
- break;
- case lang_output_section_statement_enum:
- map_input_to_output_sections (s->output_section_statement.children.head,
- target,
- &s->output_section_statement);
- break;
- case lang_output_statement_enum:
- break;
- case lang_target_statement_enum:
- target = s->target_statement.target;
- break;
- case lang_group_statement_enum:
- map_input_to_output_sections (s->group_statement.children.head,
- target,
- output_section_statement);
- break;
- case lang_data_statement_enum:
- /* Make sure that any sections mentioned in the expression
- are initialized. */
- exp_init_os (s->data_statement.exp);
- /* FALLTHROUGH */
- case lang_fill_statement_enum:
- case lang_input_section_enum:
- case lang_object_symbols_statement_enum:
- case lang_reloc_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;
- case lang_address_statement_enum:
- /* Mark the specified section with the supplied address. */
- {
- lang_output_section_statement_type *os =
- lang_output_section_statement_lookup
- (s->address_statement.section_name);
-
- if (os->bfd_section == NULL)
- init_os (os);
- os->addr_tree = s->address_statement.address;
- }
- break;
- }
- }
-}
-
-/* An output section might have been removed after its statement was
- added. For example, ldemul_before_allocation can remove dynamic
- sections if they turn out to be not needed. Clean them up here. */
-
-static void
-strip_excluded_output_sections (void)
-{
- lang_statement_union_type *u;
-
- for (u = lang_output_section_statement.head;
- u != NULL;
- u = u->output_section_statement.next)
- {
- lang_output_section_statement_type *os;
- asection *s;
-
- os = &u->output_section_statement;
- s = os->bfd_section;
- if (s != NULL && (s->flags & SEC_EXCLUDE) != 0)
- {
- asection **p;
-
- os->bfd_section = NULL;
-
- for (p = &output_bfd->sections; *p; p = &(*p)->next)
- if (*p == s)
- {
- bfd_section_list_remove (output_bfd, p);
- output_bfd->section_count--;
- break;
- }
- }
- }
-}
-
-static void
-print_output_section_statement
- (lang_output_section_statement_type *output_section_statement)
-{
- asection *section = output_section_statement->bfd_section;
- int len;
-
- if (output_section_statement != abs_output_section)
- {
- minfo ("\n%s", output_section_statement->name);
-
- if (section != NULL)
- {
- print_dot = section->vma;
-
- 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;
- }
-
- 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_statement_list (output_section_statement->children.head,
- output_section_statement);
-}
-
-static void
-print_assignment (lang_assignment_statement_type *assignment,
- lang_output_section_statement_type *output_section)
-{
- int i;
- etree_value_type result;
-
- 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_p)
- {
- const char *dst;
- bfd_vma value;
-
- value = result.value + result.section->bfd_section->vma;
- dst = assignment->exp->assign.dst;
-
- minfo ("0x%V", value);
- if (dst[0] == '.' && dst[1] == 0)
- print_dot = value;
- }
- else
- {
- minfo ("*undef* ");
-#ifdef BFD64
- minfo (" ");
-#endif
- }
-
- minfo (" ");
-
- exp_print_tree (assignment->exp);
-
- print_nl ();
-}
-
-static void
-print_input_statement (lang_input_statement_type *statm)
-{
- if (statm->filename != NULL)
- {
- fprintf (config.map_file, "LOAD %s\n", statm->filename);
- }
-}
-
-/* Print all symbols defined in a particular section. This is called
- via bfd_link_hash_traverse. */
-
-static bfd_boolean
-print_one_symbol (struct bfd_link_hash_entry *hash_entry, void *ptr)
-{
- asection *sec = 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 (lang_input_section_type *in)
-{
- asection *i = in->section;
- bfd_size_type size = i->_cooked_size != 0 ? i->_cooked_size : i->_raw_size;
-
- init_opb ();
- if (size != 0)
- {
- print_space ();
-
- minfo ("%s", i->name);
-
- if (i->output_section != NULL)
- {
- int len;
-
- 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;
- }
-
- minfo ("0x%V %W %B\n",
- i->output_section->vma + i->output_offset, TO_ADDR (size),
- i->owner);
-
- 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)
- {
- print_space ();
- --len;
- }
-
- minfo (_("%W (size before relaxing)\n"), i->_raw_size);
- }
-
- bfd_link_hash_traverse (link_info.hash, print_one_symbol, i);
-
- print_dot = (i->output_section->vma + i->output_offset
- + TO_ADDR (size));
- }
- }
-}
-
-static void
-print_fill_statement (lang_fill_statement_type *fill)
-{
- size_t size;
- unsigned char *p;
- fputs (" FILL mask 0x", config.map_file);
- for (p = fill->fill->data, size = fill->fill->size; size != 0; p++, size--)
- fprintf (config.map_file, "%02x", *p);
- fputs ("\n", config.map_file);
-}
-
-static void
-print_data_statement (lang_data_statement_type *data)
-{
- int i;
- bfd_vma addr;
- bfd_size_type size;
- const char *name;
-
- init_opb ();
- 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;
-
- switch (data->type)
- {
- default:
- abort ();
- case BYTE:
- size = BYTE_SIZE;
- name = "BYTE";
- break;
- case SHORT:
- size = SHORT_SIZE;
- name = "SHORT";
- break;
- case LONG:
- size = LONG_SIZE;
- name = "LONG";
- break;
- case QUAD:
- 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 (data->exp->type.node_class != etree_value)
- {
- print_space ();
- exp_print_tree (data->exp);
- }
-
- print_nl ();
-
- print_dot = addr + TO_ADDR (size);
-}
-
-/* Print an address statement. These are generated by options like
- -Ttext. */
-
-static void
-print_address_statement (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. */
-
-static void
-print_reloc_statement (lang_reloc_statement_type *reloc)
-{
- int i;
- bfd_vma addr;
- bfd_size_type size;
-
- init_opb ();
- for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
- print_space ();
-
- addr = reloc->output_vma;
- if (reloc->output_section != NULL)
- addr += reloc->output_section->vma;
-
- size = bfd_get_reloc_size (reloc->howto);
-
- minfo ("0x%V %W RELOC %s ", addr, size, reloc->howto->name);
-
- if (reloc->name != NULL)
- minfo ("%s+", reloc->name);
- else
- minfo ("%s+", reloc->section->name);
-
- exp_print_tree (reloc->addend_exp);
-
- print_nl ();
-
- print_dot = addr + TO_ADDR (size);
-}
-
-static void
-print_padding_statement (lang_padding_statement_type *s)
-{
- int len;
- bfd_vma addr;
-
- init_opb ();
- 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->size != 0)
- {
- size_t size;
- unsigned char *p;
- for (p = s->fill->data, size = s->fill->size; size != 0; p++, size--)
- fprintf (config.map_file, "%02x", *p);
- }
-
- print_nl ();
-
- print_dot = addr + TO_ADDR (s->size);
-}
-
-static void
-print_wild_statement (lang_wild_statement_type *w,
- lang_output_section_statement_type *os)
-{
- struct wildcard_list *sec;
-
- print_space ();
-
- if (w->filenames_sorted)
- minfo ("SORT(");
- if (w->filename != NULL)
- minfo ("%s", w->filename);
- else
- minfo ("*");
- if (w->filenames_sorted)
- minfo (")");
-
- minfo ("(");
- for (sec = w->section_list; sec; sec = sec->next)
- {
- if (sec->spec.sorted)
- minfo ("SORT(");
- if (sec->spec.exclude_name_list != NULL)
- {
- name_list *tmp;
- minfo ("EXCLUDE_FILE(%s", sec->spec.exclude_name_list->name);
- for (tmp = sec->spec.exclude_name_list->next; tmp; tmp = tmp->next)
- minfo (" %s", tmp->name);
- minfo (") ");
- }
- if (sec->spec.name != NULL)
- minfo ("%s", sec->spec.name);
- else
- minfo ("*");
- if (sec->spec.sorted)
- minfo (")");
- if (sec->next)
- minfo (" ");
- }
- minfo (")");
-
- print_nl ();
-
- print_statement_list (w->children.head, os);
-}
-
-/* Print a group statement. */
-
-static void
-print_group (lang_group_statement_type *s,
- lang_output_section_statement_type *os)
-{
- fprintf (config.map_file, "START GROUP\n");
- print_statement_list (s->children.head, os);
- fprintf (config.map_file, "END GROUP\n");
-}
-
-/* Print the list of statements in S.
- This can be called for any statement type. */
-
-static void
-print_statement_list (lang_statement_union_type *s,
- lang_output_section_statement_type *os)
-{
- while (s != NULL)
- {
- print_statement (s, os);
- s = s->header.next;
- }
-}
-
-/* Print the first statement in statement list S.
- This can be called for any statement type. */
-
-static void
-print_statement (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:
- if (constructor_list.head != NULL)
- {
- if (constructors_sorted)
- minfo (" SORT (CONSTRUCTORS)\n");
- else
- minfo (" CONSTRUCTORS\n");
- print_statement_list (constructor_list.head, os);
- }
- break;
- case lang_wild_statement_enum:
- print_wild_statement (&s->wild_statement, os);
- break;
- case lang_address_statement_enum:
- print_address_statement (&s->address_statement);
- break;
- case lang_object_symbols_statement_enum:
- minfo (" CREATE_OBJECT_SYMBOLS\n");
- break;
- case lang_fill_statement_enum:
- print_fill_statement (&s->fill_statement);
- break;
- case lang_data_statement_enum:
- print_data_statement (&s->data_statement);
- break;
- case lang_reloc_statement_enum:
- print_reloc_statement (&s->reloc_statement);
- break;
- case lang_input_section_enum:
- print_input_section (&s->input_section);
- break;
- case lang_padding_statement_enum:
- print_padding_statement (&s->padding_statement);
- break;
- case lang_output_section_statement_enum:
- print_output_section_statement (&s->output_section_statement);
- break;
- case lang_assignment_statement_enum:
- 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:
- 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);
- break;
- case lang_group_statement_enum:
- print_group (&s->group_statement, os);
- break;
- case lang_afile_asection_pair_statement_enum:
- FAIL ();
- break;
- }
-}
-
-static void
-print_statements (void)
-{
- print_statement_list (statement_list.head, abs_output_section);
-}
-
-/* Print the first N statements in statement list S to STDERR.
- If N == 0, nothing is printed.
- If N < 0, the entire list is printed.
- Intended to be called from GDB. */
-
-void
-dprint_statement (lang_statement_union_type *s, int n)
-{
- FILE *map_save = config.map_file;
-
- config.map_file = stderr;
-
- if (n < 0)
- print_statement_list (s, abs_output_section);
- else
- {
- while (s && --n >= 0)
- {
- print_statement (s, abs_output_section);
- s = s->header.next;
- }
- }
-
- config.map_file = map_save;
-}
-
-static void
-insert_pad (lang_statement_union_type **ptr,
- fill_type *fill,
- unsigned int alignment_needed,
- asection *output_section,
- bfd_vma dot)
-{
- static fill_type zero_fill = { 1, { 0 } };
- lang_statement_union_type *pad;
-
- pad = ((lang_statement_union_type *)
- ((char *) ptr - offsetof (lang_statement_union_type, header.next)));
- if (ptr != &statement_list.head
- && pad->header.type == lang_padding_statement_enum
- && pad->padding_statement.output_section == output_section)
- {
- /* Use the existing pad statement. The above test on output
- section is probably redundant, but it doesn't hurt to check. */
- }
- else
- {
- /* Make a new padding statement, linked into existing chain. */
- pad = stat_alloc (sizeof (lang_padding_statement_type));
- pad->header.next = *ptr;
- *ptr = pad;
- pad->header.type = lang_padding_statement_enum;
- pad->padding_statement.output_section = output_section;
- if (fill == NULL)
- fill = &zero_fill;
- pad->padding_statement.fill = fill;
- }
- pad->padding_statement.output_offset = dot - output_section->vma;
- pad->padding_statement.size = alignment_needed;
- output_section->_raw_size += alignment_needed;
-}
-
-/* Work out how much this section will move the dot point. */
-
-static bfd_vma
-size_input_section (lang_statement_union_type **this_ptr,
- lang_output_section_statement_type *output_section_statement,
- fill_type *fill,
- bfd_vma dot)
-{
- lang_input_section_type *is = &((*this_ptr)->input_section);
- asection *i = is->section;
-
- if (!is->ifile->just_syms_flag)
- {
- unsigned int alignment_needed;
- asection *o;
-
- /* Align this section first to the input sections requirement,
- then to the output section's requirement. If this alignment
- is greater than any seen before, then record it too. Perform
- the alignment by inserting a magic 'padding' statement. */
-
- if (output_section_statement->subsection_alignment != -1)
- i->alignment_power = output_section_statement->subsection_alignment;
-
- o = output_section_statement->bfd_section;
- if (o->alignment_power < i->alignment_power)
- o->alignment_power = i->alignment_power;
-
- alignment_needed = align_power (dot, i->alignment_power) - dot;
-
- if (alignment_needed != 0)
- {
- insert_pad (this_ptr, fill, TO_SIZE (alignment_needed), o, dot);
- dot += alignment_needed;
- }
-
- /* Remember where in the output section this input section goes. */
-
- i->output_offset = dot - o->vma;
-
- /* Mark how big the output section must be to contain this now. */
- if (i->_cooked_size != 0)
- dot += TO_ADDR (i->_cooked_size);
- else
- dot += TO_ADDR (i->_raw_size);
- o->_raw_size = TO_SIZE (dot - o->vma);
- }
- else
- {
- i->output_offset = i->vma - output_section_statement->bfd_section->vma;
- }
-
- return dot;
-}
-
-#define IGNORE_SECTION(bfd, s) \
- (((bfd_get_section_flags (bfd, s) & SEC_THREAD_LOCAL) \
- ? ((bfd_get_section_flags (bfd, s) & (SEC_LOAD | SEC_NEVER_LOAD)) \
- != SEC_LOAD) \
- : ((bfd_get_section_flags (bfd, s) & (SEC_ALLOC | SEC_NEVER_LOAD)) \
- != SEC_ALLOC)) \
- || 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. */
-
-static void
-lang_check_section_addresses (void)
-{
- asection *s;
-
- /* Scan all sections in the output list. */
- for (s = output_bfd->sections; s != NULL; s = s->next)
- {
- asection *os;
-
- /* Ignore sections which are not loaded or which have no contents. */
- if (IGNORE_SECTION (output_bfd, s))
- continue;
-
- /* Once we reach section 's' stop our seach. This prevents two
- warning messages from being produced, one for 'section A overlaps
- section B' and one for 'section B overlaps section A'. */
- for (os = output_bfd->sections; os != s; os = os->next)
- {
- bfd_vma s_start;
- bfd_vma s_end;
- bfd_vma os_start;
- bfd_vma os_end;
-
- /* Only consider loadable sections with real contents. */
- if (IGNORE_SECTION (output_bfd, os))
- continue;
-
- /* We must check the sections' LMA addresses not their
- VMA addresses because overlay sections can have
- overlapping VMAs but they must have distinct LMAs. */
- s_start = bfd_section_lma (output_bfd, s);
- os_start = bfd_section_lma (output_bfd, os);
- s_end = s_start + TO_ADDR (bfd_section_size (output_bfd, s)) - 1;
- os_end = os_start + TO_ADDR (bfd_section_size (output_bfd, os)) - 1;
-
- /* Look for an overlap. */
- if ((s_end < os_start) || (s_start > os_end))
- continue;
-
- einfo (
-_("%X%P: section %s [%V -> %V] overlaps section %s [%V -> %V]\n"),
- s->name, s_start, s_end, os->name, os_start, os_end);
-
- /* Once we have found one overlap for this section,
- stop looking for others. */
- break;
- }
- }
-}
-
-/* Make sure the new address is within the region. We explicitly permit the
- current address to be at the exact end of the region when the address is
- non-zero, in case the region is at the end of addressable memory and the
- calculation wraps around. */
-
-static void
-os_region_check (lang_output_section_statement_type *os,
- lang_memory_region_type *region,
- etree_type *tree,
- bfd_vma base)
-{
- if ((region->current < region->origin
- || (region->current - region->origin > region->length))
- && ((region->current != region->origin + region->length)
- || base == 0))
- {
- if (tree != NULL)
- {
- einfo (_("%X%P: address 0x%v of %B section %s is not within region %s\n"),
- region->current,
- os->bfd_section->owner,
- os->bfd_section->name,
- region->name);
- }
- else
- {
- einfo (_("%X%P: region %s is full (%B section %s)\n"),
- region->name,
- os->bfd_section->owner,
- os->bfd_section->name);
- }
- /* Reset the region pointer. */
- region->current = region->origin;
- }
-}
-
-/* Set the sizes for all the output sections. */
-
-static bfd_vma
-lang_size_sections_1
- (lang_statement_union_type *s,
- lang_output_section_statement_type *output_section_statement,
- lang_statement_union_type **prev,
- fill_type *fill,
- bfd_vma dot,
- bfd_boolean *relax,
- bfd_boolean check_regions)
-{
- /* Size up the sections from their constituent parts. */
- for (; s != NULL; s = s->header.next)
- {
- switch (s->header.type)
- {
- case lang_output_section_statement_enum:
- {
- bfd_vma after;
- lang_output_section_statement_type *os;
-
- os = &s->output_section_statement;
- if (os->bfd_section == NULL)
- /* This section was never actually created. */
- break;
-
- /* If this is a COFF shared library section, use the size and
- address from the input section. FIXME: This is COFF
- specific; it would be cleaner if there were some other way
- to do this, but nothing simple comes to mind. */
- if ((os->bfd_section->flags & SEC_COFF_SHARED_LIBRARY) != 0)
- {
- asection *input;
-
- if (os->children.head == NULL
- || os->children.head->header.next != NULL
- || os->children.head->header.type != lang_input_section_enum)
- einfo (_("%P%X: Internal error on COFF shared library section %s\n"),
- os->name);
-
- input = os->children.head->input_section.section;
- bfd_set_section_vma (os->bfd_section->owner,
- os->bfd_section,
- bfd_section_vma (input->owner, input));
- os->bfd_section->_raw_size = input->_raw_size;
- break;
- }
-
- if (bfd_is_abs_section (os->bfd_section))
- {
- /* No matter what happens, an abs section starts at zero. */
- ASSERT (os->bfd_section->vma == 0);
- }
- else
- {
- if (os->addr_tree == NULL)
- {
- /* No address specified for this section, get one
- from the region specification. */
- if (os->region == NULL
- || (((bfd_get_section_flags (output_bfd, os->bfd_section)
- & (SEC_ALLOC | SEC_LOAD)) != 0)
- && os->region->name[0] == '*'
- && strcmp (os->region->name, DEFAULT_MEMORY_REGION) == 0))
- {
- os->region = lang_memory_default (os->bfd_section);
- }
-
- /* If a loadable section is using the default memory
- region, and some non default memory regions were
- defined, issue an error message. */
- if (!IGNORE_SECTION (output_bfd, os->bfd_section)
- && ! link_info.relocatable
- && check_regions
- && strcmp (os->region->name, DEFAULT_MEMORY_REGION) == 0
- && lang_memory_region_list != NULL
- && (strcmp (lang_memory_region_list->name,
- DEFAULT_MEMORY_REGION) != 0
- || lang_memory_region_list->next != NULL))
- {
- /* By default this is an error rather than just a
- warning because if we allocate the section to the
- default memory region we can end up creating an
- excessively large binary, or even seg faulting when
- attempting to perform a negative seek. See
- http://sources.redhat.com/ml/binutils/2003-04/msg00423.html
- for an example of this. This behaviour can be
- overridden by the using the --no-check-sections
- switch. */
- if (command_line.check_section_addresses)
- einfo (_("%P%F: error: no memory region specified for loadable section `%s'\n"),
- bfd_get_section_name (output_bfd,
- os->bfd_section));
- else
- einfo (_("%P: warning: no memory region specified for loadable section `%s'\n"),
- bfd_get_section_name (output_bfd,
- os->bfd_section));
- }
-
- dot = os->region->current;
-
- if (os->section_alignment == -1)
- {
- 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
- {
- etree_value_type r;
-
- os->processed = -1;
- r = exp_fold_tree (os->addr_tree,
- abs_output_section,
- lang_allocating_phase_enum,
- dot, &dot);
- os->processed = 0;
-
- if (!r.valid_p)
- einfo (_("%F%S: non constant or forward reference address expression for section %s\n"),
- os->name);
-
- dot = r.value + r.section->bfd_section->vma;
- }
-
- /* The section starts here.
- First, align to what the section needs. */
-
- if (os->section_alignment != -1)
- dot = align_power (dot, os->section_alignment);
-
- bfd_set_section_vma (0, os->bfd_section, dot);
-
- os->bfd_section->output_offset = 0;
- }
-
- lang_size_sections_1 (os->children.head, os, &os->children.head,
- os->fill, dot, relax, check_regions);
-
- /* Put the section within the requested block size, or
- align at the block boundary. */
- after = ((os->bfd_section->vma
- + TO_ADDR (os->bfd_section->_raw_size)
- + os->block_value - 1)
- & - (bfd_vma) os->block_value);
-
- if (bfd_is_abs_section (os->bfd_section))
- ASSERT (after == os->bfd_section->vma);
- else
- os->bfd_section->_raw_size
- = TO_SIZE (after - os->bfd_section->vma);
-
- dot = os->bfd_section->vma;
- /* .tbss sections effectively have zero size. */
- if ((os->bfd_section->flags & SEC_HAS_CONTENTS) != 0
- || (os->bfd_section->flags & SEC_THREAD_LOCAL) == 0
- || link_info.relocatable)
- dot += TO_ADDR (os->bfd_section->_raw_size);
-
- os->processed = 1;
-
- if (os->update_dot_tree != 0)
- exp_fold_tree (os->update_dot_tree, abs_output_section,
- lang_allocating_phase_enum, dot, &dot);
-
- /* Update dot in the region ?
- We only do this if the section is going to be allocated,
- since unallocated sections do not contribute to the region's
- overall size in memory.
-
- If the SEC_NEVER_LOAD bit is not set, it will affect the
- addresses of sections after it. We have to update
- dot. */
- if (os->region != NULL
- && ((bfd_get_section_flags (output_bfd, os->bfd_section)
- & SEC_NEVER_LOAD) == 0
- || (bfd_get_section_flags (output_bfd, os->bfd_section)
- & (SEC_ALLOC | SEC_LOAD))))
- {
- os->region->current = dot;
-
- if (check_regions)
- /* Make sure the new address is within the region. */
- os_region_check (os, os->region, os->addr_tree,
- os->bfd_section->vma);
-
- /* If there's no load address specified, use the run
- region as the load region. */
- if (os->lma_region == NULL && os->load_base == NULL)
- os->lma_region = os->region;
-
- if (os->lma_region != NULL && os->lma_region != os->region)
- {
- /* Set load_base, which will be handled later. */
- os->load_base = exp_intop (os->lma_region->current);
- os->lma_region->current +=
- TO_ADDR (os->bfd_section->_raw_size);
- if (check_regions)
- os_region_check (os, os->lma_region, NULL,
- os->bfd_section->lma);
- }
- }
- }
- break;
-
- case lang_constructors_statement_enum:
- dot = lang_size_sections_1 (constructor_list.head,
- output_section_statement,
- &s->wild_statement.children.head,
- fill, dot, relax, check_regions);
- break;
-
- case lang_data_statement_enum:
- {
- unsigned int size = 0;
-
- s->data_statement.output_vma =
- dot - output_section_statement->bfd_section->vma;
- s->data_statement.output_section =
- output_section_statement->bfd_section;
-
- /* We might refer to provided symbols in the expression, and
- need to mark them as needed. */
- exp_fold_tree (s->data_statement.exp, abs_output_section,
- lang_allocating_phase_enum, dot, &dot);
-
- switch (s->data_statement.type)
- {
- default:
- abort ();
- 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;
- }
- if (size < TO_SIZE ((unsigned) 1))
- size = TO_SIZE ((unsigned) 1);
- dot += TO_ADDR (size);
- output_section_statement->bfd_section->_raw_size += size;
- /* The output section gets contents, and then we inspect for
- any flags set in the input script which override any ALLOC. */
- output_section_statement->bfd_section->flags |= SEC_HAS_CONTENTS;
- if (!(output_section_statement->flags & SEC_NEVER_LOAD))
- {
- output_section_statement->bfd_section->flags |=
- SEC_ALLOC | SEC_LOAD;
- }
- }
- break;
-
- case lang_reloc_statement_enum:
- {
- int size;
-
- s->reloc_statement.output_vma =
- dot - output_section_statement->bfd_section->vma;
- s->reloc_statement.output_section =
- output_section_statement->bfd_section;
- size = bfd_get_reloc_size (s->reloc_statement.howto);
- dot += TO_ADDR (size);
- output_section_statement->bfd_section->_raw_size += size;
- }
- break;
-
- case lang_wild_statement_enum:
-
- dot = lang_size_sections_1 (s->wild_statement.children.head,
- output_section_statement,
- &s->wild_statement.children.head,
- fill, dot, relax, check_regions);
-
- break;
-
- case lang_object_symbols_statement_enum:
- link_info.create_object_symbols_section =
- output_section_statement->bfd_section;
- break;
- case lang_output_statement_enum:
- case lang_target_statement_enum:
- break;
- case lang_input_section_enum:
- {
- asection *i;
-
- i = (*prev)->input_section.section;
- if (! relax)
- {
- if (i->_cooked_size == 0)
- i->_cooked_size = i->_raw_size;
- }
- else
- {
- bfd_boolean again;
-
- if (! bfd_relax_section (i->owner, i, &link_info, &again))
- einfo (_("%P%F: can't relax section: %E\n"));
- if (again)
- *relax = TRUE;
- }
- dot = size_input_section (prev, output_section_statement,
- output_section_statement->fill, dot);
- }
- break;
- case lang_input_statement_enum:
- break;
- case lang_fill_statement_enum:
- s->fill_statement.output_section =
- output_section_statement->bfd_section;
-
- fill = s->fill_statement.fill;
- break;
- case lang_assignment_statement_enum:
- {
- bfd_vma newdot = dot;
-
- exp_fold_tree (s->assignment_statement.exp,
- output_section_statement,
- lang_allocating_phase_enum,
- dot,
- &newdot);
-
- if (newdot != dot)
- {
- if (output_section_statement == abs_output_section)
- {
- /* If we don't have an output section, then just adjust
- the default memory address. */
- lang_memory_region_lookup (DEFAULT_MEMORY_REGION, FALSE)->current = newdot;
- }
- else
- {
- /* Insert a pad after this statement. We can't
- put the pad before when relaxing, in case the
- assignment references dot. */
- insert_pad (&s->header.next, fill, TO_SIZE (newdot - dot),
- output_section_statement->bfd_section, dot);
-
- /* Don't neuter the pad below when relaxing. */
- s = s->header.next;
- }
-
- /* If dot is advanced, this implies that the section should
- have space allocated to it, unless the user has explicitly
- stated that the section should never be loaded. */
- if (!(output_section_statement->flags & (SEC_NEVER_LOAD | SEC_ALLOC)))
- output_section_statement->bfd_section->flags |= SEC_ALLOC;
-
- dot = newdot;
- }
- }
- break;
-
- case lang_padding_statement_enum:
- /* If this is the first time lang_size_sections is called,
- we won't have any padding statements. If this is the
- second or later passes when relaxing, we should allow
- padding to shrink. If padding is needed on this pass, it
- will be added back in. */
- s->padding_statement.size = 0;
-
- /* Make sure output_offset is valid. If relaxation shrinks
- the section and this pad isn't needed, it's possible to
- have output_offset larger than the final size of the
- section. bfd_set_section_contents will complain even for
- a pad size of zero. */
- s->padding_statement.output_offset
- = dot - output_section_statement->bfd_section->vma;
- break;
-
- case lang_group_statement_enum:
- dot = lang_size_sections_1 (s->group_statement.children.head,
- output_section_statement,
- &s->group_statement.children.head,
- fill, dot, relax, check_regions);
- break;
-
- default:
- FAIL ();
- break;
-
- /* We can only get here when relaxing is turned on. */
- case lang_address_statement_enum:
- break;
- }
- prev = &s->header.next;
- }
- return dot;
-}
-
-bfd_vma
-lang_size_sections
- (lang_statement_union_type *s,
- lang_output_section_statement_type *output_section_statement,
- lang_statement_union_type **prev,
- fill_type *fill,
- bfd_vma dot,
- bfd_boolean *relax,
- bfd_boolean check_regions)
-{
- bfd_vma result;
- asection *o;
-
- /* Callers of exp_fold_tree need to increment this. */
- lang_statement_iteration++;
-
- exp_data_seg.phase = exp_dataseg_none;
- result = lang_size_sections_1 (s, output_section_statement, prev, fill,
- dot, relax, check_regions);
- if (exp_data_seg.phase == exp_dataseg_end_seen)
- {
- /* If DATA_SEGMENT_ALIGN DATA_SEGMENT_END pair was seen, check whether
- a page could be saved in the data segment. */
- bfd_vma first, last;
-
- first = -exp_data_seg.base & (exp_data_seg.pagesize - 1);
- last = exp_data_seg.end & (exp_data_seg.pagesize - 1);
- if (first && last
- && ((exp_data_seg.base & ~(exp_data_seg.pagesize - 1))
- != (exp_data_seg.end & ~(exp_data_seg.pagesize - 1)))
- && first + last <= exp_data_seg.pagesize)
- {
- exp_data_seg.phase = exp_dataseg_adjust;
- lang_statement_iteration++;
- result = lang_size_sections_1 (s, output_section_statement, prev,
- fill, dot, relax, check_regions);
- }
- }
-
- /* Some backend relaxers want to refer to the output section size. Give
- them a section size that does not change on the next call while they
- relax. We can't set this at top because lang_reset_memory_regions
- which is called before we get here, sets _raw_size to 0 on relaxing
- rounds. */
- for (o = output_bfd->sections; o != NULL; o = o->next)
- o->_cooked_size = o->_raw_size;
-
- return result;
-}
-
-/* Worker function for lang_do_assignments. Recursiveness goes here. */
-
-static bfd_vma
-lang_do_assignments_1
- (lang_statement_union_type *s,
- lang_output_section_statement_type *output_section_statement,
- fill_type *fill,
- bfd_vma dot)
-{
- for (; s != NULL; s = s->header.next)
- {
- switch (s->header.type)
- {
- case lang_constructors_statement_enum:
- dot = lang_do_assignments_1 (constructor_list.head,
- output_section_statement,
- fill,
- dot);
- break;
-
- case lang_output_section_statement_enum:
- {
- lang_output_section_statement_type *os;
-
- os = &(s->output_section_statement);
- if (os->bfd_section != NULL)
- {
- dot = os->bfd_section->vma;
- lang_do_assignments_1 (os->children.head, os, os->fill, dot);
- dot = (os->bfd_section->vma
- + TO_ADDR (os->bfd_section->_raw_size));
-
- }
- if (os->load_base)
- {
- /* If nothing has been placed into the output section then
- it won't have a bfd_section. */
- if (os->bfd_section)
- {
- os->bfd_section->lma
- = exp_get_abs_int (os->load_base, 0, "load base",
- lang_final_phase_enum);
- }
- }
- }
- break;
- case lang_wild_statement_enum:
-
- dot = lang_do_assignments_1 (s->wild_statement.children.head,
- output_section_statement,
- fill, dot);
-
- break;
-
- case lang_object_symbols_statement_enum:
- case lang_output_statement_enum:
- case lang_target_statement_enum:
-#if 0
- case lang_common_statement_enum:
-#endif
- break;
- case lang_data_statement_enum:
- {
- etree_value_type value;
-
- value = exp_fold_tree (s->data_statement.exp,
- abs_output_section,
- lang_final_phase_enum, dot, &dot);
- if (!value.valid_p)
- einfo (_("%F%P: invalid data statement\n"));
- s->data_statement.value
- = value.value + value.section->bfd_section->vma;
- }
- {
- unsigned int size;
- switch (s->data_statement.type)
- {
- default:
- abort ();
- 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;
- }
- if (size < TO_SIZE ((unsigned) 1))
- size = TO_SIZE ((unsigned) 1);
- dot += TO_ADDR (size);
- }
- break;
-
- case lang_reloc_statement_enum:
- {
- etree_value_type value;
-
- value = exp_fold_tree (s->reloc_statement.addend_exp,
- abs_output_section,
- lang_final_phase_enum, dot, &dot);
- s->reloc_statement.addend_value = value.value;
- if (!value.valid_p)
- einfo (_("%F%P: invalid reloc statement\n"));
- }
- dot += TO_ADDR (bfd_get_reloc_size (s->reloc_statement.howto));
- break;
-
- case lang_input_section_enum:
- {
- asection *in = s->input_section.section;
-
- if (in->_cooked_size != 0)
- dot += TO_ADDR (in->_cooked_size);
- else
- dot += TO_ADDR (in->_raw_size);
- }
- break;
-
- case lang_input_statement_enum:
- break;
- case lang_fill_statement_enum:
- fill = s->fill_statement.fill;
- break;
- case lang_assignment_statement_enum:
- {
- exp_fold_tree (s->assignment_statement.exp,
- output_section_statement,
- lang_final_phase_enum,
- dot,
- &dot);
- }
-
- break;
- case lang_padding_statement_enum:
- dot += TO_ADDR (s->padding_statement.size);
- break;
-
- case lang_group_statement_enum:
- dot = lang_do_assignments_1 (s->group_statement.children.head,
- output_section_statement,
- fill, dot);
-
- break;
-
- default:
- FAIL ();
- break;
- case lang_address_statement_enum:
- break;
- }
-
- }
- return dot;
-}
-
-void
-lang_do_assignments (lang_statement_union_type *s,
- lang_output_section_statement_type *output_section_statement,
- fill_type *fill,
- bfd_vma dot)
-{
- /* Callers of exp_fold_tree need to increment this. */
- lang_statement_iteration++;
- lang_do_assignments_1 (s, output_section_statement, fill, dot);
-}
-
-/* Fix any .startof. or .sizeof. symbols. When the assemblers see the
- operator .startof. (section_name), it produces an undefined symbol
- .startof.section_name. Similarly, when it sees
- .sizeof. (section_name), it produces an undefined symbol
- .sizeof.section_name. For all the output sections, we look for
- such symbols, and set them to the correct value. */
-
-static void
-lang_set_startof (void)
-{
- asection *s;
-
- if (link_info.relocatable)
- return;
-
- for (s = output_bfd->sections; s != NULL; s = s->next)
- {
- const char *secname;
- char *buf;
- struct bfd_link_hash_entry *h;
-
- secname = bfd_get_section_name (output_bfd, s);
- buf = xmalloc (10 + strlen (secname));
-
- sprintf (buf, ".startof.%s", secname);
- h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE, TRUE);
- if (h != NULL && h->type == bfd_link_hash_undefined)
- {
- h->type = bfd_link_hash_defined;
- h->u.def.value = bfd_get_section_vma (output_bfd, s);
- h->u.def.section = bfd_abs_section_ptr;
- }
-
- sprintf (buf, ".sizeof.%s", secname);
- h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE, TRUE);
- if (h != NULL && h->type == bfd_link_hash_undefined)
- {
- h->type = bfd_link_hash_defined;
- if (s->_cooked_size != 0)
- h->u.def.value = TO_ADDR (s->_cooked_size);
- else
- h->u.def.value = TO_ADDR (s->_raw_size);
- h->u.def.section = bfd_abs_section_ptr;
- }
-
- free (buf);
- }
-}
-
-static void
-lang_finish (void)
-{
- struct bfd_link_hash_entry *h;
- bfd_boolean warn;
-
- if (link_info.relocatable || link_info.shared)
- warn = FALSE;
- else
- warn = TRUE;
-
- if (entry_symbol.name == NULL)
- {
- /* No entry has been specified. Look for start, but don't warn
- if we don't find it. */
- entry_symbol.name = "start";
- warn = FALSE;
- }
-
- h = bfd_link_hash_lookup (link_info.hash, entry_symbol.name,
- FALSE, FALSE, TRUE);
- if (h != NULL
- && (h->type == bfd_link_hash_defined
- || h->type == bfd_link_hash_defweak)
- && h->u.def.section->output_section != NULL)
- {
- bfd_vma val;
-
- val = (h->u.def.value
- + bfd_get_section_vma (output_bfd,
- h->u.def.section->output_section)
- + h->u.def.section->output_offset);
- if (! bfd_set_start_address (output_bfd, val))
- einfo (_("%P%F:%s: can't set start address\n"), entry_symbol.name);
- }
- else
- {
- bfd_vma val;
- const char *send;
-
- /* We couldn't find the entry symbol. Try parsing it as a
- number. */
- val = bfd_scan_vma (entry_symbol.name, &send, 0);
- if (*send == '\0')
- {
- if (! bfd_set_start_address (output_bfd, val))
- einfo (_("%P%F: can't set start address\n"));
- }
- else
- {
- asection *ts;
-
- /* Can't find the entry symbol, and it's not a number. Use
- the first address in the text section. */
- ts = bfd_get_section_by_name (output_bfd, entry_section);
- if (ts != NULL)
- {
- if (warn)
- einfo (_("%P: warning: cannot find entry symbol %s; defaulting to %V\n"),
- entry_symbol.name,
- bfd_get_section_vma (output_bfd, ts));
- if (! bfd_set_start_address (output_bfd,
- bfd_get_section_vma (output_bfd,
- ts)))
- einfo (_("%P%F: can't set start address\n"));
- }
- else
- {
- if (warn)
- einfo (_("%P: warning: cannot find entry symbol %s; not setting start address\n"),
- entry_symbol.name);
- }
- }
- }
-
- bfd_hash_table_free (&lang_definedness_table);
-}
-
-/* This is a small function used when we want to ignore errors from
- BFD. */
-
-static void
-ignore_bfd_errors (const char *s ATTRIBUTE_UNUSED, ...)
-{
- /* 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. */
-
-static void
-lang_check (void)
-{
- lang_statement_union_type *file;
- bfd *input_bfd;
- const bfd_arch_info_type *compatible;
-
- for (file = file_chain.head; file != NULL; file = file->input_statement.next)
- {
- input_bfd = file->input_statement.the_bfd;
- compatible = bfd_arch_get_compatible (input_bfd, output_bfd,
- command_line.accept_unknown_input_arch);
-
- /* In general it is not possible to perform a relocatable
- link between differing object formats when the input
- file has relocations, because the relocations in the
- input format may not have equivalent representations in
- the output format (and besides BFD does not translate
- relocs for other link purposes than a final link). */
- if ((link_info.relocatable || link_info.emitrelocations)
- && (compatible == NULL
- || bfd_get_flavour (input_bfd) != bfd_get_flavour (output_bfd))
- && (bfd_get_file_flags (input_bfd) & HAS_RELOC) != 0)
- {
- einfo (_("%P%F: Relocatable linking with relocations from format %s (%B) to format %s (%B) is not supported\n"),
- bfd_get_target (input_bfd), input_bfd,
- bfd_get_target (output_bfd), output_bfd);
- /* einfo with %F exits. */
- }
-
- if (compatible == NULL)
- {
- 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 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
- 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 (_("%P%X: failed to merge target specific data of file %B\n"),
- input_bfd);
- }
- if (! command_line.warn_mismatch)
- bfd_set_error_handler (pfn);
- }
- }
-}
-
-/* Look through all the global common symbols and attach them to the
- correct section. The -sort-common command line switch may be used
- to roughly sort the entries by size. */
-
-static void
-lang_common (void)
-{
- if (command_line.inhibit_common_definition)
- return;
- if (link_info.relocatable
- && ! command_line.force_common_definition)
- return;
-
- if (! config.sort_common)
- bfd_link_hash_traverse (link_info.hash, lang_one_common, NULL);
- else
- {
- int power;
-
- for (power = 4; power >= 0; power--)
- bfd_link_hash_traverse (link_info.hash, lang_one_common, &power);
- }
-}
-
-/* Place one common symbol in the correct section. */
-
-static bfd_boolean
-lang_one_common (struct bfd_link_hash_entry *h, void *info)
-{
- unsigned int power_of_two;
- bfd_vma size;
- asection *section;
-
- if (h->type != bfd_link_hash_common)
- return TRUE;
-
- size = h->u.c.size;
- power_of_two = h->u.c.p->alignment_power;
-
- if (config.sort_common
- && power_of_two < (unsigned int) *(int *) info)
- return TRUE;
-
- section = h->u.c.p->section;
-
- /* Increase the size of the section to align the common sym. */
- section->_cooked_size += ((bfd_vma) 1 << (power_of_two + opb_shift)) - 1;
- section->_cooked_size &= (- (bfd_vma) 1 << (power_of_two + opb_shift));
-
- /* Adjust the alignment if necessary. */
- if (power_of_two > section->alignment_power)
- section->alignment_power = power_of_two;
-
- /* Change the symbol from common to defined. */
- h->type = bfd_link_hash_defined;
- h->u.def.section = section;
- h->u.def.value = section->_cooked_size;
-
- /* Increase the size of the section. */
- section->_cooked_size += size;
-
- /* 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)
- {
- static bfd_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;
-}
-
-/* Run through the input files and ensure that every input section has
- somewhere to go. If one is found without a destination then create
- an input request and place it into the statement tree. */
-
-static void
-lang_place_orphans (void)
-{
- LANG_FOR_EACH_INPUT_STATEMENT (file)
- {
- asection *s;
-
- for (s = file->the_bfd->sections; s != NULL; s = s->next)
- {
- if (s->output_section == NULL)
- {
- /* This section of the file is not attached, root
- around for a sensible place for it to go. */
-
- if (file->just_syms_flag)
- {
- abort ();
- }
- else if (strcmp (s->name, "COMMON") == 0)
- {
- /* This is a lonely common section which must have
- come from an archive. We attach to the section
- with the wildcard. */
- if (! link_info.relocatable
- || command_line.force_common_definition)
- {
- 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");
-
- }
- lang_add_section (&default_common_section->children, s,
- default_common_section, file);
- }
- }
- else if (ldemul_place_orphan (file, s))
- ;
- else
- {
- lang_output_section_statement_type *os;
-
- os = lang_output_section_statement_lookup (s->name);
- lang_add_section (&os->children, s, os, file);
- }
- }
- }
- }
-}
-
-void
-lang_set_flags (lang_memory_region_type *ptr, const char *flags, int invert)
-{
- flagword *ptr_flags;
-
- ptr_flags = invert ? &ptr->not_flags : &ptr->flags;
- while (*flags)
- {
- switch (*flags)
- {
- case 'A': case 'a':
- *ptr_flags |= SEC_ALLOC;
- break;
-
- case 'R': case 'r':
- *ptr_flags |= SEC_READONLY;
- break;
-
- 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;
- }
- flags++;
- }
-}
-
-/* Call a function on each input file. This function will be called
- on an archive, but not on the elements. */
-
-void
-lang_for_each_input_file (void (*func) (lang_input_statement_type *))
-{
- lang_input_statement_type *f;
-
- for (f = (lang_input_statement_type *) input_file_chain.head;
- f != NULL;
- f = (lang_input_statement_type *) f->next_real_file)
- func (f);
-}
-
-/* Call a function on each file. The function will be called on all
- the elements of an archive which are included in the link, but will
- not be called on the archive file itself. */
-
-void
-lang_for_each_file (void (*func) (lang_input_statement_type *))
-{
- LANG_FOR_EACH_INPUT_STATEMENT (f)
- {
- func (f);
- }
-}
-
-void
-ldlang_add_file (lang_input_statement_type *entry)
-{
- bfd **pp;
-
- lang_statement_append (&file_chain,
- (lang_statement_union_type *) entry,
- &entry->next);
-
- /* The BFD linker needs to have a list of all input BFDs involved in
- a link. */
- ASSERT (entry->the_bfd->link_next == NULL);
- ASSERT (entry->the_bfd != output_bfd);
- for (pp = &link_info.input_bfds; *pp != NULL; pp = &(*pp)->link_next)
- ;
- *pp = entry->the_bfd;
- entry->the_bfd->usrdata = 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, entry);
-}
-
-void
-lang_add_output (const char *name, int from_script)
-{
- /* Make -o on command line override OUTPUT in script. */
- if (!had_output_filename || !from_script)
- {
- output_filename = name;
- had_output_filename = TRUE;
- }
-}
-
-static lang_output_section_statement_type *current_section;
-
-static int
-topower (int x)
-{
- unsigned int i = 1;
- int l;
-
- if (x < 0)
- return -1;
-
- for (l = 0; l < 32; l++)
- {
- if (i >= (unsigned int) x)
- return l;
- i <<= 1;
- }
-
- return 0;
-}
-
-lang_output_section_statement_type *
-lang_enter_output_section_statement (const char *output_section_statement_name,
- etree_type *address_exp,
- enum section_type sectype,
- etree_type *align,
- etree_type *subalign,
- etree_type *ebase)
-{
- lang_output_section_statement_type *os;
-
- current_section =
- os =
- lang_output_section_statement_lookup (output_section_statement_name);
-
- /* Add this statement to tree. */
-#if 0
- add_statement (lang_output_section_statement_enum,
- output_section_statement);
-#endif
- /* Make next things chain into subchain of this. */
-
- if (os->addr_tree == NULL)
- {
- os->addr_tree = address_exp;
- }
- os->sectype = sectype;
- if (sectype != noload_section)
- os->flags = SEC_NO_FLAGS;
- else
- os->flags = SEC_NEVER_LOAD;
- os->block_value = 1;
- stat_ptr = &os->children;
-
- os->subsection_alignment =
- topower (exp_get_value_int (subalign, -1, "subsection alignment", 0));
- os->section_alignment =
- topower (exp_get_value_int (align, -1, "section alignment", 0));
-
- os->load_base = ebase;
- return os;
-}
-
-void
-lang_final (void)
-{
- lang_output_statement_type *new =
- new_stat (lang_output_statement, stat_ptr);
-
- new->name = output_filename;
-}
-
-/* Reset the current counters in the regions. */
-
-void
-lang_reset_memory_regions (void)
-{
- lang_memory_region_type *p = lang_memory_region_list;
- asection *o;
-
- for (p = lang_memory_region_list; p != NULL; p = p->next)
- {
- p->old_length = (bfd_size_type) (p->current - p->origin);
- p->current = p->origin;
- }
-
- for (o = output_bfd->sections; o != NULL; o = o->next)
- o->_raw_size = 0;
-}
-
-/* If the wild pattern was marked KEEP, the member sections
- should be as well. */
-
-static void
-gc_section_callback (lang_wild_statement_type *ptr,
- struct wildcard_list *sec ATTRIBUTE_UNUSED,
- asection *section,
- lang_input_statement_type *file ATTRIBUTE_UNUSED,
- void *data ATTRIBUTE_UNUSED)
-{
- if (ptr->keep_sections)
- section->flags |= SEC_KEEP;
-}
-
-/* Handle a wild statement, marking it against GC. */
-
-static void
-lang_gc_wild (lang_wild_statement_type *s)
-{
- walk_wild (s, gc_section_callback, NULL);
-}
-
-/* Iterate over sections marking them against GC. */
-
-static void
-lang_gc_sections_1 (lang_statement_union_type *s)
-{
- for (; s != NULL; s = s->header.next)
- {
- switch (s->header.type)
- {
- case lang_wild_statement_enum:
- lang_gc_wild (&s->wild_statement);
- break;
- case lang_constructors_statement_enum:
- lang_gc_sections_1 (constructor_list.head);
- break;
- case lang_output_section_statement_enum:
- lang_gc_sections_1 (s->output_section_statement.children.head);
- break;
- case lang_group_statement_enum:
- lang_gc_sections_1 (s->group_statement.children.head);
- break;
- default:
- break;
- }
- }
-}
-
-static void
-lang_gc_sections (void)
-{
- struct bfd_link_hash_entry *h;
- ldlang_undef_chain_list_type *ulist;
-
- /* Keep all sections so marked in the link script. */
-
- lang_gc_sections_1 (statement_list.head);
-
- /* Keep all sections containing symbols undefined on the command-line,
- and the section containing the entry symbol. */
-
- for (ulist = link_info.gc_sym_list; ulist; ulist = ulist->next)
- {
- h = bfd_link_hash_lookup (link_info.hash, ulist->name,
- FALSE, FALSE, FALSE);
-
- if (h != NULL
- && (h->type == bfd_link_hash_defined
- || h->type == bfd_link_hash_defweak)
- && ! bfd_is_abs_section (h->u.def.section))
- {
- h->u.def.section->flags |= SEC_KEEP;
- }
- }
-
- bfd_gc_sections (output_bfd, &link_info);
-}
-
-void
-lang_process (void)
-{
- lang_reasonable_defaults ();
- current_target = default_target;
-
- /* Open the output file. */
- lang_for_each_statement (ldlang_open_output);
- init_opb ();
-
- ldemul_create_output_section_statements ();
-
- /* Add to the hash table all undefineds on the command line. */
- lang_place_undefineds ();
-
- already_linked_table_init ();
-
- /* Create a bfd for each input file. */
- current_target = default_target;
- open_input_bfds (statement_list.head, FALSE);
-
- link_info.gc_sym_list = &entry_symbol;
- if (entry_symbol.name == NULL)
- link_info.gc_sym_list = ldlang_undef_chain_list_head;
-
- ldemul_after_open ();
-
- already_linked_table_free ();
-
- /* 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 ();
-
- /* Handle .exports instead of a version script if we're told to do so. */
- if (command_line.version_exports_section)
- lang_do_version_exports_section ();
-
- /* Build all sets based on the information gathered from the input
- files. */
- ldctor_build_sets ();
-
- /* Remove unreferenced sections if asked to. */
- if (command_line.gc_sections)
- lang_gc_sections ();
-
- /* If there were any SEC_MERGE sections, finish their merging, so that
- section sizes can be computed. This has to be done after GC of sections,
- so that GCed sections are not merged, but before assigning output
- sections, since removing whole input sections is hard then. */
- bfd_merge_sections (output_bfd, &link_info);
-
- /* Size up the common data. */
- lang_common ();
-
- /* Run through the contours of the script and attach input sections
- to the correct output sections. */
- map_input_to_output_sections (statement_list.head, NULL, NULL);
-
- /* Find any sections not attached explicitly and handle them. */
- lang_place_orphans ();
-
- if (! link_info.relocatable)
- {
- /* Look for a text section and set the readonly attribute in it. */
- asection *found = bfd_get_section_by_name (output_bfd, ".text");
-
- if (found != NULL)
- {
- if (config.text_read_only)
- found->flags |= SEC_READONLY;
- else
- found->flags &= ~SEC_READONLY;
- }
- }
-
- /* Do anything special before sizing sections. This is where ELF
- and other back-ends size dynamic sections. */
- ldemul_before_allocation ();
-
- if (!link_info.relocatable)
- strip_excluded_output_sections ();
-
- /* We must record the program headers before we try to fix the
- section positions, since they will affect SIZEOF_HEADERS. */
- lang_record_phdrs ();
-
- /* Size up the sections. */
- lang_size_sections (statement_list.head, abs_output_section,
- &statement_list.head, 0, 0, NULL,
- command_line.relax ? FALSE : TRUE);
-
- /* Now run around and relax if we can. */
- if (command_line.relax)
- {
- /* Keep relaxing until bfd_relax_section gives up. */
- bfd_boolean relax_again;
-
- do
- {
- relax_again = FALSE;
-
- /* Note: pe-dll.c does something like this also. If you find
- you need to change this code, you probably need to change
- pe-dll.c also. DJ */
-
- /* Do all the assignments with our current guesses as to
- section sizes. */
- lang_do_assignments (statement_list.head, abs_output_section,
- NULL, 0);
-
- /* We must do this after lang_do_assignments, because it uses
- _raw_size. */
- lang_reset_memory_regions ();
-
- /* Perform another relax pass - this time we know where the
- globals are, so can make a better guess. */
- lang_size_sections (statement_list.head, abs_output_section,
- &statement_list.head, 0, 0, &relax_again, FALSE);
-
- /* If the normal relax is done and the relax finalize pass
- is not performed yet, we perform another relax pass. */
- if (!relax_again && link_info.need_relax_finalize)
- {
- link_info.need_relax_finalize = FALSE;
- relax_again = TRUE;
- }
- }
- while (relax_again);
-
- /* Final extra sizing to report errors. */
- lang_do_assignments (statement_list.head, abs_output_section, NULL, 0);
- lang_reset_memory_regions ();
- lang_size_sections (statement_list.head, abs_output_section,
- &statement_list.head, 0, 0, NULL, TRUE);
- }
-
- /* See if anything special should be done now we know how big
- everything is. */
- ldemul_after_allocation ();
-
- /* Fix any .startof. or .sizeof. symbols. */
- lang_set_startof ();
-
- /* Do all the assignments, now that we know the final resting places
- of all the symbols. */
-
- lang_do_assignments (statement_list.head, abs_output_section, NULL, 0);
-
- /* Make sure that the section addresses make sense. */
- if (! link_info.relocatable
- && command_line.check_section_addresses)
- lang_check_section_addresses ();
-
- /* Final stuffs. */
-
- ldemul_finish ();
- lang_finish ();
-}
-
-/* EXPORTED TO YACC */
-
-void
-lang_add_wild (struct wildcard_spec *filespec,
- struct wildcard_list *section_list,
- bfd_boolean keep_sections)
-{
- struct wildcard_list *curr, *next;
- lang_wild_statement_type *new;
-
- /* Reverse the list as the parser puts it back to front. */
- for (curr = section_list, section_list = NULL;
- curr != NULL;
- section_list = curr, curr = next)
- {
- if (curr->spec.name != NULL && strcmp (curr->spec.name, "COMMON") == 0)
- placed_commons = TRUE;
-
- next = curr->next;
- curr->next = section_list;
- }
-
- if (filespec != NULL && filespec->name != NULL)
- {
- if (strcmp (filespec->name, "*") == 0)
- filespec->name = NULL;
- else if (! wildcardp (filespec->name))
- lang_has_input_file = TRUE;
- }
-
- new = new_stat (lang_wild_statement, stat_ptr);
- new->filename = NULL;
- new->filenames_sorted = FALSE;
- if (filespec != NULL)
- {
- new->filename = filespec->name;
- new->filenames_sorted = filespec->sorted;
- }
- new->section_list = section_list;
- new->keep_sections = keep_sections;
- lang_list_init (&new->children);
-}
-
-void
-lang_section_start (const char *name, etree_type *address)
-{
- lang_address_statement_type *ad;
-
- ad = new_stat (lang_address_statement, stat_ptr);
- ad->section_name = name;
- ad->address = address;
-}
-
-/* Set the start symbol to NAME. CMDLINE is nonzero if this is called
- because of a -e argument on the command line, or zero if this is
- called by ENTRY in a linker script. Command line arguments take
- precedence. */
-
-void
-lang_add_entry (const char *name, bfd_boolean cmdline)
-{
- if (entry_symbol.name == NULL
- || cmdline
- || ! entry_from_cmdline)
- {
- entry_symbol.name = name;
- entry_from_cmdline = cmdline;
- }
-}
-
-void
-lang_add_target (const char *name)
-{
- lang_target_statement_type *new = new_stat (lang_target_statement,
- stat_ptr);
-
- new->target = name;
-
-}
-
-void
-lang_add_map (const char *name)
-{
- while (*name)
- {
- switch (*name)
- {
- case 'F':
- map_option_f = TRUE;
- break;
- }
- name++;
- }
-}
-
-void
-lang_add_fill (fill_type *fill)
-{
- lang_fill_statement_type *new = new_stat (lang_fill_statement,
- stat_ptr);
-
- new->fill = fill;
-}
-
-void
-lang_add_data (int type, union etree_union *exp)
-{
-
- lang_data_statement_type *new = new_stat (lang_data_statement,
- stat_ptr);
-
- new->exp = exp;
- new->type = type;
-
-}
-
-/* Create a new reloc statement. RELOC is the BFD relocation type to
- generate. HOWTO is the corresponding howto structure (we could
- look this up, but the caller has already done so). SECTION is the
- section to generate a reloc against, or NAME is the name of the
- symbol to generate a reloc against. Exactly one of SECTION and
- NAME must be NULL. ADDEND is an expression for the addend. */
-
-void
-lang_add_reloc (bfd_reloc_code_real_type reloc,
- reloc_howto_type *howto,
- asection *section,
- const char *name,
- union etree_union *addend)
-{
- lang_reloc_statement_type *p = new_stat (lang_reloc_statement, stat_ptr);
-
- p->reloc = reloc;
- p->howto = howto;
- p->section = section;
- p->name = name;
- p->addend_exp = addend;
-
- p->addend_value = 0;
- p->output_section = NULL;
- p->output_vma = 0;
-}
-
-lang_assignment_statement_type *
-lang_add_assignment (etree_type *exp)
-{
- lang_assignment_statement_type *new = new_stat (lang_assignment_statement,
- stat_ptr);
-
- new->exp = exp;
- return new;
-}
-
-void
-lang_add_attribute (enum statement_enum attribute)
-{
- new_statement (attribute, sizeof (lang_statement_union_type), stat_ptr);
-}
-
-void
-lang_startup (const char *name)
-{
- if (startup_file != NULL)
- {
- einfo (_("%P%Fmultiple STARTUP files\n"));
- }
- first_file->filename = name;
- first_file->local_sym_name = name;
- first_file->real = TRUE;
-
- startup_file = name;
-}
-
-void
-lang_float (bfd_boolean maybe)
-{
- lang_float_flag = maybe;
-}
-
-
-/* Work out the load- and run-time regions from a script statement, and
- store them in *LMA_REGION and *REGION respectively.
-
- MEMSPEC is the name of the run-time region, or the value of
- DEFAULT_MEMORY_REGION if the statement didn't specify one.
- LMA_MEMSPEC is the name of the load-time region, or null if the
- statement didn't specify one.HAVE_LMA_P is TRUE if the statement
- had an explicit load address.
-
- It is an error to specify both a load region and a load address. */
-
-static void
-lang_get_regions (lang_memory_region_type **region,
- lang_memory_region_type **lma_region,
- const char *memspec,
- const char *lma_memspec,
- bfd_boolean have_lma,
- bfd_boolean have_vma)
-{
- *lma_region = lang_memory_region_lookup (lma_memspec, FALSE);
-
- /* If no runtime region or VMA has been specified, but the load region has
- been specified, then use the load region for the runtime region as well. */
- if (lma_memspec != NULL
- && ! have_vma
- && strcmp (memspec, DEFAULT_MEMORY_REGION) == 0)
- *region = *lma_region;
- else
- *region = lang_memory_region_lookup (memspec, FALSE);
-
- if (have_lma && lma_memspec != 0)
- einfo (_("%X%P:%S: section has both a load address and a load region\n"));
-}
-
-void
-lang_leave_output_section_statement (fill_type *fill, const char *memspec,
- lang_output_section_phdr_list *phdrs,
- const char *lma_memspec)
-{
- lang_get_regions (&current_section->region,
- &current_section->lma_region,
- memspec, lma_memspec,
- current_section->load_base != NULL,
- current_section->addr_tree != NULL);
- current_section->fill = fill;
- current_section->phdrs = phdrs;
- stat_ptr = &statement_list;
-}
-
-/* Create an absolute symbol with the given name with the value of the
- address of first byte of the section named.
-
- If the symbol already exists, then do nothing. */
-
-void
-lang_abs_symbol_at_beginning_of (const char *secname, const char *name)
-{
- struct bfd_link_hash_entry *h;
-
- h = bfd_link_hash_lookup (link_info.hash, name, TRUE, TRUE, TRUE);
- if (h == NULL)
- einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n"));
-
- if (h->type == bfd_link_hash_new
- || h->type == bfd_link_hash_undefined)
- {
- asection *sec;
-
- h->type = bfd_link_hash_defined;
-
- sec = bfd_get_section_by_name (output_bfd, secname);
- if (sec == NULL)
- h->u.def.value = 0;
- else
- h->u.def.value = bfd_get_section_vma (output_bfd, sec);
-
- h->u.def.section = bfd_abs_section_ptr;
- }
-}
-
-/* Create an absolute symbol with the given name with the value of the
- address of the first byte after the end of the section named.
-
- If the symbol already exists, then do nothing. */
-
-void
-lang_abs_symbol_at_end_of (const char *secname, const char *name)
-{
- struct bfd_link_hash_entry *h;
-
- h = bfd_link_hash_lookup (link_info.hash, name, TRUE, TRUE, TRUE);
- if (h == NULL)
- einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n"));
-
- if (h->type == bfd_link_hash_new
- || h->type == bfd_link_hash_undefined)
- {
- asection *sec;
-
- h->type = bfd_link_hash_defined;
-
- sec = bfd_get_section_by_name (output_bfd, secname);
- if (sec == NULL)
- h->u.def.value = 0;
- else
- h->u.def.value = (bfd_get_section_vma (output_bfd, sec)
- + TO_ADDR (bfd_section_size (output_bfd, sec)));
-
- h->u.def.section = bfd_abs_section_ptr;
- }
-}
-
-void
-lang_statement_append (lang_statement_list_type *list,
- lang_statement_union_type *element,
- lang_statement_union_type **field)
-{
- *(list->tail) = element;
- list->tail = field;
-}
-
-/* Set the output format type. -oformat overrides scripts. */
-
-void
-lang_add_output_format (const char *format,
- const char *big,
- const char *little,
- int from_script)
-{
- if (output_target == NULL || !from_script)
- {
- if (command_line.endian == ENDIAN_BIG
- && big != NULL)
- format = big;
- else if (command_line.endian == ENDIAN_LITTLE
- && little != NULL)
- format = little;
-
- output_target = format;
- }
-}
-
-/* Enter a group. This creates a new lang_group_statement, and sets
- stat_ptr to build new statements within the group. */
-
-void
-lang_enter_group (void)
-{
- lang_group_statement_type *g;
-
- g = new_stat (lang_group_statement, stat_ptr);
- lang_list_init (&g->children);
- stat_ptr = &g->children;
-}
-
-/* Leave a group. This just resets stat_ptr to start writing to the
- regular list of statements again. Note that this will not work if
- groups can occur inside anything else which can adjust stat_ptr,
- but currently they can't. */
-
-void
-lang_leave_group (void)
-{
- stat_ptr = &statement_list;
-}
-
-/* Add a new program header. This is called for each entry in a PHDRS
- command in a linker script. */
-
-void
-lang_new_phdr (const char *name,
- etree_type *type,
- bfd_boolean filehdr,
- bfd_boolean phdrs,
- etree_type *at,
- etree_type *flags)
-{
- struct lang_phdr *n, **pp;
-
- n = stat_alloc (sizeof (struct lang_phdr));
- n->next = NULL;
- n->name = name;
- n->type = exp_get_value_int (type, 0, "program header type",
- lang_final_phase_enum);
- n->filehdr = filehdr;
- n->phdrs = phdrs;
- n->at = at;
- n->flags = flags;
-
- for (pp = &lang_phdr_list; *pp != NULL; pp = &(*pp)->next)
- ;
- *pp = n;
-}
-
-/* Record the program header information in the output BFD. FIXME: We
- should not be calling an ELF specific function here. */
-
-static void
-lang_record_phdrs (void)
-{
- unsigned int alc;
- asection **secs;
- lang_output_section_phdr_list *last;
- struct lang_phdr *l;
- lang_statement_union_type *u;
-
- alc = 10;
- secs = xmalloc (alc * sizeof (asection *));
- last = NULL;
- for (l = lang_phdr_list; l != NULL; l = l->next)
- {
- unsigned int c;
- flagword flags;
- bfd_vma at;
-
- c = 0;
- for (u = lang_output_section_statement.head;
- u != NULL;
- u = u->output_section_statement.next)
- {
- lang_output_section_statement_type *os;
- lang_output_section_phdr_list *pl;
-
- os = &u->output_section_statement;
-
- pl = os->phdrs;
- if (pl != NULL)
- last = pl;
- else
- {
- if (os->sectype == noload_section
- || os->bfd_section == NULL
- || (os->bfd_section->flags & SEC_ALLOC) == 0)
- continue;
- pl = last;
- }
-
- if (os->bfd_section == NULL)
- continue;
-
- for (; pl != NULL; pl = pl->next)
- {
- if (strcmp (pl->name, l->name) == 0)
- {
- if (c >= alc)
- {
- alc *= 2;
- secs = xrealloc (secs, alc * sizeof (asection *));
- }
- secs[c] = os->bfd_section;
- ++c;
- pl->used = TRUE;
- }
- }
- }
-
- if (l->flags == NULL)
- flags = 0;
- else
- flags = exp_get_vma (l->flags, 0, "phdr flags",
- lang_final_phase_enum);
-
- if (l->at == NULL)
- at = 0;
- else
- at = exp_get_vma (l->at, 0, "phdr load address",
- lang_final_phase_enum);
-
- if (! bfd_record_phdr (output_bfd, l->type,
- l->flags != NULL, flags, l->at != NULL,
- at, l->filehdr, l->phdrs, c, secs))
- einfo (_("%F%P: bfd_record_phdr failed: %E\n"));
- }
-
- free (secs);
-
- /* Make sure all the phdr assignments succeeded. */
- for (u = lang_output_section_statement.head;
- u != NULL;
- u = u->output_section_statement.next)
- {
- lang_output_section_phdr_list *pl;
-
- if (u->output_section_statement.bfd_section == NULL)
- continue;
-
- for (pl = u->output_section_statement.phdrs;
- pl != NULL;
- pl = pl->next)
- if (! pl->used && strcmp (pl->name, "NONE") != 0)
- einfo (_("%X%P: section `%s' assigned to non-existent phdr `%s'\n"),
- u->output_section_statement.name, pl->name);
- }
-}
-
-/* Record a list of sections which may not be cross referenced. */
-
-void
-lang_add_nocrossref (lang_nocrossref_type *l)
-{
- struct lang_nocrossrefs *n;
-
- n = 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;
-}
-
-/* Overlay handling. We handle overlays with some static variables. */
-
-/* The overlay virtual address. */
-static etree_type *overlay_vma;
-/* And subsection alignment. */
-static etree_type *overlay_subalign;
-
-/* 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 (etree_type *vma_expr, etree_type *subalign)
-{
- /* The grammar should prevent nested overlays from occurring. */
- ASSERT (overlay_vma == NULL
- && overlay_subalign == NULL
- && overlay_max == NULL);
-
- overlay_vma = vma_expr;
- overlay_subalign = subalign;
-}
-
-/* Start a section in an overlay. We handle this by calling
- lang_enter_output_section_statement with the correct VMA.
- lang_leave_overlay sets up the LMA and memory regions. */
-
-void
-lang_enter_overlay_section (const char *name)
-{
- struct overlay_list *n;
- etree_type *size;
-
- lang_enter_output_section_statement (name, overlay_vma, normal_section,
- 0, overlay_subalign, 0);
-
- /* If this is the first section, then base the VMA 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);
-
- /* Remember the section. */
- n = xmalloc (sizeof *n);
- n->os = current_section;
- n->next = overlay_list;
- overlay_list = n;
-
- size = exp_nameop (SIZEOF, name);
-
- /* Arrange to work out the maximum section end address. */
- if (overlay_max == NULL)
- overlay_max = size;
- else
- overlay_max = exp_binop (MAX_K, overlay_max, size);
-}
-
-/* Finish a section in an overlay. There isn't any special to do
- here. */
-
-void
-lang_leave_overlay_section (fill_type *fill,
- lang_output_section_phdr_list *phdrs)
-{
- const char *name;
- char *clean, *s2;
- const char *s1;
- char *buf;
-
- name = current_section->name;
-
- /* For now, assume that DEFAULT_MEMORY_REGION is the run-time memory
- region and that no load-time region has been specified. It doesn't
- really matter what we say here, since lang_leave_overlay will
- override it. */
- lang_leave_output_section_statement (fill, DEFAULT_MEMORY_REGION, phdrs, 0);
-
- /* 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 (etree_type *lma_expr,
- int nocrossrefs,
- fill_type *fill,
- const char *memspec,
- lang_output_section_phdr_list *phdrs,
- const char *lma_memspec)
-{
- lang_memory_region_type *region;
- lang_memory_region_type *lma_region;
- struct overlay_list *l;
- lang_nocrossref_type *nocrossref;
-
- lang_get_regions (&region, &lma_region,
- memspec, lma_memspec,
- lma_expr != NULL, FALSE);
-
- nocrossref = NULL;
-
- /* After setting the size of the last section, set '.' to end of the
- overlay region. */
- if (overlay_list != NULL)
- overlay_list->os->update_dot_tree
- = exp_assop ('=', ".", exp_binop ('+', overlay_vma, overlay_max));
-
- l = overlay_list;
- while (l != NULL)
- {
- struct overlay_list *next;
-
- if (fill != NULL && l->os->fill == NULL)
- l->os->fill = fill;
-
- l->os->region = region;
- l->os->lma_region = lma_region;
-
- /* The first section has the load address specified in the
- OVERLAY statement. The rest are worked out from that.
- The base address is not needed (and should be null) if
- an LMA region was specified. */
- if (l->next == 0)
- l->os->load_base = lma_expr;
- else if (lma_region == 0)
- l->os->load_base = exp_binop ('+',
- exp_nameop (LOADADDR, l->next->os->name),
- exp_nameop (SIZEOF, l->next->os->name));
-
- if (phdrs != NULL && l->os->phdrs == NULL)
- l->os->phdrs = phdrs;
-
- if (nocrossrefs)
- {
- lang_nocrossref_type *nc;
-
- nc = 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);
-
- overlay_vma = NULL;
- overlay_list = NULL;
- overlay_max = NULL;
-}
-
-/* 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;
-
-/* If PREV is NULL, return first version pattern matching particular symbol.
- If PREV is non-NULL, return first version pattern matching particular
- symbol after PREV (previously returned by lang_vers_match). */
-
-static struct bfd_elf_version_expr *
-lang_vers_match (struct bfd_elf_version_expr_head *head,
- struct bfd_elf_version_expr *prev,
- const char *sym)
-{
- const char *cxx_sym = sym;
- const char *java_sym = sym;
- struct bfd_elf_version_expr *expr = NULL;
-
- if (head->mask & BFD_ELF_VERSION_CXX_TYPE)
- {
- cxx_sym = cplus_demangle (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);
- if (!java_sym)
- java_sym = sym;
- }
-
- if (head->htab && (prev == NULL || prev->symbol))
- {
- struct bfd_elf_version_expr e;
-
- switch (prev ? prev->mask : 0)
- {
- case 0:
- if (head->mask & BFD_ELF_VERSION_C_TYPE)
- {
- e.symbol = sym;
- expr = htab_find (head->htab, &e);
- while (expr && strcmp (expr->symbol, sym) == 0)
- if (expr->mask == BFD_ELF_VERSION_C_TYPE)
- goto out_ret;
- else
- expr = expr->next;
- }
- /* Fallthrough */
- case BFD_ELF_VERSION_C_TYPE:
- if (head->mask & BFD_ELF_VERSION_CXX_TYPE)
- {
- e.symbol = cxx_sym;
- expr = htab_find (head->htab, &e);
- while (expr && strcmp (expr->symbol, cxx_sym) == 0)
- if (expr->mask == BFD_ELF_VERSION_CXX_TYPE)
- goto out_ret;
- else
- expr = expr->next;
- }
- /* Fallthrough */
- case BFD_ELF_VERSION_CXX_TYPE:
- if (head->mask & BFD_ELF_VERSION_JAVA_TYPE)
- {
- e.symbol = java_sym;
- expr = htab_find (head->htab, &e);
- while (expr && strcmp (expr->symbol, java_sym) == 0)
- if (expr->mask == BFD_ELF_VERSION_JAVA_TYPE)
- goto out_ret;
- else
- expr = expr->next;
- }
- /* Fallthrough */
- default:
- break;
- }
- }
-
- /* Finally, try the wildcards. */
- if (prev == NULL || prev->symbol)
- expr = head->remaining;
- else
- expr = prev->next;
- while (expr)
- {
- const char *s;
-
- if (expr->pattern[0] == '*' && expr->pattern[1] == '\0')
- break;
-
- if (expr->mask == BFD_ELF_VERSION_JAVA_TYPE)
- s = java_sym;
- else if (expr->mask == BFD_ELF_VERSION_CXX_TYPE)
- s = cxx_sym;
- else
- s = sym;
- if (fnmatch (expr->pattern, s, 0) == 0)
- break;
- expr = expr->next;
- }
-
-out_ret:
- if (cxx_sym != sym)
- free ((char *) cxx_sym);
- if (java_sym != sym)
- free ((char *) java_sym);
- return expr;
-}
-
-/* Return NULL if the PATTERN argument is a glob pattern, otherwise,
- return a string pointing to the symbol name. */
-
-static const char *
-realsymbol (const char *pattern)
-{
- const char *p;
- bfd_boolean changed = FALSE, backslash = FALSE;
- char *s, *symbol = xmalloc (strlen (pattern) + 1);
-
- for (p = pattern, s = symbol; *p != '\0'; ++p)
- {
- /* It is a glob pattern only if there is no preceding
- backslash. */
- if (! backslash && (*p == '?' || *p == '*' || *p == '['))
- {
- free (symbol);
- return NULL;
- }
-
- if (backslash)
- {
- /* Remove the preceding backslash. */
- *(s - 1) = *p;
- changed = TRUE;
- }
- else
- *s++ = *p;
-
- backslash = *p == '\\';
- }
-
- if (changed)
- {
- *s = '\0';
- return symbol;
- }
- else
- {
- free (symbol);
- return pattern;
- }
-}
-
-/* This is called for each variable name or match expression. */
-
-struct bfd_elf_version_expr *
-lang_new_vers_pattern (struct bfd_elf_version_expr *orig,
- const char *new,
- const char *lang)
-{
- struct bfd_elf_version_expr *ret;
-
- ret = xmalloc (sizeof *ret);
- ret->next = orig;
- ret->pattern = new;
- ret->symver = 0;
- ret->script = 0;
- ret->symbol = realsymbol (new);
-
- if (lang == NULL || strcasecmp (lang, "C") == 0)
- ret->mask = BFD_ELF_VERSION_C_TYPE;
- else if (strcasecmp (lang, "C++") == 0)
- ret->mask = BFD_ELF_VERSION_CXX_TYPE;
- else if (strcasecmp (lang, "Java") == 0)
- ret->mask = BFD_ELF_VERSION_JAVA_TYPE;
- else
- {
- einfo (_("%X%P: unknown language `%s' in version information\n"),
- lang);
- ret->mask = BFD_ELF_VERSION_C_TYPE;
- }
-
- return ldemul_new_vers_pattern (ret);
-}
-
-/* This is called for each set of variable names and match
- expressions. */
-
-struct bfd_elf_version_tree *
-lang_new_vers_node (struct bfd_elf_version_expr *globals,
- struct bfd_elf_version_expr *locals)
-{
- struct bfd_elf_version_tree *ret;
-
- ret = xcalloc (1, sizeof *ret);
- ret->globals.list = globals;
- ret->locals.list = locals;
- ret->match = lang_vers_match;
- ret->name_indx = (unsigned int) -1;
- return ret;
-}
-
-/* This static variable keeps track of version indices. */
-
-static int version_index;
-
-static hashval_t
-version_expr_head_hash (const void *p)
-{
- const struct bfd_elf_version_expr *e = p;
-
- return htab_hash_string (e->symbol);
-}
-
-static int
-version_expr_head_eq (const void *p1, const void *p2)
-{
- const struct bfd_elf_version_expr *e1 = p1;
- const struct bfd_elf_version_expr *e2 = p2;
-
- return strcmp (e1->symbol, e2->symbol) == 0;
-}
-
-static void
-lang_finalize_version_expr_head (struct bfd_elf_version_expr_head *head)
-{
- size_t count = 0;
- struct bfd_elf_version_expr *e, *next;
- struct bfd_elf_version_expr **list_loc, **remaining_loc;
-
- for (e = head->list; e; e = e->next)
- {
- if (e->symbol)
- count++;
- head->mask |= e->mask;
- }
-
- if (count)
- {
- head->htab = htab_create (count * 2, version_expr_head_hash,
- version_expr_head_eq, NULL);
- list_loc = &head->list;
- remaining_loc = &head->remaining;
- for (e = head->list; e; e = next)
- {
- next = e->next;
- if (!e->symbol)
- {
- *remaining_loc = e;
- remaining_loc = &e->next;
- }
- else
- {
- void **loc = htab_find_slot (head->htab, e, INSERT);
-
- if (*loc)
- {
- struct bfd_elf_version_expr *e1, *last;
-
- e1 = *loc;
- last = NULL;
- do
- {
- if (e1->mask == e->mask)
- {
- last = NULL;
- break;
- }
- last = e1;
- e1 = e1->next;
- }
- while (e1 && strcmp (e1->symbol, e->symbol) == 0);
-
- if (last == NULL)
- {
- /* This is a duplicate. */
- /* FIXME: Memory leak. Sometimes pattern is not
- xmalloced alone, but in larger chunk of memory. */
- /* free (e->symbol); */
- free (e);
- }
- else
- {
- e->next = last->next;
- last->next = e;
- }
- }
- else
- {
- *loc = e;
- *list_loc = e;
- list_loc = &e->next;
- }
- }
- }
- *remaining_loc = NULL;
- *list_loc = head->remaining;
- }
- else
- head->remaining = head->list;
-}
-
-/* This is called when we know the name and dependencies of the
- version. */
-
-void
-lang_register_vers_node (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;
-
- if (name == NULL)
- name = "";
-
- if ((name[0] == '\0' && lang_elf_version_info != NULL)
- || (lang_elf_version_info && lang_elf_version_info->name[0] == '\0'))
- {
- einfo (_("%X%P: anonymous version tag cannot be combined with other version tags\n"));
- free (version);
- return;
- }
-
- /* 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);
-
- lang_finalize_version_expr_head (&version->globals);
- lang_finalize_version_expr_head (&version->locals);
-
- /* Check the global and local match names, and make sure there
- aren't any duplicates. */
-
- for (e1 = version->globals.list; e1 != NULL; e1 = e1->next)
- {
- for (t = lang_elf_version_info; t != NULL; t = t->next)
- {
- struct bfd_elf_version_expr *e2;
-
- if (t->locals.htab && e1->symbol)
- {
- e2 = htab_find (t->locals.htab, e1);
- while (e2 && strcmp (e1->symbol, e2->symbol) == 0)
- {
- if (e1->mask == e2->mask)
- einfo (_("%X%P: duplicate expression `%s' in version information\n"),
- e1->symbol);
- e2 = e2->next;
- }
- }
- else if (!e1->symbol)
- for (e2 = t->locals.remaining; e2 != NULL; e2 = e2->next)
- if (strcmp (e1->pattern, e2->pattern) == 0 && e1->mask == e2->mask)
- einfo (_("%X%P: duplicate expression `%s' in version information\n"),
- e1->pattern);
- }
- }
-
- for (e1 = version->locals.list; e1 != NULL; e1 = e1->next)
- {
- for (t = lang_elf_version_info; t != NULL; t = t->next)
- {
- struct bfd_elf_version_expr *e2;
-
- if (t->globals.htab && e1->symbol)
- {
- e2 = htab_find (t->globals.htab, e1);
- while (e2 && strcmp (e1->symbol, e2->symbol) == 0)
- {
- if (e1->mask == e2->mask)
- einfo (_("%X%P: duplicate expression `%s' in version information\n"),
- e1->symbol);
- e2 = e2->next;
- }
- }
- else if (!e1->symbol)
- for (e2 = t->globals.remaining; e2 != NULL; e2 = e2->next)
- if (strcmp (e1->pattern, e2->pattern) == 0 && e1->mask == e2->mask)
- einfo (_("%X%P: duplicate expression `%s' in version information\n"),
- e1->pattern);
- }
- }
-
- version->deps = deps;
- version->name = name;
- if (name[0] != '\0')
- {
- ++version_index;
- version->vernum = version_index;
- }
- else
- version->vernum = 0;
-
- 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 (struct bfd_elf_version_deps *list, const char *name)
-{
- struct bfd_elf_version_deps *ret;
- struct bfd_elf_version_tree *t;
-
- ret = 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;
-}
-
-static void
-lang_do_version_exports_section (void)
-{
- struct bfd_elf_version_expr *greg = NULL, *lreg;
-
- LANG_FOR_EACH_INPUT_STATEMENT (is)
- {
- asection *sec = bfd_get_section_by_name (is->the_bfd, ".exports");
- char *contents, *p;
- bfd_size_type len;
-
- if (sec == NULL)
- continue;
-
- len = bfd_section_size (is->the_bfd, sec);
- contents = xmalloc (len);
- if (!bfd_get_section_contents (is->the_bfd, sec, contents, 0, len))
- einfo (_("%X%P: unable to read .exports section contents\n"), sec);
-
- p = contents;
- while (p < contents + len)
- {
- greg = lang_new_vers_pattern (greg, p, NULL);
- p = strchr (p, '\0') + 1;
- }
-
- /* Do not free the contents, as we used them creating the regex. */
-
- /* Do not include this section in the link. */
- bfd_set_section_flags (is->the_bfd, sec,
- bfd_get_section_flags (is->the_bfd, sec) | SEC_EXCLUDE);
- }
-
- lreg = lang_new_vers_pattern (NULL, "*", NULL);
- lang_register_vers_node (command_line.version_exports_section,
- lang_new_vers_node (greg, lreg), NULL);
-}
-
-void
-lang_add_unique (const char *name)
-{
- struct unique_sections *ent;
-
- for (ent = unique_section_list; ent; ent = ent->next)
- if (strcmp (ent->name, name) == 0)
- return;
-
- ent = xmalloc (sizeof *ent);
- ent->name = xstrdup (name);
- ent->next = unique_section_list;
- unique_section_list = ent;
-}