* config/tc-ppc.c (md_assemble): When handling @l, always sign

extend if the operand expects a signed value.
PR 13667.
This commit is contained in:
Ian Lance Taylor 1997-10-24 21:29:10 +00:00
parent 022278948f
commit e59390a7eb
2 changed files with 53 additions and 10 deletions

View File

@ -1,5 +1,8 @@
Fri Oct 24 15:56:47 1997 Ian Lance Taylor <ian@cygnus.com>
* config/tc-ppc.c (md_assemble): When handling @l, always sign
extend if the operand expects a signed value.
* config/tc-mips.h (LOCAL_LABELS_DOLLAR): Don't define; use
default which is to permit dollar labels.

View File

@ -1852,7 +1852,11 @@ md_assemble (str)
break;
case BFD_RELOC_LO16:
if (ex.X_unsigned)
/* X_unsigned is the default, so if the user has done
something which cleared it, we always produce a
signed value. */
if (ex.X_unsigned
&& (operand->flags & PPC_OPERAND_SIGNED) == 0)
ex.X_add_number &= 0xffff;
else
ex.X_add_number = (((ex.X_add_number & 0xffff)
@ -2424,6 +2428,7 @@ ppc_change_csect (sym)
{
symbolS **list_ptr;
int after_toc;
int hold_chunksize;
symbolS *list;
/* This is a new csect. We need to look at the symbol class to
@ -2464,7 +2469,16 @@ ppc_change_csect (sym)
abort ();
}
/* We set the obstack chunk size to a small value before
changing subsegments, so that we don't use a lot of memory
space for what may be a small section. */
hold_chunksize = chunksize;
chunksize = 64;
subseg_new (segment_name (S_GET_SEGMENT (sym)), sym->sy_tc.subseg);
chunksize = hold_chunksize;
if (after_toc)
ppc_after_toc_frag = frag_now;
@ -4005,7 +4019,7 @@ ppc_frob_symbol (sym)
ppc_last_function = sym;
if (sym->sy_tc.size != (symbolS *) NULL)
{
resolve_symbol_value (sym->sy_tc.size);
resolve_symbol_value (sym->sy_tc.size, 1);
SA_SET_SYM_FSIZE (sym, (long) S_GET_VALUE (sym->sy_tc.size));
}
}
@ -4064,7 +4078,7 @@ ppc_frob_symbol (sym)
- S_GET_VALUE (sym));
else
{
resolve_symbol_value (sym->sy_tc.next);
resolve_symbol_value (sym->sy_tc.next, 1);
a->x_csect.x_scnlen.l = (S_GET_VALUE (sym->sy_tc.next)
- S_GET_VALUE (sym));
}
@ -4117,7 +4131,7 @@ ppc_frob_symbol (sym)
}
else
{
resolve_symbol_value (next);
resolve_symbol_value (next, 1);
a->x_csect.x_scnlen.l = (S_GET_VALUE (next)
- S_GET_VALUE (sym));
}
@ -4148,7 +4162,7 @@ ppc_frob_symbol (sym)
{
while (csect->sy_tc.next != (symbolS *) NULL)
{
resolve_symbol_value (csect->sy_tc.next);
resolve_symbol_value (csect->sy_tc.next, 1);
if (S_GET_VALUE (csect->sy_tc.next) > S_GET_VALUE (sym))
break;
csect = csect->sy_tc.next;
@ -4189,7 +4203,7 @@ ppc_frob_symbol (sym)
/* The value is the offset from the enclosing csect. */
block = sym->sy_tc.within;
csect = block->sy_tc.within;
resolve_symbol_value (csect);
resolve_symbol_value (csect, 1);
S_SET_VALUE (sym, S_GET_VALUE (sym) - S_GET_VALUE (csect));
}
else if (S_GET_STORAGE_CLASS (sym) == C_BINCL
@ -4414,7 +4428,7 @@ ppc_fix_adjustable (fix)
{
valueT val;
resolve_symbol_value (fix->fx_addsy);
resolve_symbol_value (fix->fx_addsy, 1);
val = S_GET_VALUE (fix->fx_addsy);
if (ppc_toc_csect != (symbolS *) NULL
&& fix->fx_addsy != (symbolS *) NULL
@ -4434,7 +4448,7 @@ ppc_fix_adjustable (fix)
continue;
if (sy->sy_tc.class != XMC_TC)
break;
resolve_symbol_value (sy);
resolve_symbol_value (sy, 1);
if (val == S_GET_VALUE (sy))
{
fix->fx_addsy = sy;
@ -4513,7 +4527,7 @@ ppc_fix_adjustable (fix)
&& S_GET_SEGMENT (fix->fx_addsy) == bss_section
&& ! S_IS_EXTERNAL (fix->fx_addsy))
{
resolve_symbol_value (fix->fx_addsy->sy_frag->fr_symbol);
resolve_symbol_value (fix->fx_addsy->sy_frag->fr_symbol, 1);
fix->fx_offset += (S_GET_VALUE (fix->fx_addsy)
- S_GET_VALUE (fix->fx_addsy->sy_frag->fr_symbol));
fix->fx_addsy = fix->fx_addsy->sy_frag->fr_symbol;
@ -4798,9 +4812,35 @@ md_apply_fix3 (fixp, valuep, seg)
case BFD_RELOC_24_PLT_PCREL:
case BFD_RELOC_PPC_LOCAL24PC:
if (!fixp->fx_pcrel)
if (!fixp->fx_pcrel && !fixp->fx_done)
abort ();
if (fixp->fx_done)
{
char *where;
unsigned long insn;
/* Fetch the instruction, insert the fully resolved operand
value, and stuff the instruction back again. */
where = fixp->fx_frag->fr_literal + fixp->fx_where;
if (target_big_endian)
insn = bfd_getb32 ((unsigned char *) where);
else
insn = bfd_getl32 ((unsigned char *) where);
if ((value & 3) != 0)
as_bad_where (fixp->fx_file, fixp->fx_line,
"must branch to an address a multiple of 4");
if ((long)value << 6 >> 6 != value)
as_bad_where (fixp->fx_file, fixp->fx_line,
"@local or @plt branch destination is too far "
"away, %ld bytes",
value);
insn = insn | (value & 0x03fffffc);
if (target_big_endian)
bfd_putb32 ((bfd_vma) insn, (unsigned char *) where);
else
bfd_putl32 ((bfd_vma) insn, (unsigned char *) where);
}
break;
default: