0x0000ffff, /* dst_mask */
FALSE), /* pcrel_offset */
- /* 16 bit PC relative reference. Note that the ABI document has a typo
- and claims R_MIPS_PC16 to be not rightshifted, rendering it useless.
- We do the right thing here. */
+ /* 16 bit PC relative reference. */
HOWTO (R_MIPS_PC16, /* type */
- 2, /* rightshift */
+ 0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
TRUE, /* pc_relative */
0x0000ffff, /* dst_mask */
FALSE), /* pcrel_offset */
- /* 16 bit PC relative reference. Note that the ABI document has a typo
- and claims R_MIPS_PC16 to be not rightshifted, rendering it useless.
- We do the right thing here. */
+ /* 16 bit PC relative reference. */
HOWTO (R_MIPS_PC16, /* type */
- 2, /* rightshift */
+ 0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
TRUE, /* pc_relative */
0, /* dst_mask */
FALSE); /* pcrel_offset */
\f
+/* 16 bit offset for pc-relative branches. */
+static reloc_howto_type elf_mips_gnu_rel16_s2 =
+ HOWTO (R_MIPS_GNU_REL16_S2, /* type */
+ 2, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_GNU_REL16_S2", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ TRUE); /* pcrel_offset */
+
+/* 16 bit offset for pc-relative branches. */
+static reloc_howto_type elf_mips_gnu_rela16_s2 =
+ HOWTO (R_MIPS_GNU_REL16_S2, /* type */
+ 2, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_GNU_REL16_S2", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ TRUE); /* pcrel_offset */
+\f
/* This is derived from bfd_elf_generic_reloc. NewABI allows us to have
several relocations against the same address. The addend is derived
from the addends of preceding relocations. If we don't need to
char **error_message;
{
/* If we're relocating, and this is a local symbol, we can handle it
- just like HI16. */
+ just like an R_MIPS_HI16. */
if (output_bfd != (bfd *) NULL
- && (symbol->flags & BSF_SECTION_SYM) != 0)
+ && ((symbol->flags & BSF_SECTION_SYM) != 0
+ || (symbol->flags & BSF_LOCAL) == 0))
return mips_elf_hi16_reloc (abfd, reloc_entry, symbol, data,
input_section, output_bfd, error_message);
symbol value correctly. We look up the symbol _gp in the output
BFD. If we can't find it, we're stuck. We cache it in the ELF
target data. We don't need to adjust the symbol value for an
- external symbol if we are producing relocateable output. */
+ external symbol if we are producing relocatable output. */
static bfd_reloc_status_type
-mips_elf_final_gp (output_bfd, symbol, relocateable, error_message, pgp)
+mips_elf_final_gp (output_bfd, symbol, relocatable, error_message, pgp)
bfd *output_bfd;
asymbol *symbol;
- bfd_boolean relocateable;
+ bfd_boolean relocatable;
char **error_message;
bfd_vma *pgp;
{
if (bfd_is_und_section (symbol->section)
- && ! relocateable)
+ && ! relocatable)
{
*pgp = 0;
return bfd_reloc_undefined;
*pgp = _bfd_get_gp_value (output_bfd);
if (*pgp == 0
- && (! relocateable
+ && (! relocatable
|| (symbol->flags & BSF_SECTION_SYM) != 0))
{
- if (relocateable)
+ if (relocatable)
{
/* Make up a value. */
*pgp = symbol->section->output_section->vma /*+ 0x4000*/;
bfd *output_bfd;
char **error_message ATTRIBUTE_UNUSED;
{
- bfd_boolean relocateable;
+ bfd_boolean relocatable;
bfd_reloc_status_type ret;
bfd_vma gp;
GET_RELOC_ADDEND (output_bfd, symbol, reloc_entry, input_section)
if (output_bfd != (bfd *) NULL)
- relocateable = TRUE;
+ relocatable = TRUE;
else
{
- relocateable = FALSE;
+ relocatable = FALSE;
output_bfd = symbol->section->output_section->owner;
}
- ret = mips_elf_final_gp (output_bfd, symbol, relocateable, error_message,
+ ret = mips_elf_final_gp (output_bfd, symbol, relocatable, error_message,
&gp);
if (ret != bfd_reloc_ok)
return ret;
return _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry,
- input_section, relocateable,
+ input_section, relocatable,
data, gp);
}
bfd *output_bfd;
char **error_message;
{
- bfd_boolean relocateable;
+ bfd_boolean relocatable;
bfd_reloc_status_type ret;
bfd_vma gp;
/* FIXME: The entries in the .lit8 and .lit4 sections should be merged. */
if (output_bfd != (bfd *) NULL)
- relocateable = TRUE;
+ relocatable = TRUE;
else
{
- relocateable = FALSE;
+ relocatable = FALSE;
output_bfd = symbol->section->output_section->owner;
}
- ret = mips_elf_final_gp (output_bfd, symbol, relocateable, error_message,
+ ret = mips_elf_final_gp (output_bfd, symbol, relocatable, error_message,
&gp);
if (ret != bfd_reloc_ok)
return ret;
return _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry,
- input_section, relocateable,
+ input_section, relocatable,
data, gp);
}
bfd *output_bfd;
char **error_message;
{
- bfd_boolean relocateable;
+ bfd_boolean relocatable;
bfd_reloc_status_type ret;
bfd_vma gp;
GET_RELOC_ADDEND (output_bfd, symbol, reloc_entry, input_section)
- /* R_MIPS_GPREL32 relocations are defined for local symbols only.
- We will only have an addend if this is a newly created reloc,
- not read from an ELF file. */
+ /* R_MIPS_GPREL32 relocations are defined for local symbols only. */
if (output_bfd != (bfd *) NULL
&& (symbol->flags & BSF_SECTION_SYM) == 0
- && reloc_entry->addend == 0)
+ && (symbol->flags & BSF_LOCAL) != 0)
{
*error_message = (char *)
_("32bits gp relative relocation occurs for an external symbol");
if (output_bfd != (bfd *) NULL)
{
- relocateable = TRUE;
+ relocatable = TRUE;
gp = _bfd_get_gp_value (output_bfd);
}
else
{
- relocateable = FALSE;
+ relocatable = FALSE;
output_bfd = symbol->section->output_section->owner;
- ret = mips_elf_final_gp (output_bfd, symbol, relocateable,
+ ret = mips_elf_final_gp (output_bfd, symbol, relocatable,
error_message, &gp);
if (ret != bfd_reloc_ok)
return ret;
}
return gprel32_with_gp (abfd, symbol, reloc_entry, input_section,
- relocateable, data, gp);
+ relocatable, data, gp);
}
static bfd_reloc_status_type
-gprel32_with_gp (abfd, symbol, reloc_entry, input_section, relocateable, data,
+gprel32_with_gp (abfd, symbol, reloc_entry, input_section, relocatable, data,
gp)
bfd *abfd;
asymbol *symbol;
arelent *reloc_entry;
asection *input_section;
- bfd_boolean relocateable;
+ bfd_boolean relocatable;
PTR data;
bfd_vma gp;
{
val += reloc_entry->addend;
/* Adjust val for the final section location and GP value. If we
- are producing relocateable output, we don't want to do this for
+ are producing relocatable output, we don't want to do this for
an external symbol. */
- if (! relocateable
+ if (! relocatable
|| (symbol->flags & BSF_SECTION_SYM) != 0)
val += relocation - gp;
bfd_put_32 (abfd, (bfd_vma) val, (bfd_byte *) data + reloc_entry->address);
- if (relocateable)
+ if (relocatable)
reloc_entry->address += input_section->output_offset;
return bfd_reloc_ok;
{
GET_RELOC_ADDEND (output_bfd, symbol, reloc_entry, input_section)
- reloc_entry->addend = (reloc_entry->addend & 0x00007c0)
- | (reloc_entry->addend & 0x00000800) >> 9;
+ if (reloc_entry->howto->partial_inplace)
+ {
+ reloc_entry->addend = ((reloc_entry->addend & 0x00007c0)
+ | (reloc_entry->addend & 0x00000800) >> 9);
+ }
SET_RELOC_ADDEND (reloc_entry)
bfd *output_bfd;
char **error_message;
{
- bfd_boolean relocateable;
+ bfd_boolean relocatable;
bfd_reloc_status_type ret;
bfd_vma gp;
- unsigned short extend, insn;
- unsigned long final;
+ unsigned short extend = 0;
+ unsigned short insn = 0;
+ bfd_signed_vma val;
+ bfd_vma relocation;
GET_RELOC_ADDEND (output_bfd, symbol, reloc_entry, input_section)
if (output_bfd != NULL)
- relocateable = TRUE;
+ relocatable = TRUE;
else
{
- relocateable = FALSE;
+ relocatable = FALSE;
output_bfd = symbol->section->output_section->owner;
}
- ret = mips_elf_final_gp (output_bfd, symbol, relocateable, error_message,
+ ret = mips_elf_final_gp (output_bfd, symbol, relocatable, error_message,
&gp);
if (ret != bfd_reloc_ok)
return ret;
if (reloc_entry->address > input_section->_cooked_size)
return bfd_reloc_outofrange;
- /* Pick up the mips16 extend instruction and the real instruction. */
- extend = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address);
- insn = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address + 2);
-
- /* Stuff the current addend back as a 32 bit value, do the usual
- relocation, and then clean up. */
- bfd_put_32 (abfd,
- (bfd_vma) (((extend & 0x1f) << 11)
- | (extend & 0x7e0)
- | (insn & 0x1f)),
- (bfd_byte *) data + reloc_entry->address);
-
- ret = _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry,
- input_section, relocateable, data, gp);
-
- final = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
- bfd_put_16 (abfd,
- (bfd_vma) ((extend & 0xf800)
- | ((final >> 11) & 0x1f)
- | (final & 0x7e0)),
- (bfd_byte *) data + reloc_entry->address);
- bfd_put_16 (abfd,
- (bfd_vma) ((insn & 0xffe0)
- | (final & 0x1f)),
- (bfd_byte *) data + reloc_entry->address + 2);
+ if (bfd_is_com_section (symbol->section))
+ relocation = 0;
+ else
+ relocation = symbol->value;
- return ret;
+ relocation += symbol->section->output_section->vma;
+ relocation += symbol->section->output_offset;
+
+ /* Set val to the offset into the section or symbol. */
+ val = reloc_entry->addend;
+
+ if (reloc_entry->howto->partial_inplace)
+ {
+ /* Pick up the mips16 extend instruction and the real instruction. */
+ extend = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address);
+ insn = bfd_get_16 (abfd, (bfd_byte *) data + reloc_entry->address + 2);
+ val += ((extend & 0x1f) << 11) | (extend & 0x7e0) | (insn & 0x1f);
+ }
+
+ _bfd_mips_elf_sign_extend(val, 16);
+
+ /* Adjust val for the final section location and GP value. If we
+ are producing relocatable output, we don't want to do this for
+ an external symbol. */
+ if (! relocatable
+ || (symbol->flags & BSF_SECTION_SYM) != 0)
+ val += relocation - gp;
+
+ if (reloc_entry->howto->partial_inplace)
+ {
+ bfd_put_16 (abfd,
+ (bfd_vma) ((extend & 0xf800)
+ | ((val >> 11) & 0x1f)
+ | (val & 0x7e0)),
+ (bfd_byte *) data + reloc_entry->address);
+ bfd_put_16 (abfd,
+ (bfd_vma) ((insn & 0xffe0)
+ | (val & 0x1f)),
+ (bfd_byte *) data + reloc_entry->address + 2);
+ }
+ else
+ reloc_entry->addend = val;
+
+ if (relocatable)
+ reloc_entry->address += input_section->output_offset;
+ else if (((val & ~0xffff) != ~0xffff) && ((val & ~0xffff) != 0))
+ return bfd_reloc_overflow;
+
+ return bfd_reloc_ok;
}
#undef GET_RELOC_ADDEND
/* There is no BFD reloc for R_MIPS_REL32. */
{ BFD_RELOC_CTOR, R_MIPS_32 },
{ BFD_RELOC_64, R_MIPS_64 },
- { BFD_RELOC_16_PCREL_S2, R_MIPS_PC16 },
+ { BFD_RELOC_16_PCREL, R_MIPS_PC16 },
{ BFD_RELOC_HI16_S, R_MIPS_HI16 },
{ BFD_RELOC_LO16, R_MIPS_LO16 },
{ BFD_RELOC_GPREL16, R_MIPS_GPREL16 },
return &elf_mips_gnu_vtinherit_howto;
case BFD_RELOC_VTABLE_ENTRY:
return &elf_mips_gnu_vtentry_howto;
+ case BFD_RELOC_16_PCREL_S2:
+ return &elf_mips_gnu_rela16_s2;
default:
bfd_set_error (bfd_error_bad_value);
return NULL;
return &elf_mips_gnu_vtinherit_howto;
case R_MIPS_GNU_VTENTRY:
return &elf_mips_gnu_vtentry_howto;
+ case R_MIPS_GNU_REL16_S2:
+ if (rela_p)
+ return &elf_mips_gnu_rela16_s2;
+ else
+ return &elf_mips_gnu_rel16_s2;
default:
BFD_ASSERT (r_type < (unsigned int) R_MIPS_max);
if (rela_p)
default:
return FALSE;
- case 256: /* Linux/MIPS */
+ case 440: /* Linux/MIPS N32 */
/* pr_cursig */
elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
/* pr_reg */
offset = 72;
- raw_size = 180;
+ raw_size = 360;
break;
}
#define bfd_elf32_bfd_set_private_flags _bfd_mips_elf_set_private_flags
#define bfd_elf32_bfd_print_private_bfd_data \
_bfd_mips_elf_print_private_bfd_data
+#define bfd_elf32_bfd_relax_section _bfd_mips_relax_section
/* Support for SGI-ish mips targets using n32 ABI. */