aboutsummaryrefslogtreecommitdiff
path: root/ld/ldexp.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2011-01-21 13:18:19 +0000
committerAlan Modra <amodra@gmail.com>2011-01-21 13:18:19 +0000
commit9bc8bb33fe5a5a79b3146593a39edac7bb7b0dfd (patch)
tree107833af5cdf1180b3ce46737ff14f3e67bad000 /ld/ldexp.c
parent6b069ee70de3c540cef090a8733f8fc233cdb342 (diff)
downloadfsf-binutils-gdb-9bc8bb33fe5a5a79b3146593a39edac7bb7b0dfd.zip
fsf-binutils-gdb-9bc8bb33fe5a5a79b3146593a39edac7bb7b0dfd.tar.gz
fsf-binutils-gdb-9bc8bb33fe5a5a79b3146593a39edac7bb7b0dfd.tar.bz2
* ldexp.c (fold_binary): Set result section for arithmetic and
logical operations to NULL when both operands are in same section. * ld.texinfo (Expression Section): Describe this.
Diffstat (limited to 'ld/ldexp.c')
-rw-r--r--ld/ldexp.c65
1 files changed, 48 insertions, 17 deletions
diff --git a/ld/ldexp.c b/ld/ldexp.c
index b7dc171..fc18601 100644
--- a/ld/ldexp.c
+++ b/ld/ldexp.c
@@ -335,36 +335,47 @@ fold_binary (etree_type *tree)
{
make_abs ();
lhs.value += lhs.section->vma;
+ lhs.section = bfd_abs_section_ptr;
}
/* If the rhs is just a number, keep the lhs section. */
else if (expld.result.section == NULL)
- expld.result.section = lhs.section;
+ {
+ expld.result.section = lhs.section;
+ /* Make this NULL so that we know one of the operands
+ was just a number, for later tests. */
+ lhs.section = NULL;
+ }
}
+ /* At this point we know that both operands have the same
+ section, or at least one of them is a plain number. */
switch (tree->type.node_code)
{
- case '%':
- if (expld.result.value != 0)
- 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"));
- break;
-
- case '/':
- if (expld.result.value != 0)
- 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"));
- break;
-
+ /* Arithmetic operators, bitwise AND, bitwise OR and XOR
+ keep the section of one of their operands only when the
+ other operand is a plain number. Losing the section when
+ operating on two symbols, ie. a result of a plain number,
+ is required for subtraction and XOR. It's justifiable
+ for the other operations on the grounds that adding,
+ multiplying etc. two section relative values does not
+ really make sense unless they are just treated as
+ numbers.
+ The same argument could be made for many expressions
+ involving one symbol and a number. For example,
+ "1 << x" and "100 / x" probably should not be given the
+ section of x. The trouble is that if we fuss about such
+ things the rules become complex and it is onerous to
+ document ld expression evaluation. */
#define BOP(x, y) \
case x: \
expld.result.value = lhs.value y expld.result.value; \
+ if (expld.result.section == lhs.section) \
+ expld.result.section = NULL; \
break;
+ /* Comparison operators, logical AND, and logical OR always
+ return a plain number. */
#define BOPN(x, y) \
case x: \
expld.result.value = lhs.value y expld.result.value; \
@@ -388,6 +399,26 @@ fold_binary (etree_type *tree)
BOPN (ANDAND, &&);
BOPN (OROR, ||);
+ case '%':
+ if (expld.result.value != 0)
+ 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"));
+ if (expld.result.section == lhs.section)
+ expld.result.section = NULL;
+ break;
+
+ case '/':
+ if (expld.result.value != 0)
+ 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"));
+ if (expld.result.section == lhs.section)
+ expld.result.section = NULL;
+ break;
+
case MAX_K:
if (lhs.value > expld.result.value)
expld.result.value = lhs.value;