Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions bfd/elf32-mips.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ static bool mips_elf_is_local_label_name
(bfd *, const char *);
static bfd_reloc_status_type mips16_gprel_reloc
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
static bfd_reloc_status_type dvp_u15_s3_reloc
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
static bfd_reloc_status_type mips_elf_final_gp
(bfd *, asymbol *, bool, char **, bfd_vma *);
static bool mips_elf_assign_gp
Expand Down Expand Up @@ -1676,6 +1678,69 @@ static reloc_howto_type elf_mips15_s3_howto =
0x001fffc0, /* dst_mask */
false); /* pcrel_offset */

/* DVP relocations.
Note that partial_inplace and pcrel_offset are backwards from the
mips port. This is intentional as it seems more reasonable. */
static reloc_howto_type elf_mips_dvp_11_pcrel_howto =
HOWTO (R_MIPS_DVP_11_PCREL, /* type */
3, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
11, /* bitsize */
true, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_MIPS_DVP_11_PCREL", /* name */
false, /* partial_inplace */
0x7ff, /* src_mask */
0x7ff, /* dst_mask */
true); /* pcrel_offset */

static reloc_howto_type elf_mips_dvp_27_s4_howto =
HOWTO (R_MIPS_DVP_27_S4, /* type */
4, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
27, /* bitsize */
false, /* pc_relative */
4, /* bitpos */
complain_overflow_unsigned, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_MIPS_DVP_27_S4", /* name */
false, /* partial_inplace */
0x7ffffff0, /* src_mask */
0x7ffffff0, /* dst_mask */
false); /* pcrel_offset */

static reloc_howto_type elf_mips_dvp_11_s4_howto =
HOWTO (R_MIPS_DVP_11_S4, /* type */
4, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
11, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_MIPS_DVP_11_S4", /* name */
false, /* partial_inplace */
0x03ff, /* src_mask */
0x03ff, /* dst_mask */
false); /* pcrel_offset */

static reloc_howto_type elf_mips_dvp_u15_s3_howto =
HOWTO (R_MIPS_DVP_U15_S3, /* type */
3, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
15, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_unsigned, /* complain_on_overflow */
dvp_u15_s3_reloc, /* special_function */
"R_MIPS_DVP_U15_S3", /* name */
false, /* partial_inplace */
0xf03ff, /* src_mask */
0xf03ff, /* dst_mask */
false); /* pcrel_offset */

/* Set the GP value for OUTPUT_BFD. Returns FALSE if this is a
dangerous relocation. */

Expand Down Expand Up @@ -1992,6 +2057,53 @@ mips16_gprel_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
return ret;
}

/* Handle a dvp R_MIPS_DVP_U15_S3 reloc.
This is needed because the bits aren't contiguous. */

static bfd_reloc_status_type
dvp_u15_s3_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
void *data, asection *input_section, bfd *output_bfd,
char **error_message)
{
bfd_vma relocation;
bfd_vma x;

/* If we're relocating, and this is an external symbol with no
addend, we don't want to change anything. We will only have an
addend if this is a newly created reloc, not read from an ELF
file. See bfd_elf_generic_reloc. */
if (output_bfd != NULL
&& (symbol->flags & BSF_SECTION_SYM) == 0
/* partial_inplace is false, so this test always succeeds,
but for clarity and consistency with bfd_elf_generic_reloc
this is left as is. */
&& (! reloc_entry->howto->partial_inplace
|| reloc_entry->addend == 0))
{
reloc_entry->address += input_section->output_offset;
return bfd_reloc_ok;
}

if (!_bfd_mips_reloc_offset_in_range (abfd, input_section, reloc_entry,
check_shuffle))
return bfd_reloc_outofrange;

relocation = (symbol->value
+ symbol->section->output_section->vma
+ symbol->section->output_offset);
relocation += reloc_entry->addend;
relocation >>= 3;

x = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
x |= (((relocation & 0x7800) << 10)
| (relocation & 0x7ff));
bfd_put_32 (abfd, x, (bfd_byte *) data + reloc_entry->address);

if (relocation & ~(bfd_vma) 0x7fff)
return bfd_reloc_overflow;
return bfd_reloc_ok;
}

/* A mapping from BFD reloc types to MIPS ELF reloc types. */

struct elf_reloc_map {
Expand Down Expand Up @@ -2243,6 +2355,14 @@ mips_elf32_rtype_to_howto (bfd *abfd,
return &elf_mips_eh_howto;
case R_MIPS15_S3:
return &elf_mips15_s3_howto;
case R_MIPS_DVP_11_PCREL:
return &elf_mips_dvp_11_pcrel_howto;
case R_MIPS_DVP_27_S4:
return &elf_mips_dvp_27_s4_howto;
case R_MIPS_DVP_11_S4:
return &elf_mips_dvp_11_s4_howto;
case R_MIPS_DVP_U15_S3:
return &elf_mips_dvp_u15_s3_howto;
default:
if (r_type >= R_MICROMIPS_min && r_type < R_MICROMIPS_max)
howto = &elf_micromips_howto_table_rel[r_type - R_MICROMIPS_min];
Expand Down