* expr.c (expr): Move code setting "retval" to the end of the loop,

and rearrange for efficiency.  For "PIC code" subtraction, use
	"rightseg" rather than recalculating.  For "symbol OP symbol"
	subtract, set "retval" to absolute_section if symbols in same
	section.
	* symbols.c (resolve_symbol_value): Resolve "sym +/- expr" to an
	O_symbol.  Simplify a +/- b code.  Allow equality and non-equality
	comparisons on symbols from any section.  Allow other comparison
	operators as for subtraction.
	(symbol_equated_reloc_p): New predicate function.
	* symbols.h (symbol_equated_reloc_p): Declare.
	* write.c (adjust_reloc_syms): Use symbol_equated_reloc_p.
	(write_relocs): Likewise.
	(write_object_file): Likewise.
	(relax_segment <rs_machine_dependent>): Ensure segment for
	expression syms is set correctly.
	* config/tc-mips.c (md_estimate_size_before_relax): Likewise.
	* config/tc-i386.c (md_assemble <Output jumps>): Don't lose part
	of a complex expression when setting up frag_var.
This commit is contained in:
Alan Modra 2001-09-09 14:01:17 +00:00
parent f16fbd61d9
commit e0890092b6
7 changed files with 174 additions and 76 deletions

View File

@ -1,3 +1,25 @@
2001-09-09 Alan Modra <amodra@bigpond.net.au>
* expr.c (expr): Move code setting "retval" to the end of the loop,
and rearrange for efficiency. For "PIC code" subtraction, use
"rightseg" rather than recalculating. For "symbol OP symbol"
subtract, set "retval" to absolute_section if symbols in same
section.
* symbols.c (resolve_symbol_value): Resolve "sym +/- expr" to an
O_symbol. Simplify a +/- b code. Allow equality and non-equality
comparisons on symbols from any section. Allow other comparison
operators as for subtraction.
(symbol_equated_reloc_p): New predicate function.
* symbols.h (symbol_equated_reloc_p): Declare.
* write.c (adjust_reloc_syms): Use symbol_equated_reloc_p.
(write_relocs): Likewise.
(write_object_file): Likewise.
(relax_segment <rs_machine_dependent>): Ensure segment for
expression syms is set correctly.
* config/tc-mips.c (md_estimate_size_before_relax): Likewise.
* config/tc-i386.c (md_assemble <Output jumps>): Don't lose part
of a complex expression when setting up frag_var.
2001-09-07 Richard Henderson <rth@redhat.com>
* config/tc-alpha.c (alpha_reloc_op_tag): Replace need_seq with

View File

