* 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.
This commit is contained in:
Alan Modra 2011-01-21 13:18:19 +00:00
parent 6b069ee70d
commit 9bc8bb33fe
3 changed files with 61 additions and 19 deletions

View File

@ -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

View File

@ -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.

View File

@ -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;