/* Linker command language support.
Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003
+ 2001, 2002, 2003, 2004
Free Software Foundation, Inc.
This file is part of GLD, the Gnu Linker.
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,
lookup->next = NULL;
lookup->bfd_section = NULL;
- lookup->processed = FALSE;
+ lookup->processed = 0;
lookup->sectype = normal_section;
lookup->addr_tree = NULL;
lang_list_init (&lookup->children);
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;
flags &= ~ (SEC_MERGE | SEC_STRINGS);
}
- /* For now make .tbss normal section. */
- if ((flags & SEC_THREAD_LOCAL) && ! link_info.relocatable)
- flags |= SEC_LOAD;
-
section->output_section->flags |= flags;
if (flags & SEC_MERGE)
search != NULL;
search = (lang_input_statement_type *) search->next_real_file)
{
- if (search->filename == NULL && name == NULL)
+ /* 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 (search->filename != NULL
+ if (filename != NULL
&& name != NULL
- && strcmp (search->filename, name) == 0)
+ && strcmp (filename, name) == 0)
break;
}
if (search == NULL)
- search = new_afile (name, lang_input_file_is_file_enum, default_target,
+ 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
}
}
+/* 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
/* Maybe we should load the file's symbols. */
if (s->wild_statement.filename
&& ! wildcardp (s->wild_statement.filename))
- (void) lookup_name (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:
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_data_statement_enum:
case lang_reloc_statement_enum:
case lang_padding_statement_enum:
case lang_input_statement_enum:
{
asection *i = in->section;
bfd_size_type size = i->_cooked_size != 0 ? i->_cooked_size : i->_raw_size;
- unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
- ldfile_output_machine);
+
+ init_opb ();
if (size != 0)
{
print_space ();
}
minfo ("0x%V %W %B\n",
- i->output_section->vma + i->output_offset, size / opb,
+ i->output_section->vma + i->output_offset, TO_ADDR (size),
i->owner);
if (i->_cooked_size != 0 && i->_cooked_size != i->_raw_size)
bfd_link_hash_traverse (link_info.hash, print_one_symbol, i);
- print_dot = i->output_section->vma + i->output_offset + size / opb;
+ print_dot = (i->output_section->vma + i->output_offset
+ + TO_ADDR (size));
}
}
}
bfd_vma addr;
bfd_size_type size;
const char *name;
- unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
- ldfile_output_machine);
+ init_opb ();
for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
print_space ();
print_nl ();
- print_dot = addr + size / opb;
-
+ print_dot = addr + TO_ADDR (size);
}
/* Print an address statement. These are generated by options like
int i;
bfd_vma addr;
bfd_size_type size;
- unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
- ldfile_output_machine);
+ init_opb ();
for (i = 0; i < SECTION_NAME_MAP_LENGTH; i++)
print_space ();
print_nl ();
- print_dot = addr + size / opb;
+ print_dot = addr + TO_ADDR (size);
}
static void
{
int len;
bfd_vma addr;
- unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
- ldfile_output_machine);
+ init_opb ();
minfo (" *fill*");
len = sizeof " *fill*" - 1;
print_nl ();
- print_dot = addr + s->size / opb;
+ print_dot = addr + TO_ADDR (s->size);
}
static void
if (!is->ifile->just_syms_flag)
{
- unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
- ldfile_output_machine);
unsigned int alignment_needed;
asection *o;
if (alignment_needed != 0)
{
- insert_pad (this_ptr, fill, alignment_needed * opb, o, dot);
+ insert_pad (this_ptr, fill, TO_SIZE (alignment_needed), o, dot);
dot += alignment_needed;
}
/* Mark how big the output section must be to contain this now. */
if (i->_cooked_size != 0)
- dot += i->_cooked_size / opb;
+ dot += TO_ADDR (i->_cooked_size);
else
- dot += i->_raw_size / opb;
- o->_raw_size = (dot - o->vma) * opb;
+ dot += TO_ADDR (i->_raw_size);
+ o->_raw_size = TO_SIZE (dot - o->vma);
}
else
{
}
#define IGNORE_SECTION(bfd, s) \
- (((bfd_get_section_flags (bfd, s) & (SEC_ALLOC | SEC_LOAD)) \
- != (SEC_ALLOC | SEC_LOAD)) \
+ (((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
lang_check_section_addresses (void)
{
asection *s;
- unsigned opb = bfd_octets_per_byte (output_bfd);
/* Scan all sections in the output list. */
for (s = output_bfd->sections; s != NULL; s = s->next)
/* 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);
+ s_start = bfd_section_lma (output_bfd, s);
os_start = bfd_section_lma (output_bfd, os);
- s_end = s_start + bfd_section_size (output_bfd, s) / opb - 1;
- os_end = os_start + bfd_section_size (output_bfd, os) / opb - 1;
+ 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))
static void
os_region_check (lang_output_section_statement_type *os,
- struct memory_region_struct *region,
+ lang_memory_region_type *region,
etree_type *tree,
bfd_vma base)
{
bfd_boolean *relax,
bfd_boolean check_regions)
{
- unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
- ldfile_output_machine);
-
/* Size up the sections from their constituent parts. */
for (; s != NULL; s = s->header.next)
{
region, and some non default memory regions were
defined, issue an error message. */
if (!IGNORE_SECTION (output_bfd, os->bfd_section)
- && (bfd_get_section_flags (output_bfd, os->bfd_section)
- & SEC_NEVER_LOAD) == 0
&& ! link_info.relocatable
&& check_regions
&& strcmp (os->region->name, DEFAULT_MEMORY_REGION) == 0
/* 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
- excessivly large binary, or even seg faulting when
- attmepting to perform a negative seek. See
+ 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
{
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 address expression for section %s\n"),
+ einfo (_("%F%S: non constant or forward reference address expression for section %s\n"),
os->name);
dot = r.value + r.section->bfd_section->vma;
/* Put the section within the requested block size, or
align at the block boundary. */
- after = align_n (os->bfd_section->vma
- + os->bfd_section->_raw_size / opb,
- (bfd_vma) os->block_value);
+ 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 if ((os->bfd_section->flags & SEC_HAS_CONTENTS) == 0
- && (os->bfd_section->flags & SEC_THREAD_LOCAL)
- && ! link_info.relocatable)
- os->bfd_section->_raw_size = 0;
else
- os->bfd_section->_raw_size =
- (after - os->bfd_section->vma) * opb;
+ 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);
- dot = os->bfd_section->vma + os->bfd_section->_raw_size / opb;
- os->processed = TRUE;
+ os->processed = 1;
if (os->update_dot_tree != 0)
exp_fold_tree (os->update_dot_tree, abs_output_section,
/* 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;
+ TO_ADDR (os->bfd_section->_raw_size);
if (check_regions)
os_region_check (os, os->lma_region, NULL,
os->bfd_section->lma);
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:
size = BYTE_SIZE;
break;
}
- if (size < opb)
- size = opb;
- dot += size / opb;
+ 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. */
s->reloc_statement.output_section =
output_section_statement->bfd_section;
size = bfd_get_reloc_size (s->reloc_statement.howto);
- dot += size / opb;
+ dot += TO_ADDR (size);
output_section_statement->bfd_section->_raw_size += size;
}
break;
/* 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, (newdot - dot) * opb,
+ 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;
}
}
&& 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);
}
fill_type *fill,
bfd_vma dot)
{
- unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
- ldfile_output_machine);
-
for (; s != NULL; s = s->header.next)
{
switch (s->header.type)
if (os->bfd_section != NULL)
{
dot = os->bfd_section->vma;
- (void) lang_do_assignments_1 (os->children.head, os,
- os->fill, dot);
- dot = os->bfd_section->vma + os->bfd_section->_raw_size / opb;
+ 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)
value = exp_fold_tree (s->data_statement.exp,
abs_output_section,
lang_final_phase_enum, dot, &dot);
- s->data_statement.value = value.value;
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;
size = BYTE_SIZE;
break;
}
- if (size < opb)
- size = opb;
- dot += size / opb;
+ if (size < TO_SIZE ((unsigned) 1))
+ size = TO_SIZE ((unsigned) 1);
+ dot += TO_ADDR (size);
}
break;
if (!value.valid_p)
einfo (_("%F%P: invalid reloc statement\n"));
}
- dot += bfd_get_reloc_size (s->reloc_statement.howto) / opb;
+ 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 += in->_cooked_size / opb;
+ dot += TO_ADDR (in->_cooked_size);
else
- dot += in->_raw_size / opb;
+ dot += TO_ADDR (in->_raw_size);
}
break;
break;
case lang_padding_statement_enum:
- dot += s->padding_statement.size / opb;
+ dot += TO_ADDR (s->padding_statement.size);
break;
case lang_group_statement_enum:
return dot;
}
-bfd_vma
+void
lang_do_assignments (lang_statement_union_type *s,
- lang_output_section_statement_type
- *output_section_statement,
+ lang_output_section_statement_type *output_section_statement,
fill_type *fill,
bfd_vma dot)
{
h = bfd_link_hash_lookup (link_info.hash, buf, FALSE, FALSE, TRUE);
if (h != NULL && h->type == bfd_link_hash_undefined)
{
- unsigned opb;
-
- opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
- ldfile_output_machine);
h->type = bfd_link_hash_defined;
if (s->_cooked_size != 0)
- h->u.def.value = s->_cooked_size / opb;
+ h->u.def.value = TO_ADDR (s->_cooked_size);
else
- h->u.def.value = s->_raw_size / opb;
+ h->u.def.value = TO_ADDR (s->_raw_size);
h->u.def.section = bfd_abs_section_ptr;
}
if (! bfd_merge_private_bfd_data (input_bfd, output_bfd))
{
if (command_line.warn_mismatch)
- einfo (_("%E%X: failed to merge target specific data of file %B\n"),
+ einfo (_("%P%X: failed to merge target specific data of file %B\n"),
input_bfd);
}
if (! command_line.warn_mismatch)
unsigned int power_of_two;
bfd_vma size;
asection *section;
- unsigned opb = bfd_arch_mach_octets_per_byte (ldfile_output_architecture,
- ldfile_output_machine);
if (h->type != bfd_link_hash_common)
return TRUE;
section = h->u.c.p->section;
- /* Increase the size of the section. */
- section->_cooked_size = align_n ((section->_cooked_size + opb - 1) / opb,
- (bfd_vma) 1 << power_of_two) * opb;
+ /* 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)
}
}
-#if 0
-
-/* Not used. */
-
-void
-lang_for_each_input_section (void (*func) (bfd *ab, asection *as))
-{
- LANG_FOR_EACH_INPUT_STATEMENT (f)
- {
- asection *s;
-
- for (s = f->the_bfd->sections; s != NULL; s = s->next)
- func (f->the_bfd, s);
- }
-}
-
-#endif
-
void
ldlang_add_file (lang_input_statement_type *entry)
{
lang_enter_output_section_statement (const char *output_section_statement_name,
etree_type *address_exp,
enum section_type sectype,
- bfd_vma block_value,
etree_type *align,
etree_type *subalign,
etree_type *ebase)
os->flags = SEC_NO_FLAGS;
else
os->flags = SEC_NEVER_LOAD;
- os->block_value = block_value ? block_value : 1;
+ os->block_value = 1;
stat_ptr = &os->children;
os->subsection_alignment =
/* Open the output file. */
lang_for_each_statement (ldlang_open_output);
+ init_opb ();
ldemul_create_output_section_statements ();
do
{
- lang_reset_memory_regions ();
-
relax_again = FALSE;
/* Note: pe-dll.c does something like this also. If you find
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,
/* 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.relax_finalizing)
+ if (!relax_again && link_info.need_relax_finalize)
{
- link_info.relax_finalizing = TRUE;
+ link_info.need_relax_finalize = FALSE;
relax_again = TRUE;
}
}
while (relax_again);
/* Final extra sizing to report errors. */
- lang_reset_memory_regions ();
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);
}
It is an error to specify both a load region and a load address. */
static void
-lang_get_regions (struct memory_region_struct **region,
- struct memory_region_struct **lma_region,
+lang_get_regions (lang_memory_region_type **region,
+ lang_memory_region_type **lma_region,
const char *memspec,
const char *lma_memspec,
- int have_lma_p)
+ bfd_boolean have_lma,
+ bfd_boolean have_vma)
{
*lma_region = lang_memory_region_lookup (lma_memspec, FALSE);
- /* If no runtime region has been given, but the load region has
- been, use the load region. */
- if (lma_memspec != 0 && strcmp (memspec, DEFAULT_MEMORY_REGION) == 0)
+ /* 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_p && lma_memspec != 0)
+ 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,
- struct lang_output_section_phdr_list *phdrs, const char *lma_memspec)
+lang_leave_output_section_statement (fill_type *fill, const char *memspec,
+ 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->load_base != NULL,
+ current_section->addr_tree != NULL);
current_section->fill = fill;
current_section->phdrs = phdrs;
stat_ptr = &statement_list;
h->u.def.value = 0;
else
h->u.def.value = (bfd_get_section_vma (output_bfd, sec)
- + bfd_section_size (output_bfd, sec) /
- bfd_octets_per_byte (output_bfd));
+ + TO_ADDR (bfd_section_size (output_bfd, sec)));
h->u.def.section = bfd_abs_section_ptr;
}
{
unsigned int alc;
asection **secs;
- struct lang_output_section_phdr_list *last;
+ lang_output_section_phdr_list *last;
struct lang_phdr *l;
lang_statement_union_type *u;
u = u->output_section_statement.next)
{
lang_output_section_statement_type *os;
- struct lang_output_section_phdr_list *pl;
+ lang_output_section_phdr_list *pl;
os = &u->output_section_statement;
u != NULL;
u = u->output_section_statement.next)
{
- struct lang_output_section_phdr_list *pl;
+ lang_output_section_phdr_list *pl;
if (u->output_section_statement.bfd_section == NULL)
continue;
/* Record a list of sections which may not be cross referenced. */
void
-lang_add_nocrossref (struct lang_nocrossref *l)
+lang_add_nocrossref (lang_nocrossref_type *l)
{
struct lang_nocrossrefs *n;
etree_type *size;
lang_enter_output_section_statement (name, overlay_vma, normal_section,
- 0, 0, overlay_subalign, 0);
+ 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
void
lang_leave_overlay_section (fill_type *fill,
- struct lang_output_section_phdr_list *phdrs)
+ lang_output_section_phdr_list *phdrs)
{
const char *name;
char *clean, *s2;
int nocrossrefs,
fill_type *fill,
const char *memspec,
- struct lang_output_section_phdr_list *phdrs,
+ 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;
- struct lang_nocrossref *nocrossref;
+ lang_nocrossref_type *nocrossref;
lang_get_regions (®ion, &lma_region,
memspec, lma_memspec,
- lma_expr != 0);
+ lma_expr != NULL, FALSE);
nocrossref = NULL;
if (nocrossrefs)
{
- struct lang_nocrossref *nc;
+ lang_nocrossref_type *nc;
nc = xmalloc (sizeof *nc);
nc->name = l->os->name;
if (head->mask & BFD_ELF_VERSION_CXX_TYPE)
{
- cxx_sym = cplus_demangle (sym, /* DMGL_NO_TPARAMS */ 0);
+ cxx_sym = cplus_demangle (sym, DMGL_PARAMS | DMGL_ANSI);
if (!cxx_sym)
cxx_sym = sym;
}
- else if (head->mask & BFD_ELF_VERSION_JAVA_TYPE)
+ if (head->mask & BFD_ELF_VERSION_JAVA_TYPE)
{
java_sym = cplus_demangle (sym, DMGL_JAVA);
if (!java_sym)