diff --git a/ld/ChangeLog b/ld/ChangeLog index 7a00e7d14d..fe66fb886d 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,9 @@ +2011-01-21 Alan Modra + + * 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 * ldmain.c (main): Flush stdout before and stderr after printing diff --git a/ld/ld.texinfo b/ld/ld.texinfo index 4ea720fe04..9957d03b15 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 b7dc171b85..fc18601648 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;