/* MIPS-specific support for 32-bit ELF
- Copyright 1993, 1994, 1995, 1996 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>.
#define ECOFF_32
#include "ecoffswap.h"
-static bfd_reloc_status_type mips_elf_hi16_reloc PARAMS ((bfd *abfd,
- arelent *reloc,
- asymbol *symbol,
- PTR data,
- asection *section,
- bfd *output_bfd,
- char **error));
-static bfd_reloc_status_type mips_elf_got16_reloc PARAMS ((bfd *abfd,
- arelent *reloc,
- asymbol *symbol,
- PTR data,
- asection *section,
- bfd *output_bfd,
- char **error));
-static bfd_reloc_status_type mips_elf_lo16_reloc PARAMS ((bfd *abfd,
- arelent *reloc,
- asymbol *symbol,
- PTR data,
- asection *section,
- bfd *output_bfd,
- char **error));
-static bfd_reloc_status_type mips_elf_gprel16_reloc PARAMS ((bfd *abfd,
- arelent *reloc,
- asymbol *symbol,
- PTR data,
- asection *section,
- bfd *output_bfd,
- char **error));
-static bfd_reloc_status_type mips_elf_gprel32_reloc PARAMS ((bfd *abfd,
- arelent *reloc,
- asymbol *symbol,
- PTR data,
- asection *section,
- bfd *output_bfd,
- char **error));
+static bfd_reloc_status_type mips32_64bit_reloc
+ PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
PARAMS ((bfd *, bfd_reloc_code_real_type));
static void mips_info_to_howto_rel
static void bfd_mips_elf32_swap_gptab_out
PARAMS ((bfd *, const Elf32_gptab *, Elf32_External_gptab *));
static boolean mips_elf_sym_is_global PARAMS ((bfd *, asymbol *));
-static boolean mips_elf_object_p PARAMS ((bfd *));
+static boolean mips_elf32_object_p PARAMS ((bfd *));
static boolean mips_elf_create_procedure_table
PARAMS ((PTR, bfd *, struct bfd_link_info *, asection *,
struct ecoff_debug_info *));
static int mips_elf_additional_program_headers PARAMS ((bfd *));
static boolean mips_elf_modify_segment_map PARAMS ((bfd *));
-static void mips_elf_final_write_processing
- PARAMS ((bfd *, boolean));
-static boolean mips_elf_set_private_flags PARAMS ((bfd *, flagword));
-static boolean mips_elf_copy_private_bfd_data PARAMS ((bfd *, bfd *));
-static boolean mips_elf_merge_private_bfd_data PARAMS ((bfd *, bfd *));
-static boolean mips_elf_section_from_shdr
+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_elf_fake_sections
- PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *));
-static boolean mips_elf_section_from_bfd_section
- PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *, int *));
-static boolean mips_elf_section_processing
+static boolean mips_elf32_section_processing
PARAMS ((bfd *, Elf32_Internal_Shdr *));
-static void mips_elf_symbol_processing PARAMS ((bfd *, asymbol *));
-static boolean mips_elf_read_ecoff_info
- PARAMS ((bfd *, asection *, struct ecoff_debug_info *));
-static boolean mips_elf_is_local_label
- PARAMS ((bfd *, asymbol *));
-static boolean mips_elf_find_nearest_line
- PARAMS ((bfd *, asection *, asymbol **, bfd_vma, const char **,
- const char **, unsigned int *));
+static boolean mips_elf_is_local_label_name
+ PARAMS ((bfd *, const char *));
static struct bfd_hash_entry *mips_elf_link_hash_newfunc
PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *));
static struct bfd_link_hash_table *mips_elf_link_hash_table_create
static void mips_elf_relocate_hi16
PARAMS ((bfd *, Elf_Internal_Rela *, Elf_Internal_Rela *, bfd_byte *,
bfd_vma));
-static void mips_elf_relocate_got_local
+static boolean mips_elf_relocate_got_local
PARAMS ((bfd *, bfd *, asection *, Elf_Internal_Rela *,
Elf_Internal_Rela *, bfd_byte *, bfd_vma));
static void mips_elf_relocate_global_got
PARAMS ((bfd *, Elf_Internal_Rela *, bfd_byte *, bfd_vma));
+static bfd_reloc_status_type mips16_jump_reloc
+ 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
PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
Elf_Internal_Rela *, Elf_Internal_Sym *, asection **));
+static boolean mips_elf_link_output_symbol_hook
+ PARAMS ((bfd *, struct bfd_link_info *, const char *, Elf_Internal_Sym *,
+ asection *));
static boolean mips_elf_create_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
static boolean mips_elf_create_compact_rel_section
const Elf_Internal_Rela *));
static boolean mips_elf_adjust_dynamic_symbol
PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
+static boolean mips_elf_always_size_sections
+ PARAMS ((bfd *, struct bfd_link_info *));
static boolean mips_elf_size_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *));
static boolean mips_elf_finish_dynamic_symbol
unsigned long global_gotsym;
/* The number of local .got entries. */
unsigned int local_gotno;
+ /* The number of local .got entries we have used. */
+ unsigned int assigned_gotno;
};
/* The number of local .got entries we reserve. */
#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
-};
-
static reloc_howto_type elf_mips_howto_table[] =
{
/* No relocation. */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- mips_elf_hi16_reloc, /* special_function */
+ _bfd_mips_elf_hi16_reloc, /* special_function */
"R_MIPS_HI16", /* name */
true, /* partial_inplace */
0xffff, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- mips_elf_lo16_reloc, /* special_function */
+ _bfd_mips_elf_lo16_reloc, /* special_function */
"R_MIPS_LO16", /* name */
true, /* partial_inplace */
0xffff, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- mips_elf_gprel16_reloc, /* special_function */
+ _bfd_mips_elf_gprel16_reloc, /* special_function */
"R_MIPS_GPREL16", /* name */
true, /* partial_inplace */
0xffff, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- mips_elf_gprel16_reloc, /* special_function */
+ _bfd_mips_elf_gprel16_reloc, /* special_function */
"R_MIPS_LITERAL", /* name */
true, /* partial_inplace */
0xffff, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- mips_elf_got16_reloc, /* special_function */
+ _bfd_mips_elf_got16_reloc, /* special_function */
"R_MIPS_GOT16", /* name */
false, /* partial_inplace */
0, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
- mips_elf_gprel32_reloc, /* special_function */
+ _bfd_mips_elf_gprel32_reloc, /* special_function */
"R_MIPS_GPREL32", /* name */
true, /* partial_inplace */
0xffffffff, /* src_mask */
0x000007c4, /* dst_mask */
false), /* pcrel_offset */
- /* A 64 bit relocation. Presumably not used in 32 bit ELF. */
- { R_MIPS_64 },
+ /* A 64 bit relocation. This is used in 32 bit ELF when addresses
+ are 64 bits long; the upper 32 bits are simply a sign extension.
+ The fields of the howto should be the same as for R_MIPS_32,
+ other than the type, name, and special_function. */
+ HOWTO (R_MIPS_64, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_bitfield, /* complain_on_overflow */
+ mips32_64bit_reloc, /* special_function */
+ "R_MIPS_64", /* name */
+ true, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ false), /* pcrel_offset */
/* Displacement in the global offset table. */
/* FIXME: Not handled correctly. */
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
+ is a hack to make the linker think that we need 64 bit values. */
+static reloc_howto_type elf_mips_ctor64_howto =
+ HOWTO (R_MIPS_64, /* type */
+ 0, /* rightshift */
+ 4, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ mips32_64bit_reloc, /* special_function */
+ "R_MIPS_64", /* name */
+ true, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ false); /* pcrel_offset */
+
+/* The reloc used for the mips16 jump instruction. */
+static reloc_howto_type elf_mips16_jump_howto =
+ HOWTO (R_MIPS16_26, /* type */
+ 2, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 26, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ /* This needs complex overflow
+ detection, because the upper four
+ bits must match the PC. */
+ mips16_jump_reloc, /* special_function */
+ "R_MIPS16_26", /* name */
+ true, /* partial_inplace */
+ 0x3ffffff, /* src_mask */
+ 0x3ffffff, /* dst_mask */
+ false); /* pcrel_offset */
+
+/* The reloc used for the mips16 gprel instruction. The src_mask and
+ dsk_mask for this howto do not reflect the actual instruction, in
+ which the value is not contiguous; the masks are for the
+ convenience of the relocate_section routine. */
+static reloc_howto_type elf_mips16_gprel_howto =
+ HOWTO (R_MIPS16_GPREL, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ mips16_gprel_reloc, /* special_function */
+ "R_MIPS16_GPREL", /* name */
+ true, /* partial_inplace */
+ 0xffff, /* src_mask */
+ 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.
+ 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 */
+/* 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
static struct mips_hi16 *mips_hi16_list;
-static bfd_reloc_status_type
-mips_elf_hi16_reloc (abfd,
+bfd_reloc_status_type
+_bfd_mips_elf_hi16_reloc (abfd,
reloc_entry,
symbol,
data,
inplace relocation; this function exists in order to do the
R_MIPS_HI16 relocation described above. */
-static bfd_reloc_status_type
-mips_elf_lo16_reloc (abfd,
+bfd_reloc_status_type
+_bfd_mips_elf_lo16_reloc (abfd,
reloc_entry,
symbol,
data,
This implementation suffices for the assembler, but the linker does
not yet know how to create global offset tables. */
-static bfd_reloc_status_type
-mips_elf_got16_reloc (abfd,
+bfd_reloc_status_type
+_bfd_mips_elf_got16_reloc (abfd,
reloc_entry,
symbol,
data,
just like HI16. */
if (output_bfd != (bfd *) NULL
&& (symbol->flags & BSF_SECTION_SYM) != 0)
- return mips_elf_hi16_reloc (abfd, reloc_entry, symbol, data,
- input_section, output_bfd, error_message);
+ return _bfd_mips_elf_hi16_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message);
abort ();
}
*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;
}
}
arelent *, asection *,
boolean, PTR, bfd_vma));
-static bfd_reloc_status_type
-mips_elf_gprel16_reloc (abfd,
- reloc_entry,
- symbol,
- data,
- input_section,
- output_bfd,
- error_message)
+bfd_reloc_status_type
+_bfd_mips_elf_gprel16_reloc (abfd, reloc_entry, symbol, data, input_section,
+ output_bfd, error_message)
bfd *abfd;
arelent *reloc_entry;
asymbol *symbol;
insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
/* Set val to the offset into the section or symbol. */
- val = ((insn & 0xffff) + reloc_entry->addend) & 0xffff;
- if (val & 0x8000)
- val -= 0x10000;
+ if (reloc_entry->howto->src_mask == 0)
+ {
+ /* This case occurs with the 64-bit MIPS ELF ABI. */
+ val = reloc_entry->addend;
+ }
+ else
+ {
+ val = ((insn & 0xffff) + reloc_entry->addend) & 0xffff;
+ if (val & 0x8000)
+ val -= 0x10000;
+ }
/* Adjust val for the final section location and GP value. If we
are producing relocateable output, we don't want to do this for
arelent *, asection *,
boolean, PTR, bfd_vma));
-static bfd_reloc_status_type
-mips_elf_gprel32_reloc (abfd,
+bfd_reloc_status_type
+_bfd_mips_elf_gprel32_reloc (abfd,
reloc_entry,
symbol,
data,
&& 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 (reloc_entry->address > input_section->_cooked_size)
return bfd_reloc_outofrange;
- val = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
+ if (reloc_entry->howto->src_mask == 0)
+ {
+ /* This case arises with the 64-bit MIPS ELF ABI. */
+ val = 0;
+ }
+ else
+ val = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
/* Set val to the offset into the section or symbol. */
val += reloc_entry->addend;
return bfd_reloc_ok;
}
+/* Handle a 64 bit reloc in a 32 bit MIPS ELF file. These are
+ generated when addreses are 64 bits. The upper 32 bits are a simle
+ sign extension. */
+
+static bfd_reloc_status_type
+mips32_64bit_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;
+{
+ bfd_reloc_status_type r;
+ arelent reloc32;
+ unsigned long val;
+ bfd_size_type addr;
+
+ r = bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message);
+ if (r != bfd_reloc_continue)
+ return r;
+
+ /* Do a normal 32 bit relocation on the lower 32 bits. */
+ reloc32 = *reloc_entry;
+ if (bfd_big_endian (abfd))
+ reloc32.address += 4;
+ reloc32.howto = &elf_mips_howto_table[R_MIPS_32];
+ r = bfd_perform_relocation (abfd, &reloc32, data, input_section,
+ output_bfd, error_message);
+
+ /* Sign extend into the upper 32 bits. */
+ val = bfd_get_32 (abfd, (bfd_byte *) data + reloc32.address);
+ if ((val & 0x80000000) != 0)
+ val = 0xffffffff;
+ else
+ val = 0;
+ addr = reloc_entry->address;
+ if (bfd_little_endian (abfd))
+ addr += 4;
+ bfd_put_32 (abfd, val, (bfd_byte *) data + addr);
+
+ return r;
+}
+
+/* Handle a mips16 jump. */
+
+static bfd_reloc_status_type
+mips16_jump_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;
+{
+ if (output_bfd != (bfd *) NULL
+ && (symbol->flags & BSF_SECTION_SYM) == 0
+ && reloc_entry->addend == 0)
+ {
+ reloc_entry->address += input_section->output_offset;
+ return bfd_reloc_ok;
+ }
+
+ /* FIXME. */
+ {
+ static boolean warned;
+
+ if (! warned)
+ (*_bfd_error_handler)
+ (_("Linking mips16 objects into %s format is not supported"),
+ bfd_get_target (input_section->output_section->owner));
+ warned = true;
+ }
+
+ return bfd_reloc_undefined;
+}
+
+/* Handle a mips16 GP relative reloc. */
+
+static bfd_reloc_status_type
+mips16_gprel_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 gp;
+ unsigned short extend, insn;
+ unsigned long final;
+
+ /* 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. */
+ if (output_bfd != NULL
+ && (symbol->flags & BSF_SECTION_SYM) == 0
+ && reloc_entry->addend == 0)
+ {
+ reloc_entry->address += input_section->output_offset;
+ return bfd_reloc_ok;
+ }
+
+ if (output_bfd != NULL)
+ relocateable = true;
+ else
+ {
+ relocateable = false;
+ output_bfd = symbol->section->output_section->owner;
+ }
+
+ ret = mips_elf_final_gp (output_bfd, symbol, relocateable, 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,
+ (((extend & 0x1f) << 11)
+ | (extend & 0x7e0)
+ | (insn & 0x1f)),
+ (bfd_byte *) data + reloc_entry->address);
+
+ ret = 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,
+ ((extend & 0xf800)
+ | ((final >> 11) & 0x1f)
+ | (final & 0x7e0)),
+ (bfd_byte *) data + reloc_entry->address);
+ bfd_put_16 (abfd,
+ ((insn & 0xffe0)
+ | (final & 0x1f)),
+ (bfd_byte *) data + reloc_entry->address + 2);
+
+ 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
+elf_mips_isa (flags)
+ flagword flags;
+{
+ switch (flags & EF_MIPS_ARCH)
+ {
+ case E_MIPS_ARCH_1:
+ return 1;
+ case E_MIPS_ARCH_2:
+ return 2;
+ case E_MIPS_ARCH_3:
+ return 3;
+ case E_MIPS_ARCH_4:
+ return 4;
+ }
+ 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[] =
{ BFD_RELOC_NONE, R_MIPS_NONE, },
{ BFD_RELOC_16, R_MIPS_16 },
{ BFD_RELOC_32, R_MIPS_32 },
- { BFD_RELOC_CTOR, R_MIPS_32 },
- { BFD_RELOC_32_PCREL, R_MIPS_REL32 },
+ { BFD_RELOC_64, R_MIPS_64 },
{ BFD_RELOC_MIPS_JMP, R_MIPS_26 },
{ BFD_RELOC_HI16_S, R_MIPS_HI16 },
{ BFD_RELOC_LO16, R_MIPS_LO16 },
if (mips_reloc_map[i].bfd_reloc_val == code)
return &elf_mips_howto_table[(int) mips_reloc_map[i].elf_reloc_val];
}
- return NULL;
+
+ switch (code)
+ {
+ 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;
+
+ 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 */
+ 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 */
+ 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);
- BFD_ASSERT (r_type < (unsigned int) R_MIPS_max);
- cache_ptr->howto = &elf_mips_howto_table[r_type];
+ 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 */
+ 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 */
+ 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
value for the object file. We get the addend now, rather than
(bfd_byte *) ex->ri_gp_value);
}
+/* In the 64 bit ABI, the .MIPS.options section holds register
+ information in an Elf64_Reginfo structure. These routines swap
+ them in and out. They are globally visible because they are used
+ outside of BFD. These routines are here so that gas can call them
+ without worrying about whether the 64 bit ABI has been included. */
+
+void
+bfd_mips_elf64_swap_reginfo_in (abfd, ex, in)
+ bfd *abfd;
+ const Elf64_External_RegInfo *ex;
+ Elf64_Internal_RegInfo *in;
+{
+ in->ri_gprmask = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_gprmask);
+ in->ri_pad = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_pad);
+ in->ri_cprmask[0] = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_cprmask[0]);
+ in->ri_cprmask[1] = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_cprmask[1]);
+ in->ri_cprmask[2] = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_cprmask[2]);
+ in->ri_cprmask[3] = bfd_h_get_32 (abfd, (bfd_byte *) ex->ri_cprmask[3]);
+ in->ri_gp_value = bfd_h_get_64 (abfd, (bfd_byte *) ex->ri_gp_value);
+}
+
+void
+bfd_mips_elf64_swap_reginfo_out (abfd, in, ex)
+ bfd *abfd;
+ const Elf64_Internal_RegInfo *in;
+ Elf64_External_RegInfo *ex;
+{
+ bfd_h_put_32 (abfd, (bfd_vma) in->ri_gprmask,
+ (bfd_byte *) ex->ri_gprmask);
+ bfd_h_put_32 (abfd, (bfd_vma) in->ri_pad,
+ (bfd_byte *) ex->ri_pad);
+ bfd_h_put_32 (abfd, (bfd_vma) in->ri_cprmask[0],
+ (bfd_byte *) ex->ri_cprmask[0]);
+ bfd_h_put_32 (abfd, (bfd_vma) in->ri_cprmask[1],
+ (bfd_byte *) ex->ri_cprmask[1]);
+ bfd_h_put_32 (abfd, (bfd_vma) in->ri_cprmask[2],
+ (bfd_byte *) ex->ri_cprmask[2]);
+ bfd_h_put_32 (abfd, (bfd_vma) in->ri_cprmask[3],
+ (bfd_byte *) ex->ri_cprmask[3]);
+ bfd_h_put_64 (abfd, (bfd_vma) in->ri_gp_value,
+ (bfd_byte *) ex->ri_gp_value);
+}
+
/* Swap an entry in a .gptab section. Note that these routines rely
on the equivalence of the two elements of the union. */
bfd_h_put_32 (abfd, (bfd_vma) in->konst, ex->konst);
bfd_h_put_32 (abfd, (bfd_vma) in->vaddr, ex->vaddr);
}
+
+/* Swap in an options header. */
+
+void
+bfd_mips_elf_swap_options_in (abfd, ex, in)
+ bfd *abfd;
+ const Elf_External_Options *ex;
+ Elf_Internal_Options *in;
+{
+ in->kind = bfd_h_get_8 (abfd, ex->kind);
+ in->size = bfd_h_get_8 (abfd, ex->size);
+ in->section = bfd_h_get_16 (abfd, ex->section);
+ in->info = bfd_h_get_32 (abfd, ex->info);
+}
+
+/* Swap out an options header. */
+
+void
+bfd_mips_elf_swap_options_out (abfd, in, ex)
+ bfd *abfd;
+ const Elf_Internal_Options *in;
+ Elf_External_Options *ex;
+{
+ bfd_h_put_8 (abfd, in->kind, ex->kind);
+ bfd_h_put_8 (abfd, in->size, ex->size);
+ bfd_h_put_16 (abfd, in->section, ex->section);
+ bfd_h_put_32 (abfd, in->info, ex->info);
+}
\f
/* Determine whether a symbol is global for the purposes of splitting
the symbol table into global symbols and local symbols. At least
return (sym->flags & BSF_SECTION_SYM) == 0 ? true : false;
}
\f
-/* Set the right machine number for a MIPS ELF file. */
+/* Set the right machine number for a MIPS ELF file. This is used for
+ both the 32-bit and the 64-bit ABI. */
-static boolean
-mips_elf_object_p (abfd)
+boolean
+_bfd_mips_elf_object_p (abfd)
bfd *abfd;
{
- switch (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH)
- {
- default:
- case E_MIPS_ARCH_1:
- /* Just use the default, which was set in elfcode.h. */
- break;
-
- case E_MIPS_ARCH_2:
- (void) bfd_default_set_arch_mach (abfd, bfd_arch_mips, 6000);
- break;
+ bfd_default_set_arch_mach (abfd, bfd_arch_mips,
+ elf_mips_mach (elf_elfheader (abfd)->e_flags));
+ return true;
+}
- case E_MIPS_ARCH_3:
- (void) bfd_default_set_arch_mach (abfd, bfd_arch_mips, 4000);
- break;
- }
+/* Set the right machine number for a 32-bit MIPS ELF file. */
+static boolean
+mips_elf32_object_p (abfd)
+ bfd *abfd;
+{
/* Irix 5 is broken. Object file symbol tables are not always
sorted correctly such that local symbols precede global symbols,
and the sh_info field in the symbol table is not always right. */
elf_bad_symtab (abfd) = true;
- return true;
+ return _bfd_mips_elf_object_p (abfd);
}
/* The final processing done just before writing out a MIPS ELF object
file. This gets the MIPS architecture right based on the machine
- number. */
+ number. This is used by both the 32-bit and the 64-bit ABI. */
/*ARGSUSED*/
-static void
-mips_elf_final_write_processing (abfd, linker)
+void
+_bfd_mips_elf_final_write_processing (abfd, linker)
bfd *abfd;
boolean linker;
{
unsigned long val;
unsigned int i;
Elf_Internal_Shdr **hdrpp;
+ const char *name;
+ asection *sec;
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;
- default:
- val = 0;
+ case bfd_mach_mips4010:
+ val = E_MIPS_ARCH_3 | E_MIPS_MACH_4010;
+ break;
+
+ 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++)
{
- if ((*hdrpp)->sh_type == SHT_MIPS_GPTAB)
+ switch ((*hdrpp)->sh_type)
{
- const char *name;
- asection *sec;
+ case SHT_MIPS_LIBLIST:
+ sec = bfd_get_section_by_name (abfd, ".dynstr");
+ if (sec != NULL)
+ (*hdrpp)->sh_link = elf_section_data (sec)->this_idx;
+ break;
+ case SHT_MIPS_GPTAB:
BFD_ASSERT ((*hdrpp)->bfd_section != NULL);
name = bfd_get_section_name (abfd, (*hdrpp)->bfd_section);
BFD_ASSERT (name != NULL
sec = bfd_get_section_by_name (abfd, name + sizeof ".gptab" - 1);
BFD_ASSERT (sec != NULL);
(*hdrpp)->sh_info = elf_section_data (sec)->this_idx;
+ break;
+
+ case SHT_MIPS_CONTENT:
+ BFD_ASSERT ((*hdrpp)->bfd_section != NULL);
+ name = bfd_get_section_name (abfd, (*hdrpp)->bfd_section);
+ BFD_ASSERT (name != NULL
+ && strncmp (name, ".MIPS.content",
+ sizeof ".MIPS.content" - 1) == 0);
+ sec = bfd_get_section_by_name (abfd,
+ name + sizeof ".MIPS.content" - 1);
+ BFD_ASSERT (sec != NULL);
+ (*hdrpp)->sh_info = elf_section_data (sec)->this_idx;
+ break;
+
+ case SHT_MIPS_SYMBOL_LIB:
+ sec = bfd_get_section_by_name (abfd, ".dynsym");
+ if (sec != NULL)
+ (*hdrpp)->sh_link = elf_section_data (sec)->this_idx;
+ sec = bfd_get_section_by_name (abfd, ".liblist");
+ if (sec != NULL)
+ (*hdrpp)->sh_info = elf_section_data (sec)->this_idx;
+ break;
+
+ case SHT_MIPS_EVENTS:
+ BFD_ASSERT ((*hdrpp)->bfd_section != NULL);
+ name = bfd_get_section_name (abfd, (*hdrpp)->bfd_section);
+ BFD_ASSERT (name != NULL);
+ if (strncmp (name, ".MIPS.events", sizeof ".MIPS.events" - 1) == 0)
+ sec = bfd_get_section_by_name (abfd,
+ name + sizeof ".MIPS.events" - 1);
+ else
+ {
+ BFD_ASSERT (strncmp (name, ".MIPS.post_rel",
+ sizeof ".MIPS.post_rel" - 1) == 0);
+ sec = bfd_get_section_by_name (abfd,
+ (name
+ + sizeof ".MIPS.post_rel" - 1));
+ }
+ 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 */
}
}
}
\f
/* Function to keep MIPS specific file flags like as EF_MIPS_PIC. */
-static boolean
-mips_elf_set_private_flags (abfd, flags)
+boolean
+_bfd_mips_elf_set_private_flags (abfd, flags)
bfd *abfd;
flagword flags;
{
/* Copy backend specific data from one object module to another */
-static boolean
-mips_elf_copy_private_bfd_data (ibfd, obfd)
+boolean
+_bfd_mips_elf_copy_private_bfd_data (ibfd, obfd)
bfd *ibfd;
bfd *obfd;
{
- /* This function is selected based on the input vector. We only
- want to copy information over if the output BFD also uses Elf
- format. */
- if (bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+ || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
return true;
BFD_ASSERT (!elf_flags_init (obfd)
|| (elf_elfheader (obfd)->e_flags
== elf_elfheader (ibfd)->e_flags));
+ elf_gp (obfd) = elf_gp (ibfd);
elf_elfheader (obfd)->e_flags = elf_elfheader (ibfd)->e_flags;
elf_flags_init (obfd) = true;
return true;
/* Merge backend specific data from an object file to the output
object file when linking. */
-static boolean
-mips_elf_merge_private_bfd_data (ibfd, obfd)
+boolean
+_bfd_mips_elf_merge_private_bfd_data (ibfd, obfd)
bfd *ibfd;
bfd *obfd;
{
flagword old_flags;
flagword new_flags;
+ boolean ok;
/* Check if we have the same endianess */
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;
}
- /* This function is selected based on the input vector. We only
- want to copy information over if the output BFD also uses Elf
- format. */
- if (bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+ if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+ || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
return true;
new_flags = elf_elfheader (ibfd)->e_flags;
elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_NOREORDER;
old_flags = elf_elfheader (obfd)->e_flags;
- if (!elf_flags_init (obfd)) /* First call, no flags set */
+ if (! elf_flags_init (obfd))
{
elf_flags_init (obfd) = true;
elf_elfheader (obfd)->e_flags = new_flags;
+
+ if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
+ && bfd_get_arch_info (obfd)->the_default)
+ {
+ if (! bfd_set_arch_mach (obfd, bfd_get_arch (ibfd),
+ bfd_get_mach (ibfd)))
+ return false;
+ }
+
+ return true;
+ }
+
+ /* Check flag compatibility. */
+
+ new_flags &= ~EF_MIPS_NOREORDER;
+ old_flags &= ~EF_MIPS_NOREORDER;
+
+ if (new_flags == old_flags)
+ return true;
+
+ ok = true;
+
+ if ((new_flags & EF_MIPS_PIC) != (old_flags & EF_MIPS_PIC))
+ {
+ new_flags &= ~EF_MIPS_PIC;
+ old_flags &= ~EF_MIPS_PIC;
+ (*_bfd_error_handler)
+ (_("%s: linking PIC files with non-PIC files"),
+ bfd_get_filename (ibfd));
+ ok = false;
+ }
+
+ if ((new_flags & EF_MIPS_CPIC) != (old_flags & EF_MIPS_CPIC))
+ {
+ new_flags &= ~EF_MIPS_CPIC;
+ old_flags &= ~EF_MIPS_CPIC;
+ (*_bfd_error_handler)
+ (_("%s: linking abicalls files with non-abicalls files"),
+ bfd_get_filename (ibfd));
+ ok = false;
}
- else if (((new_flags ^ old_flags) & ~EF_MIPS_NOREORDER)
- == 0) /* Compatible flags are ok */
- ;
- else /* Incompatible flags */
+
+ /* Compare the ISA's. */
+ if ((new_flags & (EF_MIPS_ARCH | EF_MIPS_MACH))
+ != (old_flags & (EF_MIPS_ARCH | EF_MIPS_MACH)))
{
- /* Warn about -fPIC mismatch */
- if ((new_flags & EF_MIPS_PIC) != (old_flags & EF_MIPS_PIC))
+ /* If either has no machine specified, just compare the general isa's. */
+ if ( !(new_flags & EF_MIPS_MACH) || !(old_flags & EF_MIPS_MACH))
{
- new_flags &= ~EF_MIPS_PIC;
- (*_bfd_error_handler)
- ("%s: needs all files compiled with -fPIC",
- bfd_get_filename (ibfd));
+ 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))
+ {
+ (*_bfd_error_handler)
+ (_("%s: ISA mismatch (-mips%d) with previous modules (-mips%d)"),
+ bfd_get_filename (ibfd), new_isa, old_isa);
+ ok = false;
+ }
}
- if ((new_flags & EF_MIPS_CPIC) != (old_flags & EF_MIPS_CPIC))
+ else
{
- new_flags &= ~EF_MIPS_CPIC;
(*_bfd_error_handler)
- ("%s: needs all files compiled with -mabicalls",
- bfd_get_filename (ibfd));
+ (_("%s: ISA mismatch (%d) with previous modules (%d)"),
+ bfd_get_filename (ibfd),
+ elf_mips_mach (new_flags),
+ elf_mips_mach (old_flags));
+ ok = false;
}
- /* 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)",
- bfd_get_filename (ibfd), (unsigned long) new_flags,
- (unsigned long) old_flags);
+ 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)"),
+ bfd_get_filename (ibfd), (unsigned long) new_flags,
+ (unsigned long) old_flags);
+ ok = false;
+ }
+
+ if (! ok)
+ {
bfd_set_error (bfd_error_bad_value);
return false;
}
\f
/* Handle a MIPS specific section when reading an object file. This
is called when elfcode.h finds a section with an unknown type.
+ This routine supports both the 32-bit and 64-bit ELF ABI.
+
FIXME: We need to handle the SHF_MIPS_GPREL flag, but I'm not sure
how to. */
-static boolean
-mips_elf_section_from_shdr (abfd, hdr, name)
+boolean
+_bfd_mips_elf_section_from_shdr (abfd, hdr, name)
bfd *abfd;
- Elf32_Internal_Shdr *hdr;
- char *name;
+ Elf_Internal_Shdr *hdr;
+ const char *name;
{
- asection *newsect;
-
/* There ought to be a place to keep ELF backend specific flags, but
at the moment there isn't one. We just keep track of the
sections by their name, instead. Fortunately, the ABI gives
|| hdr->sh_size != sizeof (Elf32_External_RegInfo))
return false;
break;
+ case SHT_MIPS_IFACE:
+ if (strcmp (name, ".MIPS.interfaces") != 0)
+ return false;
+ break;
+ case SHT_MIPS_CONTENT:
+ if (strncmp (name, ".MIPS.content", sizeof ".MIPS.content" - 1) != 0)
+ return false;
+ break;
case SHT_MIPS_OPTIONS:
- if (strcmp (name, ".options") != 0)
+ if (strcmp (name, ".options") != 0
+ && strcmp (name, ".MIPS.options") != 0)
return false;
break;
case SHT_MIPS_DWARF:
if (strncmp (name, ".debug_", sizeof ".debug_" - 1) != 0)
return false;
break;
+ case SHT_MIPS_SYMBOL_LIB:
+ if (strcmp (name, ".MIPS.symlib") != 0)
+ return false;
+ break;
case SHT_MIPS_EVENTS:
- if (strncmp (name, ".MIPS.events.", sizeof ".MIPS.events." - 1) != 0)
+ if (strncmp (name, ".MIPS.events", sizeof ".MIPS.events" - 1) != 0
+ && strncmp (name, ".MIPS.post_rel",
+ 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;
}
if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name))
return false;
- newsect = hdr->bfd_section;
if (hdr->sh_type == SHT_MIPS_DEBUG)
{
- if (! bfd_set_section_flags (abfd, newsect,
- (bfd_get_section_flags (abfd, newsect)
+ if (! bfd_set_section_flags (abfd, hdr->bfd_section,
+ (bfd_get_section_flags (abfd,
+ hdr->bfd_section)
| SEC_DEBUGGING)))
return false;
}
+ return true;
+}
+
+/* Handle a 32-bit MIPS ELF specific section. */
+
+static boolean
+mips_elf32_section_from_shdr (abfd, hdr, name)
+ bfd *abfd;
+ Elf_Internal_Shdr *hdr;
+ char *name;
+{
+ if (! _bfd_mips_elf_section_from_shdr (abfd, hdr, name))
+ return false;
+
/* FIXME: We should record sh_info for a .gptab section. */
/* For a .reginfo section, set the gp value in the tdata information
from the contents of this section. We need the gp value while
- processing relocs, so we just get it now. */
+ processing relocs, so we just get it now. The .reginfo section
+ is not used in the 64-bit MIPS ELF ABI. */
if (hdr->sh_type == SHT_MIPS_REGINFO)
{
Elf32_External_RegInfo ext;
Elf32_RegInfo s;
- if (! bfd_get_section_contents (abfd, newsect, (PTR) &ext,
+ if (! bfd_get_section_contents (abfd, hdr->bfd_section, (PTR) &ext,
(file_ptr) 0, sizeof ext))
return false;
bfd_mips_elf32_swap_reginfo_in (abfd, &ext, &s);
elf_gp (abfd) = s.ri_gp_value;
}
+ /* For a SHT_MIPS_OPTIONS section, look for a ODK_REGINFO entry, and
+ set the gp value based on what we find. We may see both
+ SHT_MIPS_REGINFO and SHT_MIPS_OPTIONS/ODK_REGINFO; in that case,
+ they should agree. */
+ if (hdr->sh_type == SHT_MIPS_OPTIONS)
+ {
+ bfd_byte *contents, *l, *lend;
+
+ contents = (bfd_byte *) bfd_malloc (hdr->sh_size);
+ if (contents == NULL)
+ return false;
+ if (! bfd_get_section_contents (abfd, hdr->bfd_section, contents,
+ (file_ptr) 0, hdr->sh_size))
+ {
+ free (contents);
+ return false;
+ }
+ l = contents;
+ lend = contents + hdr->sh_size;
+ while (l + sizeof (Elf_External_Options) <= lend)
+ {
+ Elf_Internal_Options intopt;
+
+ bfd_mips_elf_swap_options_in (abfd, (Elf_External_Options *) l,
+ &intopt);
+ if (intopt.kind == ODK_REGINFO)
+ {
+ Elf32_RegInfo intreg;
+
+ bfd_mips_elf32_swap_reginfo_in
+ (abfd,
+ ((Elf32_External_RegInfo *)
+ (l + sizeof (Elf_External_Options))),
+ &intreg);
+ elf_gp (abfd) = intreg.ri_gp_value;
+ }
+ l += intopt.size;
+ }
+ free (contents);
+ }
+
return true;
}
/* Set the correct type for a MIPS ELF section. We do this by the
- section name, which is a hack, but ought to work. */
+ section name, which is a hack, but ought to work. This routine is
+ used by both the 32-bit and the 64-bit ABI. */
-static boolean
-mips_elf_fake_sections (abfd, hdr, sec)
+boolean
+_bfd_mips_elf_fake_sections (abfd, hdr, sec)
bfd *abfd;
Elf32_Internal_Shdr *hdr;
asection *sec;
{
hdr->sh_type = SHT_MIPS_LIBLIST;
hdr->sh_info = sec->_raw_size / sizeof (Elf32_Lib);
- /* FIXME: Set the sh_link field. */
+ /* The sh_link field is set in final_write_processing. */
}
else if (strcmp (name, ".msym") == 0)
{
{
hdr->sh_type = SHT_MIPS_GPTAB;
hdr->sh_entsize = sizeof (Elf32_External_gptab);
- /* The sh_info field is set in mips_elf_final_write_processing. */
+ /* The sh_info field is set in final_write_processing. */
}
else if (strcmp (name, ".ucode") == 0)
hdr->sh_type = SHT_MIPS_UCODE;
|| strcmp (name, ".lit4") == 0
|| strcmp (name, ".lit8") == 0)
hdr->sh_flags |= SHF_MIPS_GPREL;
- else if (strcmp (name, ".options") == 0)
+ else if (strcmp (name, ".MIPS.interfaces") == 0)
+ {
+ hdr->sh_type = SHT_MIPS_IFACE;
+ hdr->sh_flags |= SHF_MIPS_NOSTRIP;
+ }
+ else if (strcmp (name, ".MIPS.content") == 0)
+ {
+ hdr->sh_type = SHT_MIPS_CONTENT;
+ /* The sh_info field is set in final_write_processing. */
+ }
+ else if (strcmp (name, ".options") == 0
+ || strcmp (name, ".MIPS.options") == 0)
{
hdr->sh_type = SHT_MIPS_OPTIONS;
hdr->sh_entsize = 1;
+ hdr->sh_flags |= SHF_MIPS_NOSTRIP;
}
else if (strncmp (name, ".debug_", sizeof ".debug_" - 1) == 0)
hdr->sh_type = SHT_MIPS_DWARF;
- else if (strncmp (name, ".MIPS.events.", sizeof ".MIPS.events." - 1) == 0)
- hdr->sh_type = SHT_MIPS_EVENTS;
+ else if (strcmp (name, ".MIPS.symlib") == 0)
+ {
+ hdr->sh_type = SHT_MIPS_SYMBOL_LIB;
+ /* The sh_link and sh_info fields are set in
+ final_write_processing. */
+ }
+ else if (strncmp (name, ".MIPS.events", sizeof ".MIPS.events" - 1) == 0
+ || strncmp (name, ".MIPS.post_rel",
+ sizeof ".MIPS.post_rel" - 1) == 0)
+ {
+ hdr->sh_type = SHT_MIPS_EVENTS;
+ 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;
}
/* Given a BFD section, try to locate the corresponding ELF section
- index. */
+ index. This is used by both the 32-bit and the 64-bit ABI.
+ Actually, it's not clear to me that the 64-bit ABI supports these,
+ but for non-PIC objects we will certainly want support for at least
+ the .scommon section. */
-static boolean
-mips_elf_section_from_bfd_section (abfd, hdr, sec, retval)
+boolean
+_bfd_mips_elf_section_from_bfd_section (abfd, hdr, sec, retval)
bfd *abfd;
Elf32_Internal_Shdr *hdr;
asection *sec;
return false;
}
-/* Work over a section just before writing it out. We update the GP
- value in the .reginfo section based on the value we are using.
- FIXME: We recognize sections that need the SHF_MIPS_GPREL flag by
- name; there has to be a better way. */
+/* When are writing out the .options or .MIPS.options section,
+ remember the bytes we are writing out, so that we can install the
+ GP value in the section_processing routine. */
-static boolean
-mips_elf_section_processing (abfd, hdr)
+boolean
+_bfd_mips_elf_set_section_contents (abfd, section, location, offset, count)
bfd *abfd;
- Elf32_Internal_Shdr *hdr;
+ sec_ptr section;
+ PTR location;
+ file_ptr offset;
+ bfd_size_type count;
{
- if (hdr->sh_type == SHT_MIPS_REGINFO)
+ if (strcmp (section->name, ".options") == 0
+ || strcmp (section->name, ".MIPS.options") == 0)
{
- bfd_byte buf[4];
+ bfd_byte *c;
- BFD_ASSERT (hdr->sh_size == sizeof (Elf32_External_RegInfo));
- BFD_ASSERT (hdr->contents == NULL);
+ if (elf_section_data (section) == NULL)
+ {
+ section->used_by_bfd =
+ (PTR) bfd_zalloc (abfd, sizeof (struct bfd_elf_section_data));
+ if (elf_section_data (section) == NULL)
+ return false;
+ }
+ c = (bfd_byte *) elf_section_data (section)->tdata;
+ if (c == NULL)
+ {
+ bfd_size_type size;
- if (bfd_seek (abfd,
- hdr->sh_offset + sizeof (Elf32_External_RegInfo) - 4,
- SEEK_SET) == -1)
- return false;
- bfd_h_put_32 (abfd, (bfd_vma) elf_gp (abfd), buf);
- if (bfd_write (buf, (bfd_size_type) 1, (bfd_size_type) 4, abfd) != 4)
- return false;
+ if (section->_cooked_size != 0)
+ size = section->_cooked_size;
+ else
+ size = section->_raw_size;
+ c = (bfd_byte *) bfd_zalloc (abfd, size);
+ if (c == NULL)
+ return false;
+ elf_section_data (section)->tdata = (PTR) c;
+ }
+
+ memcpy (c + offset, location, count);
}
+ return _bfd_elf_set_section_contents (abfd, section, location, offset,
+ count);
+}
+
+/* Work over a section just before writing it out. This routine is
+ used by both the 32-bit and the 64-bit ABI. FIXME: We recognize
+ sections that need the SHF_MIPS_GPREL flag by name; there has to be
+ a better way. */
+
+boolean
+_bfd_mips_elf_section_processing (abfd, hdr)
+ bfd *abfd;
+ Elf_Internal_Shdr *hdr;
+{
if (hdr->bfd_section != NULL)
{
const char *name = bfd_get_section_name (abfd, hdr->bfd_section);
return true;
}
+
+/* Work over a section just before writing it out. We update the GP
+ value in the SHT_MIPS_REGINFO and SHT_MIPS_OPTIONS sections based
+ on the value we are using. */
+
+static boolean
+mips_elf32_section_processing (abfd, hdr)
+ bfd *abfd;
+ Elf32_Internal_Shdr *hdr;
+{
+ if (hdr->sh_type == SHT_MIPS_REGINFO)
+ {
+ bfd_byte buf[4];
+
+ BFD_ASSERT (hdr->sh_size == sizeof (Elf32_External_RegInfo));
+ BFD_ASSERT (hdr->contents == NULL);
+
+ if (bfd_seek (abfd,
+ hdr->sh_offset + sizeof (Elf32_External_RegInfo) - 4,
+ SEEK_SET) == -1)
+ return false;
+ bfd_h_put_32 (abfd, (bfd_vma) elf_gp (abfd), buf);
+ if (bfd_write (buf, (bfd_size_type) 1, (bfd_size_type) 4, abfd) != 4)
+ return false;
+ }
+
+ if (hdr->sh_type == SHT_MIPS_OPTIONS
+ && hdr->bfd_section != NULL
+ && elf_section_data (hdr->bfd_section) != NULL
+ && elf_section_data (hdr->bfd_section)->tdata != NULL)
+ {
+ bfd_byte *contents, *l, *lend;
+
+ /* We stored the section contents in the elf_section_data tdata
+ field in the set_section_contents routine. We save the
+ section contents so that we don't have to read them again.
+ At this point we know that elf_gp is set, so we can look
+ through the section contents to see if there is an
+ ODK_REGINFO structure. */
+
+ contents = (bfd_byte *) elf_section_data (hdr->bfd_section)->tdata;
+ l = contents;
+ lend = contents + hdr->sh_size;
+ while (l + sizeof (Elf_External_Options) <= lend)
+ {
+ Elf_Internal_Options intopt;
+
+ bfd_mips_elf_swap_options_in (abfd, (Elf_External_Options *) l,
+ &intopt);
+ if (intopt.kind == ODK_REGINFO)
+ {
+ bfd_byte buf[4];
+
+ if (bfd_seek (abfd,
+ (hdr->sh_offset
+ + (l - contents)
+ + sizeof (Elf_External_Options)
+ + (sizeof (Elf32_External_RegInfo) - 4)),
+ SEEK_SET) == -1)
+ return false;
+ bfd_h_put_32 (abfd, elf_gp (abfd), buf);
+ if (bfd_write (buf, 1, 4, abfd) != 4)
+ return false;
+ }
+ l += intopt.size;
+ }
+ }
+
+ return _bfd_mips_elf_section_processing (abfd, hdr);
+}
\f
/* MIPS ELF uses two common sections. One is the usual one, and the
other is for small objects. All the small objects are kept
static asymbol *mips_elf_scom_symbol_ptr;
/* MIPS ELF also uses an acommon section, which represents an
- allocated common symbol which may be overridden by a
+ allocated common symbol which may be overridden by a
definition in a shared library. */
static asection mips_elf_acom_section;
static asymbol mips_elf_acom_symbol;
static asymbol mips_elf_data_symbol;
static asymbol *mips_elf_data_symbol_ptr;
-/* Handle the special MIPS section numbers that a symbol may use. */
+/* Handle the special MIPS section numbers that a symbol may use.
+ This is used for both the 32-bit and the 64-bit ABI. */
-static void
-mips_elf_symbol_processing (abfd, asym)
+void
+_bfd_mips_elf_symbol_processing (abfd, asym)
bfd *abfd;
asymbol *asym;
{
*pm = m;
}
}
-
+
/* If there are .dynamic and .mdebug sections, we make a room for
the RTPROC header. FIXME: Rewrite without section names. */
if (bfd_get_section_by_name (abfd, ".interp") == NULL
/* Read ECOFF debugging information from a .mdebug section into a
ecoff_debug_info structure. */
-static boolean
-mips_elf_read_ecoff_info (abfd, section, debug)
+boolean
+_bfd_mips_elf_read_ecoff_info (abfd, section, debug)
bfd *abfd;
asection *section;
struct ecoff_debug_info *debug;
/*ARGSUSED*/
static boolean
-mips_elf_is_local_label (abfd, symbol)
+mips_elf_is_local_label_name (abfd, name)
bfd *abfd;
- asymbol *symbol;
+ const char *name;
{
- return symbol->name[0] == '$';
+ if (name[0] == '$')
+ return true;
+
+ /* On Irix 6, the labels go back to starting with '.', so we accept
+ the generic ELF local label syntax as well. */
+ return _bfd_elf_is_local_label_name (abfd, name);
}
/* MIPS ELF uses a special find_nearest_line routine in order the
struct ecoff_find_line i;
};
-static boolean
-mips_elf_find_nearest_line (abfd, section, symbols, offset, filename_ptr,
- functionname_ptr, line_ptr)
+boolean
+_bfd_mips_elf_find_nearest_line (abfd, section, symbols, offset, filename_ptr,
+ functionname_ptr, line_ptr)
bfd *abfd;
asection *section;
asymbol **symbols;
{
asection *msec;
+ if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
+ filename_ptr, functionname_ptr,
+ line_ptr))
+ return true;
+
msec = bfd_get_section_by_name (abfd, ".mdebug");
if (msec != NULL)
{
return false;
}
- if (! mips_elf_read_ecoff_info (abfd, msec, &fi->d))
+ if (! _bfd_mips_elf_read_ecoff_info (abfd, msec, &fi->d))
{
msec->flags = origflags;
return false;
line_ptr);
}
\f
+ /* The mips16 compiler uses a couple of special sections to handle
+ floating point arguments.
+
+ Section names that look like .mips16.fn.FNNAME contain stubs that
+ copy floating point arguments from the fp regs to the gp regs and
+ then jump to FNNAME. If any 32 bit function calls FNNAME, the
+ call should be redirected to the stub instead. If no 32 bit
+ function calls FNNAME, the stub should be discarded. We need to
+ consider any reference to the function, not just a call, because
+ if the address of the function is taken we will need the stub,
+ since the address might be passed to a 32 bit function.
+
+ Section names that look like .mips16.call.FNNAME contain stubs
+ that copy floating point arguments from the gp regs to the fp
+ regs and then jump to FNNAME. If FNNAME is a 32 bit function,
+ then any 16 bit function that calls FNNAME should be redirected
+ to the stub instead. If FNNAME is not a 32 bit function, the
+ stub should be discarded.
+
+ .mips16.call.fp.FNNAME sections are similar, but contain stubs
+ which call FNNAME and then copy the return value from the fp regs
+ to the gp regs. These stubs store the return value in $18 while
+ calling FNNAME; any function which might call one of these stubs
+ must arrange to save $18 around the call. (This case is not
+ needed for 32 bit functions that call 16 bit functions, because
+ 16 bit functions always return floating point values in both
+ $f0/$f1 and $2/$3.)
+
+ Note that in all cases FNNAME might be defined statically.
+ Therefore, FNNAME is not used literally. Instead, the relocation
+ information will indicate which symbol the section is for.
+
+ We record any stubs that we find in the symbol table. */
+
+#define FN_STUB ".mips16.fn."
+#define CALL_STUB ".mips16.call."
+#define CALL_FP_STUB ".mips16.call.fp."
+
/* The MIPS ELF linker needs additional information for each symbol in
the global hash table. */
/* Number of MIPS_32 or MIPS_REL32 relocs against this symbol. */
unsigned int mips_32_relocs;
+
+ /* If there is a stub that 32 bit functions should use to call this
+ 16 bit function, this points to the section containing the stub. */
+ asection *fn_stub;
+
+ /* Whether we need the fn_stub; this is set if this symbol appears
+ in any relocs other than a 16 bit call. */
+ boolean need_fn_stub;
+
+ /* If there is a stub that 16 bit functions should use to call this
+ 32 bit function, this points to the section containing the stub. */
+ asection *call_stub;
+
+ /* This is like the call_stub field, but it is used if the function
+ being called returns a floating point value. */
+ asection *call_fp_stub;
};
/* MIPS ELF linker hash table. */
bfd_size_type procedure_count;
/* The size of the .compact_rel section (if SGI_COMPAT). */
bfd_size_type compact_rel_size;
+ /* This flag indicates that the value of DT_MIPS_RLD_MAP dynamic
+ entry is set to the address of __rld_obj_head as in Irix 5. */
+ boolean use_rld_obj_head;
+ /* This is the value of the __rld_map or __rld_obj_head symbol. */
+ bfd_vma rld_value;
+ /* This is set if we see any mips16 stub sections. */
+ boolean mips16_stubs_seen;
};
/* Look up an entry in a MIPS ELF linker hash table. */
not been set. -1 means there is no associated ifd. */
ret->esym.ifd = -2;
ret->mips_32_relocs = 0;
+ ret->fn_stub = NULL;
+ ret->need_fn_stub = false;
+ ret->call_stub = NULL;
+ ret->call_fp_stub = NULL;
}
return (struct bfd_hash_entry *) ret;
ret->dynsym_sec_strindex[i] = (bfd_size_type) -1;
ret->procedure_count = 0;
ret->compact_rel_size = 0;
+ ret->use_rld_obj_head = false;
+ ret->rld_value = 0;
+ ret->mips16_stubs_seen = false;
return &ret->root.root;
}
mips_elf_text_section.name = ".text";
mips_elf_text_section.flags = SEC_NO_FLAGS;
mips_elf_text_section.output_section = NULL;
- mips_elf_text_section.owner = abfd;
mips_elf_text_section.symbol = &mips_elf_text_symbol;
mips_elf_text_section.symbol_ptr_ptr = &mips_elf_text_symbol_ptr;
mips_elf_text_symbol.name = ".text";
mips_elf_text_symbol_ptr = &mips_elf_text_symbol;
mips_elf_text_section_ptr = &mips_elf_text_section;
}
- if (info->shared)
- *secp = bfd_und_section_ptr;
- else
- *secp = mips_elf_text_section_ptr;
+ /* This code used to do *secp = bfd_und_section_ptr if
+ info->shared. I don't know why, and that doesn't make sense,
+ so I took it out. */
+ *secp = mips_elf_text_section_ptr;
break;
case SHN_MIPS_ACOMMON:
mips_elf_data_section.name = ".data";
mips_elf_data_section.flags = SEC_NO_FLAGS;
mips_elf_data_section.output_section = NULL;
- mips_elf_data_section.owner = abfd;
mips_elf_data_section.symbol = &mips_elf_data_symbol;
mips_elf_data_section.symbol_ptr_ptr = &mips_elf_data_symbol_ptr;
mips_elf_data_symbol.name = ".data";
mips_elf_data_symbol_ptr = &mips_elf_data_symbol;
mips_elf_data_section_ptr = &mips_elf_data_section;
}
- if (info->shared)
- *secp = bfd_und_section_ptr;
- else
- *secp = mips_elf_data_section_ptr;
+ /* This code used to do *secp = bfd_und_section_ptr if
+ info->shared. I don't know why, and that doesn't make sense,
+ so I took it out. */
+ *secp = mips_elf_data_section_ptr;
break;
case SHN_MIPS_SUNDEFINED:
break;
}
+ if (SGI_COMPAT (abfd)
+ && ! info->shared
+ && info->hash->creator == abfd->xvec
+ && strcmp (*namep, "__rld_obj_head") == 0)
+ {
+ struct elf_link_hash_entry *h;
+
+ /* Mark __rld_obj_head as dynamic. */
+ h = NULL;
+ if (! (_bfd_generic_link_add_one_symbol
+ (info, abfd, *namep, BSF_GLOBAL, *secp,
+ (bfd_vma) *valp, (const char *) NULL, false,
+ get_elf_backend_data (abfd)->collect,
+ (struct bfd_link_hash_entry **) &h)))
+ return false;
+ h->elf_link_hash_flags &=~ ELF_LINK_NON_ELF;
+ h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+ h->type = STT_OBJECT;
+
+ if (! bfd_elf32_link_record_dynamic_symbol (info, h))
+ return false;
+
+ mips_elf_hash_table (info)->use_rld_obj_head = true;
+ }
+
+ /* If this is a mips16 text symbol, add 1 to the value to make it
+ odd. This will cause something like .word SYM to come up with
+ the right value when it is loaded into the PC. */
+ if (sym->st_other == STO_MIPS16)
+ ++*valp;
+
return true;
}
else
{
name = bfd_section_name (output_section->owner, output_section);
-
+
if (strcmp (name, ".text") == 0)
h->esym.asym.sc = scText;
else if (strcmp (name, ".data") == 0)
{
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
#if 0 /* FIXME? */
h->esym.ifd = 0;
#endif
- }
+ }
if (! bfd_ecoff_debug_one_external (einfo->abfd, einfo->debug, einfo->swap,
h->root.root.root.string,
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;
/* Set the size and contents of .rtproc section. */
s->_raw_size = size;
- s->contents = rtproc;
+ s->contents = (bfd_byte *) rtproc;
/* Skip this section later on (I don't think this currently
matters, but someday it might). */
reginfo.ri_cprmask[3] |= sub.ri_cprmask[3];
/* ri_gp_value is set by the function
- mips_elf_section_processing when the section is
+ mips_elf32_section_processing when the section is
finally written out. */
/* Hack: reset the SEC_HAS_CONTENTS flag so that
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
esym.asym.value = last;
-
+
if (! bfd_ecoff_debug_one_external (abfd, &debug, swap,
name[i], &esym))
return false;
/* The ECOFF linking code expects that we have already
read in the debugging information and set up an
ecoff_debug_info structure, so we do that now. */
- if (! mips_elf_read_ecoff_info (input_bfd, input_section,
- &input_debug))
+ if (! _bfd_mips_elf_read_ecoff_info (input_bfd, input_section,
+ &input_debug))
return false;
if (! (bfd_ecoff_debug_accumulate
if (rtproc_sec == NULL)
{
flagword flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY
- | SEC_READONLY);
+ | SEC_LINKER_CREATED | SEC_READONLY);
rtproc_sec = bfd_make_section (abfd, ".rtproc");
if (rtproc_sec == NULL
|| ! bfd_set_section_flags (abfd, rtproc_sec, flags)
- || ! bfd_set_section_alignment (abfd, rtproc_sec, 12))
+ || ! bfd_set_section_alignment (abfd, rtproc_sec, 4))
return false;
}
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;
/* Handle a MIPS ELF local GOT16 reloc. */
-static void
+static boolean
mips_elf_relocate_got_local (output_bfd, input_bfd, sgot, relhi, rello,
contents, addend)
bfd *output_bfd;
bfd_byte *contents;
bfd_vma addend;
{
- int local_gotno;
- int i;
+ unsigned int assigned_gotno;
+ unsigned int i;
bfd_vma insn;
bfd_vma addlo;
bfd_vma address;
g = (struct mips_got_info *) elf_section_data (sgot)->tdata;
BFD_ASSERT (g != NULL);
- local_gotno = g->local_gotno;
+ assigned_gotno = g->assigned_gotno;
got_contents = sgot->contents;
hipage = addend & 0xffff0000;
- for (i = MIPS_RESERVED_GOTNO; i < local_gotno; i++)
+ for (i = MIPS_RESERVED_GOTNO; i < assigned_gotno; i++)
{
address = bfd_get_32 (input_bfd, got_contents + i * 4);
if (hipage == (address & 0xffff0000))
break;
- if (address == (bfd_vma) 0)
+ }
+
+ if (i == assigned_gotno)
+ {
+ if (assigned_gotno >= g->local_gotno)
{
- bfd_put_32 (input_bfd, hipage, got_contents + i * 4);
- break;
+ (*_bfd_error_handler)
+ (_("more got entries are needed for hipage relocations"));
+ bfd_set_error (bfd_error_bad_value);
+ return false;
}
- }
- BFD_ASSERT (i < local_gotno);
-#if 1
- if (i == local_gotno)
- (*_bfd_error_handler)
- ("ELF MIPS linker: more got entries are needed for hipage: %x",
- hipage);
-#endif
+ bfd_put_32 (input_bfd, hipage, got_contents + assigned_gotno * 4);
+ ++g->assigned_gotno;
+ }
i = - ELF_MIPS_GP_OFFSET (output_bfd) + i * 4;
bfd_put_32 (input_bfd, (insn & 0xffff0000) | (i & 0xffff),
contents + relhi->r_offset);
+
+ return true;
}
/* Handle MIPS ELF CALL16 reloc and global GOT16 reloc. */
struct elf_link_hash_entry *h;
asection *sec;
Elf_Internal_Sym *sym;
+ struct mips_elf_link_hash_entry *mh;
+ int other;
bfd_reloc_status_type r;
r_type = ELF32_R_TYPE (rel->r_info);
- if (r_type < 0 || r_type >= (int) R_MIPS_max)
+ 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)
{
bfd_set_error (bfd_error_bad_value);
return false;
}
- howto = elf_mips_howto_table + r_type;
+ if (r_type == R_MIPS16_26)
+ 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 (dynobj != NULL
&& (r_type == R_MIPS_CALL16
/* Mix in the change in GP address for a GP relative reloc. */
if (r_type != R_MIPS_GPREL16
&& r_type != R_MIPS_LITERAL
- && r_type != R_MIPS_GPREL32)
+ && r_type != R_MIPS_GPREL32
+ && r_type != R_MIPS16_GPREL)
addend = 0;
else
{
{
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;
/* If this is HI16 or GOT16 with an associated LO16,
adjust the addend accordingly. Otherwise, just
relocate. */
- if (r_type != R_MIPS_HI16 && r_type != R_MIPS_GOT16)
+ if (r_type == R_MIPS_64 && bfd_big_endian (input_bfd))
+ r = _bfd_relocate_contents (howto, input_bfd,
+ addend,
+ contents + rel->r_offset + 4);
+ else if (r_type != R_MIPS_HI16 && r_type != R_MIPS_GOT16)
r = _bfd_relocate_contents (howto, input_bfd,
addend,
contents + rel->r_offset);
{
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)
value. */
if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
relocation += sym->st_value;
+
+ /* mips16 text labels should be treated as odd. */
+ if (sym->st_other == STO_MIPS16)
+ ++relocation;
}
else
{
{
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;
}
}
+ mh = (struct mips_elf_link_hash_entry *) h;
+ if (h != NULL)
+ other = h->other;
+ else if (sym != NULL)
+ other = sym->st_other;
+ else
+ other = 0;
+
+ /* If this function has an fn_stub, then it is a mips16
+ function which needs a stub if it is called by a 32 bit
+ function. If this reloc is anything other than a 16 bit
+ call, redirect the reloc to the stub. We don't redirect
+ relocs from other stub functions. */
+ if (r_type != R_MIPS16_26
+ && ((mh != NULL
+ && mh->fn_stub != NULL)
+ || (mh == NULL
+ && elf_tdata (input_bfd)->local_stubs != NULL
+ && elf_tdata (input_bfd)->local_stubs[r_symndx] != NULL))
+ && strncmp (bfd_get_section_name (input_bfd, input_section),
+ FN_STUB, sizeof FN_STUB - 1) != 0
+ && strncmp (bfd_get_section_name (input_bfd, input_section),
+ CALL_STUB, sizeof CALL_STUB - 1) != 0
+ && strncmp (bfd_get_section_name (input_bfd, input_section),
+ CALL_FP_STUB, sizeof CALL_FP_STUB - 1) != 0)
+ {
+ if (mh != NULL)
+ {
+ BFD_ASSERT (mh->need_fn_stub);
+ relocation = (mh->fn_stub->output_section->vma
+ + mh->fn_stub->output_offset);
+ }
+ else
+ {
+ asection *fn_stub;
+
+ fn_stub = elf_tdata (input_bfd)->local_stubs[r_symndx];
+ relocation = (fn_stub->output_section->vma
+ + fn_stub->output_offset);
+ }
+
+ /* RELOCATION now points to 32 bit code. */
+ other = 0;
+ }
+
+ /* If this function has a call_stub, then it is called by a
+ mips16 function; the call needs to go through a stub if
+ this function is a 32 bit function. If this reloc is a
+ 16 bit call, and the symbol is not a 16 bit function,
+ then redirect the reloc to the stub. Note that we don't
+ need to worry about calling the function through a
+ function pointer; such calls are handled by routing
+ through a special mips16 routine. We don't have to check
+ whether this call is from a stub; it can't be, because a
+ stub contains 32 bit code, and hence can not have a 16
+ bit reloc. */
+ if (r_type == R_MIPS16_26
+ && mh != NULL
+ && (mh->call_stub != NULL || mh->call_fp_stub != NULL)
+ && other != STO_MIPS16)
+ {
+ asection *stub;
+
+ /* If both call_stub and call_fp_stub are defined, we
+ can figure out which one to use by seeing which one
+ appears in the input file. */
+ if (mh->call_stub != NULL && mh->call_fp_stub != NULL)
+ {
+ asection *o;
+
+ stub = NULL;
+ for (o = input_bfd->sections; o != NULL; o = o->next)
+ {
+ if (strncmp (bfd_get_section_name (input_bfd, o),
+ CALL_FP_STUB, sizeof CALL_FP_STUB - 1) == 0)
+ {
+ stub = mh->call_fp_stub;
+ break;
+ }
+ }
+ if (stub == NULL)
+ stub = mh->call_stub;
+ }
+ else if (mh->call_stub != NULL)
+ stub = mh->call_stub;
+ else
+ stub = mh->call_fp_stub;
+
+ BFD_ASSERT (stub->_raw_size > 0);
+ relocation = stub->output_section->vma + stub->output_offset;
+ }
+
if (r_type == R_MIPS_HI16)
{
Elf_Internal_Rela *lorel;
if ((rel + 1) < relend
&& ELF32_R_TYPE ((rel + 1)->r_info) == R_MIPS_LO16)
{
- mips_elf_relocate_got_local (output_bfd, input_bfd, sgot,
- rel, rel + 1,
- contents,
- relocation + addend);
+ if (! mips_elf_relocate_got_local (output_bfd, input_bfd,
+ sgot, rel, rel + 1,
+ contents,
+ relocation + addend))
+ return false;
r = bfd_reloc_ok;
}
else
/* 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
bfd_byte *cr;
if ((info->shared
- || (h != NULL
+ || (elf_hash_table (info)->dynamic_sections_created
+ && h != NULL
&& ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)
== 0)))
&& (input_section->flags & SEC_ALLOC) != 0)
{
+ boolean skip;
+
/* When generating a shared object, these
relocations are copied into the output file to be
resolved at run time. */
BFD_ASSERT (sreloc != NULL);
}
- outrel.r_offset = (rel->r_offset
- + input_section->output_section->vma
- + input_section->output_offset);
+ skip = false;
+
+ if (elf_section_data (input_section)->stab_info == NULL)
+ outrel.r_offset = rel->r_offset;
+ else
+ {
+ bfd_vma off;
+
+ off = (_bfd_stab_section_offset
+ (output_bfd, &elf_hash_table (info)->stab_info,
+ input_section,
+ &elf_section_data (input_section)->stab_info,
+ rel->r_offset));
+ if (off == (bfd_vma) -1)
+ skip = true;
+ outrel.r_offset = off;
+ }
+
+ outrel.r_offset += (input_section->output_section->vma
+ + input_section->output_offset);
addend = bfd_get_32 (input_bfd, contents + rel->r_offset);
- if (h != NULL
- && (! info->symbolic
- || (h->elf_link_hash_flags
- & ELF_LINK_HASH_DEF_REGULAR) == 0))
+ if (skip)
+ memset (&outrel, 0, sizeof outrel);
+ else if (h != NULL
+ && (! info->symbolic
+ || (h->elf_link_hash_flags
+ & ELF_LINK_HASH_DEF_REGULAR) == 0))
{
BFD_ASSERT (h->dynindx != -1);
outrel.r_info = ELF32_R_INFO (h->dynindx, R_MIPS_REL32);
addend += relocation;
}
- bfd_put_32 (output_bfd, addend, contents + rel->r_offset);
+ if (! skip)
+ bfd_put_32 (output_bfd, addend, contents + rel->r_offset);
+
bfd_elf32_swap_reloc_out (output_bfd, &outrel,
(((Elf32_External_Rel *)
sreloc->contents)
+ sreloc->reloc_count));
++sreloc->reloc_count;
- if (SGI_COMPAT (output_bfd))
+ if (! skip && SGI_COMPAT (output_bfd))
{
if (scpt == NULL)
continue;
contents, rel->r_offset,
relocation, addend);
}
+ else if (r_type == R_MIPS_64)
+ {
+ bfd_size_type addr;
+ unsigned long val;
+
+ /* Do a 32 bit relocation, and sign extend to 64 bits. */
+ addr = rel->r_offset;
+ if (bfd_big_endian (input_bfd))
+ addr += 4;
+ r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+ contents, addr, relocation,
+ addend);
+ val = bfd_get_32 (input_bfd, contents + addr);
+ if ((val & 0x80000000) != 0)
+ val = 0xffffffff;
+ else
+ val = 0;
+ addr = rel->r_offset;
+ if (bfd_little_endian (input_bfd))
+ addr += 4;
+ bfd_put_32 (input_bfd, val, contents + addr);
+ }
+ else if (r_type == R_MIPS_26 && other == STO_MIPS16)
+ {
+ unsigned long insn;
+
+ /* This is a jump to a mips16 routine from a mips32
+ routine. We need to change jal into jalx. */
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ if (((insn >> 26) & 0x3f) != 0x3
+ && ((insn >> 26) & 0x3f) != 0x1d)
+ {
+ (*_bfd_error_handler)
+ (_("%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);
+ bfd_set_error (bfd_error_bad_value);
+ return false;
+ }
+ insn = (insn & 0x3ffffff) | (0x1d << 26);
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+ r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+ contents, rel->r_offset,
+ relocation, addend);
+ }
+ else if (r_type == R_MIPS16_26)
+ {
+ /* It's easiest to do the normal relocation, and then
+ dig out the instruction and swap the first word the
+ way the mips16 expects it. If this is little endian,
+ though, we need to swap the two words first, and then
+ swap them back again later, so that the address looks
+ right. */
+
+ if (bfd_little_endian (input_bfd))
+ {
+ unsigned long insn;
+
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ insn = ((insn >> 16) & 0xffff) | ((insn & 0xffff) << 16);
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+ }
+
+ r = _bfd_final_link_relocate (howto, input_bfd, input_section,
+ contents, rel->r_offset,
+ relocation, addend);
+ if (r == bfd_reloc_ok)
+ {
+ unsigned long insn;
+
+ if (bfd_little_endian (input_bfd))
+ {
+ insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
+ insn = ((insn >> 16) & 0xffff) | ((insn & 0xffff) << 16);
+ bfd_put_32 (input_bfd, insn, contents + rel->r_offset);
+ }
+
+ insn = bfd_get_16 (input_bfd, contents + rel->r_offset);
+ insn = ((insn & 0xfc00)
+ | ((insn & 0x1f) << 5)
+ | ((insn & 0x3e0) >> 5));
+ /* If this is a jump to a 32 bit routine, then make
+ it jalx. */
+ if (other != STO_MIPS16)
+ insn |= 0x400;
+ bfd_put_16 (input_bfd, insn, contents + rel->r_offset);
+ }
+ }
+ else if (r_type == R_MIPS16_GPREL)
+ {
+ unsigned short extend, insn;
+ bfd_byte buf[4];
+ unsigned long final;
+
+ /* Extract the addend into buf, run the regular reloc,
+ and stuff the resulting value back into the
+ instructions. */
+ if (rel->r_offset > input_section->_raw_size)
+ r = bfd_reloc_outofrange;
+ else
+ {
+ extend = bfd_get_16 (input_bfd, contents + rel->r_offset);
+ insn = bfd_get_16 (input_bfd, contents + rel->r_offset + 2);
+ bfd_put_32 (input_bfd,
+ (((extend & 0x1f) << 11)
+ | (extend & 0x7e0)
+ | (insn & 0x1f)),
+ buf);
+ r = _bfd_final_link_relocate (howto, input_bfd,
+ input_section, buf,
+ (bfd_vma) 0, relocation,
+ addend);
+ final = bfd_get_32 (input_bfd, buf);
+ bfd_put_16 (input_bfd,
+ ((extend & 0xf800)
+ | ((final >> 11) & 0x1f)
+ | (final & 0x7e0)),
+ contents + rel->r_offset);
+ bfd_put_16 (input_bfd,
+ ((insn & 0xffe0)
+ | (final & 0x1f)),
+ 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,
relocation, addend);
+ /* The jal instruction can only jump to an address which is
+ divisible by 4, and it can only jump to an address with
+ the same upper 4 bits as the PC. */
+ if (r == bfd_reloc_ok
+ && (r_type == R_MIPS16_26 || r_type == R_MIPS_26))
+ {
+ bfd_vma addr;
+
+ addr = relocation;
+ if (other == STO_MIPS16)
+ addr &= ~ (bfd_vma) 1;
+ addr += addend;
+ if ((addr & 3) != 0
+ || ((addr & 0xf0000000)
+ != ((input_section->output_section->vma
+ + input_section->output_offset
+ + rel->r_offset)
+ & 0xf0000000)))
+ 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)
return true;
}
+
+/* This hook function is called before the linker writes out a global
+ symbol. We mark symbols as small common if appropriate. This is
+ also where we undo the increment of the value for a mips16 symbol. */
+
+/*ARGSIGNORED*/
+static boolean
+mips_elf_link_output_symbol_hook (abfd, info, name, sym, input_sec)
+ bfd *abfd;
+ struct bfd_link_info *info;
+ const char *name;
+ Elf_Internal_Sym *sym;
+ asection *input_sec;
+{
+ /* If we see a common symbol, which implies a relocatable link, then
+ if a symbol was small common in an input file, mark it as small
+ common in the output file. */
+ if (sym->st_shndx == SHN_COMMON
+ && strcmp (input_sec->name, ".scommon") == 0)
+ sym->st_shndx = SHN_MIPS_SCOMMON;
+
+ if (sym->st_other == STO_MIPS16
+ && (sym->st_value & 1) != 0)
+ --sym->st_value;
+
+ return true;
+}
\f
/* Functions for the dynamic linker. */
const char * const *namep;
flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
- | SEC_READONLY);
+ | SEC_LINKER_CREATED | SEC_READONLY);
/* Mips ABI requests the .dynamic section to be read only. */
s = bfd_get_section_by_name (abfd, ".dynamic");
return false;
}
+ if (SGI_COMPAT (abfd)
+ && !info->shared
+ && bfd_get_section_by_name (abfd, ".rld_map") == NULL)
+ {
+ s = bfd_make_section (abfd, ".rld_map");
+ if (s == NULL
+ || ! bfd_set_section_flags (abfd, s, flags & ~SEC_READONLY)
+ || ! bfd_set_section_alignment (abfd, s, 2))
+ return false;
+ }
+
if (SGI_COMPAT (abfd))
{
for (namep = mips_elf_dynsym_rtproc_names; *namep != NULL; namep++)
get_elf_backend_data (abfd)->collect,
(struct bfd_link_hash_entry **) &h)))
return false;
- h->elf_link_hash_flags ^=~ ELF_LINK_NON_ELF;
+ h->elf_link_hash_flags &=~ ELF_LINK_NON_ELF;
h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
h->type = STT_SECTION;
- if (! bfd_elf32_link_record_dynamic_symbol (info, h))
- return false;
+ if (! bfd_elf32_link_record_dynamic_symbol (info, h))
+ return false;
+
+ if (! mips_elf_hash_table (info)->use_rld_obj_head)
+ {
+ /* __rld_map is a four byte word located in the .data section
+ and is filled in by the rtld to contain a pointer to
+ the _r_debug structure. Its symbol value will be set in
+ mips_elf_finish_dynamic_symbol. */
+ s = bfd_get_section_by_name (abfd, ".rld_map");
+ BFD_ASSERT (s != NULL);
+
+ h = NULL;
+ if (! (_bfd_generic_link_add_one_symbol
+ (info, abfd, "__rld_map", BSF_GLOBAL, s,
+ (bfd_vma) 0, (const char *) NULL, false,
+ get_elf_backend_data (abfd)->collect,
+ (struct bfd_link_hash_entry **) &h)))
+ return false;
+ h->elf_link_hash_flags &=~ ELF_LINK_NON_ELF;
+ h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR;
+ h->type = STT_OBJECT;
+
+ if (! bfd_elf32_link_record_dynamic_symbol (info, h))
+ return false;
+ }
}
return true;
if (bfd_get_section_by_name (abfd, ".compact_rel") == NULL)
{
- flags = SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_READONLY;
+ flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED
+ | SEC_READONLY);
s = bfd_make_section (abfd, ".compact_rel");
if (s == NULL
return true;
}
-
+
/* Create the .got section to hold the global offset table. */
static boolean
if (bfd_get_section_by_name (abfd, ".got") != NULL)
return true;
- flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
+ flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED);
s = bfd_make_section (abfd, ".got");
if (s == NULL
return false;
g->global_gotsym = 0;
g->local_gotno = MIPS_RESERVED_GOTNO;
+ g->assigned_gotno = MIPS_RESERVED_GOTNO;
if (elf_section_data (s) == NULL)
{
s->used_by_bfd =
asection *sec;
const Elf_Internal_Rela *relocs;
{
+ const char *name;
bfd *dynobj;
Elf_Internal_Shdr *symtab_hdr;
struct elf_link_hash_entry **sym_hashes;
sym_hashes = elf_sym_hashes (abfd);
extsymoff = (elf_bad_symtab (abfd)) ? 0 : symtab_hdr->sh_info;
- sgot = NULL;
+ /* Check for the mips16 stub sections. */
+
+ name = bfd_get_section_name (abfd, sec);
+ if (strncmp (name, FN_STUB, sizeof FN_STUB - 1) == 0)
+ {
+ unsigned long r_symndx;
+
+ /* Look at the relocation information to figure out which symbol
+ this is for. */
+
+ r_symndx = ELF32_R_SYM (relocs->r_info);
+
+ if (r_symndx < extsymoff
+ || sym_hashes[r_symndx - extsymoff] == NULL)
+ {
+ asection *o;
+
+ /* This stub is for a local symbol. This stub will only be
+ needed if there is some relocation in this BFD, other
+ than a 16 bit function call, which refers to this symbol. */
+ for (o = abfd->sections; o != NULL; o = o->next)
+ {
+ Elf_Internal_Rela *sec_relocs;
+ const Elf_Internal_Rela *r, *rend;
+
+ /* We can ignore stub sections when looking for relocs. */
+ if ((o->flags & SEC_RELOC) == 0
+ || o->reloc_count == 0
+ || strncmp (bfd_get_section_name (abfd, o), FN_STUB,
+ sizeof FN_STUB - 1) == 0
+ || strncmp (bfd_get_section_name (abfd, o), CALL_STUB,
+ sizeof CALL_STUB - 1) == 0
+ || strncmp (bfd_get_section_name (abfd, o), CALL_FP_STUB,
+ sizeof CALL_FP_STUB - 1) == 0)
+ continue;
+
+ sec_relocs = (_bfd_elf32_link_read_relocs
+ (abfd, o, (PTR) NULL,
+ (Elf_Internal_Rela *) NULL,
+ info->keep_memory));
+ if (sec_relocs == NULL)
+ return false;
+
+ rend = sec_relocs + o->reloc_count;
+ for (r = sec_relocs; r < rend; r++)
+ if (ELF32_R_SYM (r->r_info) == r_symndx
+ && ELF32_R_TYPE (r->r_info) != R_MIPS16_26)
+ break;
+
+ if (! info->keep_memory)
+ free (sec_relocs);
+
+ if (r < rend)
+ break;
+ }
+
+ if (o == NULL)
+ {
+ /* There is no non-call reloc for this stub, so we do
+ not need it. Since this function is called before
+ the linker maps input sections to output sections, we
+ can easily discard it by setting the SEC_EXCLUDE
+ flag. */
+ sec->flags |= SEC_EXCLUDE;
+ return true;
+ }
+
+ /* Record this stub in an array of local symbol stubs for
+ this BFD. */
+ if (elf_tdata (abfd)->local_stubs == NULL)
+ {
+ unsigned long symcount;
+ asection **n;
+
+ if (elf_bad_symtab (abfd))
+ symcount = symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
+ else
+ symcount = symtab_hdr->sh_info;
+ n = (asection **) bfd_zalloc (abfd,
+ symcount * sizeof (asection *));
+ if (n == NULL)
+ return false;
+ elf_tdata (abfd)->local_stubs = n;
+ }
+
+ elf_tdata (abfd)->local_stubs[r_symndx] = sec;
+
+ /* We don't need to set mips16_stubs_seen in this case.
+ That flag is used to see whether we need to look through
+ the global symbol table for stubs. We don't need to set
+ it here, because we just have a local stub. */
+ }
+ else
+ {
+ struct mips_elf_link_hash_entry *h;
+
+ h = ((struct mips_elf_link_hash_entry *)
+ sym_hashes[r_symndx - extsymoff]);
+
+ /* H is the symbol this stub is for. */
+
+ h->fn_stub = sec;
+ mips_elf_hash_table (info)->mips16_stubs_seen = true;
+ }
+ }
+ else if (strncmp (name, CALL_STUB, sizeof CALL_STUB - 1) == 0
+ || strncmp (name, CALL_FP_STUB, sizeof CALL_FP_STUB - 1) == 0)
+ {
+ unsigned long r_symndx;
+ struct mips_elf_link_hash_entry *h;
+ asection **loc;
+
+ /* Look at the relocation information to figure out which symbol
+ this is for. */
+
+ r_symndx = ELF32_R_SYM (relocs->r_info);
+
+ if (r_symndx < extsymoff
+ || sym_hashes[r_symndx - extsymoff] == NULL)
+ {
+ /* This stub was actually built for a static symbol defined
+ in the same file. We assume that all static symbols in
+ mips16 code are themselves mips16, so we can simply
+ discard this stub. Since this function is called before
+ the linker maps input sections to output sections, we can
+ easily discard it by setting the SEC_EXCLUDE flag. */
+ sec->flags |= SEC_EXCLUDE;
+ return true;
+ }
+
+ h = ((struct mips_elf_link_hash_entry *)
+ sym_hashes[r_symndx - extsymoff]);
+
+ /* H is the symbol this stub is for. */
+
+ if (strncmp (name, CALL_FP_STUB, sizeof CALL_FP_STUB - 1) == 0)
+ loc = &h->call_fp_stub;
+ else
+ loc = &h->call_stub;
+
+ /* If we already have an appropriate stub for this function, we
+ don't need another one, so we can discard this one. Since
+ this function is called before the linker maps input sections
+ to output sections, we can easily discard it by setting the
+ SEC_EXCLUDE flag. We can also discard this section if we
+ happen to already know that this is a mips16 function; it is
+ not necessary to check this here, as it is checked later, but
+ it is slightly faster to check now. */
+ if (*loc != NULL || h->root.other == STO_MIPS16)
+ {
+ sec->flags |= SEC_EXCLUDE;
+ return true;
+ }
+
+ *loc = sec;
+ mips_elf_hash_table (info)->mips16_stubs_seen = true;
+ }
+
+ if (dynobj == NULL)
+ {
+ sgot = NULL;
+ g = NULL;
+ }
+ else
+ {
+ sgot = bfd_get_section_by_name (dynobj, ".got");
+ if (sgot == NULL)
+ g = NULL;
+ else
+ {
+ BFD_ASSERT (elf_section_data (sgot) != NULL);
+ g = (struct mips_got_info *) elf_section_data (sgot)->tdata;
+ BFD_ASSERT (g != NULL);
+ }
+ }
+
sreloc = NULL;
rel_end = relocs + sec->reloc_count;
if (r_symndx < extsymoff)
h = NULL;
else
- h = sym_hashes[r_symndx - extsymoff];
+ {
+ h = sym_hashes[r_symndx - extsymoff];
+
+ /* This may be an indirect symbol created because of a version. */
+ if (h != NULL)
+ {
+ while (h->root.type == bfd_link_hash_indirect)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ }
+ }
/* Some relocs require a global offset table. */
- if (dynobj == NULL)
+ if (dynobj == NULL || sgot == NULL)
{
switch (ELF32_R_TYPE (rel->r_info))
{
case R_MIPS_CALL_LO16:
case R_MIPS_GOT_HI16:
case R_MIPS_GOT_LO16:
- elf_hash_table (info)->dynobj = dynobj = abfd;
+ if (dynobj == NULL)
+ elf_hash_table (info)->dynobj = dynobj = abfd;
if (! mips_elf_create_got_section (dynobj, info))
return false;
+ sgot = bfd_get_section_by_name (dynobj, ".got");
+ BFD_ASSERT (sgot != NULL);
+ BFD_ASSERT (elf_section_data (sgot) != NULL);
+ g = (struct mips_got_info *) elf_section_data (sgot)->tdata;
+ BFD_ASSERT (g != NULL);
+ break;
+
+ case R_MIPS_32:
+ case R_MIPS_REL32:
+ if (dynobj == NULL
+ && (info->shared || h != NULL)
+ && (sec->flags & SEC_ALLOC) != 0)
+ elf_hash_table (info)->dynobj = dynobj = abfd;
break;
default:
case R_MIPS_CALL_HI16:
case R_MIPS_CALL_LO16:
/* This symbol requires a global offset table entry. */
- if (sgot == NULL)
+
+ if (h == NULL)
{
- sgot = bfd_get_section_by_name (dynobj, ".got");
- BFD_ASSERT (sgot != NULL);
- BFD_ASSERT (elf_section_data (sgot) != NULL);
- g = (struct mips_got_info *) elf_section_data (sgot)->tdata;
- BFD_ASSERT (g != NULL);
+ (*_bfd_error_handler)
+ (_("%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;
}
- BFD_ASSERT (h != NULL);
-
/* Make sure this symbol is output as a dynamic symbol. */
if (h->dynindx == -1)
{
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
case R_MIPS_GOT_HI16:
case R_MIPS_GOT_LO16:
/* This symbol requires a global offset table entry. */
- if (sgot == NULL)
- {
- sgot = bfd_get_section_by_name (dynobj, ".got");
- BFD_ASSERT (sgot != NULL);
- BFD_ASSERT (elf_section_data (sgot) != NULL);
- g = (struct mips_got_info *) elf_section_data (sgot)->tdata;
- BFD_ASSERT (g != NULL);
- }
if (h != NULL)
{
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;
if ((info->shared || h != NULL)
&& (sec->flags & SEC_ALLOC) != 0)
{
- /* When creating a shared object, we must copy these
- reloc types into the output file as R_MIPS_REL32
- relocs. We create the .rel.dyn reloc section in
- dynobj and make room for this reloc. */
if (sreloc == NULL)
{
const char *name = ".rel.dyn";
| SEC_LOAD
| SEC_HAS_CONTENTS
| SEC_IN_MEMORY
+ | SEC_LINKER_CREATED
| SEC_READONLY))
- || ! bfd_set_section_alignment (dynobj, sreloc, 4))
+ || ! bfd_set_section_alignment (dynobj, sreloc,
+ 4))
return false;
-
+ }
+ }
+ if (info->shared)
+ {
+ /* When creating a shared object, we must copy these
+ reloc types into the output file as R_MIPS_REL32
+ relocs. We make room for this reloc in the
+ .rel.dyn reloc section */
+ if (sreloc->_raw_size == 0)
+ {
/* Add a null element. */
sreloc->_raw_size += sizeof (Elf32_External_Rel);
++sreloc->reloc_count;
}
+ sreloc->_raw_size += sizeof (Elf32_External_Rel);
}
-
- if (info->shared)
- sreloc->_raw_size += sizeof (Elf32_External_Rel);
else
{
struct mips_elf_link_hash_entry *hmips;
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;
}
+
+ /* If this reloc is not a 16 bit call, and it has a global
+ symbol, then we will need the fn_stub if there is one.
+ References from a stub section do not count. */
+ if (h != NULL
+ && ELF32_R_TYPE (rel->r_info) != R_MIPS16_26
+ && strncmp (bfd_get_section_name (abfd, sec), FN_STUB,
+ sizeof FN_STUB - 1) != 0
+ && strncmp (bfd_get_section_name (abfd, sec), CALL_STUB,
+ sizeof CALL_STUB - 1) != 0
+ && strncmp (bfd_get_section_name (abfd, sec), CALL_FP_STUB,
+ sizeof CALL_FP_STUB - 1) != 0)
+ {
+ struct mips_elf_link_hash_entry *mh;
+
+ mh = (struct mips_elf_link_hash_entry *) h;
+ mh->need_fn_stub = true;
+ }
+ }
+
+ 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
s = bfd_get_section_by_name (dynobj, ".rel.dyn");
BFD_ASSERT (s != NULL);
+ if (s->_raw_size == 0)
+ {
+ /* Make room for a null element. */
+ s->_raw_size += sizeof (Elf32_External_Rel);
+ ++s->reloc_count;
+ }
s->_raw_size += hmips->mips_32_relocs * sizeof (Elf32_External_Rel);
}
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;
return true;
}
+/* This function is called after all the input files have been read,
+ and the input sections have been assigned to output sections. We
+ check for any mips16 stub sections that we can discard. */
+
+static boolean mips_elf_check_mips16_stubs
+ PARAMS ((struct mips_elf_link_hash_entry *, PTR));
+
+static boolean
+mips_elf_always_size_sections (output_bfd, info)
+ bfd *output_bfd;
+ struct bfd_link_info *info;
+{
+ if (info->relocateable
+ || ! mips_elf_hash_table (info)->mips16_stubs_seen)
+ return true;
+
+ mips_elf_link_hash_traverse (mips_elf_hash_table (info),
+ mips_elf_check_mips16_stubs,
+ (PTR) NULL);
+
+ return true;
+}
+
+/* Check the mips16 stubs for a particular symbol, and see if we can
+ discard them. */
+
+/*ARGSUSED*/
+static boolean
+mips_elf_check_mips16_stubs (h, data)
+ struct mips_elf_link_hash_entry *h;
+ PTR data;
+{
+ if (h->fn_stub != NULL
+ && ! h->need_fn_stub)
+ {
+ /* We don't need the fn_stub; the only references to this symbol
+ are 16 bit calls. Clobber the size to 0 to prevent it from
+ being included in the link. */
+ h->fn_stub->_raw_size = 0;
+ h->fn_stub->_cooked_size = 0;
+ h->fn_stub->flags &= ~ SEC_RELOC;
+ h->fn_stub->reloc_count = 0;
+ h->fn_stub->flags |= SEC_EXCLUDE;
+ }
+
+ if (h->call_stub != NULL
+ && h->root.other == STO_MIPS16)
+ {
+ /* We don't need the call_stub; this is a 16 bit function, so
+ calls from other 16 bit functions are OK. Clobber the size
+ to 0 to prevent it from being included in the link. */
+ h->call_stub->_raw_size = 0;
+ h->call_stub->_cooked_size = 0;
+ h->call_stub->flags &= ~ SEC_RELOC;
+ h->call_stub->reloc_count = 0;
+ h->call_stub->flags |= SEC_EXCLUDE;
+ }
+
+ if (h->call_fp_stub != NULL
+ && h->root.other == STO_MIPS16)
+ {
+ /* We don't need the call_stub; this is a 16 bit function, so
+ calls from other 16 bit functions are OK. Clobber the size
+ to 0 to prevent it from being included in the link. */
+ h->call_fp_stub->_raw_size = 0;
+ h->call_fp_stub->_cooked_size = 0;
+ h->call_fp_stub->flags &= ~ SEC_RELOC;
+ h->call_fp_stub->reloc_count = 0;
+ h->call_fp_stub->flags |= SEC_EXCLUDE;
+ }
+
+ return true;
+}
+
/* Set the sizes of the dynamic sections. */
static boolean
of the dynobj section names depend upon the input files. */
name = bfd_get_section_name (dynobj, s);
- if ((s->flags & SEC_IN_MEMORY) == 0)
+ if ((s->flags & SEC_LINKER_CREATED) == 0)
continue;
strip = false;
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;
asection *target;
/* If this relocation section applies to a read only
assert a DT_TEXTREL entry rather than testing whether
there exists a relocation to a read only section or
not. */
- target = bfd_get_section_by_name (output_bfd, name + 4);
- if ((target != NULL && (target->flags & SEC_READONLY) != 0)
- || strcmp (name, ".rel.dyn") == 0)
+ outname = bfd_get_section_name (output_bfd,
+ s->output_section);
+ target = bfd_get_section_by_name (output_bfd, outname + 4);
+ if ((target != NULL
+ && (target->flags & SEC_READONLY) != 0
+ && (target->flags & SEC_ALLOC) != 0)
+ || strcmp (outname, ".rel.dyn") == 0)
reltext = true;
/* We use the reloc_count field as a counter if we need
of .text section. So put a dummy. XXX */
s->_raw_size += MIPS_FUNCTION_STUB_SIZE;
}
+ else if (! info->shared
+ && ! mips_elf_hash_table (info)->use_rld_obj_head
+ && strncmp (name, ".rld_map", 8) == 0)
+ {
+ /* We add a room for __rld_map. It will be filled in by the
+ rtld to contain a pointer to the _r_debug structure. */
+ s->_raw_size += 4;
+ }
else if (SGI_COMPAT (output_bfd)
&& strncmp (name, ".compact_rel", 12) == 0)
s->_raw_size += mips_elf_hash_table (info)->compact_rel_size;
dynamic linker and used by the debugger. */
if (! info->shared)
{
- if (! bfd_elf32_add_dynamic_entry (info, DT_DEBUG, 0))
- return false;
+ if (SGI_COMPAT (output_bfd))
+ {
+ /* SGI object has the equivalence of DT_DEBUG in the
+ DT_MIPS_RLD_MAP entry. */
+ if (! bfd_elf32_add_dynamic_entry (info, DT_MIPS_RLD_MAP, 0))
+ return false;
+ }
+ else
+ if (! bfd_elf32_add_dynamic_entry (info, DT_DEBUG, 0))
+ return false;
}
if (reltext)
struct bfd_strtab_hash *dynstr;
struct mips_got_info *g;
+ c = 0;
if (elf_hash_table (info)->dynamic_sections_created)
{
if (SGI_COMPAT (output_bfd))
}
}
- s = bfd_get_section_by_name (dynobj, ".got");
- BFD_ASSERT (s != NULL);
- BFD_ASSERT (elf_section_data (s) != NULL);
- g = (struct mips_got_info *) elf_section_data (s)->tdata;
- BFD_ASSERT (g != NULL);
-
- /* If there are no global got symbols, fake the last symbol so for
- safety. */
- if (g->global_gotsym)
- g->global_gotsym += c;
- else
- g->global_gotsym = elf_hash_table (info)->dynsymcount - 1;
+ if (sgot != NULL)
+ {
+ BFD_ASSERT (elf_section_data (sgot) != NULL);
+ g = (struct mips_got_info *) elf_section_data (sgot)->tdata;
+ BFD_ASSERT (g != NULL);
+
+ /* If there are no global got symbols, fake the last symbol so
+ for safety. */
+ if (g->global_gotsym)
+ g->global_gotsym += c;
+ else
+ g->global_gotsym = elf_hash_table (info)->dynsymcount - 1;
+ }
}
return true;
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_value = mips_elf_hash_table (info)->procedure_count;
sym->st_shndx = SHN_ABS;
}
- else if (sym->st_shndx != SHN_UNDEF)
+ else if (sym->st_shndx != SHN_UNDEF && sym->st_shndx != SHN_ABS)
{
if (h->type == STT_FUNC)
sym->st_shndx = SHN_MIPS_TEXT;
}
}
+ if (SGI_COMPAT (output_bfd)
+ && ! info->shared)
+ {
+ if (! mips_elf_hash_table (info)->use_rld_obj_head
+ && strcmp (name, "__rld_map") == 0)
+ {
+ asection *s = bfd_get_section_by_name (dynobj, ".rld_map");
+ BFD_ASSERT (s != NULL);
+ sym->st_value = s->output_section->vma + s->output_offset;
+ bfd_put_32 (output_bfd, (bfd_vma) 0, s->contents);
+ if (mips_elf_hash_table (info)->rld_value == 0)
+ mips_elf_hash_table (info)->rld_value = sym->st_value;
+ }
+ else if (mips_elf_hash_table (info)->use_rld_obj_head
+ && strcmp (name, "__rld_obj_head") == 0)
+ {
+ asection *s = bfd_get_section_by_name (dynobj, ".rld_map");
+ BFD_ASSERT (s != NULL);
+ mips_elf_hash_table (info)->rld_value = sym->st_value;
+ }
+ }
+
+ /* If this is a mips16 symbol, force the value to be even. */
+ if (sym->st_other == STO_MIPS16
+ && (sym->st_value & 1) != 0)
+ --sym->st_value;
+
return true;
}
sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
sgot = bfd_get_section_by_name (dynobj, ".got");
- BFD_ASSERT (sgot != NULL);
-
- BFD_ASSERT (elf_section_data (sgot) != NULL);
- g = (struct mips_got_info *) elf_section_data (sgot)->tdata;
- BFD_ASSERT (g != NULL);
+ if (sgot == NULL)
+ g = NULL;
+ else
+ {
+ BFD_ASSERT (elf_section_data (sgot) != NULL);
+ g = (struct mips_got_info *) elf_section_data (sgot)->tdata;
+ BFD_ASSERT (g != NULL);
+ }
if (elf_hash_table (info)->dynamic_sections_created)
{
Elf32_External_Dyn *dyncon, *dynconend;
BFD_ASSERT (sdyn != NULL);
+ BFD_ASSERT (g != NULL);
dyncon = (Elf32_External_Dyn *) sdyn->contents;
dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size);
time ((time_t *) &dyn.d_un.d_val);
bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
break;
-
+
case DT_MIPS_ICHECKSUM:
/* XXX FIXME: */
break;
bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
break;
+ case DT_MIPS_RLD_MAP:
+ dyn.d_un.d_ptr = mips_elf_hash_table (info)->rld_value;
+ bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
+ break;
+
}
}
}
/* The first entry of the global offset table will be filled at
runtime. The second entry will be used by some runtime loaders.
This isn't the case of Irix rld. */
- if (sgot->_raw_size > 0)
+ if (sgot != NULL && sgot->_raw_size > 0)
{
bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents);
bfd_put_32 (output_bfd, (bfd_vma) 0x80000000, sgot->contents + 4);
}
- elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
+ if (sgot != NULL)
+ elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
{
asection *sdynsym;
sym.st_other = 0;
i = 0;
+ last = 0;
+ dindx = 0;
while ((name = *namep++) != NULL)
{
s = bfd_get_section_by_name (output_bfd, name);
+ sizeof (Elf32_External_compact_rel));
cpt.reserved0 = 0;
cpt.reserved1 = 0;
- bfd_elf32_swap_compact_rel_out (output_bfd, &cpt,
+ bfd_elf32_swap_compact_rel_out (output_bfd, &cpt,
((Elf32_External_compact_rel *)
s->contents));
/* Clean up a first relocation in .rel.dyn. */
s = bfd_get_section_by_name (dynobj, ".rel.dyn");
- if (s != NULL)
+ if (s != NULL && s->_raw_size > 0)
memset (s->contents, 0, sizeof (Elf32_External_Rel));
}
fall over on its own. */
}
else if ((*parent)->howto->special_function
- == mips_elf_gprel16_reloc)
+ == _bfd_mips_elf_gprel16_reloc)
{
/* bypass special_function call */
r = gprel16_with_gp (input_bfd, sym, *parent, input_section,
\f
/* ECOFF swapping routines. These are used when dealing with the
.mdebug section, which is in the ECOFF debugging format. */
-static const struct ecoff_debug_swap mips_elf_ecoff_debug_swap =
+static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap =
{
/* Symbol table magic number. */
magicSym,
_bfd_ecoff_swap_tir_out,
_bfd_ecoff_swap_rndx_out,
/* Function to read in symbolic data. */
- mips_elf_read_ecoff_info
+ _bfd_mips_elf_read_ecoff_info
};
\f
#define TARGET_LITTLE_SYM bfd_elf32_littlemips_vec
#define TARGET_BIG_NAME "elf32-bigmips"
#define ELF_ARCH bfd_arch_mips
#define ELF_MACHINE_CODE EM_MIPS
-#define ELF_MAXPAGESIZE 0x10000
+
+/* The SVR4 MIPS ABI says that this should be 0x10000, but Irix 5 uses
+ a value of 0x1000, and we are compatible. */
+#define ELF_MAXPAGESIZE 0x1000
+
#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
-#define elf_backend_object_p mips_elf_object_p
-#define elf_backend_section_from_shdr mips_elf_section_from_shdr
-#define elf_backend_fake_sections mips_elf_fake_sections
+#define elf_backend_object_p mips_elf32_object_p
+#define elf_backend_section_from_shdr mips_elf32_section_from_shdr
+#define elf_backend_fake_sections _bfd_mips_elf_fake_sections
#define elf_backend_section_from_bfd_section \
- mips_elf_section_from_bfd_section
-#define elf_backend_section_processing mips_elf_section_processing
-#define elf_backend_symbol_processing mips_elf_symbol_processing
+ _bfd_mips_elf_section_from_bfd_section
+#define elf_backend_section_processing mips_elf32_section_processing
+#define elf_backend_symbol_processing _bfd_mips_elf_symbol_processing
#define elf_backend_additional_program_headers \
mips_elf_additional_program_headers
#define elf_backend_modify_segment_map mips_elf_modify_segment_map
#define elf_backend_final_write_processing \
- mips_elf_final_write_processing
-#define elf_backend_ecoff_debug_swap &mips_elf_ecoff_debug_swap
-
-#define bfd_elf32_bfd_is_local_label mips_elf_is_local_label
-#define bfd_elf32_find_nearest_line mips_elf_find_nearest_line
+ _bfd_mips_elf_final_write_processing
+#define elf_backend_ecoff_debug_swap &mips_elf32_ecoff_debug_swap
+#define bfd_elf32_bfd_is_local_label_name \
+ mips_elf_is_local_label_name
+#define bfd_elf32_find_nearest_line _bfd_mips_elf_find_nearest_line
+#define bfd_elf32_set_section_contents _bfd_mips_elf_set_section_contents
#define bfd_elf32_bfd_link_hash_table_create \
mips_elf_link_hash_table_create
#define bfd_elf32_bfd_final_link mips_elf_final_link
#define bfd_elf32_bfd_copy_private_bfd_data \
- mips_elf_copy_private_bfd_data
+ _bfd_mips_elf_copy_private_bfd_data
#define bfd_elf32_bfd_merge_private_bfd_data \
- mips_elf_merge_private_bfd_data
-#define bfd_elf32_bfd_set_private_flags mips_elf_set_private_flags
+ _bfd_mips_elf_merge_private_bfd_data
+#define bfd_elf32_bfd_set_private_flags _bfd_mips_elf_set_private_flags
#define elf_backend_add_symbol_hook mips_elf_add_symbol_hook
#define elf_backend_create_dynamic_sections \
mips_elf_create_dynamic_sections
#define elf_backend_check_relocs mips_elf_check_relocs
#define elf_backend_adjust_dynamic_symbol \
mips_elf_adjust_dynamic_symbol
+#define elf_backend_always_size_sections \
+ mips_elf_always_size_sections
#define elf_backend_size_dynamic_sections \
mips_elf_size_dynamic_sections
#define elf_backend_relocate_section mips_elf_relocate_section
+#define elf_backend_link_output_symbol_hook \
+ mips_elf_link_output_symbol_hook
#define elf_backend_finish_dynamic_symbol \
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"