/* This module handles expression trees.
- Copyright (C) 1991-2021 Free Software Foundation, Inc.
+ Copyright (C) 1991-2023 Free Software Foundation, Inc.
Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>.
This file is part of the GNU Binutils.
{ RSHIFTEQ, ">>=" },
{ ANDEQ, "&=" },
{ OREQ, "|=" },
+ { XOREQ, "^=" },
{ OROR, "||" },
{ ANDAND, "&&" },
{ EQ, "==" },
{
bfd_vma value = expld.result.value;
bfd_vma result = -1;
- bfd_boolean round_up = FALSE;
+ bool 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;
+ round_up = true;
}
while (value >>= 1);
if (expld.result.section != NULL)
expld.result.value += expld.result.section->vma;
expld.result.section = bfd_abs_section_ptr;
- expld.rel_from_abs = FALSE;
+ expld.rel_from_abs = false;
}
static void
new_abs (bfd_vma value)
{
- expld.result.valid_p = TRUE;
+ expld.result.valid_p = true;
expld.result.section = bfd_abs_section_ptr;
expld.result.value = value;
expld.result.str = NULL;
static void
new_number (bfd_vma value)
{
- expld.result.valid_p = TRUE;
+ expld.result.valid_p = true;
expld.result.value = value;
expld.result.str = NULL;
expld.result.section = NULL;
static void
new_rel (bfd_vma value, asection *section)
{
- expld.result.valid_p = TRUE;
+ expld.result.valid_p = true;
expld.result.value = value;
expld.result.str = NULL;
expld.result.section = section;
{
asection *s = expld.section;
- expld.rel_from_abs = TRUE;
- expld.result.valid_p = TRUE;
+ expld.rel_from_abs = true;
+ expld.result.valid_p = true;
expld.result.value = value - s->vma;
expld.result.str = NULL;
expld.result.section = s;
symbol_defined (const char *name)
{
return ((struct definedness_hash_entry *)
- bfd_hash_lookup (&definedness_table, name, FALSE, FALSE));
+ bfd_hash_lookup (&definedness_table, name, false, false));
}
/* Update the definedness state of NAME. Return FALSE if script symbol
is multiply defining a strong symbol in an object. */
-static bfd_boolean
+static bool
update_definedness (const char *name, struct bfd_link_hash_entry *h)
{
- bfd_boolean ret;
+ bool ret;
struct definedness_hash_entry *defentry
= (struct definedness_hash_entry *)
- bfd_hash_lookup (&definedness_table, name, TRUE, FALSE);
+ bfd_hash_lookup (&definedness_table, name, true, false);
if (defentry == NULL)
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. */
- ret = TRUE;
+ ret = true;
if (!h->ldscript_def
&& (h->type == bfd_link_hash_defined
|| h->type == bfd_link_hash_defweak
defentry->by_object = 1;
if (h->type == bfd_link_hash_defined
&& h->u.def.section->output_section != NULL
+ && !bfd_is_abs_section (h->u.def.section)
&& !h->linker_def)
- ret = FALSE;
+ ret = false;
}
defentry->iteration = lang_statement_iteration;
}
static void
-fold_segment_end (seg_align_type *seg)
+fold_segment_end (void)
{
+ seg_align_type *seg = &expld.dataseg;
+
if (expld.phase == lang_first_phase_enum
|| expld.section != bfd_abs_section_ptr)
{
- expld.result.valid_p = FALSE;
+ expld.result.valid_p = false;
}
else if (seg->phase == exp_seg_align_seen
|| seg->phase == exp_seg_relro_seen)
/* OK. */
}
else
- expld.result.valid_p = FALSE;
+ expld.result.valid_p = false;
}
static void
if (expld.phase != lang_first_phase_enum)
new_rel_from_abs (align_n (expld.dot, expld.result.value));
else
- expld.result.valid_p = FALSE;
+ expld.result.valid_p = false;
break;
case ABSOLUTE:
expld.result.value = align_n (expld.dot, expld.result.value);
}
else
- expld.result.valid_p = FALSE;
+ expld.result.valid_p = false;
break;
case DATA_SEGMENT_END:
- fold_segment_end (&expld.dataseg);
+ fold_segment_end ();
break;
default:
}
static void
-fold_segment_align (seg_align_type *seg, etree_value_type *lhs)
+fold_segment_align (etree_value_type *lhs)
{
+ seg_align_type *seg = &expld.dataseg;
+
seg->relro = exp_seg_relro_start;
if (expld.phase == lang_first_phase_enum
|| expld.section != bfd_abs_section_ptr)
- expld.result.valid_p = FALSE;
+ expld.result.valid_p = false;
else
{
bfd_vma maxpage = lhs->value;
}
else
{
- expld.result.value += expld.dot & (maxpage - 1);
+ if (!link_info.relro)
+ expld.result.value += expld.dot & (maxpage - 1);
if (seg->phase == exp_seg_done)
{
/* OK. */
{
seg->phase = exp_seg_align_seen;
seg->base = expld.result.value;
- seg->pagesize = commonpage;
+ seg->commonpagesize = commonpage;
seg->maxpagesize = maxpage;
+ seg->relropagesize = maxpage;
seg->relro_end = 0;
}
else
- expld.result.valid_p = FALSE;
+ expld.result.valid_p = false;
}
}
}
static void
-fold_segment_relro_end (seg_align_type *seg, etree_value_type *lhs)
+fold_segment_relro_end (etree_value_type *lhs)
{
+ seg_align_type *seg = &expld.dataseg;
+
/* Operands swapped! XXX_SEGMENT_RELRO_END(offset,exp) has offset
in expld.result and exp in lhs. */
seg->relro = exp_seg_relro_end;
seg->relro_offset = expld.result.value;
if (expld.phase == lang_first_phase_enum
|| expld.section != bfd_abs_section_ptr)
- expld.result.valid_p = FALSE;
+ expld.result.valid_p = false;
else if (seg->phase == exp_seg_align_seen
|| seg->phase == exp_seg_adjust
|| seg->phase == exp_seg_relro_adjust
seg->relro_end = lhs->value + expld.result.value;
if (seg->phase == exp_seg_relro_adjust
- && (seg->relro_end & (seg->pagesize - 1)))
+ && (seg->relro_end & (seg->relropagesize - 1)))
{
- seg->relro_end += seg->pagesize - 1;
- seg->relro_end &= ~(seg->pagesize - 1);
+ seg->relro_end += seg->relropagesize - 1;
+ seg->relro_end &= ~(seg->relropagesize - 1);
expld.result.value = seg->relro_end - expld.result.value;
}
else
seg->phase = exp_seg_relro_seen;
}
else
- expld.result.valid_p = FALSE;
+ expld.result.valid_p = false;
}
static void
einfo (_("%P: warning: address of `%s' "
"isn't multiple of maximum page size\n"),
segment_name);
- seg->used = TRUE;
+ seg->used = true;
value = seg->value;
break;
}
break;
case DATA_SEGMENT_ALIGN:
- fold_segment_align (&expld.dataseg, &lhs);
+ fold_segment_align (&lhs);
break;
case DATA_SEGMENT_RELRO_END:
- fold_segment_relro_end (&expld.dataseg, &lhs);
+ fold_segment_relro_end (&lhs);
break;
default:
: tree->trinary.rhs);
}
+static lang_output_section_statement_type *
+output_section_find (const char *name)
+{
+ lang_output_section_statement_type *os = lang_output_section_find (name);
+
+ if (os == NULL && strcmp (name, "NEXT_SECTION") == 0)
+ {
+ os = expld.last_os;
+ if (os != NULL)
+ while ((os = os->next) != NULL)
+ if (os->constraint >= 0 && os->bfd_section != NULL)
+ break;
+ if (os == NULL)
+ os = abs_output_section;
+ }
+ return os;
+}
+
static void
fold_name (etree_type *tree)
{
h = bfd_wrapped_link_hash_lookup (link_info.output_bfd,
&link_info,
tree->name.name,
- FALSE, FALSE, TRUE);
+ false, false, true);
new_number (h != NULL
&& (h->type == bfd_link_hash_defined
|| h->type == bfd_link_hash_defweak
h = bfd_wrapped_link_hash_lookup (link_info.output_bfd,
&link_info,
tree->name.name,
- TRUE, FALSE, TRUE);
+ true, false, true);
if (!h)
{
if (expld.phase != lang_first_phase_enum)
{
lang_output_section_statement_type *os;
- os = lang_output_section_find (tree->name.name);
+ os = output_section_find (tree->name.name);
if (os == NULL)
{
if (expld.phase == lang_final_phase_enum)
bfd_vma val;
if (tree->type.node_code == SIZEOF)
- val = (os->bfd_section->size
- / bfd_octets_per_byte (link_info.output_bfd,
- os->bfd_section));
+ {
+ if (os->processed_vma)
+ val = os->bfd_section->size;
+ else
+ /* If we've just called lang_reset_memory_regions,
+ size will be zero and a previous estimate of
+ size will be in rawsize. */
+ val = os->bfd_section->rawsize;
+ val /= bfd_octets_per_byte (link_info.output_bfd,
+ os->bfd_section);
+ }
else
val = (bfd_vma)1 << os->bfd_section->alignment_power;
{
lang_memory_region_type *mem;
- mem = lang_memory_region_lookup (tree->name.name, FALSE);
+ mem = lang_memory_region_lookup (tree->name.name, false);
if (mem != NULL)
new_number (mem->length);
else
{
lang_memory_region_type *mem;
- mem = lang_memory_region_lookup (tree->name.name, FALSE);
+ mem = lang_memory_region_lookup (tree->name.name, false);
if (mem != NULL)
new_rel_from_abs (mem->origin);
else
/* Return true if TREE is '.'. */
-static bfd_boolean
+static bool
is_dot (const etree_type *tree)
{
return (tree->type.node_class == etree_name
/* Return true if TREE is a constant equal to VAL. */
-static bfd_boolean
+static bool
is_value (const etree_type *tree, bfd_vma val)
{
return (tree->type.node_class == etree_value
/* Return true if TREE is an absolute symbol equal to VAL defined in
a linker script. */
-static bfd_boolean
+static bool
is_sym_value (const etree_type *tree, bfd_vma val)
{
struct bfd_link_hash_entry *h;
&& (h = bfd_wrapped_link_hash_lookup (link_info.output_bfd,
&link_info,
tree->name.name,
- FALSE, FALSE, TRUE)) != NULL
+ false, false, true)) != NULL
&& h->ldscript_def
&& h->type == bfd_link_hash_defined
&& h->u.def.section == bfd_abs_section_ptr
/* Return true if TREE is ". != 0". */
-static bfd_boolean
+static bool
is_dot_ne_0 (const etree_type *tree)
{
return (tree->type.node_class == etree_binary
/* Return true if TREE is ". = . + 0" or ". = . + sym" where sym is an
absolute constant with value 0 defined in a linker script. */
-static bfd_boolean
+static bool
is_dot_plus_0 (const etree_type *tree)
{
return (tree->type.node_class == etree_binary
/* Return true if TREE is "ALIGN (. != 0 ? some_expression : 1)". */
-static bfd_boolean
+static bool
is_align_conditional (const etree_type *tree)
{
if (tree->type.node_class == etree_unary
&& is_dot_ne_0 (tree->trinary.cond)
&& is_value (tree->trinary.rhs, 1));
}
- return FALSE;
+ return false;
}
static void
if (expld.phase != lang_first_phase_enum)
{
/* Notify the folder that this is an assignment to dot. */
- expld.assigning_to_dot = TRUE;
+ expld.assigning_to_dot = true;
exp_fold_tree_1 (tree->assign.src);
- expld.assigning_to_dot = FALSE;
+ expld.assigning_to_dot = false;
/* If we are assigning to dot inside an output section
arrange to keep the section, except for certain
if (tree->type.node_class == etree_provide)
{
h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst,
- FALSE, FALSE, TRUE);
+ false, false, true);
if (h == NULL
|| !(h->type == bfd_link_hash_new
|| h->type == bfd_link_hash_undefined
if (h == NULL)
{
h = bfd_link_hash_lookup (link_info.hash, tree->assign.dst,
- TRUE, FALSE, TRUE);
+ true, false, true);
if (h == NULL)
einfo (_("%F%P:%s: hash creation failed\n"),
tree->assign.dst);
{
expld.result.value = 0;
expld.result.section = NULL;
- expld.result.valid_p = TRUE;
+ expld.result.valid_p = true;
}
if (expld.result.valid_p)
{
bfd_copy_link_hash_symbol_type (link_info.output_bfd,
h, expld.assign_src);
- expld.assign_src->non_ir_ref_regular = TRUE;
+ expld.assign_src->non_ir_ref_regular = true;
}
}
}
}
void
-exp_fold_tree (etree_type *tree, asection *current_section, bfd_vma *dotp)
+exp_fold_tree (etree_type *tree, lang_output_section_statement_type *os,
+ asection *current_section, bfd_vma *dotp)
{
- expld.rel_from_abs = FALSE;
+ expld.rel_from_abs = false;
expld.dot = *dotp;
expld.dotp = dotp;
expld.section = current_section;
+ expld.last_os = os;
exp_fold_tree_1 (tree);
}
void
-exp_fold_tree_no_dot (etree_type *tree)
+exp_fold_tree_no_dot (etree_type *tree, lang_output_section_statement_type *os)
{
- expld.rel_from_abs = FALSE;
+ expld.rel_from_abs = false;
expld.dot = 0;
expld.dotp = NULL;
expld.section = bfd_abs_section_ptr;
+ expld.last_os = os;
exp_fold_tree_1 (tree);
}
static void
exp_value_fold (etree_type *tree)
{
- exp_fold_tree_no_dot (tree);
+ exp_fold_tree_no_dot (tree, NULL);
if (expld.result.valid_p)
{
tree->type.node_code = INT;
exp_assop (const char *dst,
etree_type *src,
enum node_tree_enum class,
- bfd_boolean hidden)
+ bool hidden)
{
etree_type *n;
/* Handle linker script assignments and HIDDEN. */
etree_type *
-exp_assign (const char *dst, etree_type *src, bfd_boolean hidden)
+exp_assign (const char *dst, etree_type *src, bool hidden)
{
return exp_assop (dst, src, etree_assign, hidden);
}
etree_type *
exp_defsym (const char *dst, etree_type *src)
{
- return exp_assop (dst, src, etree_assign, FALSE);
+ return exp_assop (dst, src, etree_assign, false);
}
/* Handle PROVIDE. */
etree_type *
-exp_provide (const char *dst, etree_type *src, bfd_boolean hidden)
+exp_provide (const char *dst, etree_type *src, bool hidden)
{
return exp_assop (dst, src, etree_provide, hidden);
}
void
exp_print_tree (etree_type *tree)
{
- bfd_boolean function_like;
+ bool function_like;
if (config.map_file == NULL)
config.map_file = stderr;
return;
case etree_assign:
fputs (tree->assign.dst, config.map_file);
- exp_print_token (tree->type.node_code, TRUE);
+ exp_print_token (tree->type.node_code, true);
exp_print_tree (tree->assign.src);
break;
case etree_provide:
fputc (')', config.map_file);
break;
case etree_binary:
- function_like = FALSE;
+ function_like = false;
switch (tree->type.node_code)
{
case MAX_K:
case ALIGN_K:
case DATA_SEGMENT_ALIGN:
case DATA_SEGMENT_RELRO_END:
- function_like = TRUE;
+ 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);
+ exp_print_token (tree->type.node_code, false);
fputs (" (\"", config.map_file);
exp_print_tree (tree->binary.rhs);
fputs ("\", ", config.map_file);
}
if (function_like)
{
- exp_print_token (tree->type.node_code, FALSE);
+ exp_print_token (tree->type.node_code, false);
fputc (' ', config.map_file);
}
fputc ('(', config.map_file);
if (function_like)
fprintf (config.map_file, ", ");
else
- exp_print_token (tree->type.node_code, TRUE);
+ exp_print_token (tree->type.node_code, true);
exp_print_tree (tree->binary.rhs);
fputc (')', config.map_file);
break;
exp_print_tree (tree->trinary.rhs);
break;
case etree_unary:
- exp_print_token (tree->unary.type.node_code, FALSE);
+ exp_print_token (tree->unary.type.node_code, false);
if (tree->unary.child)
{
fprintf (config.map_file, " (");
fputs (tree->name.name, config.map_file);
else
{
- exp_print_token (tree->type.node_code, FALSE);
+ exp_print_token (tree->type.node_code, false);
if (tree->name.name)
fprintf (config.map_file, " (%s)", tree->name.name);
}
}
bfd_vma
-exp_get_vma (etree_type *tree, bfd_vma def, char *name)
+exp_get_vma (etree_type *tree, lang_output_section_statement_type *os,
+ bfd_vma def, char *name)
{
if (tree != NULL)
{
- exp_fold_tree_no_dot (tree);
+ exp_fold_tree_no_dot (tree, os);
if (expld.result.valid_p)
return expld.result.value;
else if (name != NULL && expld.phase != lang_mark_phase_enum)
NULL or cannot be resolved, return -1. */
int
-exp_get_power (etree_type *tree, char *name)
+exp_get_power (etree_type *tree, lang_output_section_statement_type *os,
+ char *name)
{
- bfd_vma x = exp_get_vma (tree, -1, name);
+ bfd_vma x = exp_get_vma (tree, os, -1, name);
bfd_vma p2;
int n;
if (tree == NULL)
return def;
- exp_fold_tree_no_dot (tree);
+ exp_fold_tree_no_dot (tree, NULL);
if (!expld.result.valid_p)
{
if (name != NULL && expld.phase != lang_mark_phase_enum)
{
if (tree != NULL)
{
- exp_fold_tree_no_dot (tree);
+ exp_fold_tree_no_dot (tree, NULL);
if (expld.result.valid_p)
{
SEGMENT_START or ORIGIN) outside of an output section statement,
to section relative. */
-static bfd_boolean
+static bool
set_sym_sections (struct bfd_hash_entry *bh, void *inf ATTRIBUTE_UNUSED)
{
struct definedness_hash_entry *def = (struct definedness_hash_entry *) bh;
{
struct bfd_link_hash_entry *h;
h = bfd_link_hash_lookup (link_info.hash, bh->string,
- FALSE, FALSE, TRUE);
+ false, false, true);
if (h != NULL
&& h->type == bfd_link_hash_defined
&& h->u.def.section == bfd_abs_section_ptr)
h->u.def.section = def->final_sec;
}
}
- return TRUE;
+ return true;
}
void
/* Determine whether a symbol is going to remain absolute even after
ldexp_finalize_syms() has run. */
-bfd_boolean
+bool
ldexp_is_final_sym_absolute (const struct bfd_link_hash_entry *h)
{
if (h->type == bfd_link_hash_defined
const struct definedness_hash_entry *def;
if (!h->ldscript_def)
- return TRUE;
+ return true;
def = symbol_defined (h->root.string);
if (def != NULL)
return def->final_sec == bfd_abs_section_ptr;
}
- return FALSE;
+ return false;
}
void