* config/tc-mips.h (DIFF_EXPR_OK): Define.

* config/tc-mips.c (macro_build): Permit BFD_RELOC_PCREL_LO16 for
	certain cases of 'i', 'j' and 'o'.  Change 'u' to take an
	argument, the reloc type.
	(load_register): Pass reloc type to macro_build for 'u'.
	(macro): Likewise.  For M_LA_AB permit a difference expression
	when generating embedded PIC code between an arbitrary symbol and
	a symbol in the .text section.
	(mips_force_relocation): Force BFD_RELOC_PCREL_HI16_S and
	BFD_RELOC_PCREL_LO16 to be emitted.
	(md_apply_fix): Check that most relocs are not PC relative.
	Handle BFD_RELOC_PCREL_HI16_S and BFD_RELOC_PCREL_LO16.
	(tc_gen_reloc): Change #error to as_fatal.  Handle
	BFD_RELOC_PCREL_LO16 and BFD_RELOC_PCREL_HI16_S.
This commit is contained in:
Ian Lance Taylor 1994-04-14 17:39:55 +00:00
parent 4f996613fa
commit ecd4ca1cef

View file

@ -1350,13 +1350,30 @@ macro_build (place, counter, ep, name, fmt, va_alist)
|| r == BFD_RELOC_MIPS_LITERAL
|| r == BFD_RELOC_LO16
|| r == BFD_RELOC_MIPS_GOT16
|| r == BFD_RELOC_MIPS_CALL16);
|| r == BFD_RELOC_MIPS_CALL16
|| (ep->X_op == O_subtract
&& now_seg == text_section
&& S_GET_SEGMENT (ep->X_op_symbol) == text_section
&& r == BFD_RELOC_PCREL_LO16));
continue;
case 'u':
assert (ep != NULL && ep->X_op == O_constant);
insn.insn_opcode |= (ep->X_add_number >> 16) & 0xffff;
ep = NULL;
r = (bfd_reloc_code_real_type) va_arg (args, int);
assert (ep != NULL
&& (ep->X_op == O_constant
|| (ep->X_op == O_symbol
&& (r == BFD_RELOC_HI16_S
|| r == BFD_RELOC_HI16))
|| (ep->X_op == O_subtract
&& now_seg == text_section
&& S_GET_SEGMENT (ep->X_op_symbol) == text_section
&& r == BFD_RELOC_PCREL_HI16_S)));
if (ep->X_op == O_constant)
{
insn.insn_opcode |= (ep->X_add_number >> 16) & 0xffff;
ep = NULL;
r = BFD_RELOC_UNUSED;
}
continue;
case 'p':
@ -1517,7 +1534,8 @@ load_register (counter, reg, ep)
|| ((ep->X_add_number &~ (offsetT) 0x7fffffff)
== ~ (offsetT) 0x7fffffff))
{
macro_build ((char *) NULL, counter, ep, "lui", "t,u", reg);
macro_build ((char *) NULL, counter, ep, "lui", "t,u", reg,
(int) BFD_RELOC_HI16);
if ((ep->X_add_number & 0xffff) != 0)
macro_build ((char *) NULL, counter, ep, "ori", "t,r,i", reg, reg,
(int) BFD_RELOC_LO16);
@ -2206,7 +2224,8 @@ macro (ip)
else
{
expr1.X_add_number = 0x80000000;
macro_build ((char *) NULL, &icnt, &expr1, "lui", "t,u", AT);
macro_build ((char *) NULL, &icnt, &expr1, "lui", "t,u", AT,
(int) BFD_RELOC_HI16);
}
if (mips_trap)
macro_build ((char *) NULL, &icnt, NULL, "teq", "s,t", sreg, AT);
@ -2333,6 +2352,30 @@ macro (ip)
case M_LA_AB:
/* Load the address of a symbol into a register. If breg is not
zero, we then add a base register to it. */
/* When generating embedded PIC code, we permit expressions of
the form
la $4,foo-bar
where bar is an address in the .text section. These are used
when getting the addresses of functions. We don't permit
X_add_number to be non-zero, because if the symbol is
external the relaxing code needs to know that any addend is
purely the offset to X_op_symbol. */
if (mips_pic == EMBEDDED_PIC
&& offset_expr.X_op == O_subtract
&& now_seg == text_section
&& S_GET_SEGMENT (offset_expr.X_op_symbol) == text_section
&& breg == 0
&& offset_expr.X_add_number == 0)
{
macro_build ((char *) NULL, &icnt, &offset_expr, "lui", "t,u",
treg, (int) BFD_RELOC_PCREL_HI16_S);
macro_build ((char *) NULL, &icnt, &offset_expr,
mips_isa < 3 ? "addiu" : "daddiu",
"t,r,j", treg, treg, (int) BFD_RELOC_PCREL_LO16);
return;
}
if (offset_expr.X_op != O_symbol
&& offset_expr.X_op != O_constant)
{
@ -5085,7 +5128,10 @@ mips_force_relocation (fixp)
fixS *fixp;
{
return (mips_pic == EMBEDDED_PIC
&& (fixp->fx_pcrel || SWITCH_TABLE (fixp)));
&& (fixp->fx_pcrel
|| SWITCH_TABLE (fixp)
|| fixp->fx_r_type == BFD_RELOC_PCREL_HI16_S
|| fixp->fx_r_type == BFD_RELOC_PCREL_LO16));
}
/* Apply a fixup to the object file. */
@ -5116,9 +5162,42 @@ md_apply_fix (fixP, valueP)
case BFD_RELOC_MIPS_CALL16:
case BFD_RELOC_MIPS_GOT16:
case BFD_RELOC_MIPS_GPREL32:
if (fixP->fx_pcrel)
as_bad ("Invalid PC relative reloc");
/* Nothing needed to do. The value comes from the reloc entry */
break;
case BFD_RELOC_PCREL_HI16_S:
/* The addend for this is tricky if it is internal, so we just
do everything here rather than in bfd_perform_relocation. */
if ((fixP->fx_addsy->bsym->flags & BSF_SECTION_SYM) == 0)
{
/* For an external symbol adjust by the address to make it
pcrel_offset. We use the address of the RELLO reloc
which follows this one. */
value += (fixP->fx_next->fx_frag->fr_address
+ fixP->fx_next->fx_where);
}
if (value & 0x8000)
value += 0x10000;
value >>= 16;
buf = fixP->fx_frag->fr_literal + fixP->fx_where;
if (byte_order == BIG_ENDIAN)
buf += 2;
md_number_to_chars (buf, value, 2);
break;
case BFD_RELOC_PCREL_LO16:
/* The addend for this is tricky if it is internal, so we just
do everything here rather than in bfd_perform_relocation. */
if ((fixP->fx_addsy->bsym->flags & BSF_SECTION_SYM) == 0)
value += fixP->fx_frag->fr_address + fixP->fx_where;
buf = fixP->fx_frag->fr_literal + fixP->fx_where;
if (byte_order == BIG_ENDIAN)
buf += 2;
md_number_to_chars (buf, value, 2);
break;
case BFD_RELOC_32:
/* If we are deleting this reloc entry, we must fill in the
value now. This can happen if we have a .word which is not
@ -5152,6 +5231,7 @@ md_apply_fix (fixP, valueP)
* might be deleting the relocation entry (i.e., a branch within
* the current segment).
*/
assert (fixP->fx_pcrel);
if (value & 0x3)
as_warn ("Branch to odd address (%lx)", value);
value >>= 2;
@ -5962,10 +6042,34 @@ tc_gen_reloc (section, fixp)
subtrahend. */
reloc->addend = reloc->address - S_GET_VALUE (fixp->fx_subsy);
#ifndef OBJ_ECOFF
#error Double check fx_r_type here
as_fatal ("Double check fx_r_type in tc-mips.c:tc_gen_reloc");
#endif
fixp->fx_r_type = BFD_RELOC_GPREL32;
}
else if (fixp->fx_r_type == BFD_RELOC_PCREL_LO16)
{
/* We use a special addend for an internal RELLO reloc. */
if (fixp->fx_addsy->bsym->flags & BSF_SECTION_SYM)
reloc->addend = reloc->address - S_GET_VALUE (fixp->fx_subsy);
else
reloc->addend = fixp->fx_addnumber + reloc->address;
}
else if (fixp->fx_r_type == BFD_RELOC_PCREL_HI16_S)
{
assert (fixp->fx_next != NULL
&& fixp->fx_next->fx_r_type == BFD_RELOC_PCREL_LO16);
/* We use a special addend for an internal RELHI reloc. The
reloc is relative to the RELLO; adjust the addend
accordingly. */
if (fixp->fx_addsy->bsym->flags & BSF_SECTION_SYM)
reloc->addend = (fixp->fx_next->fx_frag->fr_address
+ fixp->fx_next->fx_where
- S_GET_VALUE (fixp->fx_subsy));
else
reloc->addend = (fixp->fx_addnumber
+ fixp->fx_next->fx_frag->fr_address
+ fixp->fx_next->fx_where);
}
else if (fixp->fx_pcrel == 0)
reloc->addend = fixp->fx_addnumber;
else