From: Ian Lance Taylor Date: Mon, 3 Feb 1997 17:38:41 +0000 (+0000) Subject: * symbols.c (resolve_symbol_value): Don't change X_add_number for X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=3569064fb5f1bce22b31a3c9d425e7fffdd214c7;p=binutils-gdb.git * symbols.c (resolve_symbol_value): Don't change X_add_number for an equated symbol. * write.c (write_relocs): Avoid looping on equated symbols. Adjust fx_offset by X_add_number for each symbol. * config/obj-coff.c (do_relocs_for): Avoid looping on equated symbols. (fixup_segment): Add a loop to track down equated symbols and adjust fx_offset appropriately. --- diff --git a/gas/ChangeLog b/gas/ChangeLog index c917491f9af..51d9df0aef7 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,14 @@ +Mon Feb 3 12:35:54 1997 Ian Lance Taylor + + * symbols.c (resolve_symbol_value): Don't change X_add_number for + an equated symbol. + * write.c (write_relocs): Avoid looping on equated symbols. + Adjust fx_offset by X_add_number for each symbol. + * config/obj-coff.c (do_relocs_for): Avoid looping on equated + symbols. + (fixup_segment): Add a loop to track down equated symbols and + adjust fx_offset appropriately. + Fri Jan 31 15:21:02 1997 Jeffrey A Law (law@cygnus.com) * config/tc-mn10200.c (md_relax_table): Add entries to allow diff --git a/gas/symbols.c b/gas/symbols.c index fa2fadbe4b1..def3f6be537 100644 --- a/gas/symbols.c +++ b/gas/symbols.c @@ -639,7 +639,35 @@ resolve_symbol_value (symp) 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: @@ -668,22 +696,26 @@ resolve_symbol_value (symp) if (symp->sy_value.X_add_number == 0) copy_symbol_attributes (symp, symp->sy_value.X_add_symbol); - S_SET_VALUE (symp, - (symp->sy_value.X_add_number - + symp->sy_frag->fr_address - + S_GET_VALUE (symp->sy_value.X_add_symbol))); - if (S_GET_SEGMENT (symp) == expr_section - || S_GET_SEGMENT (symp) == undefined_section) - S_SET_SEGMENT (symp, - S_GET_SEGMENT (symp->sy_value.X_add_symbol)); - /* If we have equated this symbol to an undefined symbol, we - keep X_op set to O_symbol. This permits the routine - which writes out relocation to detect this case, and - convert the relocation to be against the symbol to which - this symbol is equated. */ - if (! S_IS_DEFINED (symp) || S_IS_COMMON (symp)) + keep X_op set to O_symbol, and we don't change + X_add_number. This permits the routine which writes out + relocation to detect this case, and convert the + relocation to be against the symbol to which this symbol + is equated. */ + if (! S_IS_DEFINED (symp->sy_value.X_add_symbol) + || S_IS_COMMON (symp->sy_value.X_add_symbol)) symp->sy_value.X_op = O_symbol; + else + { + S_SET_VALUE (symp, + (symp->sy_value.X_add_number + + symp->sy_frag->fr_address + + S_GET_VALUE (symp->sy_value.X_add_symbol))); + if (S_GET_SEGMENT (symp) == expr_section + || S_GET_SEGMENT (symp) == undefined_section) + S_SET_SEGMENT (symp, + S_GET_SEGMENT (symp->sy_value.X_add_symbol)); + } resolved = symp->sy_value.X_add_symbol->sy_resolved; break; @@ -708,39 +740,6 @@ resolve_symbol_value (symp) 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 +749,7 @@ resolve_symbol_value (symp) 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 +763,50 @@ resolve_symbol_value (symp) 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"); + { + if (seg_left == undefined_section + || seg_right == undefined_section) + as_bad_where (file, line, + "undefined symbol %s in operation", + (seg_left == undefined_section + ? S_GET_NAME (symp->sy_value.X_add_symbol) + : S_GET_NAME (symp->sy_value.X_op_symbol))); + else + as_bad_where (file, line, "invalid section for operation"); + } else - as_bad ("%s set to illegal operation on non-absolute symbols", - S_GET_NAME (symp)); + { + if (seg_left == undefined_section + || seg_right == undefined_section) + as_bad ("undefined symbol %s in operation setting %s", + (seg_left == undefined_section + ? S_GET_NAME (symp->sy_value.X_add_symbol) + : S_GET_NAME (symp->sy_value.X_op_symbol)), + S_GET_NAME (symp)); + else + 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; diff --git a/gas/write.c b/gas/write.c index 0cd68c30f5a..a67b34aee8a 100644 --- a/gas/write.c +++ b/gas/write.c @@ -874,7 +874,17 @@ write_relocs (abfd, sec, xxx) sym = fixp->fx_addsy; while (sym->sy_value.X_op == O_symbol && (! S_IS_DEFINED (sym) || S_IS_COMMON (sym))) - sym = sym->sy_value.X_add_symbol; + { + symbolS *n; + + /* We must avoid looping, as that can occur with a badly + written program. */ + n = sym->sy_value.X_add_symbol; + if (n == sym) + break; + fixp->fx_offset += sym->sy_value.X_add_number; + sym = n; + } fixp->fx_addsy = sym; reloc = tc_gen_reloc (sec, fixp);