aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ld/ChangeLog6
-rw-r--r--ld/ld.texinfo9
-rw-r--r--ld/ldexp.c65
3 files changed, 61 insertions, 19 deletions
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 7a00e7d..fe66fb8 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,9 @@
+2011-01-21 Alan Modra <amodra@gmail.com>
+
+ * 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.
+
2011-01-14 Alan Modra <amodra@gmail.com>
* ldmain.c (main): Flush stdout before and stderr after printing
diff --git a/ld/ld.texinfo b/ld/ld.texinfo
index 4ea720f..9957d03 100644
--- a/ld/ld.texinfo
+++ b/ld/ld.texinfo
@@ -5567,8 +5567,13 @@ An operation involving only numbers results in a number.
@item
The result of comparisons, @samp{&&} and @samp{||} is also a number.
@item
-The result of other operations on relative addresses (after above
-conversions) is a relative address in the same section as the operand(s).
+The result of other binary arithmetic and logical operations on two
+relative addresses in the same section or two absolute addresess
+(after above conversions) is also a number.
+@item
+The result of other operations on relative addresses or one
+relative address and a number, is a relative address in the same
+section as the relative operand(s).
@item
The result of other operations on absolute addresses (after above
conversions) is an absolute address.
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;