/* This module handles expression trees.
- Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
- 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
- Free Software Foundation, Inc.
+ Copyright 1991-2013 Free Software Foundation, Inc.
Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>.
This file is part of the GNU Binutils.
static const struct
{
token_code_type code;
- char * name;
+ const char * name;
}
table[] =
{
{ GE, ">=" },
{ LSHIFT, "<<" },
{ RSHIFT, ">>" },
+ { LOG2CEIL, "LOG2CEIL" },
{ ALIGN_K, "ALIGN" },
{ BLOCK, "BLOCK" },
{ QUAD, "QUAD" },
fputc (' ', config.map_file);
}
+static void
+make_log2ceil (void)
+{
+ bfd_vma value = expld.result.value;
+ bfd_vma result = -1;
+ bfd_boolean round_up = FALSE;
+
+ do
+ {
+ result++;
+ /* If more than one bit is set in the value we will need to round up. */
+ if ((value > 1) && (value & 1))
+ round_up = TRUE;
+ }
+ while (value >>= 1);
+
+ if (round_up)
+ result += 1;
+ expld.result.section = NULL;
+ expld.result.value = result;
+}
+
static void
make_abs (void)
{
static void
new_rel_from_abs (bfd_vma value)
{
+ asection *s = expld.section;
+
+ if (s == bfd_abs_section_ptr && expld.phase == lang_final_phase_enum)
+ s = section_for_dot ();
expld.result.valid_p = TRUE;
- expld.result.value = value - expld.section->vma;
+ expld.result.value = value - s->vma;
expld.result.str = NULL;
- expld.result.section = expld.section;
+ expld.result.section = s;
}
static void
make_abs ();
break;
+ case LOG2CEIL:
+ make_log2ceil ();
+ break;
+
case '~':
expld.result.value = ~expld.result.value;
break;
/* Check to see if the user has overridden the default
value. */
segment_name = tree->binary.rhs->name.name;
- for (seg = segments; seg; seg = seg->next)
+ for (seg = segments; seg; seg = seg->next)
if (strcmp (seg->name, segment_name) == 0)
{
if (!seg->used
break;
case NAME:
+ if (expld.assign_name != NULL
+ && strcmp (expld.assign_name, tree->name.name) == 0)
+ expld.assign_name = NULL;
if (expld.phase == lang_first_phase_enum)
;
else if (tree->name.name[0] == '.' && tree->name.name[1] == 0)
output_section = h->u.def.section->output_section;
if (output_section == NULL)
{
- if (expld.phase != lang_mark_phase_enum)
+ if (expld.phase == lang_mark_phase_enum)
+ new_rel (h->u.def.value, h->u.def.section);
+ else
einfo (_("%X%S: unresolvable symbol `%s'"
" referenced in expression\n"),
tree, tree->name.name);
output_section);
}
else if (expld.phase == lang_final_phase_enum
- || expld.assigning_to_dot)
+ || (expld.phase != lang_mark_phase_enum
+ && expld.assigning_to_dot))
einfo (_("%F%S: undefined symbol `%s'"
" referenced in expression\n"),
tree, tree->name.name);
tree, tree->name.name);
new_number (0);
}
- else if (os->processed_vma)
+ else if (os->bfd_section != NULL)
{
bfd_vma val;
/ bfd_octets_per_byte (link_info.output_bfd));
else
val = (bfd_vma)1 << os->bfd_section->alignment_power;
-
+
new_number (val);
}
+ else
+ new_number (0);
}
break;
case LENGTH:
{
lang_memory_region_type *mem;
-
- mem = lang_memory_region_lookup (tree->name.name, FALSE);
- if (mem != NULL)
+
+ mem = lang_memory_region_lookup (tree->name.name, FALSE);
+ if (mem != NULL)
new_number (mem->length);
- else
+ else
einfo (_("%F%S: undefined MEMORY region `%s'"
" referenced in expression\n"),
tree, tree->name.name);
if (expld.phase != lang_first_phase_enum)
{
lang_memory_region_type *mem;
-
- mem = lang_memory_region_lookup (tree->name.name, FALSE);
- if (mem != NULL)
+
+ mem = lang_memory_region_lookup (tree->name.name, FALSE);
+ if (mem != NULL)
new_rel_from_abs (mem->origin);
- else
+ else
einfo (_("%F%S: undefined MEMORY region `%s'"
" referenced in expression\n"),
tree, tree->name.name);
if (tree->type.node_class != etree_assign)
einfo (_("%F%S can not PROVIDE assignment to"
" location counter\n"), tree);
- /* After allocation, assignment to dot should not be done inside
- an output section since allocation adds a padding statement
- that effectively duplicates the assignment. */
- if (expld.phase == lang_mark_phase_enum
- || expld.phase == lang_allocating_phase_enum
- || ((expld.phase == lang_assigning_phase_enum
- || expld.phase == lang_final_phase_enum)
- && expld.section == bfd_abs_section_ptr))
+ if (expld.phase != lang_first_phase_enum)
{
/* Notify the folder that this is an assignment to dot. */
expld.assigning_to_dot = TRUE;
}
else if (expld.dotp == NULL)
einfo (_("%F%S assignment to location counter"
- " invalid outside of SECTION\n"), tree);
- else
+ " invalid outside of SECTIONS\n"), tree);
+
+ /* After allocation, assignment to dot should not be
+ done inside an output section since allocation adds a
+ padding statement that effectively duplicates the
+ assignment. */
+ else if (expld.phase <= lang_allocating_phase_enum
+ || expld.section == bfd_abs_section_ptr)
{
bfd_vma nextdot;
}
else
{
- etree_type *name;
-
struct bfd_link_hash_entry *h = NULL;
if (tree->type.node_class == etree_provide)
}
}
- name = tree->assign.src;
- if (name->type.node_class == etree_trinary)
- {
- exp_fold_tree_1 (name->trinary.cond);
- if (expld.result.valid_p)
- name = (expld.result.value
- ? name->trinary.lhs : name->trinary.rhs);
- }
-
- if (name->type.node_class == etree_name
- && name->type.node_code == NAME
- && strcmp (tree->assign.dst, name->name.name) == 0)
- /* Leave it alone. Do not replace a symbol with its own
- output address, in case there is another section sizing
- pass. Folding does not preserve input sections. */
- break;
-
+ expld.assign_name = tree->assign.dst;
exp_fold_tree_1 (tree->assign.src);
- if (expld.result.valid_p
- || (expld.phase == lang_first_phase_enum
+ /* expld.assign_name remaining equal to tree->assign.dst
+ below indicates the evaluation of tree->assign.src did
+ not use the value of tree->assign.dst. We don't allow
+ self assignment until the final phase for two reasons:
+ 1) Expressions are evaluated multiple times. With
+ relaxation, the number of times may vary.
+ 2) Section relative symbol values cannot be correctly
+ converted to absolute values, as is required by many
+ expressions, until final section sizing is complete. */
+ if ((expld.result.valid_p
+ && (expld.phase == lang_final_phase_enum
+ || expld.assign_name != NULL))
+ || (expld.phase <= lang_mark_phase_enum
&& tree->type.node_class == etree_assign
- && tree->assign.hidden))
+ && tree->assign.defsym))
{
if (h == NULL)
{
&& h->type == bfd_link_hash_new)
h->type = bfd_link_hash_undefined;
}
+ expld.assign_name = NULL;
}
break;
exp_assop (const char *dst,
etree_type *src,
enum node_tree_enum class,
+ bfd_boolean defsym,
bfd_boolean hidden)
{
etree_type *n;
n->assign.type.node_class = class;
n->assign.src = src;
n->assign.dst = dst;
+ n->assign.defsym = defsym;
n->assign.hidden = hidden;
return n;
}
+/* Handle linker script assignments and HIDDEN. */
+
etree_type *
-exp_assign (const char *dst, etree_type *src)
+exp_assign (const char *dst, etree_type *src, bfd_boolean hidden)
{
- return exp_assop (dst, src, etree_assign, FALSE);
+ return exp_assop (dst, src, etree_assign, FALSE, hidden);
}
+/* Handle --defsym command-line option. */
+
etree_type *
exp_defsym (const char *dst, etree_type *src)
{
- return exp_assop (dst, src, etree_assign, TRUE);
+ return exp_assop (dst, src, etree_assign, TRUE, FALSE);
}
/* Handle PROVIDE. */
etree_type *
exp_provide (const char *dst, etree_type *src, bfd_boolean hidden)
{
- return exp_assop (dst, src, etree_provide, hidden);
+ return exp_assop (dst, src, etree_provide, FALSE, hidden);
}
/* Handle ASSERT. */
case DATA_SEGMENT_ALIGN:
case DATA_SEGMENT_RELRO_END:
function_like = TRUE;
+ break;
+ case SEGMENT_START:
+ /* Special handling because arguments are in reverse order and
+ the segment name is quoted. */
+ exp_print_token (tree->type.node_code, FALSE);
+ fputs (" (\"", config.map_file);
+ exp_print_tree (tree->binary.rhs);
+ fputs ("\", ", config.map_file);
+ exp_print_tree (tree->binary.lhs);
+ fputc (')', config.map_file);
+ return;
}
if (function_like)
{