/* Linker command language support.
Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001
+ 2001, 2002
Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
#include "ld.h"
#include "ldmain.h"
-#include "ldgram.h"
#include "ldexp.h"
#include "ldlang.h"
+#include "ldgram.h"
#include "ldlex.h"
#include "ldmisc.h"
#include "ldctor.h"
static void ldlang_open_output PARAMS ((lang_statement_union_type *));
static void open_input_bfds PARAMS ((lang_statement_union_type *, boolean));
static void lang_reasonable_defaults PARAMS ((void));
+static void insert_undefined PARAMS ((const char *));
static void lang_place_undefineds PARAMS ((void));
static void map_input_to_output_sections
PARAMS ((lang_statement_union_type *, const char *,
PARAMS ((lang_statement_union_type *, lang_output_section_statement_type *));
static void print_statements PARAMS ((void));
static void insert_pad
- PARAMS ((lang_statement_union_type **, fill_type,
+ PARAMS ((lang_statement_union_type **, fill_type *,
unsigned int, asection *, bfd_vma));
static bfd_vma size_input_section
PARAMS ((lang_statement_union_type **, lang_output_section_statement_type *,
- fill_type, bfd_vma));
+ fill_type *, bfd_vma));
static void lang_finish PARAMS ((void));
static void ignore_bfd_errors PARAMS ((const char *, ...));
static void lang_check PARAMS ((void));
static void lang_place_orphans PARAMS ((void));
static int topower PARAMS ((int));
static void lang_set_startof PARAMS ((void));
-static void reset_memory_regions PARAMS ((void));
static void gc_section_callback
PARAMS ((lang_wild_statement_type *, struct wildcard_list *, asection *,
lang_input_statement_type *, PTR));
+static void lang_get_regions PARAMS ((struct memory_region_struct **,
+ struct memory_region_struct **,
+ const char *, const char *, int));
static void lang_record_phdrs PARAMS ((void));
static void lang_gc_wild PARAMS ((lang_wild_statement_type *));
static void lang_gc_sections_1 PARAMS ((lang_statement_union_type *));
static void os_region_check
PARAMS ((lang_output_section_statement_type *,
struct memory_region_struct *, etree_type *, bfd_vma));
+static bfd_vma lang_size_sections_1
+ PARAMS ((lang_statement_union_type *, lang_output_section_statement_type *,
+ lang_statement_union_type **, fill_type *, bfd_vma, boolean *));
typedef void (*callback_t) PARAMS ((lang_wild_statement_type *,
struct wildcard_list *,
lang_statement_list_type *stat_ptr = &statement_list;
lang_statement_list_type file_chain = { NULL, NULL };
const char *entry_symbol = NULL;
+const char *entry_section = ".text";
boolean entry_from_cmdline;
boolean lang_has_input_file = false;
boolean had_output_filename = false;
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;
}
{
lang_memory_region_type *p;
+ /* NAME is NULL for LMA memspecs if no region was specified. */
+ if (name == NULL)
+ return NULL;
+
for (p = lang_memory_region_list;
p != (lang_memory_region_type *) NULL;
p = p->next)
new_stat (lang_output_section_statement, stat_ptr);
lookup->region = (lang_memory_region_type *) NULL;
lookup->lma_region = (lang_memory_region_type *) NULL;
- lookup->fill = 0;
+ lookup->fill = (fill_type *) 0;
lookup->block_value = 1;
lookup->name = name;
lookup->subsection_alignment = -1;
lookup->section_alignment = -1;
lookup->load_base = (union etree_union *) NULL;
+ lookup->update_dot_tree = NULL;
lookup->phdrs = NULL;
lang_statement_append (&lang_output_section_statement,
discard all sections. */
if (entry->just_syms_flag)
{
- sec->output_section = bfd_abs_section_ptr;
- sec->output_offset = sec->vma;
+ bfd_link_just_syms (sec, &link_info);
return;
}
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 in link once semantics
+ causes trouble for MIPS ELF, which relies on link once semantics
to handle the .reginfo section correctly. */
name = bfd_get_section_name (abfd, sec);
section. */
sec->output_section = bfd_abs_section_ptr;
+ if (flags & SEC_GROUP)
+ bfd_discard_group (abfd, sec);
+
return;
}
}
flags &= ~ (SEC_MERGE | SEC_STRINGS);
}
+ /* For now make .tbss normal section. */
+ if (flags & SEC_THREAD_LOCAL)
+ flags |= SEC_LOAD;
+
section->output_section->flags |= flags;
if (flags & SEC_MERGE)
bfd_error_type err;
lang_statement_list_type *hold;
boolean bad_load = true;
-
+
err = bfd_get_error ();
/* See if the emulation has some special knowledge. */
einfo (_("%F%B: file not recognized: %E\n"), entry->the_bfd);
else
bad_load = false;
-
+
bfd_close (entry->the_bfd);
entry->the_bfd = NULL;
case bfd_archive:
if (entry->whole_archive)
{
- bfd * member = NULL;
+ bfd *member = NULL;
boolean loaded = true;
for (;;)
if (member == NULL)
break;
-
+
if (! bfd_check_format (member, bfd_object))
{
einfo (_("%F%B: member %B in archive is not an object\n"),
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. */
+ later get something which doesn't know where to put it. */
default_common_section = output;
}
}
}
/* Add the supplied name to the symbol table as an undefined reference.
- Remove items from the chain as we open input bfds. */
+ 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 ldlang_undef_chain_list
{
struct ldlang_undef_chain_list *next;
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 (name)
+ const char *name;
+{
+ struct bfd_link_hash_entry *h;
+
+ h = bfd_link_hash_lookup (link_info.hash, name, true, false, true);
+ if (h == (struct bfd_link_hash_entry *) 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
ptr != (ldlang_undef_chain_list_type *) NULL;
ptr = ptr->next)
{
- struct bfd_link_hash_entry *h;
-
- h = bfd_link_hash_lookup (link_info.hash, ptr->name, true, false, true);
- if (h == (struct bfd_link_hash_entry *) NULL)
- einfo (_("%P%F: bfd_link_hash_lookup failed: %E\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);
- }
+ insert_undefined (ptr->name);
}
}
{
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,
result = exp_fold_tree (assignment->exp->assign.src, output_section,
lang_final_phase_enum, print_dot, &print_dot);
if (result.valid_p)
- minfo ("0x%V", result.value + result.section->bfd_section->vma);
+ {
+ 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* ");
print_fill_statement (fill)
lang_fill_statement_type *fill;
{
- fprintf (config.map_file, " FILL mask 0x%x\n", fill->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
addr = s->output_offset;
if (s->output_section != NULL)
addr += s->output_section->vma;
- minfo ("0x%V %W", addr, s->size);
+ minfo ("0x%V %W ", addr, s->size);
- if (s->fill != 0)
- minfo (" %u", s->fill);
+ 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 ();
static void
insert_pad (ptr, fill, alignment_needed, output_section, dot)
lang_statement_union_type **ptr;
- fill_type fill;
+ 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 *)
*ptr = pad;
pad->header.type = lang_padding_statement_enum;
pad->padding_statement.output_section = output_section;
+ if (fill == (fill_type *) 0)
+ fill = &zero_fill;
pad->padding_statement.fill = fill;
}
pad->padding_statement.output_offset = dot - output_section->vma;
size_input_section (this_ptr, output_section_statement, fill, dot)
lang_statement_union_type **this_ptr;
lang_output_section_statement_type *output_section_statement;
- fill_type fill;
+ fill_type *fill;
bfd_vma dot;
{
lang_input_section_type *is = &((*this_ptr)->input_section);
if ((region->current < region->origin
|| (region->current - region->origin > region->length))
&& ((region->current != region->origin + region->length)
- || base == 0))
+ || base == 0))
{
if (tree != (etree_type *) 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);
- }
+ {
+ 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);
- }
+ {
+ 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. */
-bfd_vma
-lang_size_sections (s, output_section_statement, prev, fill, dot, relax)
+static bfd_vma
+lang_size_sections_1 (s, output_section_statement, prev, fill, dot, relax)
lang_statement_union_type *s;
lang_output_section_statement_type *output_section_statement;
lang_statement_union_type **prev;
- fill_type fill;
+ fill_type *fill;
bfd_vma dot;
boolean *relax;
{
/* This section was never actually created. */
break;
+ /* The section might have been removed after its statement was
+ added. For example, ldemul_before_allocation can remove
+ dynamic sections if they turn out not to be needed. */
+ if (!link_info.relocateable
+ && (bfd_get_section_flags (output_bfd, os->bfd_section)
+ & SEC_EXCLUDE) != 0)
+ 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
defined, issue a warning. */
if ((bfd_get_section_flags (output_bfd, os->bfd_section)
& (SEC_ALLOC | SEC_LOAD)) != 0
+ && (bfd_get_section_flags (output_bfd, os->bfd_section)
+ & SEC_NEVER_LOAD) == 0
&& ! link_info.relocateable
&& strcmp (os->region->name, "*default*") == 0
&& lang_memory_region_list != NULL
os->bfd_section->output_offset = 0;
}
- lang_size_sections (os->children.head, os, &os->children.head,
- os->fill, dot, relax);
+ lang_size_sections_1 (os->children.head, os, &os->children.head,
+ os->fill, dot, relax);
/* Put the section within the requested block size, or
align at the block boundary. */
if (bfd_is_abs_section (os->bfd_section))
ASSERT (after == os->bfd_section->vma);
+ else if ((os->bfd_section->flags & SEC_HAS_CONTENTS) == 0
+ && (os->bfd_section->flags & SEC_THREAD_LOCAL))
+ os->bfd_section->_raw_size = 0;
else
os->bfd_section->_raw_size =
(after - os->bfd_section->vma) * opb;
+
dot = os->bfd_section->vma + os->bfd_section->_raw_size / opb;
os->processed = true;
+ 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
if (os->lma_region == NULL && os->load_base == NULL)
os->lma_region = os->region;
- if (os->lma_region != NULL)
+ if (os->lma_region != NULL && os->lma_region != os->region)
{
- if (os->load_base != NULL)
- {
- einfo (_("%X%P: use an absolute load address or a load memory region, not both\n"));
- }
- else
- {
- /* Don't allocate twice. */
- if (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 +=
- os->bfd_section->_raw_size / opb;
- os_region_check (os, os->lma_region, NULL,
- os->bfd_section->lma);
- }
- }
+ /* Set load_base, which will be handled later. */
+ os->load_base = exp_intop (os->lma_region->current);
+ os->lma_region->current +=
+ os->bfd_section->_raw_size / opb;
+ os_region_check (os, os->lma_region, NULL,
+ os->bfd_section->lma);
}
}
}
break;
case lang_constructors_statement_enum:
- dot = lang_size_sections (constructor_list.head,
- output_section_statement,
- &s->wild_statement.children.head,
- fill, dot, relax);
+ dot = lang_size_sections_1 (constructor_list.head,
+ output_section_statement,
+ &s->wild_statement.children.head,
+ fill, dot, relax);
break;
case lang_data_statement_enum:
case lang_wild_statement_enum:
- dot = lang_size_sections (s->wild_statement.children.head,
- output_section_statement,
- &s->wild_statement.children.head,
- fill, dot, relax);
+ dot = lang_size_sections_1 (s->wild_statement.children.head,
+ output_section_statement,
+ &s->wild_statement.children.head,
+ fill, dot, relax);
break;
break;
case lang_group_statement_enum:
- dot = lang_size_sections (s->group_statement.children.head,
- output_section_statement,
- &s->group_statement.children.head,
- fill, dot, relax);
+ dot = lang_size_sections_1 (s->group_statement.children.head,
+ output_section_statement,
+ &s->group_statement.children.head,
+ fill, dot, relax);
break;
default:
return dot;
}
+bfd_vma
+lang_size_sections (s, output_section_statement, prev, fill, dot, relax)
+ lang_statement_union_type *s;
+ lang_output_section_statement_type *output_section_statement;
+ lang_statement_union_type **prev;
+ fill_type *fill;
+ bfd_vma dot;
+ boolean *relax;
+{
+ bfd_vma result;
+
+ exp_data_seg.phase = exp_dataseg_none;
+ result = lang_size_sections_1 (s, output_section_statement, prev, fill,
+ dot, relax);
+ 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;
+ result = lang_size_sections_1 (s, output_section_statement, prev,
+ fill, dot, relax);
+ }
+ }
+
+ return result;
+}
+
bfd_vma
lang_do_assignments (s, output_section_statement, fill, dot)
lang_statement_union_type *s;
lang_output_section_statement_type *output_section_statement;
- fill_type fill;
+ fill_type *fill;
bfd_vma dot;
{
unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
if (value.valid_p == false)
einfo (_("%F%P: invalid data statement\n"));
}
- {
- unsigned int size;
+ {
+ unsigned int size;
switch (s->data_statement.type)
{
default:
h = bfd_link_hash_lookup (link_info.hash, buf, false, false, true);
if (h != NULL && h->type == bfd_link_hash_undefined)
{
- unsigned opb;
+ unsigned opb;
- opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
+ opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
ldfile_output_machine);
h->type = bfd_link_hash_defined;
if (s->_cooked_size != 0)
/* 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, ".text");
+ ts = bfd_get_section_by_name (output_bfd, entry_section);
if (ts != (asection *) NULL)
{
if (warn)
file = file->input_statement.next)
{
input_bfd = file->input_statement.the_bfd;
- compatible = bfd_arch_get_compatible (input_bfd,
- output_bfd);
+ compatible = bfd_arch_get_compatible (input_bfd, output_bfd);
+
+ /* 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.relocateable || 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)
bfd_printable_name (input_bfd), input_bfd,
bfd_printable_name (output_bfd));
}
- else if (link_info.relocateable
- /* 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). */
- && 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);
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. */
+ private data of the output bfd. */
bfd_error_handler_type pfn = NULL;
if (file->just_syms_flag)
{
- /* We are only retrieving symbol values from this
- file. We want the symbols to act as though the
- values in the file are absolute. */
- s->output_section = bfd_abs_section_ptr;
- s->output_offset = s->vma;
+ abort ();
}
else if (strcmp (s->name, "COMMON") == 0)
{
/* Reset the current counters in the regions. */
-static void
-reset_memory_regions ()
+void
+lang_reset_memory_regions ()
{
lang_memory_region_type *p = lang_memory_region_list;
asection *o;
{
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;
/* Find any sections not attached explicitly and handle them. */
lang_place_orphans ();
+ if (! link_info.relocateable)
+ {
+ /* Look for a text section and set the readonly attribute in it. */
+ asection *found = bfd_get_section_by_name (output_bfd, ".text");
+
+ if (found != (asection *) 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 ();
/* We must record the program headers before we try to fix the
do
{
- reset_memory_regions ();
+ lang_reset_memory_regions ();
relax_again = false;
section sizes. */
lang_do_assignments (statement_list.head,
abs_output_section,
- (fill_type) 0, (bfd_vma) 0);
+ (fill_type *) 0, (bfd_vma) 0);
/* Perform another relax pass - this time we know where the
- globals are, so can make better guess. */
+ globals are, so can make a better guess. */
lang_size_sections (statement_list.head,
abs_output_section,
- &(statement_list.head), 0, (bfd_vma) 0,
+ &statement_list.head, 0, (bfd_vma) 0,
&relax_again);
}
while (relax_again);
lang_do_assignments (statement_list.head,
abs_output_section,
- (fill_type) 0, (bfd_vma) 0);
+ (fill_type *) 0, (bfd_vma) 0);
/* Make sure that the section addresses make sense. */
if (! link_info.relocateable
}
void
-lang_add_fill (exp)
- int exp;
+lang_add_fill (fill)
+ fill_type *fill;
{
lang_fill_statement_type *new = new_stat (lang_fill_statement,
stat_ptr);
- new->fill = exp;
+ new->fill = fill;
}
void
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 "*default*" 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 (region, lma_region, memspec, lma_memspec, have_lma_p)
+ struct memory_region_struct **region, **lma_region;
+ const char *memspec, *lma_memspec;
+ int have_lma_p;
+{
+ *lma_region = lang_memory_region_lookup (lma_memspec);
+
+ /* If no runtime region has been given, but the load region has
+ been, use the load region. */
+ if (lma_memspec != 0 && strcmp (memspec, "*default*") == 0)
+ *region = *lma_region;
+ else
+ *region = lang_memory_region_lookup (memspec);
+
+ if (have_lma_p && 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, memspec, phdrs, lma_memspec)
- bfd_vma fill;
+ fill_type *fill;
const char *memspec;
struct lang_output_section_phdr_list *phdrs;
const char *lma_memspec;
{
+ lang_get_regions (¤t_section->region,
+ ¤t_section->lma_region,
+ memspec, lma_memspec,
+ current_section->load_base != 0);
current_section->fill = fill;
- current_section->region = lang_memory_region_lookup (memspec);
- if (strcmp (lma_memspec, "*default*") != 0)
- {
- current_section->lma_region = lang_memory_region_lookup (lma_memspec);
- /* If no runtime region has been given, but the load region has
- been, use the load region. */
- if (strcmp (memspec, "*default*") == 0)
- current_section->region = lang_memory_region_lookup (lma_memspec);
- }
current_section->phdrs = phdrs;
stat_ptr = &statement_list;
}
/* The overlay virtual address. */
static etree_type *overlay_vma;
-/* The overlay load address. */
-static etree_type *overlay_lma;
-
-/* Whether nocrossrefs is set for this overlay. */
-static int overlay_nocrossrefs;
-
/* An expression for the maximum section size seen so far. */
static etree_type *overlay_max;
/* Start handling an overlay. */
void
-lang_enter_overlay (vma_expr, lma_expr, nocrossrefs)
+lang_enter_overlay (vma_expr)
etree_type *vma_expr;
- etree_type *lma_expr;
- int nocrossrefs;
{
/* The grammar should prevent nested overlays from occurring. */
- ASSERT (overlay_vma == NULL
- && overlay_lma == NULL
- && overlay_list == NULL
- && overlay_max == NULL);
+ ASSERT (overlay_vma == NULL && overlay_max == NULL);
overlay_vma = vma_expr;
- overlay_lma = lma_expr;
- overlay_nocrossrefs = nocrossrefs;
}
/* Start a section in an overlay. We handle this by calling
- lang_enter_output_section_statement with the correct VMA and LMA. */
+ lang_enter_output_section_statement with the correct VMA.
+ lang_leave_overlay sets up the LMA and memory regions. */
void
lang_enter_overlay_section (name)
etree_type *size;
lang_enter_output_section_statement (name, overlay_vma, normal_section,
- 0, 0, 0, overlay_lma);
+ 0, 0, 0, 0);
- /* If this is the first section, then base the VMA and LMA of future
+ /* 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);
- overlay_lma = exp_nameop (LOADADDR, name);
- }
+ overlay_vma = exp_nameop (ADDR, name);
/* Remember the section. */
n = (struct overlay_list *) xmalloc (sizeof *n);
size = exp_nameop (SIZEOF, name);
- /* Adjust the LMA for the next section. */
- overlay_lma = exp_binop ('+', overlay_lma, size);
-
/* Arrange to work out the maximum section end address. */
if (overlay_max == NULL)
overlay_max = size;
void
lang_leave_overlay_section (fill, phdrs)
- bfd_vma fill;
+ fill_type *fill;
struct lang_output_section_phdr_list *phdrs;
{
const char *name;
name = current_section->name;
- lang_leave_output_section_statement (fill, "*default*",
- phdrs, "*default*");
+ /* For now, assume that "*default*" 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*", phdrs, 0);
/* Define the magic symbols. */
looks through all the sections in the overlay and sets them. */
void
-lang_leave_overlay (fill, memspec, phdrs, lma_memspec)
- bfd_vma fill;
+lang_leave_overlay (lma_expr, nocrossrefs, fill, memspec, phdrs, lma_memspec)
+ etree_type *lma_expr;
+ int nocrossrefs;
+ fill_type *fill;
const char *memspec;
struct lang_output_section_phdr_list *phdrs;
const char *lma_memspec;
{
lang_memory_region_type *region;
- lang_memory_region_type * default_region;
lang_memory_region_type *lma_region;
struct overlay_list *l;
struct lang_nocrossref *nocrossref;
- default_region = lang_memory_region_lookup ("*default*");
-
- if (memspec == NULL)
- region = NULL;
- else
- region = lang_memory_region_lookup (memspec);
-
- if (lma_memspec == NULL)
- lma_region = NULL;
- else
- lma_region = lang_memory_region_lookup (lma_memspec);
+ lang_get_regions (®ion, &lma_region,
+ memspec, lma_memspec,
+ lma_expr != 0);
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 != 0 && l->os->fill == 0)
+ if (fill != (fill_type *) 0 && l->os->fill == (fill_type *) 0)
l->os->fill = fill;
- /* Assign a region to the sections, if one has been specified.
- Override the assignment of the default section, but not
- other sections. */
- if (region != NULL &&
- (l->os->region == NULL ||
- l->os->region == default_region))
- l->os->region = region;
-
- /* We only set lma_region for the first overlay section, as
- subsequent overlay sections will have load_base set relative
- to the first section. Also, don't set lma_region if
- load_base is specified. FIXME: There should really be a test
- that `AT ( LDADDR )' doesn't conflict with `AT >LMA_REGION'
- rather than letting LDADDR simply override LMA_REGION. */
- if (lma_region != NULL && l->os->lma_region == NULL
- && l->next == NULL && l->os->load_base == NULL)
- l->os->lma_region = lma_region;
+ 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 (overlay_nocrossrefs)
+ if (nocrossrefs)
{
struct lang_nocrossref *nc;
if (nocrossref != NULL)
lang_add_nocrossref (nocrossref);
- /* Update . for the end of the overlay. */
- lang_add_assignment (exp_assop ('=', ".",
- exp_binop ('+', overlay_vma, overlay_max)));
-
overlay_vma = NULL;
- overlay_lma = NULL;
- overlay_nocrossrefs = 0;
overlay_list = NULL;
overlay_max = NULL;
}
/* This is called for each variable name or match expression. */
struct bfd_elf_version_expr *
-lang_new_vers_regex (orig, new, lang)
+lang_new_vers_pattern (orig, new, lang)
struct bfd_elf_version_expr *orig;
const char *new;
const char *lang;
ret->match = lang_vers_match_lang_c;
}
- return ret;
+ return ldemul_new_vers_pattern (ret);
}
/* This is called for each set of variable names and match
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"));
+ 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)
version->deps = deps;
version->name = name;
- ++version_index;
- version->vernum = version_index;
+ 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)
;
bfd_size_type len;
if (sec == NULL)
- continue;
+ continue;
len = bfd_section_size (is->the_bfd, sec);
contents = xmalloc (len);
p = contents;
while (p < contents + len)
{
- greg = lang_new_vers_regex (greg, p, NULL);
+ greg = lang_new_vers_pattern (greg, p, NULL);
p = strchr (p, '\0') + 1;
}
bfd_get_section_flags (is->the_bfd, sec) | SEC_EXCLUDE);
}
- lreg = lang_new_vers_regex (NULL, "*", NULL);
+ lreg = lang_new_vers_pattern (NULL, "*", NULL);
lang_register_vers_node (command_line.version_exports_section,
lang_new_vers_node (greg, lreg), NULL);
}