@ -2741,6 +2741,9 @@ md_assemble (line)
{
int code16;
int prefix;
relax_substateT subtype;
symbolS *sym;
offsetT off;
code16 = 0;
if (flag_code == CODE_16BIT)
@ -2785,19 +2788,29 @@ md_assemble (line)
if (i.prefix[REX_PREFIX])
*p++ = i.prefix[REX_PREFIX];
*p = i.tm.base_opcode;
/* 1 possible extra opcode + displacement go in var part.
if ((unsigned char) *p == JUMP_PC_RELATIVE)
subtype = ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL);
else if ((cpu_arch_flags & Cpu386) != 0)
subtype = ENCODE_RELAX_STATE (COND_JUMP, SMALL);
else
subtype = ENCODE_RELAX_STATE (COND_JUMP86, SMALL);
subtype |= code16;
sym = i.op[0].disps->X_add_symbol;
off = i.op[0].disps->X_add_number;
if (i.op[0].disps->X_op != O_constant
&& i.op[0].disps->X_op != O_symbol)
{
/* Handle complex expressions. */
sym = make_expr_symbol (i.op[0].disps);
off = 0;
}
/* 1 possible extra opcode + 4 byte displacement go in var part.
Pass reloc in fr_var. */
frag_var (rs_machine_dependent,
1 + 4,
i.reloc[0],
((unsigned char) *p == JUMP_PC_RELATIVE
? ENCODE_RELAX_STATE (UNCOND_JUMP, SMALL) | code16
: ((cpu_arch_flags & Cpu386) != 0
? ENCODE_RELAX_STATE (COND_JUMP, SMALL) | code16
: ENCODE_RELAX_STATE (COND_JUMP86, SMALL) | code16)),
i.op[0].disps->X_add_symbol,
i.op[0].disps->X_add_number,
p);
frag_var (rs_machine_dependent, 5, i.reloc[0], subtype, sym, off, p);
}
else if (i.tm.opcode_modifier & (JumpByte | JumpDword))
{

View File

@ -11143,8 +11143,7 @@ md_estimate_size_before_relax (fragp, segtype)
sym = fragp->fr_symbol;
/* Handle the case of a symbol equated to another symbol. */
while (symbol_equated_p (sym)
&& (! S_IS_DEFINED (sym) || S_IS_COMMON (sym)))
while (symbol_equated_reloc_p (sym))
{
symbolS *n;

View File

@ -1699,21 +1699,6 @@ expr (rankarg, resultP)
}
}
if (retval == undefined_section)
{
if (SEG_NORMAL (rightseg))
retval = rightseg;
}
else if (! SEG_NORMAL (retval))
retval = rightseg;
else if (SEG_NORMAL (rightseg)
&& retval != rightseg
#ifdef DIFF_EXPR_OK
&& op_left != O_subtract
#endif
)
as_bad (_("operation combines symbols in different segments"));
op_right = operator (&op_chars);
know (op_right == O_illegal
@ -1769,8 +1754,7 @@ expr (rankarg, resultP)
&& resultP->X_op == O_symbol
&& (symbol_get_frag (right.X_add_symbol)
== symbol_get_frag (resultP->X_add_symbol))
&& SEG_NORMAL (S_GET_SEGMENT (right.X_add_symbol)))
&& SEG_NORMAL (rightseg))
{
resultP->X_add_number -= right.X_add_number;
resultP->X_add_number += (S_GET_VALUE (resultP->X_add_symbol)
@ -1865,7 +1849,14 @@ expr (rankarg, resultP)
if (op_left == O_add)
resultP->X_add_number += right.X_add_number;
else if (op_left == O_subtract)
resultP->X_add_number -= right.X_add_number;
{
resultP->X_add_number -= right.X_add_number;
if (retval == rightseg && SEG_NORMAL (retval))
{
retval = absolute_section;
rightseg = absolute_section;
}
}
}
else
{
@ -1877,6 +1868,21 @@ expr (rankarg, resultP)
resultP->X_unsigned = 1;
}
if (retval != rightseg)
{
if (! SEG_NORMAL (retval))
{
if (retval != undefined_section || SEG_NORMAL (rightseg))
retval = rightseg;
}
else if (SEG_NORMAL (rightseg)
#ifdef DIFF_EXPR_OK
&& op_left != O_subtract
#endif
)
as_bad (_("operation combines symbols in different segments"));
}
op_left = op_right;
} /* While next operator is >= this rank. */

View File

