aboutsummaryrefslogtreecommitdiff
path: root/bfd/elfn32-mips.c
diff options
context:
space:
mode:
Diffstat (limited to 'bfd/elfn32-mips.c')
-rw-r--r--bfd/elfn32-mips.c158
1 files changed, 92 insertions, 66 deletions
diff --git a/bfd/elfn32-mips.c b/bfd/elfn32-mips.c
index 2e49948..60c6ad0 100644
--- a/bfd/elfn32-mips.c
+++ b/bfd/elfn32-mips.c
@@ -1453,9 +1453,10 @@ mips_elf_got16_reloc (abfd, reloc_entry, symbol, data, input_section,
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);
@@ -1519,18 +1520,18 @@ mips_elf_assign_gp (output_bfd, pgp)
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;
@@ -1538,10 +1539,10 @@ mips_elf_final_gp (output_bfd, symbol, relocateable, error_message, pgp)
*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*/;
@@ -1572,27 +1573,27 @@ mips_elf_gprel16_reloc (abfd, reloc_entry, symbol, data, input_section,
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);
}
@@ -1609,7 +1610,7 @@ mips_elf_literal_reloc (abfd, reloc_entry, symbol, data, input_section,
bfd *output_bfd;
char **error_message;
{
- bfd_boolean relocateable;
+ bfd_boolean relocatable;
bfd_reloc_status_type ret;
bfd_vma gp;
@@ -1617,20 +1618,20 @@ mips_elf_literal_reloc (abfd, reloc_entry, symbol, data, input_section,
/* 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);
}
@@ -1648,18 +1649,16 @@ mips_elf_gprel32_reloc (abfd, reloc_entry, symbol, data, input_section,
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");
@@ -1668,32 +1667,32 @@ mips_elf_gprel32_reloc (abfd, reloc_entry, symbol, data, input_section,
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;
{
@@ -1720,15 +1719,15 @@ gprel32_with_gp (abfd, symbol, reloc_entry, input_section, relocateable, data,
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;
@@ -1750,8 +1749,11 @@ mips_elf_shift6_reloc (abfd, reloc_entry, symbol, data, input_section,
{
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)
@@ -1798,23 +1800,25 @@ mips16_gprel_reloc (abfd, reloc_entry, symbol, data, input_section,
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;
@@ -1822,33 +1826,55 @@ mips16_gprel_reloc (abfd, reloc_entry, symbol, data, input_section,
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