/* This module handles expression trees.
Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003
+ 2001, 2002, 2003, 2004
Free Software Foundation, Inc.
Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>.
static etree_value_type exp_fold_tree_no_dot
(etree_type *, lang_output_section_statement_type *, lang_phase_type);
+static bfd_vma align_n
+ (bfd_vma, bfd_vma);
struct exp_data_seg exp_data_seg;
{ MAX_K, "MAX_K" },
{ REL, "relocatable" },
{ DATA_SEGMENT_ALIGN, "DATA_SEGMENT_ALIGN" },
+ { DATA_SEGMENT_RELRO_END, "DATA_SEGMENT_RELRO_END" },
{ DATA_SEGMENT_END, "DATA_SEGMENT_END" }
};
unsigned int idx;
return new;
}
-static void
-check (lang_output_section_statement_type *os,
- const char *name,
- const char *op)
-{
- if (os == NULL)
- einfo (_("%F%P: %s uses undefined section %s\n"), op, name);
- if (! os->processed)
- einfo (_("%F%P: %s forward reference of section %s\n"), op, name);
-}
-
etree_type *
exp_intop (bfd_vma value)
{
result.valid_p = FALSE;
break;
+ case DATA_SEGMENT_RELRO_END:
+ if (allocation_done != lang_first_phase_enum
+ && (exp_data_seg.phase == exp_dataseg_align_seen
+ || exp_data_seg.phase == exp_dataseg_adjust
+ || exp_data_seg.phase == exp_dataseg_relro_adjust
+ || allocation_done != lang_allocating_phase_enum))
+ {
+ if (exp_data_seg.phase == exp_dataseg_align_seen
+ || exp_data_seg.phase == exp_dataseg_relro_adjust)
+ exp_data_seg.relro_end
+ = result.value + current_section->bfd_section->vma;
+ if (exp_data_seg.phase == exp_dataseg_align_seen)
+ exp_data_seg.phase = exp_dataseg_relro_seen;
+ result.value = dot - current_section->bfd_section->vma;
+ }
+ else
+ result.valid_p = FALSE;
+ break;
+
case DATA_SEGMENT_END:
if (allocation_done != lang_first_phase_enum
&& current_section == abs_output_section
&& (exp_data_seg.phase == exp_dataseg_align_seen
+ || exp_data_seg.phase == exp_dataseg_relro_seen
|| exp_data_seg.phase == exp_dataseg_adjust
+ || exp_data_seg.phase == exp_dataseg_relro_adjust
|| allocation_done != lang_allocating_phase_enum))
{
- if (exp_data_seg.phase == exp_dataseg_align_seen)
+ if (exp_data_seg.phase == exp_dataseg_align_seen
+ || exp_data_seg.phase == exp_dataseg_relro_seen)
{
exp_data_seg.phase = exp_dataseg_end_seen;
exp_data_seg.end = result.value;
result = other;
break;
+ case ALIGN_K:
+ result.value = align_n (result.value, other.value);
+ break;
+
case DATA_SEGMENT_ALIGN:
if (allocation_done != lang_first_phase_enum
&& current_section == abs_output_section
&& (exp_data_seg.phase == exp_dataseg_none
|| exp_data_seg.phase == exp_dataseg_adjust
+ || exp_data_seg.phase == exp_dataseg_relro_adjust
|| allocation_done != lang_allocating_phase_enum))
{
bfd_vma maxpage = result.value;
result.value = align_n (dot, maxpage);
- if (exp_data_seg.phase != exp_dataseg_adjust)
+ if (exp_data_seg.phase == exp_dataseg_relro_adjust)
+ {
+ /* Attempt to align DATA_SEGMENT_RELRO_END at
+ a common page boundary. */
+ bfd_vma relro;
+
+ relro = exp_data_seg.relro_end - exp_data_seg.base;
+ result.value += -relro & (other.value - 1);
+ exp_data_seg.base = result.value;
+ }
+ else if (exp_data_seg.phase != exp_dataseg_adjust)
{
result.value += dot & (maxpage - 1);
if (allocation_done == lang_allocating_phase_enum)
exp_data_seg.phase = exp_dataseg_align_seen;
exp_data_seg.base = result.value;
exp_data_seg.pagesize = other.value;
+ exp_data_seg.relro_end = 0;
}
}
else if (other.value < maxpage)
return result;
}
-etree_value_type
-invalid (void)
-{
- etree_value_type new;
- new.valid_p = FALSE;
- return new;
-}
-
static etree_value_type
fold_name (etree_type *tree,
lang_output_section_statement_type *current_section,
{
etree_value_type result;
+ result.valid_p = FALSE;
+
switch (tree->type.node_code)
{
case SIZEOF_HEADERS:
if (allocation_done != lang_first_phase_enum)
- {
- result = new_abs (bfd_sizeof_headers (output_bfd,
- link_info.relocatable));
- }
- else
- {
- result.valid_p = FALSE;
- }
+ result = new_abs (bfd_sizeof_headers (output_bfd,
+ link_info.relocatable));
break;
case DEFINED:
if (allocation_done == lang_first_phase_enum)
- {
- lang_track_definedness (tree->name.name);
- result.valid_p = FALSE;
- }
+ lang_track_definedness (tree->name.name);
else
{
struct bfd_link_hash_entry *h;
}
break;
case NAME:
- result.valid_p = FALSE;
if (tree->name.name[0] == '.' && tree->name.name[1] == 0)
{
if (allocation_done != lang_first_phase_enum)
result = new_rel_from_section (dot, current_section);
- else
- result = invalid ();
}
else if (allocation_done != lang_first_phase_enum)
{
h = bfd_wrapped_link_hash_lookup (output_bfd, &link_info,
tree->name.name,
- FALSE, FALSE, TRUE);
- if (h != NULL
- && (h->type == bfd_link_hash_defined
- || h->type == bfd_link_hash_defweak))
+ TRUE, FALSE, TRUE);
+ if (!h)
+ einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n"));
+ else if (h->type == bfd_link_hash_defined
+ || h->type == bfd_link_hash_defweak)
{
if (bfd_is_abs_section (h->u.def.section))
result = new_abs (h->u.def.value);
else if (allocation_done == lang_final_phase_enum)
einfo (_("%F%S: undefined symbol `%s' referenced in expression\n"),
tree->name.name);
+ else 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);
+ }
}
break;
lang_output_section_statement_type *os;
os = lang_output_section_find (tree->name.name);
- check (os, tree->name.name, "ADDR");
- result = new_rel (0, NULL, os);
+ if (os && os->processed > 0)
+ result = new_rel (0, NULL, os);
}
- else
- result = invalid ();
break;
case LOADADDR:
lang_output_section_statement_type *os;
os = lang_output_section_find (tree->name.name);
- check (os, tree->name.name, "LOADADDR");
- if (os->load_base == NULL)
- result = new_rel (0, NULL, os);
- else
- result = exp_fold_tree_no_dot (os->load_base,
- abs_output_section,
- allocation_done);
+ if (os && os->processed != 0)
+ {
+ if (os->load_base == NULL)
+ result = new_rel (0, NULL, os);
+ else
+ result = exp_fold_tree_no_dot (os->load_base,
+ abs_output_section,
+ allocation_done);
+ }
}
- else
- result = invalid ();
break;
case SIZEOF:
lang_output_section_statement_type *os;
os = lang_output_section_find (tree->name.name);
- check (os, tree->name.name, "SIZEOF");
- result = new_abs (os->bfd_section->_raw_size / opb);
+ if (os && os->processed > 0)
+ result = new_abs (os->bfd_section->_raw_size / opb);
}
- else
- result = invalid ();
break;
default:
else
create = FALSE;
h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst,
- create, FALSE, FALSE);
+ create, FALSE, TRUE);
if (h == NULL)
{
- if (tree->type.node_class == etree_assign)
+ if (create)
einfo (_("%P%F:%s: hash creation failed\n"),
tree->assign.dst);
}
else if (tree->type.node_class == etree_provide
+ && h->type != bfd_link_hash_new
&& h->type != bfd_link_hash_undefined
&& h->type != bfd_link_hash_common)
{
return res.value;
}
-bfd_vma align_n (bfd_vma value, bfd_vma align)
+static bfd_vma
+align_n (bfd_vma value, bfd_vma align)
{
if (align <= 1)
return value;