@ -914,13 +914,16 @@ resolve_symbol_value (symp)
case O_symbol:
case O_symbol_rva:
left = resolve_symbol_value (add_symbol);
do_symbol:
seg_left = S_GET_SEGMENT (add_symbol);
if (finalize_syms)
symp->sy_value.X_op_symbol = NULL;
do_symbol:
if (symp->sy_mri_common)
{
/* This is a symbol inside an MRI common section. The
relocation routines are going to handle it specially.
Don't change the value. */
relocation routines are going to handle it specially.
Don't change the value. */
resolved = symbol_resolved_p (add_symbol);
break;
}
@ -933,31 +936,51 @@ resolve_symbol_value (symp)
copy_symbol_attributes (symp, add_symbol);
}
/* If we have equated this symbol to an undefined symbol, we
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 we have equated this symbol to an undefined or common
symbol, keep X_op set to O_symbol, and 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 (add_symbol) || S_IS_COMMON (add_symbol))
{
if (finalize_syms)
{
final_seg = S_GET_SEGMENT (add_symbol);
symp->sy_value.X_op = O_symbol;
symp->sy_value.X_add_symbol = add_symbol;
symp->sy_value.X_add_number = final_val;
/* Use X_op_symbol as a flag. */
symp->sy_value.X_op_symbol = add_symbol;
final_seg = seg_left;
}
final_val = 0;
resolved = symbol_resolved_p (add_symbol);
symp->sy_resolving = 0;
goto exit_dont_set_value;
}
else if (finalize_syms && final_seg == expr_section
&& seg_left != expr_section)
{
/* If the symbol is an expression symbol, do similarly
as for undefined and common syms above. Handles
"sym +/- expr" where "expr" cannot be evaluated
immediately, and we want relocations to be against
"sym", eg. because it is weak. */
symp->sy_value.X_op = O_symbol;
symp->sy_value.X_add_symbol = add_symbol;
symp->sy_value.X_add_number = final_val;
symp->sy_value.X_op_symbol = add_symbol;
final_seg = seg_left;
final_val += symp->sy_frag->fr_address + left;
resolved = symbol_resolved_p (add_symbol);
symp->sy_resolving = 0;
goto exit_dont_set_value;
}
else
{
final_val += symp->sy_frag->fr_address + left;
if (final_seg == expr_section || final_seg == undefined_section)
final_seg = S_GET_SEGMENT (add_symbol);
final_seg = seg_left;
}
resolved = symbol_resolved_p (add_symbol);
@ -1008,42 +1031,49 @@ resolve_symbol_value (symp)
/* Simplify addition or subtraction of a constant by folding the
constant into X_add_number. */
if (op == O_add || op == O_subtract)
if (op == O_add)
{
if (seg_right == absolute_section)
{
if (op == O_add)
final_val += right;
else
final_val -= right;
op = O_symbol;
op_symbol = NULL;
final_val += right;
goto do_symbol;
}
else if (seg_left == absolute_section && op == O_add)
else if (seg_left == absolute_section)
{
op = O_symbol;
final_val += left;
add_symbol = op_symbol;
left = right;
op_symbol = NULL;
seg_left = seg_right;
goto do_symbol;
}
}
else if (op == O_subtract)
{
if (seg_right == absolute_section)
{
final_val -= right;
goto do_symbol;
}
}
/* 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. */
/* Don't emit messages unless we're finalizing the symbol value,
/* Equality and non-equality tests are permitted on anything.
Subtraction, and other comparison operators are 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.
Don't emit messages unless we're finalizing the symbol value,
otherwise we may get the same message multiple times. */
if ((seg_left != absolute_section
|| seg_right != absolute_section)
&& (op != O_subtract
if (op != O_eq && op != O_ne
&& (seg_left != absolute_section
|| seg_right != absolute_section)
&& ((op != O_subtract
&& op != O_lt && op != O_le && op != O_ge && op != O_gt)
|| seg_left != seg_right
|| seg_left == undefined_section)
|| (seg_left == undefined_section
&& add_symbol != op_symbol))
&& finalize_syms)
{
char *file;
@ -1085,7 +1115,7 @@ resolve_symbol_value (symp)
if ((op == O_divide || op == O_modulus) && right == 0)
{
/* If seg_right is not absolute_section, then we've
already issued a warning about using a bad symbol. */
already issued a warning about using a bad symbol. */
if (seg_right == absolute_section && finalize_syms)
{
char *file;
@ -1114,8 +1144,15 @@ resolve_symbol_value (symp)
case O_bit_and: left &= right; break;
case O_add: left += right; break;
case O_subtract: left -= right; break;
case O_eq: left = left == right ? ~ (offsetT) 0 : 0; break;
case O_ne: left = left != right ? ~ (offsetT) 0 : 0; break;
case O_eq:
case O_ne:
left = (left == right && seg_left == seg_right
&& (seg_left != undefined_section
|| add_symbol == op_symbol)
? ~ (offsetT) 0 : 0);
if (symp->sy_value.X_op == O_ne)
left = ~left;
break;
case O_lt: left = left < right ? ~ (offsetT) 0 : 0; break;
case O_le: left = left <= right ? ~ (offsetT) 0 : 0; break;
case O_ge: left = left >= right ? ~ (offsetT) 0 : 0; break;
@ -2146,6 +2183,24 @@ symbol_equated_p (s)
return s->sy_value.X_op == O_symbol;
}
/* Return whether a symbol is equated to another symbol, and should be
treated specially when writing out relocs. */
int
symbol_equated_reloc_p (s)
symbolS *s;
{
if (LOCAL_SYMBOL_CHECK (s))
return 0;
/* X_op_symbol, normally not used for O_symbol, is set by
resolve_symbol_value to flag expression syms that have been
equated. */
return (s->sy_value.X_op == O_symbol
&& ((s->sy_resolved && s->sy_value.X_op_symbol != NULL)
|| ! S_IS_DEFINED (s)
|| S_IS_COMMON (s)));
}
/* Return whether a symbol has a constant value. */
int

View File

@ -185,6 +185,7 @@ extern void symbol_mark_resolved PARAMS ((symbolS *));
extern int symbol_resolved_p PARAMS ((symbolS *));
extern int symbol_section_p PARAMS ((symbolS *));
extern int symbol_equated_p PARAMS ((symbolS *));
extern int symbol_equated_reloc_p PARAMS ((symbolS *));
extern int symbol_constant_p PARAMS ((symbolS *));
#ifdef BFD_ASSEMBLER

View File

@ -769,8 +769,7 @@ adjust_reloc_syms (abfd, sec, xxx)
/* If this symbol is equated to an undefined symbol, convert
the fixup to being against that symbol. */
if (sym != NULL && symbol_equated_p (sym)
&& (! S_IS_DEFINED (sym) || S_IS_COMMON (sym)))
if (sym != NULL && symbol_equated_reloc_p (sym))
{
fixp->fx_offset += symbol_get_value_expression (sym)->X_add_number;
sym = symbol_get_value_expression (sym)->X_add_symbol;
@ -983,11 +982,10 @@ write_relocs (abfd, sec, xxx)
}
/* If this is an undefined symbol which was equated to another
symbol, then use generate the reloc against the latter symbol
symbol, then generate the reloc against the latter symbol
rather than the former. */
sym = fixp->fx_addsy;
while (symbol_equated_p (sym)
&& (! S_IS_DEFINED (sym) || S_IS_COMMON (sym)))
while (symbol_equated_reloc_p (sym))
{
symbolS *n;
@ -1059,8 +1057,7 @@ write_relocs (abfd, sec, xxx)
symbol, then generate the reloc against the latter symbol
rather than the former. */
sym = fixp->fx_addsy;
while (symbol_equated_p (sym)
&& (! S_IS_DEFINED (sym) || S_IS_COMMON (sym)))
while (symbol_equated_reloc_p (sym))
sym = symbol_get_value_expression (sym)->X_add_symbol;
fixp->fx_addsy = sym;
@ -1960,8 +1957,7 @@ write_object_file ()
/* Skip symbols which were equated to undefined or common
symbols. */
if (symbol_equated_p (symp)
&& (! S_IS_DEFINED (symp) || S_IS_COMMON (symp)))
if (symbol_equated_reloc_p (symp))
{
symbol_remove (symp, &symbol_rootP, &symbol_lastP);
continue;
@ -2264,6 +2260,12 @@ relax_segment (segment_frag_root, segment)
break;
case rs_machine_dependent:
/* If fr_symbol is an expression, this call to
resolve_symbol_value sets up the correct segment, which will
likely be needed in md_estimate_size_before_relax. */
if (fragP->fr_symbol)
resolve_symbol_value (fragP->fr_symbol);
address += md_estimate_size_before_relax (fragP, segment);
break;