/* This module handles expression trees.
- Copyright (C) 1991-2017 Free Software Foundation, Inc.
+ Copyright (C) 1991-2020 Free Software Foundation, Inc.
Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>.
This file is part of the GNU Binutils.
#include "sysdep.h"
#include "bfd.h"
#include "bfdlink.h"
+#include "ctf-api.h"
#include "ld.h"
#include "ldmain.h"
etree_type *
exp_intop (bfd_vma value)
{
- etree_type *new_e = (etree_type *) stat_alloc (sizeof (new_e->value));
+ etree_type *new_e = stat_alloc (sizeof (new_e->value));
new_e->type.node_code = INT;
new_e->type.filename = ldlex_filename ();
new_e->type.lineno = lineno;
etree_type *
exp_bigintop (bfd_vma value, char *str)
{
- etree_type *new_e = (etree_type *) stat_alloc (sizeof (new_e->value));
+ etree_type *new_e = stat_alloc (sizeof (new_e->value));
new_e->type.node_code = INT;
new_e->type.filename = ldlex_filename ();
new_e->type.lineno = lineno;
etree_type *
exp_relop (asection *section, bfd_vma value)
{
- etree_type *new_e = (etree_type *) stat_alloc (sizeof (new_e->rel));
+ etree_type *new_e = stat_alloc (sizeof (new_e->rel));
new_e->type.node_code = REL;
new_e->type.filename = ldlex_filename ();
new_e->type.lineno = lineno;
bfd_hash_allocate (table, sizeof (struct definedness_hash_entry));
if (ret == NULL)
- einfo (_("%P%F: bfd_hash_allocate failed creating symbol %s\n"), name);
+ einfo (_("%F%P: bfd_hash_allocate failed creating symbol %s\n"), name);
ret->by_object = 0;
ret->iteration = 0;
bfd_hash_lookup (&definedness_table, name, TRUE, FALSE);
if (defentry == NULL)
- einfo (_("%P%F: bfd_hash_lookup failed creating symbol %s\n"), name);
+ einfo (_("%F%P: bfd_hash_lookup failed creating symbol %s\n"), name);
/* If the symbol was already defined, and not by a script, then it
must be defined by an object file or by the linker target code. */
operand, binary.rhs is first operand. */
if (expld.result.valid_p && tree->type.node_code == SEGMENT_START)
{
+ bfd_vma value = expld.result.value;
const char *segment_name;
segment_type *seg;
{
if (!seg->used
&& config.magic_demand_paged
+ && config.maxpagesize != 0
&& (seg->value % config.maxpagesize) != 0)
einfo (_("%P: warning: address of `%s' "
"isn't multiple of maximum page size\n"),
segment_name);
seg->used = TRUE;
- new_rel_from_abs (seg->value);
+ value = seg->value;
break;
}
+ new_rel_from_abs (value);
return;
}
expld.result.value = ((bfd_signed_vma) lhs.value
% (bfd_signed_vma) expld.result.value);
else if (expld.phase != lang_mark_phase_enum)
- einfo (_("%F%S %% by zero\n"), tree->binary.rhs);
+ einfo (_("%F%P:%pS %% by zero\n"), tree->binary.rhs);
arith_result_section (&lhs);
break;
expld.result.value = ((bfd_signed_vma) lhs.value
/ (bfd_signed_vma) expld.result.value);
else if (expld.phase != lang_mark_phase_enum)
- einfo (_("%F%S / by zero\n"), tree->binary.rhs);
+ einfo (_("%F%P:%pS / by zero\n"), tree->binary.rhs);
arith_result_section (&lhs);
break;
switch (tree->type.node_code)
{
case SIZEOF_HEADERS:
+ link_info.load_phdrs = 1;
if (expld.phase != lang_first_phase_enum)
{
bfd_vma hdr_size = 0;
break;
case NAME:
- if (expld.assign_name != NULL
- && strcmp (expld.assign_name, tree->name.name) == 0)
- {
- /* Self-assignment is only allowed for absolute symbols
- defined in a linker script. */
- h = bfd_wrapped_link_hash_lookup (link_info.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)
- && h->u.def.section == bfd_abs_section_ptr
- && (def = symbol_defined (tree->name.name)) != NULL
- && def->iteration == (lang_statement_iteration & 255)))
- expld.assign_name = NULL;
- }
if (tree->name.name[0] == '.' && tree->name.name[1] == 0)
new_rel_from_abs (expld.dot);
else
tree->name.name,
TRUE, FALSE, TRUE);
if (!h)
- einfo (_("%P%F: bfd_link_hash_lookup failed: %E\n"));
+ einfo (_("%F%P: bfd_link_hash_lookup failed: %E\n"));
else if (h->type == bfd_link_hash_defined
|| h->type == bfd_link_hash_defweak)
{
if (expld.phase <= lang_mark_phase_enum)
new_rel (h->u.def.value, h->u.def.section);
else
- einfo (_("%X%S: unresolvable symbol `%s'"
+ einfo (_("%X%P:%pS: unresolvable symbol `%s'"
" referenced in expression\n"),
tree, tree->name.name);
}
else if (expld.phase == lang_final_phase_enum
|| (expld.phase != lang_mark_phase_enum
&& expld.assigning_to_dot))
- einfo (_("%F%S: undefined symbol `%s'"
+ einfo (_("%F%P:%pS: undefined symbol `%s'"
" referenced in expression\n"),
tree, tree->name.name);
else if (h->type == bfd_link_hash_new)
if (expld.assign_src == NULL)
expld.assign_src = h;
else
- expld.assign_src = (struct bfd_link_hash_entry *) 0 - 1;
+ expld.assign_src = (struct bfd_link_hash_entry *) - 1;
+
+ /* Self-assignment is only allowed for absolute symbols
+ defined in a linker script. */
+ if (expld.assign_name != NULL
+ && strcmp (expld.assign_name, tree->name.name) == 0
+ && !(h != NULL
+ && (h->type == bfd_link_hash_defined
+ || h->type == bfd_link_hash_defweak)
+ && h->u.def.section == bfd_abs_section_ptr
+ && (def = symbol_defined (tree->name.name)) != NULL
+ && def->iteration == (lang_statement_iteration & 255)))
+ expld.assign_name = NULL;
}
break;
if (os == NULL)
{
if (expld.phase == lang_final_phase_enum)
- einfo (_("%F%S: undefined section `%s'"
+ einfo (_("%F%P:%pS: undefined section `%s'"
" referenced in expression\n"),
tree, tree->name.name);
}
if (os == NULL)
{
if (expld.phase == lang_final_phase_enum)
- einfo (_("%F%S: undefined section `%s'"
+ einfo (_("%F%P:%pS: undefined section `%s'"
" referenced in expression\n"),
tree, tree->name.name);
}
if (os == NULL)
{
if (expld.phase == lang_final_phase_enum)
- einfo (_("%F%S: undefined section `%s'"
+ einfo (_("%F%P:%pS: undefined section `%s'"
" referenced in expression\n"),
tree, tree->name.name);
new_number (0);
if (tree->type.node_code == SIZEOF)
val = (os->bfd_section->size
- / bfd_octets_per_byte (link_info.output_bfd));
+ / bfd_octets_per_byte (link_info.output_bfd,
+ os->bfd_section));
else
val = (bfd_vma)1 << os->bfd_section->alignment_power;
case LENGTH:
{
- if (expld.phase != lang_first_phase_enum)
- {
- lang_memory_region_type *mem;
-
- mem = lang_memory_region_lookup (tree->name.name, FALSE);
- if (mem != NULL)
- new_number (mem->length);
- else
- einfo (_("%F%S: undefined MEMORY region `%s'"
- " referenced in expression\n"),
- tree, tree->name.name);
- }
+ lang_memory_region_type *mem;
+
+ mem = lang_memory_region_lookup (tree->name.name, FALSE);
+ if (mem != NULL)
+ new_number (mem->length);
+ else
+ einfo (_("%F%P:%pS: undefined MEMORY region `%s'"
+ " referenced in expression\n"),
+ tree, tree->name.name);
}
break;
case ORIGIN:
- if (expld.phase != lang_first_phase_enum)
- {
- lang_memory_region_type *mem;
-
- mem = lang_memory_region_lookup (tree->name.name, FALSE);
- if (mem != NULL)
- new_rel_from_abs (mem->origin);
- else
- einfo (_("%F%S: undefined MEMORY region `%s'"
- " referenced in expression\n"),
- tree, tree->name.name);
- }
+ {
+ lang_memory_region_type *mem;
+
+ mem = lang_memory_region_lookup (tree->name.name, FALSE);
+ if (mem != NULL)
+ new_rel_from_abs (mem->origin);
+ else
+ einfo (_("%F%P:%pS: undefined MEMORY region `%s'"
+ " referenced in expression\n"),
+ tree, tree->name.name);
+ }
break;
case CONSTANT:
else if (strcmp (tree->name.name, "COMMONPAGESIZE") == 0)
new_number (config.commonpagesize);
else
- einfo (_("%F%S: unknown constant `%s' referenced in expression\n"),
+ einfo (_("%F%P:%pS: unknown constant `%s' referenced in expression\n"),
tree, tree->name.name);
break;
if (tree->assign.dst[0] == '.' && tree->assign.dst[1] == 0)
{
if (tree->type.node_class != etree_assign)
- einfo (_("%F%S can not PROVIDE assignment to"
+ einfo (_("%F%P:%pS can not PROVIDE assignment to"
" location counter\n"), tree);
if (expld.phase != lang_first_phase_enum)
{
|| expld.section == bfd_und_section_ptr)
{
if (expld.phase != lang_mark_phase_enum)
- einfo (_("%F%S invalid assignment to"
+ einfo (_("%F%P:%pS invalid assignment to"
" location counter\n"), tree);
}
else if (expld.dotp == NULL)
- einfo (_("%F%S assignment to location counter"
+ einfo (_("%F%P:%pS assignment to location counter"
" invalid outside of SECTIONS\n"), tree);
/* After allocation, assignment to dot should not be
nextdot += expld.section->vma;
if (nextdot < expld.dot
&& expld.section != bfd_abs_section_ptr)
- einfo (_("%F%S cannot move location counter backwards"
+ einfo (_("%F%P:%pS cannot move location counter backwards"
" (from %V to %V)\n"),
tree, expld.dot, nextdot);
else
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.defsym))
+ if (expld.phase == lang_final_phase_enum
+ || expld.phase == lang_fixed_phase_enum
+ || expld.assign_name != NULL)
{
+ if (tree->type.node_class == etree_provide)
+ tree->type.node_class = etree_provided;
+
if (h == NULL)
{
h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst,
TRUE, FALSE, TRUE);
if (h == NULL)
- einfo (_("%P%F:%s: hash creation failed\n"),
+ einfo (_("%F%P:%s: hash creation failed\n"),
tree->assign.dst);
}
- if (expld.result.section == NULL)
- expld.result.section = expld.section;
- if (!update_definedness (tree->assign.dst, h) && 0)
+ /* If the expression is not valid then fake a zero value. In
+ the final phase any errors will already have been raised,
+ in earlier phases we want to create this definition so
+ that it can be seen by other expressions. */
+ if (!expld.result.valid_p
+ && h->type == bfd_link_hash_new)
+ {
+ expld.result.value = 0;
+ expld.result.section = NULL;
+ expld.result.valid_p = TRUE;
+ }
+
+ if (expld.result.valid_p)
{
- /* Symbol was already defined. For now this error
- is disabled because it causes failures in the ld
- testsuite: ld-elf/var1, ld-scripts/defined5, and
- ld-scripts/pr14962. Some of these no doubt
- reflect scripts used in the wild. */
- (*link_info.callbacks->multiple_definition)
- (&link_info, h, link_info.output_bfd,
- expld.result.section, expld.result.value);
+ if (expld.result.section == NULL)
+ expld.result.section = expld.section;
+ if (!update_definedness (tree->assign.dst, h) && 0)
+ {
+ /* Symbol was already defined. For now this error
+ is disabled because it causes failures in the ld
+ testsuite: ld-elf/var1, ld-scripts/defined5, and
+ ld-scripts/pr14962. Some of these no doubt
+ reflect scripts used in the wild. */
+ (*link_info.callbacks->multiple_definition)
+ (&link_info, h, link_info.output_bfd,
+ expld.result.section, expld.result.value);
+ }
+ if (expld.phase == lang_fixed_phase_enum)
+ {
+ if (h->type == bfd_link_hash_defined)
+ {
+ expld.result.value = h->u.def.value;
+ expld.result.section = h->u.def.section;
+ }
+ }
+ else
+ {
+ h->type = bfd_link_hash_defined;
+ h->u.def.value = expld.result.value;
+ h->u.def.section = expld.result.section;
+ h->linker_def = ! tree->assign.type.lineno;
+ h->ldscript_def = 1;
+ h->rel_from_abs = expld.rel_from_abs;
+ if (tree->assign.hidden)
+ bfd_link_hide_symbol (link_info.output_bfd,
+ &link_info, h);
+
+ /* Copy the symbol type if this is an expression only
+ referencing a single symbol. (If the expression
+ contains ternary conditions, ignoring symbols on
+ false branches.) */
+ if (expld.assign_src != NULL
+ && (expld.assign_src
+ != (struct bfd_link_hash_entry *) -1))
+ bfd_copy_link_hash_symbol_type (link_info.output_bfd,
+ h, expld.assign_src);
+ }
}
- h->type = bfd_link_hash_defined;
- h->u.def.value = expld.result.value;
- h->u.def.section = expld.result.section;
- h->linker_def = ! tree->assign.type.lineno;
- h->ldscript_def = 1;
- if (tree->type.node_class == etree_provide)
- tree->type.node_class = etree_provided;
-
- /* Copy the symbol type if this is an expression only
- referencing a single symbol. (If the expression
- contains ternary conditions, ignoring symbols on
- false branches.) */
- if (expld.result.valid_p
- && expld.assign_src != NULL
- && expld.assign_src != (struct bfd_link_hash_entry *) 0 - 1)
- bfd_copy_link_hash_symbol_type (link_info.output_bfd, h,
- expld.assign_src);
}
- else if (expld.phase == lang_final_phase_enum)
- {
- h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst,
- FALSE, FALSE, TRUE);
- if (h != NULL
- && h->type == bfd_link_hash_new)
- h->type = bfd_link_hash_undefined;
- }
- expld.assign_name = NULL;
+ if (expld.phase != lang_fixed_phase_enum)
+ expld.assign_name = NULL;
}
break;
etree_type *
exp_binop (int code, etree_type *lhs, etree_type *rhs)
{
- etree_type *new_e = (etree_type *) stat_alloc (MAX (sizeof (new_e->binary),
- sizeof (new_e->value)));
+ etree_type *new_e = stat_alloc (MAX (sizeof (new_e->binary),
+ sizeof (new_e->value)));
new_e->type.node_code = code;
new_e->type.filename = lhs->type.filename;
new_e->type.lineno = lhs->type.lineno;
etree_type *
exp_trinop (int code, etree_type *cond, etree_type *lhs, etree_type *rhs)
{
- etree_type *new_e = (etree_type *) stat_alloc (MAX (sizeof (new_e->trinary),
- sizeof (new_e->value)));
+ etree_type *new_e = stat_alloc (MAX (sizeof (new_e->trinary),
+ sizeof (new_e->value)));
new_e->type.node_code = code;
new_e->type.filename = cond->type.filename;
new_e->type.lineno = cond->type.lineno;
etree_type *
exp_unop (int code, etree_type *child)
{
- etree_type *new_e = (etree_type *) stat_alloc (MAX (sizeof (new_e->unary),
- sizeof (new_e->value)));
+ etree_type *new_e = stat_alloc (MAX (sizeof (new_e->unary),
+ sizeof (new_e->value)));
new_e->unary.type.node_code = code;
new_e->unary.type.filename = child->type.filename;
new_e->unary.type.lineno = child->type.lineno;
etree_type *
exp_nameop (int code, const char *name)
{
- etree_type *new_e = (etree_type *) stat_alloc (sizeof (new_e->name));
+ etree_type *new_e = stat_alloc (sizeof (new_e->name));
new_e->name.type.node_code = code;
new_e->name.type.filename = ldlex_filename ();
exp_assop (const char *dst,
etree_type *src,
enum node_tree_enum class,
- bfd_boolean defsym,
bfd_boolean hidden)
{
etree_type *n;
- n = (etree_type *) stat_alloc (sizeof (n->assign));
+ n = stat_alloc (sizeof (n->assign));
n->assign.type.node_code = '=';
n->assign.type.filename = src->type.filename;
n->assign.type.lineno = src->type.lineno;
n->assign.type.node_class = class;
n->assign.src = src;
n->assign.dst = dst;
- n->assign.defsym = defsym;
n->assign.hidden = hidden;
return n;
}
etree_type *
exp_assign (const char *dst, etree_type *src, bfd_boolean hidden)
{
- return exp_assop (dst, src, etree_assign, FALSE, hidden);
+ return exp_assop (dst, src, etree_assign, hidden);
}
/* Handle --defsym command-line option. */
etree_type *
exp_defsym (const char *dst, etree_type *src)
{
- return exp_assop (dst, src, etree_assign, TRUE, FALSE);
+ return exp_assop (dst, src, etree_assign, FALSE);
}
/* Handle PROVIDE. */
etree_type *
exp_provide (const char *dst, etree_type *src, bfd_boolean hidden)
{
- return exp_assop (dst, src, etree_provide, FALSE, hidden);
+ return exp_assop (dst, src, etree_provide, hidden);
}
/* Handle ASSERT. */
{
etree_type *n;
- n = (etree_type *) stat_alloc (sizeof (n->assert_s));
+ n = stat_alloc (sizeof (n->assert_s));
n->assert_s.type.node_code = '!';
n->assert_s.type.filename = exp->type.filename;
n->assert_s.type.lineno = exp->type.lineno;
return;
case etree_rel:
if (tree->rel.section->owner != NULL)
- minfo ("%B:", tree->rel.section->owner);
+ minfo ("%pB:", tree->rel.section->owner);
minfo ("%s+0x%v", tree->rel.section->name, tree->rel.value);
return;
case etree_assign:
break;
case etree_provide:
case etree_provided:
- fprintf (config.map_file, "PROVIDE (%s, ", tree->assign.dst);
+ fprintf (config.map_file, "PROVIDE (%s = ", tree->assign.dst);
exp_print_tree (tree->assign.src);
fputc (')', config.map_file);
break;
if (expld.result.valid_p)
return expld.result.value;
else if (name != NULL && expld.phase != lang_mark_phase_enum)
- einfo (_("%F%S: nonconstant expression for %s\n"),
+ einfo (_("%F%P:%pS: nonconstant expression for %s\n"),
tree, name);
}
return def;
}
+/* Return the smallest non-negative integer such that two raised to
+ that power is at least as large as the vma evaluated at TREE, if
+ TREE is a non-NULL expression that can be resolved. If TREE is
+ NULL or cannot be resolved, return -1. */
+
int
-exp_get_value_int (etree_type *tree, int def, char *name)
+exp_get_power (etree_type *tree, char *name)
{
- return exp_get_vma (tree, def, name);
+ bfd_vma x = exp_get_vma (tree, -1, name);
+ bfd_vma p2;
+ int n;
+
+ if (x == (bfd_vma) -1)
+ return -1;
+
+ for (n = 0, p2 = 1; p2 < x; ++n, p2 <<= 1)
+ if (p2 == 0)
+ break;
+
+ return n;
}
fill_type *
if (!expld.result.valid_p)
{
if (name != NULL && expld.phase != lang_mark_phase_enum)
- einfo (_("%F%S: nonconstant expression for %s\n"),
+ einfo (_("%F%P:%pS: nonconstant expression for %s\n"),
tree, name);
return def;
}
}
else if (name != NULL && expld.phase != lang_mark_phase_enum)
{
- einfo (_("%F%S: nonconstant expression for %s\n"),
+ einfo (_("%F%P:%pS: nonconstant expression for %s\n"),
tree, name);
}
}
definedness_newfunc,
sizeof (struct definedness_hash_entry),
13))
- einfo (_("%P%F: can not create hash table: %E\n"));
+ einfo (_("%F%P: can not create hash table: %E\n"));
}
/* Convert absolute symbols defined by a script from "dot" (also