/* MIPS-specific support for 32-bit ELF
- Copyright 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
+ Copyright 1993, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
Most of the information added by Ian Lance Taylor, Cygnus Support,
<ian@cygnus.com>.
static int mips_elf_additional_program_headers PARAMS ((bfd *));
static boolean mips_elf_modify_segment_map PARAMS ((bfd *));
static INLINE int elf_mips_isa PARAMS ((flagword));
+static INLINE int elf_mips_mach PARAMS ((flagword));
static boolean mips_elf32_section_from_shdr
PARAMS ((bfd *, Elf32_Internal_Shdr *, char *));
static boolean mips_elf32_section_processing
PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
static bfd_reloc_status_type mips16_gprel_reloc
PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+/* start-sanitize-sky */
+static bfd_reloc_status_type dvp_u15_s3_reloc
+ PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
+/* end-sanitize-sky */
static boolean mips_elf_adjust_dynindx
PARAMS ((struct elf_link_hash_entry *, PTR));
static boolean mips_elf_relocate_section
#define USE_REL 1 /* MIPS uses REL relocations instead of RELA */
-enum reloc_type
-{
- R_MIPS_NONE = 0,
- R_MIPS_16, R_MIPS_32,
- R_MIPS_REL32, R_MIPS_26,
- R_MIPS_HI16, R_MIPS_LO16,
- R_MIPS_GPREL16, R_MIPS_LITERAL,
- R_MIPS_GOT16, R_MIPS_PC16,
- R_MIPS_CALL16, R_MIPS_GPREL32,
- /* The remaining relocs are defined on Irix, although they are not
- in the MIPS ELF ABI. */
- R_MIPS_UNUSED1, R_MIPS_UNUSED2,
- R_MIPS_UNUSED3,
- R_MIPS_SHIFT5, R_MIPS_SHIFT6,
- R_MIPS_64, R_MIPS_GOT_DISP,
- R_MIPS_GOT_PAGE, R_MIPS_GOT_OFST,
- R_MIPS_GOT_HI16, R_MIPS_GOT_LO16,
- R_MIPS_SUB, R_MIPS_INSERT_A,
- R_MIPS_INSERT_B, R_MIPS_DELETE,
- R_MIPS_HIGHER, R_MIPS_HIGHEST,
- R_MIPS_CALL_HI16, R_MIPS_CALL_LO16,
- R_MIPS_max,
- /* These relocs are used for the mips16. */
- R_MIPS16_26 = 100,
- R_MIPS16_GPREL = 101
-/* start-sanitize-sky */
- /* These relocs are for the dvp. */
- , R_MIPS_DVP_11_PCREL = 120
-/* end-sanitize-sky */
-};
-
static reloc_howto_type elf_mips_howto_table[] =
{
/* No relocation. */
true, /* partial_inplace */
0x0000ffff, /* src_mask */
0x0000ffff, /* dst_mask */
- false) /* pcrel_offset */
+ false), /* pcrel_offset */
+
+ { R_MIPS_SCN_DISP },
+ { R_MIPS_REL16 },
+ { R_MIPS_ADD_IMMEDIATE },
+ { R_MIPS_PJUMP },
+ { R_MIPS_RELGOT }
};
/* The reloc used for BFD_RELOC_CTOR when doing a 64 bit link. This
0xffff, /* dst_mask */
false); /* pcrel_offset */
+/* start-sanitize-r5900 */
+static reloc_howto_type elf_mips15_s3_howto =
+ HOWTO (R_MIPS15_S3, /* type */
+ 3, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 15, /* bitsize */
+ false, /* pc_relative */
+ 6, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_MIPS15_S3", /* name */
+ true, /* partial_inplace */
+ 0x001fffc0, /* src_mask */
+ 0x001fffc0, /* dst_mask */
+ false); /* pcrel_offset */
+
+/* end-sanitize-r5900 */
/* start-sanitize-sky */
-/* DVP relocations. */
-static reloc_howto_type elf_mips_dvp_11_pcrel_howto =
+/* 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) */
complain_overflow_signed, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_MIPS_DVP_11_PCREL", /* name */
- true, /* partial_inplace */
+ 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 */
/* end-sanitize-sky */
+/* GNU extension to record C++ vtable hierarchy */
+static reloc_howto_type elf_mips_gnu_vtinherit_howto =
+ HOWTO (R_MIPS_GNU_VTINHERIT, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 0, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ NULL, /* special_function */
+ "R_MIPS_GNU_VTINHERIT", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ false); /* pcrel_offset */
+
+/* GNU extension to record C++ vtable member usage */
+static reloc_howto_type elf_mips_gnu_vtentry_howto =
+ HOWTO (R_MIPS_GNU_VTENTRY, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 0, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ NULL, /* special_function */
+ "R_MIPS_GNU_VTENTRY", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ false); /* pcrel_offset */
+
/* Do a R_MIPS_HI16 relocation. This has to be done in combination
with a R_MIPS_LO16 reloc, because there is a carry from the LO16 to
the HI16. Here we just save the information we need; we do the
*pgp = 4;
_bfd_set_gp_value (output_bfd, *pgp);
*error_message =
- (char *) "GP relative relocation when _gp not defined";
+ (char *) _("GP relative relocation when _gp not defined");
return bfd_reloc_dangerous;
}
}
&& reloc_entry->addend == 0)
{
*error_message = (char *)
- "32bits gp relative relocation occurs for an external symbol";
+ _("32bits gp relative relocation occurs for an external symbol");
return bfd_reloc_outofrange;
}
if (! warned)
(*_bfd_error_handler)
- ("Linking mips16 objects into %s format is not supported",
+ (_("Linking mips16 objects into %s format is not supported"),
bfd_get_target (input_section->output_section->owner));
warned = true;
}
return ret;
}
+/* start-sanitize-sky */
+/* 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 (abfd, reloc_entry, symbol, data, input_section,
+ output_bfd, error_message)
+ bfd *abfd;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data;
+ asection *input_section;
+ bfd *output_bfd;
+ char **error_message;
+{
+ boolean relocateable;
+ bfd_reloc_status_type ret;
+ 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 (reloc_entry->address > input_section->_cooked_size)
+ 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;
+}
+
+/* end-sanitize-sky */
/* Return the ISA for a MIPS e_flags value. */
static INLINE int
return 4;
}
+/* Return the MACH for a MIPS e_flags value. */
+
+static INLINE int
+elf_mips_mach (flags)
+ flagword flags;
+{
+ switch (flags & EF_MIPS_MACH)
+ {
+ case E_MIPS_MACH_3900:
+ return bfd_mach_mips3900;
+
+ case E_MIPS_MACH_4010:
+ return bfd_mach_mips4010;
+
+ case E_MIPS_MACH_4100:
+ return bfd_mach_mips4100;
+ /* start-sanitize-vr4320 */
+
+ case E_MIPS_MACH_4320:
+ return bfd_mach_mips4320;
+ /* end-sanitize-vr4320 */
+
+ case E_MIPS_MACH_4650:
+ return bfd_mach_mips4650;
+ /* start-sanitize-tx49 */
+
+ case E_MIPS_MACH_4900:
+ return bfd_mach_mips4900;
+ /* end-sanitize-tx49 */
+ /* start-sanitize-cygnus */
+ /* CYGNUS LOCAL vr5400/raeburn */
+
+ case E_MIPS_MACH_5400:
+ return bfd_mach_mips5400;
+ /* end-sanitize-cygnus */
+ /* start-sanitize-r5900 */
+
+ case E_MIPS_MACH_5900:
+ return bfd_mach_mips5900;
+ /* end-sanitize-r5900 */
+
+ default:
+ switch (flags & EF_MIPS_ARCH)
+ {
+ default:
+ case E_MIPS_ARCH_1:
+ return bfd_mach_mips3000;
+ break;
+
+ case E_MIPS_ARCH_2:
+ return bfd_mach_mips6000;
+ break;
+
+ case E_MIPS_ARCH_3:
+ return bfd_mach_mips4000;
+ break;
+
+ case E_MIPS_ARCH_4:
+ return bfd_mach_mips8000;
+ break;
+ }
+ }
+
+ return 0;
+}
+
/* A mapping from BFD reloc types to MIPS ELF reloc types. */
struct elf_reloc_map {
bfd_reloc_code_real_type bfd_reloc_val;
- enum reloc_type elf_reloc_val;
+ enum elf_mips_reloc_type elf_reloc_val;
};
static CONST struct elf_reloc_map mips_reloc_map[] =
return &elf_mips_howto_table[(int) mips_reloc_map[i].elf_reloc_val];
}
- /* We need to handle BFD_RELOC_CTOR specially. If this is a mips3
- file, then we assume that we are using 64 bit addresses, and use
- R_MIPS_64. Otherwise, we use R_MIPS_32. */
- if (code == BFD_RELOC_CTOR)
+ switch (code)
{
- if (elf_mips_isa (elf_elfheader (abfd)->e_flags) < 3)
+ default:
+ bfd_set_error (bfd_error_bad_value);
+ return NULL;
+
+ case BFD_RELOC_CTOR:
+ /* We need to handle BFD_RELOC_CTOR specially.
+ Select the right relocation (R_MIPS_32 or R_MIPS_64) based on the
+ size of addresses on this architecture. */
+ if (bfd_arch_bits_per_address (abfd) == 32)
return &elf_mips_howto_table[(int) R_MIPS_32];
else
return &elf_mips_ctor64_howto;
- }
- /* Special handling for the MIPS16 relocs, since they are made up
- reloc types with a large value. */
- if (code == BFD_RELOC_MIPS16_JMP)
- return &elf_mips16_jump_howto;
- else if (code == BFD_RELOC_MIPS16_GPREL)
- return &elf_mips16_gprel_howto;
+ case BFD_RELOC_MIPS16_JMP:
+ return &elf_mips16_jump_howto;
+ case BFD_RELOC_MIPS16_GPREL:
+ return &elf_mips16_gprel_howto;
+/* start-sanitize-r5900 */
+ case BFD_RELOC_MIPS15_S3:
+ return &elf_mips15_s3_howto;
+/* end-sanitize-r5900 */
/* start-sanitize-sky */
- else if (code == BFD_RELOC_MIPS_DVP_11_PCREL)
- return &elf_mips_dvp_11_pcrel_howto;
+ case BFD_RELOC_MIPS_DVP_11_PCREL:
+ return &elf_mips_dvp_11_pcrel_howto;
+ case BFD_RELOC_MIPS_DVP_27_S4:
+ return &elf_mips_dvp_27_s4_howto;
+ case BFD_RELOC_MIPS_DVP_11_S4:
+ return &elf_mips_dvp_11_s4_howto;
+ case BFD_RELOC_MIPS_DVP_U15_S3:
+ return &elf_mips_dvp_u15_s3_howto;
/* end-sanitize-sky */
-
- return NULL;
+ case BFD_RELOC_VTABLE_INHERIT:
+ return &elf_mips_gnu_vtinherit_howto;
+ case BFD_RELOC_VTABLE_ENTRY:
+ return &elf_mips_gnu_vtentry_howto;
+ }
}
/* Given a MIPS reloc type, fill in an arelent structure. */
unsigned int r_type;
r_type = ELF32_R_TYPE (dst->r_info);
- if (r_type == R_MIPS16_26)
- cache_ptr->howto = &elf_mips16_jump_howto;
- else if (r_type == R_MIPS16_GPREL)
- cache_ptr->howto = &elf_mips16_gprel_howto;
+ switch (r_type)
+ {
+ case R_MIPS16_26:
+ cache_ptr->howto = &elf_mips16_jump_howto;
+ break;
+ case R_MIPS16_GPREL:
+ cache_ptr->howto = &elf_mips16_gprel_howto;
+ break;
+/* start-sanitize-r5900 */
+ case R_MIPS15_S3:
+ cache_ptr->howto = &elf_mips15_s3_howto;
+ break;
+/* end-sanitize-r5900 */
/* start-sanitize-sky */
- else if (r_type == R_MIPS_DVP_11_PCREL)
- cache_ptr->howto = &elf_mips_dvp_11_pcrel_howto;
+ case R_MIPS_DVP_11_PCREL:
+ cache_ptr->howto = &elf_mips_dvp_11_pcrel_howto;
+ break;
+ case R_MIPS_DVP_27_S4:
+ cache_ptr->howto = &elf_mips_dvp_27_s4_howto;
+ break;
+ case R_MIPS_DVP_11_S4:
+ cache_ptr->howto = &elf_mips_dvp_11_s4_howto;
+ break;
+ case R_MIPS_DVP_U15_S3:
+ cache_ptr->howto = &elf_mips_dvp_u15_s3_howto;
+ break;
/* end-sanitize-sky */
- else
- {
+ case R_MIPS_GNU_VTINHERIT:
+ cache_ptr->howto = &elf_mips_gnu_vtinherit_howto;
+ break;
+ case R_MIPS_GNU_VTENTRY:
+ cache_ptr->howto = &elf_mips_gnu_vtentry_howto;
+ break;
+
+ default:
BFD_ASSERT (r_type < (unsigned int) R_MIPS_max);
cache_ptr->howto = &elf_mips_howto_table[r_type];
+ break;
}
/* The addend for a GPREL16 or LITERAL relocation comes from the GP
_bfd_mips_elf_object_p (abfd)
bfd *abfd;
{
- switch (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH)
- {
- default:
- case E_MIPS_ARCH_1:
- (void) bfd_default_set_arch_mach (abfd, bfd_arch_mips, 3000);
- break;
-
- case E_MIPS_ARCH_2:
- (void) bfd_default_set_arch_mach (abfd, bfd_arch_mips, 6000);
- break;
-
- case E_MIPS_ARCH_3:
- (void) bfd_default_set_arch_mach (abfd, bfd_arch_mips, 4000);
- break;
-
- case E_MIPS_ARCH_4:
- (void) bfd_default_set_arch_mach (abfd, bfd_arch_mips, 8000);
- break;
- }
-
+ bfd_default_set_arch_mach (abfd, bfd_arch_mips,
+ elf_mips_mach (elf_elfheader (abfd)->e_flags));
return true;
}
switch (bfd_get_mach (abfd))
{
- case 3000:
+ default:
+ case bfd_mach_mips3000:
val = E_MIPS_ARCH_1;
break;
- case 6000:
+ case bfd_mach_mips3900:
+ val = E_MIPS_ARCH_1 | E_MIPS_MACH_3900;
+ break;
+
+ case bfd_mach_mips6000:
val = E_MIPS_ARCH_2;
break;
- case 4000:
+ case bfd_mach_mips4000:
val = E_MIPS_ARCH_3;
break;
- case 8000:
- val = E_MIPS_ARCH_4;
+ case bfd_mach_mips4010:
+ val = E_MIPS_ARCH_3 | E_MIPS_MACH_4010;
break;
- default:
- val = 0;
+ case bfd_mach_mips4100:
+ val = E_MIPS_ARCH_3 | E_MIPS_MACH_4100;
+ break;
+ /* start-sanitize-vr4320 */
+
+ case bfd_mach_mips4320:
+ val = E_MIPS_ARCH_3 | E_MIPS_MACH_4320;
+ break;
+ /* end-sanitize-vr4320 */
+
+ case bfd_mach_mips4650:
+ val = E_MIPS_ARCH_3 | E_MIPS_MACH_4650;
+ break;
+ /* start-sanitize-tx49 */
+
+ case bfd_mach_mips4900:
+ val = E_MIPS_ARCH_3 | E_MIPS_MACH_4900;
+ break;
+ /* end-sanitize-tx49 */
+ /* start-sanitize-cygnus */
+ /* CYGNUS LOCAL vr5400/raeburn */
+
+ case bfd_mach_mips5400:
+ val = E_MIPS_ARCH_3 | E_MIPS_MACH_5400;
+ break;
+ /* end-sanitize-cygnus */
+ /* start-sanitize-r5900 */
+
+ case bfd_mach_mips5900:
+ val = E_MIPS_ARCH_3 | E_MIPS_MACH_5900;
+ break;
+ /* end-sanitize-r5900 */
+
+ case bfd_mach_mips8000:
+ val = E_MIPS_ARCH_4;
break;
}
- elf_elfheader (abfd)->e_flags &=~ EF_MIPS_ARCH;
+ elf_elfheader (abfd)->e_flags &= ~ (EF_MIPS_ARCH | EF_MIPS_MACH);
elf_elfheader (abfd)->e_flags |= val;
- /* Set the sh_info field for .gptab sections. */
+ /* Set the sh_info field for .gptab sections and other appropriate
+ info for each special section. */
for (i = 1, hdrpp = elf_elfsections (abfd) + 1;
i < elf_elfheader (abfd)->e_shnum;
i++, hdrpp++)
BFD_ASSERT (sec != NULL);
(*hdrpp)->sh_link = elf_section_data (sec)->this_idx;
break;
+
+/* start-sanitize-sky */
+ case SHT_DVP_OVERLAY_TABLE:
+ /* ??? This may not be technically necessary, just going with
+ the flow ... */
+ sec = bfd_get_section_by_name (abfd, SHNAME_DVP_OVERLAY_STRTAB);
+ if (sec != NULL)
+ (*hdrpp)->sh_link = elf_section_data (sec)->this_idx;
+ break;
+/* end-sanitize-sky */
}
}
}
if (ibfd->xvec->byteorder != obfd->xvec->byteorder
&& obfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN)
{
- (*_bfd_error_handler)
- ("%s: compiled for a %s endian system and target is %s endian",
- bfd_get_filename (ibfd),
- bfd_big_endian (ibfd) ? "big" : "little",
- bfd_big_endian (obfd) ? "big" : "little");
+ const char *msg;
+
+ if (bfd_big_endian (ibfd))
+ msg = _("%s: compiled for a big endian system and target is little endian");
+ else
+ msg = _("%s: compiled for a little endian system and target is big endian");
+
+ (*_bfd_error_handler) (msg, bfd_get_filename (ibfd));
bfd_set_error (bfd_error_wrong_format);
return false;
new_flags &= ~EF_MIPS_PIC;
old_flags &= ~EF_MIPS_PIC;
(*_bfd_error_handler)
- ("%s: linking PIC files with non-PIC files",
+ (_("%s: linking PIC files with non-PIC files"),
bfd_get_filename (ibfd));
ok = false;
}
new_flags &= ~EF_MIPS_CPIC;
old_flags &= ~EF_MIPS_CPIC;
(*_bfd_error_handler)
- ("%s: linking abicalls files with non-abicalls files",
+ (_("%s: linking abicalls files with non-abicalls files"),
bfd_get_filename (ibfd));
ok = false;
}
- /* Don't warn about mixing -mips1 and -mips2 code, or mixing -mips3
- and -mips4 code. They will normally use the same data sizes and
- calling conventions. */
- if ((new_flags & EF_MIPS_ARCH) != (old_flags & EF_MIPS_ARCH))
+ /* Compare the ISA's. */
+ if ((new_flags & (EF_MIPS_ARCH | EF_MIPS_MACH))
+ != (old_flags & (EF_MIPS_ARCH | EF_MIPS_MACH)))
{
- int new_isa, old_isa;
+ /* If either has no machine specified, just compare the general isa's. */
+ if ( !(new_flags & EF_MIPS_MACH) || !(old_flags & EF_MIPS_MACH))
+ {
+ int new_isa, old_isa;
+
+ /* Don't warn about mixing -mips1 and -mips2 code, or mixing -mips3
+ and -mips4 code. They will normally use the same data sizes and
+ calling conventions. */
- new_isa = elf_mips_isa (new_flags);
- old_isa = elf_mips_isa (old_flags);
- if ((new_isa == 1 || new_isa == 2)
- ? (old_isa != 1 && old_isa != 2)
- : (old_isa == 1 || old_isa == 2))
+ new_isa = elf_mips_isa (new_flags);
+ old_isa = elf_mips_isa (old_flags);
+ if ((new_isa == 1 || new_isa == 2)
+ ? (old_isa != 1 && old_isa != 2)
+ : (old_isa == 1 || old_isa == 2))
+ {
+ (*_bfd_error_handler)
+ (_("%s: ISA mismatch (-mips%d) with previous modules (-mips%d)"),
+ bfd_get_filename (ibfd), new_isa, old_isa);
+ ok = false;
+ }
+ }
+
+ else
{
(*_bfd_error_handler)
- ("%s: ISA mismatch (-mips%d) with previous modules (-mips%d)",
- bfd_get_filename (ibfd), new_isa, old_isa);
+ (_("%s: ISA mismatch (%d) with previous modules (%d)"),
+ bfd_get_filename (ibfd),
+ elf_mips_mach (new_flags),
+ elf_mips_mach (old_flags));
ok = false;
}
- new_flags &= ~ EF_MIPS_ARCH;
- old_flags &= ~ EF_MIPS_ARCH;
+ new_flags &= ~ (EF_MIPS_ARCH | EF_MIPS_MACH);
+ old_flags &= ~ (EF_MIPS_ARCH | EF_MIPS_MACH);
}
/* Warn about any other mismatches */
if (new_flags != old_flags)
{
(*_bfd_error_handler)
- ("%s: uses different e_flags (0x%lx) fields than previous modules (0x%lx)",
+ (_("%s: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"),
bfd_get_filename (ibfd), (unsigned long) new_flags,
(unsigned long) old_flags);
ok = false;
sizeof ".MIPS.post_rel" - 1) != 0)
return false;
break;
+/* start-sanitize-sky */
+ case SHT_DVP_OVERLAY_TABLE:
+ if (strcmp (name, SHNAME_DVP_OVERLAY_TABLE) !=0)
+ return false;
+ break;
+ case SHT_DVP_OVERLAY:
+ if (strncmp (name, SHNAME_DVP_OVERLAY_PREFIX,
+ sizeof (SHNAME_DVP_OVERLAY_PREFIX) - 1) !=0)
+ return false;
+ break;
+/* end-sanitize-sky */
default:
return false;
}
hdr->sh_flags |= SHF_MIPS_NOSTRIP;
/* The sh_link field is set in final_write_processing. */
}
+/* start-sanitize-sky */
+ else if (strcmp (name, SHNAME_DVP_OVERLAY_TABLE) == 0)
+ {
+ hdr->sh_type = SHT_DVP_OVERLAY_TABLE;
+ hdr->sh_entsize = sizeof (Elf32_Dvp_External_Overlay);
+ /* The sh_link field is set in final_write_processing. */
+ }
+ else if (strcmp (name, SHNAME_DVP_OVERLAY_STRTAB) == 0)
+ hdr->sh_type = SHT_STRTAB;
+ else if (strncmp (name, SHNAME_DVP_OVERLAY_PREFIX,
+ sizeof (SHNAME_DVP_OVERLAY_PREFIX) - 1) == 0)
+ hdr->sh_type = SHT_DVP_OVERLAY;
+/* end-sanitize-sky */
return true;
}
asection *msec;
if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
- filename_ptr, functionname_ptr,
+ filename_ptr, functionname_ptr,
line_ptr))
return true;
{
output_section = sec->output_section;
if (output_section != NULL)
- h->esym.asym.value = (h->root.plt_offset
+ h->esym.asym.value = (h->root.plt.offset
+ sec->output_offset
+ output_section->vma);
else
unsigned long i;
PDR pdr;
SYMR sym;
- const char *no_name_func = "static procedure (no name)";
+ const char *no_name_func = _("static procedure (no name)");
epdr = NULL;
rpdr = NULL;
esym.asym.st = stLocal;
esym.asym.reserved = 0;
esym.asym.index = indexNil;
+ last = 0;
for (i = 0; i < 8; i++)
{
esym.asym.sc = sc[i];
else
{
(*_bfd_error_handler)
- ("%s: illegal section name `%s'",
+ (_("%s: illegal section name `%s'"),
bfd_get_filename (abfd), o->name);
bfd_set_error (bfd_error_nonrepresentable_section);
return false;
if (assigned_gotno >= g->local_gotno)
{
(*_bfd_error_handler)
- ("more got entries are needed for hipage relocations");
+ (_("more got entries are needed for hipage relocations"));
bfd_set_error (bfd_error_bad_value);
return false;
}
bfd_reloc_status_type r;
r_type = ELF32_R_TYPE (rel->r_info);
+ if (r_type == R_MIPS_GNU_VTINHERIT
+ || r_type == R_MIPS_GNU_VTENTRY)
+ continue;
if ((r_type < 0 || r_type >= (int) R_MIPS_max)
+/* start-sanitize-r5900 */
+ && r_type != R_MIPS15_S3
+/* end-sanitize-r5900 */
/* start-sanitize-sky */
&& r_type != R_MIPS_DVP_11_PCREL
+ && r_type != R_MIPS_DVP_27_S4
+ && r_type != R_MIPS_DVP_11_S4
+ && r_type != R_MIPS_DVP_U15_S3
/* end-sanitize-sky */
&& r_type != R_MIPS16_26
&& r_type != R_MIPS16_GPREL)
howto = &elf_mips16_jump_howto;
else if (r_type == R_MIPS16_GPREL)
howto = &elf_mips16_gprel_howto;
+/* start-sanitize-r5900 */
+ else if (r_type == R_MIPS15_S3)
+ howto = &elf_mips15_s3_howto;
+/* end-sanitize-r5900 */
/* start-sanitize-sky */
else if (r_type == R_MIPS_DVP_11_PCREL)
howto = &elf_mips_dvp_11_pcrel_howto;
+ else if (r_type == R_MIPS_DVP_27_S4)
+ howto = &elf_mips_dvp_27_s4_howto;
+ else if (r_type == R_MIPS_DVP_11_S4)
+ howto = &elf_mips_dvp_11_s4_howto;
+ else if (r_type == R_MIPS_DVP_U15_S3)
+ howto = &elf_mips_dvp_u15_s3_howto;
/* end-sanitize-sky */
else
howto = elf_mips_howto_table + r_type;
{
if (! ((*info->callbacks->reloc_dangerous)
(info,
- "GP relative relocation when GP not defined",
+ _("GP relative relocation when GP not defined"),
input_bfd, input_section,
rel->r_offset)))
return false;
{
bfd_vma relocation;
boolean local;
+ boolean undefined_error;
/* This is a final link. */
+ undefined_error = false;
sym = NULL;
if (r_symndx < extsymoff
|| (elf_bad_symtab (input_bfd)
{
if (! ((*info->callbacks->reloc_dangerous)
(info,
- "_gp_disp used when GP not defined",
+ _("_gp_disp used when GP not defined"),
input_bfd, input_section,
rel->r_offset)))
return false;
(info, h->root.root.string, input_bfd,
input_section, rel->r_offset)))
return false;
+ undefined_error = true;
relocation = 0;
}
}
/* This symbol must be registered as a global symbol
having the corresponding got entry. */
- BFD_ASSERT (h->got_offset != (bfd_vma) -1);
+ BFD_ASSERT (h->got.offset != (bfd_vma) -1);
offset = (h->dynindx - g->global_gotsym + g->local_gotno) * 4;
BFD_ASSERT (g->local_gotno <= offset
/* This must be a global symbol with a got entry. The
next reloc must be the corresponding LO16 reloc. */
- BFD_ASSERT (h != NULL && h->got_offset != (bfd_vma) -1);
+ BFD_ASSERT (h != NULL && h->got.offset != (bfd_vma) -1);
BFD_ASSERT ((rel + 1) < relend);
- BFD_ASSERT (ELF32_R_TYPE ((rel + 1)->r_info)
+ BFD_ASSERT ((int) ELF32_R_TYPE ((rel + 1)->r_info)
== (r_type == R_MIPS_CALL_HI16
- ? R_MIPS_CALL_LO16
- : R_MIPS_GOT_LO16));
+ ? (int) R_MIPS_CALL_LO16
+ : (int) R_MIPS_GOT_LO16));
offset = (h->dynindx - g->global_gotsym + g->local_gotno) * 4;
BFD_ASSERT (g->local_gotno <= offset
&& ((insn >> 26) & 0x3f) != 0x1d)
{
(*_bfd_error_handler)
- ("%s: %s+0x%lx: jump to mips16 routine which is not jal",
+ (_("%s: %s+0x%lx: jump to mips16 routine which is not jal"),
bfd_get_filename (input_bfd),
input_section->name,
(unsigned long) rel->r_offset);
contents + rel->r_offset + 2);
}
}
+ /* start-sanitize-sky */
+ else if (r_type == R_MIPS_DVP_U15_S3)
+ {
+ if (rel->r_offset > input_section->_raw_size)
+ r = bfd_reloc_outofrange;
+ else
+ {
+ bfd_vma x;
+
+ relocation += rel->r_addend;
+ relocation >>= 3;
+
+ x = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ relocation += ((x & (0xf << 21)) >> 10) + (x & 0x7ff);
+ x &= ~ ((0xf << 21) | 0x7ff);
+ x |= (((relocation & 0x7800) << 10)
+ | (relocation & 0x7ff));
+ bfd_put_32 (input_bfd, x, contents + rel->r_offset);
+
+ if (relocation & ~ (bfd_vma) 0x7fff)
+ r = bfd_reloc_overflow;
+ else
+ r = bfd_reloc_ok;
+ }
+ }
+ /* end-sanitize-sky */
else
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
contents, rel->r_offset,
r = bfd_reloc_overflow;
}
+ /* Don't bother to report a relocation overflow for a call
+ to a weak undefined symbol with a value of zero. This
+ permits us to use
+ if (!f) f();
+ even if we aren't in range to call address zero. */
+ if (r == bfd_reloc_overflow
+ && (r_type == R_MIPS16_26 || r_type == R_MIPS_26)
+ && relocation + addend == 0
+ && h != NULL
+ && h->root.type == bfd_link_hash_undefweak)
+ r = bfd_reloc_ok;
+
+ /* If we've already issued an error for an undefined symbol,
+ don't issue another useless error. */
+ if (undefined_error
+ && (r == bfd_reloc_undefined || r == bfd_reloc_overflow))
+ r = bfd_reloc_ok;
+
if (SGI_COMPAT (abfd)
&& scpt != NULL
&& (input_section->flags & SEC_ALLOC) != 0)
if (h == NULL)
{
(*_bfd_error_handler)
- ("%s: CALL16 reloc at 0x%lx not against global symbol",
+ (_("%s: CALL16 reloc at 0x%lx not against global symbol"),
bfd_get_filename (abfd), (unsigned long) rel->r_offset);
bfd_set_error (bfd_error_bad_value);
return false;
return false;
}
- if (h->got_offset != (bfd_vma) -1)
+ if (h->got.offset != (bfd_vma) -1)
{
/* We have already allocated space in the .got. */
break;
g->global_gotsym = h->dynindx;
/* Make this symbol to have the corresponding got entry. */
- h->got_offset = 0;
+ h->got.offset = 0;
/* We need a stub, not a plt entry for the undefined
function. But we record it as if it needs plt. See
return false;
}
- if (h->got_offset != (bfd_vma) -1)
+ if (h->got.offset != (bfd_vma) -1)
{
/* We have already allocated space in the .got. */
break;
g->global_gotsym = h->dynindx;
/* Make this symbol to be the global got symbol. */
- h->got_offset = 0;
+ h->got.offset = 0;
}
break;
sizeof (Elf32_External_crinfo);
break;
+ /* This relocation describes the C++ object vtable hierarchy.
+ Reconstruct it for later use during GC. */
+ case R_MIPS_GNU_VTINHERIT:
+ if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
+ return false;
+ break;
+
+ /* This relocation describes which C++ vtable entries are actually
+ used. Record for later use during GC. */
+ case R_MIPS_GNU_VTENTRY:
+ if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_offset))
+ return false;
+ break;
+
default:
break;
}
return true;
}
+/* Return the section that should be marked against GC for a given
+ relocation. */
+
+static asection *
+mips_elf_gc_mark_hook (abfd, info, rel, h, sym)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ Elf_Internal_Rela *rel;
+ struct elf_link_hash_entry *h;
+ Elf_Internal_Sym *sym;
+{
+ /* ??? Do mips16 stub sections need to be handled special? */
+
+ if (h != NULL)
+ {
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ case R_MIPS_GNU_VTINHERIT:
+ case R_MIPS_GNU_VTENTRY:
+ break;
+
+ default:
+ switch (h->root.type)
+ {
+ case bfd_link_hash_defined:
+ case bfd_link_hash_defweak:
+ return h->root.u.def.section;
+
+ case bfd_link_hash_common:
+ return h->root.u.c.p->section;
+ }
+ }
+ }
+ else
+ {
+ if (!(elf_bad_symtab (abfd)
+ && ELF_ST_BIND (sym->st_info) != STB_LOCAL)
+ && ! ((sym->st_shndx <= 0 || sym->st_shndx >= SHN_LORESERVE)
+ && sym->st_shndx != SHN_COMMON))
+ {
+ return bfd_section_from_elf_index (abfd, sym->st_shndx);
+ }
+ }
+
+ return NULL;
+}
+
+/* Update the got entry reference counts for the section being removed. */
+
+static boolean
+mips_elf_gc_sweep_hook (abfd, info, sec, relocs)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ asection *sec;
+ const Elf_Internal_Rela *relocs;
+{
+#if 0
+ Elf_Internal_Shdr *symtab_hdr;
+ struct elf_link_hash_entry **sym_hashes;
+ bfd_signed_vma *local_got_refcounts;
+ const Elf_Internal_Rela *rel, *relend;
+ unsigned long r_symndx;
+ struct elf_link_hash_entry *h;
+
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+ sym_hashes = elf_sym_hashes (abfd);
+ local_got_refcounts = elf_local_got_refcounts (abfd);
+
+ relend = relocs + sec->reloc_count;
+ for (rel = relocs; rel < relend; rel++)
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ case R_MIPS_GOT16:
+ case R_MIPS_CALL16:
+ case R_MIPS_CALL_HI16:
+ case R_MIPS_CALL_LO16:
+ case R_MIPS_GOT_HI16:
+ case R_MIPS_GOT_LO16:
+ /* ??? It would seem that the existing MIPS code does no sort
+ of reference counting or whatnot on its GOT and PLT entries,
+ so it is not possible to garbage collect them at this time. */
+ break;
+
+ default:
+ break;
+ }
+#endif
+
+ return true;
+}
+
+
/* Adjust a symbol defined by a dynamic object and referenced by a
regular object. The current definition is in some section of the
dynamic object, but we're not including those sections. We have to
h->root.u.def.value = s->_raw_size;
/* XXX Write this stub address somewhere. */
- h->plt_offset = s->_raw_size;
+ h->plt.offset = s->_raw_size;
/* Make room for this stub code. */
s->_raw_size += MIPS_FUNCTION_STUB_SIZE;
if (strncmp (name, ".rel", 4) == 0)
{
if (s->_raw_size == 0)
- strip = true;
+ {
+ /* We only strip the section if the output section name
+ has the same name. Otherwise, there might be several
+ input sections for this output section. FIXME: This
+ code is probably not needed these days anyhow, since
+ the linker now does not create empty output sections. */
+ if (s->output_section != NULL
+ && strcmp (name,
+ bfd_get_section_name (s->output_section->owner,
+ s->output_section)) == 0)
+ strip = true;
+ }
else
{
const char *outname;
dynobj = elf_hash_table (info)->dynobj;
gval = sym->st_value;
- if (h->plt_offset != (bfd_vma) -1)
+ if (h->plt.offset != (bfd_vma) -1)
{
asection *s;
bfd_byte *p;
p += 4;
bfd_put_32 (output_bfd, STUB_LI16 + h->dynindx, p);
- BFD_ASSERT (h->plt_offset <= s->_raw_size);
- memcpy (s->contents + h->plt_offset, stub, MIPS_FUNCTION_STUB_SIZE);
+ BFD_ASSERT (h->plt.offset <= s->_raw_size);
+ memcpy (s->contents + h->plt.offset, stub, MIPS_FUNCTION_STUB_SIZE);
- /* Mark the symbol as undefined. plt_offset != -1 occurs
+ /* Mark the symbol as undefined. plt.offset != -1 occurs
only for the referenced symbol. */
sym->st_shndx = SHN_UNDEF;
/* The run-time linker uses the st_value field of the symbol
to reset the global offset table entry for this external
to its stub address when unlinking a shared object. */
- gval = s->output_section->vma + s->output_offset + h->plt_offset;
+ gval = s->output_section->vma + s->output_offset + h->plt.offset;
sym->st_value = gval;
}
/* This symbol has an entry in the global offset table. Set its
value to the corresponding got entry, if needed. */
- if (h->got_offset == (bfd_vma) -1)
+ if (h->got.offset == (bfd_vma) -1)
{
offset = (h->dynindx - g->global_gotsym + g->local_gotno) * 4;
BFD_ASSERT (g->local_gotno * 4 <= offset
sym.st_other = 0;
i = 0;
+ last = 0;
+ dindx = 0;
while ((name = *namep++) != NULL)
{
s = bfd_get_section_by_name (output_bfd, name);
#define elf_backend_collect true
#define elf_backend_type_change_ok true
+#define elf_backend_can_gc_sections true
#define elf_info_to_howto 0
#define elf_info_to_howto_rel mips_info_to_howto_rel
#define elf_backend_sym_is_global mips_elf_sym_is_global
mips_elf_finish_dynamic_symbol
#define elf_backend_finish_dynamic_sections \
mips_elf_finish_dynamic_sections
+#define elf_backend_gc_mark_hook mips_elf_gc_mark_hook
+#define elf_backend_gc_sweep_hook mips_elf_gc_sweep_hook
+
+#define elf_backend_got_header_size (4*MIPS_RESERVED_GOTNO)
+#define elf_backend_plt_header_size 0
#include "elf32-target.h"