mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-20 18:08:24 +08:00
* 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:
@ -1350,13 +1350,30 @@ macro_build (place, counter, ep, name, fmt, va_alist)
|
|||||||
|| r == BFD_RELOC_MIPS_LITERAL
|
|| r == BFD_RELOC_MIPS_LITERAL
|
||||||
|| r == BFD_RELOC_LO16
|
|| r == BFD_RELOC_LO16
|
||||||
|| r == BFD_RELOC_MIPS_GOT16
|
|| 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;
|
continue;
|
||||||
|
|
||||||
case 'u':
|
case 'u':
|
||||||
assert (ep != NULL && ep->X_op == O_constant);
|
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;
|
insn.insn_opcode |= (ep->X_add_number >> 16) & 0xffff;
|
||||||
ep = NULL;
|
ep = NULL;
|
||||||
|
r = BFD_RELOC_UNUSED;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case 'p':
|
case 'p':
|
||||||
@ -1517,7 +1534,8 @@ load_register (counter, reg, ep)
|
|||||||
|| ((ep->X_add_number &~ (offsetT) 0x7fffffff)
|
|| ((ep->X_add_number &~ (offsetT) 0x7fffffff)
|
||||||
== ~ (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)
|
if ((ep->X_add_number & 0xffff) != 0)
|
||||||
macro_build ((char *) NULL, counter, ep, "ori", "t,r,i", reg, reg,
|
macro_build ((char *) NULL, counter, ep, "ori", "t,r,i", reg, reg,
|
||||||
(int) BFD_RELOC_LO16);
|
(int) BFD_RELOC_LO16);
|
||||||
@ -2206,7 +2224,8 @@ macro (ip)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
expr1.X_add_number = 0x80000000;
|
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)
|
if (mips_trap)
|
||||||
macro_build ((char *) NULL, &icnt, NULL, "teq", "s,t", sreg, AT);
|
macro_build ((char *) NULL, &icnt, NULL, "teq", "s,t", sreg, AT);
|
||||||
@ -2333,6 +2352,30 @@ macro (ip)
|
|||||||
case M_LA_AB:
|
case M_LA_AB:
|
||||||
/* Load the address of a symbol into a register. If breg is not
|
/* Load the address of a symbol into a register. If breg is not
|
||||||
zero, we then add a base register to it. */
|
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
|
if (offset_expr.X_op != O_symbol
|
||||||
&& offset_expr.X_op != O_constant)
|
&& offset_expr.X_op != O_constant)
|
||||||
{
|
{
|
||||||
@ -5085,7 +5128,10 @@ mips_force_relocation (fixp)
|
|||||||
fixS *fixp;
|
fixS *fixp;
|
||||||
{
|
{
|
||||||
return (mips_pic == EMBEDDED_PIC
|
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. */
|
/* 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_CALL16:
|
||||||
case BFD_RELOC_MIPS_GOT16:
|
case BFD_RELOC_MIPS_GOT16:
|
||||||
case BFD_RELOC_MIPS_GPREL32:
|
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 */
|
/* Nothing needed to do. The value comes from the reloc entry */
|
||||||
break;
|
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:
|
case BFD_RELOC_32:
|
||||||
/* If we are deleting this reloc entry, we must fill in the
|
/* 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
|
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
|
* might be deleting the relocation entry (i.e., a branch within
|
||||||
* the current segment).
|
* the current segment).
|
||||||
*/
|
*/
|
||||||
|
assert (fixP->fx_pcrel);
|
||||||
if (value & 0x3)
|
if (value & 0x3)
|
||||||
as_warn ("Branch to odd address (%lx)", value);
|
as_warn ("Branch to odd address (%lx)", value);
|
||||||
value >>= 2;
|
value >>= 2;
|
||||||
@ -5962,10 +6042,34 @@ tc_gen_reloc (section, fixp)
|
|||||||
subtrahend. */
|
subtrahend. */
|
||||||
reloc->addend = reloc->address - S_GET_VALUE (fixp->fx_subsy);
|
reloc->addend = reloc->address - S_GET_VALUE (fixp->fx_subsy);
|
||||||
#ifndef OBJ_ECOFF
|
#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
|
#endif
|
||||||
fixp->fx_r_type = BFD_RELOC_GPREL32;
|
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)
|
else if (fixp->fx_pcrel == 0)
|
||||||
reloc->addend = fixp->fx_addnumber;
|
reloc->addend = fixp->fx_addnumber;
|
||||||
else
|
else
|
||||||
|
Reference in New Issue
Block a user