From mboxrd@z Thu Jan 1 00:00:00 1970 From: Ian Lance Taylor To: richard.earnshaw@armltd.co.uk Cc: raeburn@cygnus.com, richard.earnshaw@armltd.co.uk, gas2@cygnus.com Subject: Re: Inconsistent behaviour (in resolve_symbol_value?) Date: Wed, 07 Aug 1996 12:34:00 -0000 Message-id: <199608071934.PAA24880@sanguine.cygnus.com> References: <9608051502.AA02481@sun52.armltd> X-SW-Source: 1996/msg00072.html Date: Mon, 05 Aug 1996 16:02:35 +0100 From: Richard Earnshaw The problem seems to be the code in resolve_symbol_value that handles various binary operations. I'm not sure what the code is trying to check for so I'm not sure what the fix should be. Both 'if' clauses involve checks for undefined sections, but the cases are very specific. Further, after the logical operation has been performed the type of the node is changed to O_constant, so it is no-longer possible to recover the operation in the back end. That code doesn't really make any sense to me either, even though I wrote it. I think I'll apply this patch. It requires that both operands of an arithmetic operator be absolute, except in the special cases of adding or subtracting a constant, or subtracting two symbols in the same section. Please let me know if this seems to have any problems. Ian Index: symbols.c =================================================================== RCS file: /cvs/cvsfiles/devo/gas/symbols.c,v retrieving revision 1.86 diff -u -r1.86 symbols.c --- symbols.c 1996/07/26 15:58:57 1.86 +++ symbols.c 1996/08/07 19:32:08 @@ -639,7 +639,35 @@ symp->sy_resolving = 1; - reduce: + /* Simplify addition or subtraction of a constant by folding the + constant into X_add_number. */ + if (symp->sy_value.X_op == O_add + || symp->sy_value.X_op == O_subtract) + { + resolve_symbol_value (symp->sy_value.X_add_symbol); + resolve_symbol_value (symp->sy_value.X_op_symbol); + if (S_GET_SEGMENT (symp->sy_value.X_op_symbol) == absolute_section) + { + right = S_GET_VALUE (symp->sy_value.X_op_symbol); + if (symp->sy_value.X_op == O_add) + symp->sy_value.X_add_number += right; + else + symp->sy_value.X_add_number -= right; + symp->sy_value.X_op = O_symbol; + symp->sy_value.X_op_symbol = NULL; + } + else if ((S_GET_SEGMENT (symp->sy_value.X_add_symbol) + == absolute_section) + && symp->sy_value.X_op == O_add) + { + left = S_GET_VALUE (symp->sy_value.X_add_symbol); + symp->sy_value.X_add_symbol = symp->sy_value.X_op_symbol; + symp->sy_value.X_add_number += left; + symp->sy_value.X_op = O_symbol; + symp->sy_value.X_op_symbol = NULL; + } + } + switch (symp->sy_value.X_op) { case O_absent: @@ -708,39 +736,6 @@ resolved = symp->sy_value.X_add_symbol->sy_resolved; break; - case O_add: - resolve_symbol_value (symp->sy_value.X_add_symbol); - resolve_symbol_value (symp->sy_value.X_op_symbol); - seg_left = S_GET_SEGMENT (symp->sy_value.X_add_symbol); - seg_right = S_GET_SEGMENT (symp->sy_value.X_op_symbol); - /* This case comes up with PIC support. */ - { - symbolS *s_left = symp->sy_value.X_add_symbol; - symbolS *s_right = symp->sy_value.X_op_symbol; - - if (seg_left == absolute_section) - { - symbolS *t; - segT ts; - t = s_left; - s_left = s_right; - s_right = t; - ts = seg_left; - seg_left = seg_right; - seg_right = ts; - } - if (seg_right == absolute_section - && s_right->sy_resolved) - { - symp->sy_value.X_add_number += S_GET_VALUE (s_right); - symp->sy_value.X_op_symbol = 0; - symp->sy_value.X_add_symbol = s_left; - symp->sy_value.X_op = O_symbol; - goto reduce; - } - } - /* fall through */ - case O_multiply: case O_divide: case O_modulus: @@ -750,6 +745,7 @@ case O_bit_or_not: case O_bit_exclusive_or: case O_bit_and: + case O_add: case O_subtract: case O_eq: case O_ne: @@ -763,38 +759,30 @@ resolve_symbol_value (symp->sy_value.X_op_symbol); seg_left = S_GET_SEGMENT (symp->sy_value.X_add_symbol); seg_right = S_GET_SEGMENT (symp->sy_value.X_op_symbol); - if (seg_left != seg_right - && seg_left != undefined_section - && seg_right != undefined_section) - { - char *file; - unsigned int line; + left = S_GET_VALUE (symp->sy_value.X_add_symbol); + right = S_GET_VALUE (symp->sy_value.X_op_symbol); - if (expr_symbol_where (symp, &file, &line)) - as_bad_where - (file, line, - "illegal operation on symbols in different sections"); - else - as_bad - ("%s set to illegal operation on symbols in different sections", - S_GET_NAME (symp)); - } - if ((S_GET_SEGMENT (symp->sy_value.X_add_symbol) - != absolute_section) - && symp->sy_value.X_op != O_subtract) + /* Subtraction is permitted if both operands are in the same + section. Otherwise, both operands must be absolute. We + already handled the case of addition or subtraction of a + constant above. This will probably need to be changed + for an object file format which supports arbitrary + expressions, such as IEEE-695. */ + if ((seg_left != absolute_section + || seg_right != absolute_section) + && (symp->sy_value.X_op != O_subtract + || seg_left != seg_right)) { char *file; unsigned int line; if (expr_symbol_where (symp, &file, &line)) - as_bad_where (file, line, - "illegal operation on non-absolute symbols"); + as_bad_where (file, line, "invalid section for operation"); else - as_bad ("%s set to illegal operation on non-absolute symbols", + as_bad ("invalid section for operation setting %s", S_GET_NAME (symp)); } - left = S_GET_VALUE (symp->sy_value.X_add_symbol); - right = S_GET_VALUE (symp->sy_value.X_op_symbol); + switch (symp->sy_value.X_op) { case O_multiply: val = left * right; break;