#include "bfd.h"
#include "sysdep.h"
#include "libbfd.h"
#include "bfdlink.h"
#include "genlink.h"
#include "elf-bfd.h"
#include "elfxx-mips.h"
#include "elf/mips.h"
#include "coff/sym.h"
#include "coff/symconst.h"
#include "coff/internal.h"
#include "coff/ecoff.h"
#include "coff/mips.h"
#define ECOFF_SIGNED_32
#include "ecoffswap.h"
static bfd_reloc_status_type gprel32_with_gp
(bfd *, asymbol *, arelent *, asection *, bfd_boolean, void *, bfd_vma);
static bfd_reloc_status_type mips_elf_gprel32_reloc
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
static bfd_reloc_status_type mips32_64bit_reloc
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
(bfd *, bfd_reloc_code_real_type);
static reloc_howto_type *mips_elf32_rtype_to_howto
(unsigned int, bfd_boolean);
static void mips_info_to_howto_rel
(bfd *, arelent *, Elf_Internal_Rela *);
static void mips_info_to_howto_rela
(bfd *, arelent *, Elf_Internal_Rela *);
static bfd_boolean mips_elf_sym_is_global
(bfd *, asymbol *);
static bfd_boolean mips_elf32_object_p
(bfd *);
static bfd_boolean mips_elf_is_local_label_name
(bfd *, const char *);
static bfd_reloc_status_type mips16_jump_reloc
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
static bfd_reloc_status_type mips16_gprel_reloc
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
static bfd_reloc_status_type mips_elf_final_gp
(bfd *, asymbol *, bfd_boolean, char **, bfd_vma *);
static bfd_boolean mips_elf_assign_gp
(bfd *, bfd_vma *);
static bfd_boolean elf32_mips_grok_prstatus
(bfd *, Elf_Internal_Note *);
static bfd_boolean elf32_mips_grok_psinfo
(bfd *, Elf_Internal_Note *);
static irix_compat_t elf32_mips_irix_compat
(bfd *);
extern const bfd_target bfd_elf32_bigmips_vec;
extern const bfd_target bfd_elf32_littlemips_vec;
#define ABI_N32_P(abfd) \
((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI2) != 0)
#define SGI_COMPAT(abfd) \
(elf32_mips_irix_compat (abfd) != ict_none)
#define MIPS_RESERVED_GOTNO (2)
#define MINUS_ONE (((bfd_vma)0) - 1)
static reloc_howto_type elf_mips_howto_table_rel[] =
{
HOWTO (R_MIPS_NONE,
0,
0,
0,
FALSE,
0,
complain_overflow_dont,
_bfd_mips_elf_generic_reloc,
"R_MIPS_NONE",
FALSE,
0,
0,
FALSE),
HOWTO (R_MIPS_16,
0,
2,
16,
FALSE,
0,
complain_overflow_signed,
_bfd_mips_elf_generic_reloc,
"R_MIPS_16",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
HOWTO (R_MIPS_32,
0,
2,
32,
FALSE,
0,
complain_overflow_dont,
_bfd_mips_elf_generic_reloc,
"R_MIPS_32",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (R_MIPS_REL32,
0,
2,
32,
FALSE,
0,
complain_overflow_dont,
_bfd_mips_elf_generic_reloc,
"R_MIPS_REL32",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (R_MIPS_26,
2,
2,
26,
FALSE,
0,
complain_overflow_dont,
_bfd_mips_elf_generic_reloc,
"R_MIPS_26",
TRUE,
0x03ffffff,
0x03ffffff,
FALSE),
HOWTO (R_MIPS_HI16,
16,
2,
16,
FALSE,
0,
complain_overflow_dont,
_bfd_mips_elf_hi16_reloc,
"R_MIPS_HI16",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
HOWTO (R_MIPS_LO16,
0,
2,
16,
FALSE,
0,
complain_overflow_dont,
_bfd_mips_elf_lo16_reloc,
"R_MIPS_LO16",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
HOWTO (R_MIPS_GPREL16,
0,
2,
16,
FALSE,
0,
complain_overflow_signed,
_bfd_mips_elf32_gprel16_reloc,
"R_MIPS_GPREL16",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
HOWTO (R_MIPS_LITERAL,
0,
2,
16,
FALSE,
0,
complain_overflow_signed,
_bfd_mips_elf32_gprel16_reloc,
"R_MIPS_LITERAL",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
HOWTO (R_MIPS_GOT16,
0,
2,
16,
FALSE,
0,
complain_overflow_signed,
_bfd_mips_elf_got16_reloc,
"R_MIPS_GOT16",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
HOWTO (R_MIPS_PC16,
0,
2,
16,
TRUE,
0,
complain_overflow_signed,
_bfd_mips_elf_generic_reloc,
"R_MIPS_PC16",
TRUE,
0x0000ffff,
0x0000ffff,
TRUE),
HOWTO (R_MIPS_CALL16,
0,
2,
16,
FALSE,
0,
complain_overflow_signed,
_bfd_mips_elf_generic_reloc,
"R_MIPS_CALL16",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
HOWTO (R_MIPS_GPREL32,
0,
2,
32,
FALSE,
0,
complain_overflow_dont,
mips_elf_gprel32_reloc,
"R_MIPS_GPREL32",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
EMPTY_HOWTO (13),
EMPTY_HOWTO (14),
EMPTY_HOWTO (15),
HOWTO (R_MIPS_SHIFT5,
0,
2,
5,
FALSE,
6,
complain_overflow_bitfield,
_bfd_mips_elf_generic_reloc,
"R_MIPS_SHIFT5",
TRUE,
0x000007c0,
0x000007c0,
FALSE),
HOWTO (R_MIPS_SHIFT6,
0,
2,
6,
FALSE,
6,
complain_overflow_bitfield,
_bfd_mips_elf_generic_reloc,
"R_MIPS_SHIFT6",
TRUE,
0x000007c4,
0x000007c4,
FALSE),
HOWTO (R_MIPS_64,
0,
4,
64,
FALSE,
0,
complain_overflow_dont,
mips32_64bit_reloc,
"R_MIPS_64",
TRUE,
MINUS_ONE,
MINUS_ONE,
FALSE),
HOWTO (R_MIPS_GOT_DISP,
0,
2,
16,
FALSE,
0,
complain_overflow_signed,
_bfd_mips_elf_generic_reloc,
"R_MIPS_GOT_DISP",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
HOWTO (R_MIPS_GOT_PAGE,
0,
2,
16,
FALSE,
0,
complain_overflow_signed,
_bfd_mips_elf_generic_reloc,
"R_MIPS_GOT_PAGE",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
HOWTO (R_MIPS_GOT_OFST,
0,
2,
16,
FALSE,
0,
complain_overflow_signed,
_bfd_mips_elf_generic_reloc,
"R_MIPS_GOT_OFST",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
HOWTO (R_MIPS_GOT_HI16,
0,
2,
16,
FALSE,
0,
complain_overflow_dont,
_bfd_mips_elf_generic_reloc,
"R_MIPS_GOT_HI16",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
HOWTO (R_MIPS_GOT_LO16,
0,
2,
16,
FALSE,
0,
complain_overflow_dont,
_bfd_mips_elf_generic_reloc,
"R_MIPS_GOT_LO16",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
HOWTO (R_MIPS_SUB,
0,
4,
64,
FALSE,
0,
complain_overflow_dont,
_bfd_mips_elf_generic_reloc,
"R_MIPS_SUB",
TRUE,
MINUS_ONE,
MINUS_ONE,
FALSE),
EMPTY_HOWTO (R_MIPS_INSERT_A),
EMPTY_HOWTO (R_MIPS_INSERT_B),
EMPTY_HOWTO (R_MIPS_DELETE),
HOWTO (R_MIPS_HIGHER,
0,
2,
16,
FALSE,
0,
complain_overflow_dont,
_bfd_mips_elf_generic_reloc,
"R_MIPS_HIGHER",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
HOWTO (R_MIPS_HIGHEST,
0,
2,
16,
FALSE,
0,
complain_overflow_dont,
_bfd_mips_elf_generic_reloc,
"R_MIPS_HIGHEST",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
HOWTO (R_MIPS_CALL_HI16,
0,
2,
16,
FALSE,
0,
complain_overflow_dont,
_bfd_mips_elf_generic_reloc,
"R_MIPS_CALL_HI16",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
HOWTO (R_MIPS_CALL_LO16,
0,
2,
16,
FALSE,
0,
complain_overflow_dont,
_bfd_mips_elf_generic_reloc,
"R_MIPS_CALL_LO16",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
HOWTO (R_MIPS_SCN_DISP,
0,
2,
32,
FALSE,
0,
complain_overflow_dont,
_bfd_mips_elf_generic_reloc,
"R_MIPS_SCN_DISP",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
EMPTY_HOWTO (R_MIPS_REL16),
EMPTY_HOWTO (R_MIPS_ADD_IMMEDIATE),
EMPTY_HOWTO (R_MIPS_PJUMP),
EMPTY_HOWTO (R_MIPS_RELGOT),
HOWTO (R_MIPS_JALR,
0,
2,
32,
FALSE,
0,
complain_overflow_dont,
_bfd_mips_elf_generic_reloc,
"R_MIPS_JALR",
FALSE,
0x00000000,
0x00000000,
FALSE),
HOWTO (R_MIPS_TLS_DTPMOD32,
0,
2,
32,
FALSE,
0,
complain_overflow_dont,
_bfd_mips_elf_generic_reloc,
"R_MIPS_TLS_DTPMOD32",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
HOWTO (R_MIPS_TLS_DTPREL32,
0,
2,
32,
FALSE,
0,
complain_overflow_dont,
_bfd_mips_elf_generic_reloc,
"R_MIPS_TLS_DTPREL32",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
EMPTY_HOWTO (R_MIPS_TLS_DTPMOD64),
EMPTY_HOWTO (R_MIPS_TLS_DTPREL64),
HOWTO (R_MIPS_TLS_GD,
0,
2,
16,
FALSE,
0,
complain_overflow_signed,
_bfd_mips_elf_generic_reloc,
"R_MIPS_TLS_GD",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
HOWTO (R_MIPS_TLS_LDM,
0,
2,
16,
FALSE,
0,
complain_overflow_signed,
_bfd_mips_elf_generic_reloc,
"R_MIPS_TLS_LDM",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
HOWTO (R_MIPS_TLS_DTPREL_HI16,
0,
2,
16,
FALSE,
0,
complain_overflow_signed,
_bfd_mips_elf_generic_reloc,
"R_MIPS_TLS_DTPREL_HI16",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
HOWTO (R_MIPS_TLS_DTPREL_LO16,
0,
2,
16,
FALSE,
0,
complain_overflow_signed,
_bfd_mips_elf_generic_reloc,
"R_MIPS_TLS_DTPREL_LO16",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
HOWTO (R_MIPS_TLS_GOTTPREL,
0,
2,
16,
FALSE,
0,
complain_overflow_signed,
_bfd_mips_elf_generic_reloc,
"R_MIPS_TLS_GOTTPREL",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
HOWTO (R_MIPS_TLS_TPREL32,
0,
2,
32,
FALSE,
0,
complain_overflow_dont,
_bfd_mips_elf_generic_reloc,
"R_MIPS_TLS_TPREL32",
TRUE,
0xffffffff,
0xffffffff,
FALSE),
EMPTY_HOWTO (R_MIPS_TLS_TPREL64),
HOWTO (R_MIPS_TLS_TPREL_HI16,
0,
2,
16,
FALSE,
0,
complain_overflow_signed,
_bfd_mips_elf_generic_reloc,
"R_MIPS_TLS_TPREL_HI16",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
HOWTO (R_MIPS_TLS_TPREL_LO16,
0,
2,
16,
FALSE,
0,
complain_overflow_signed,
_bfd_mips_elf_generic_reloc,
"R_MIPS_TLS_TPREL_LO16",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
};
static reloc_howto_type elf_mips_ctor64_howto =
HOWTO (R_MIPS_64,
0,
4,
32,
FALSE,
0,
complain_overflow_signed,
mips32_64bit_reloc,
"R_MIPS_64",
TRUE,
0xffffffff,
0xffffffff,
FALSE);
static reloc_howto_type elf_mips16_howto_table_rel[] =
{
HOWTO (R_MIPS16_26,
2,
2,
26,
FALSE,
0,
complain_overflow_dont,
mips16_jump_reloc,
"R_MIPS16_26",
TRUE,
0x3ffffff,
0x3ffffff,
FALSE),
HOWTO (R_MIPS16_GPREL,
0,
2,
16,
FALSE,
0,
complain_overflow_signed,
mips16_gprel_reloc,
"R_MIPS16_GPREL",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
EMPTY_HOWTO (R_MIPS16_GOT16),
EMPTY_HOWTO (R_MIPS16_CALL16),
HOWTO (R_MIPS16_HI16,
16,
2,
16,
FALSE,
0,
complain_overflow_dont,
_bfd_mips_elf_hi16_reloc,
"R_MIPS16_HI16",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
HOWTO (R_MIPS16_LO16,
0,
2,
16,
FALSE,
0,
complain_overflow_dont,
_bfd_mips_elf_lo16_reloc,
"R_MIPS16_LO16",
TRUE,
0x0000ffff,
0x0000ffff,
FALSE),
};
static reloc_howto_type elf_mips_gnu_rel16_s2 =
HOWTO (R_MIPS_GNU_REL16_S2,
2,
2,
16,
TRUE,
0,
complain_overflow_signed,
_bfd_mips_elf_generic_reloc,
"R_MIPS_GNU_REL16_S2",
TRUE,
0xffff,
0xffff,
TRUE);
static reloc_howto_type elf_mips_gnu_pcrel32 =
HOWTO (R_MIPS_PC32,
0,
2,
32,
TRUE,
0,
complain_overflow_signed,
_bfd_mips_elf_generic_reloc,
"R_MIPS_PC32",
TRUE,
0xffffffff,
0xffffffff,
TRUE);
static reloc_howto_type elf_mips_gnu_vtinherit_howto =
HOWTO (R_MIPS_GNU_VTINHERIT,
0,
2,
0,
FALSE,
0,
complain_overflow_dont,
NULL,
"R_MIPS_GNU_VTINHERIT",
FALSE,
0,
0,
FALSE);
static reloc_howto_type elf_mips_gnu_vtentry_howto =
HOWTO (R_MIPS_GNU_VTENTRY,
0,
2,
0,
FALSE,
0,
complain_overflow_dont,
_bfd_elf_rel_vtable_reloc_fn,
"R_MIPS_GNU_VTENTRY",
FALSE,
0,
0,
FALSE);
static bfd_boolean
mips_elf_assign_gp (bfd *output_bfd, bfd_vma *pgp)
{
unsigned int count;
asymbol **sym;
unsigned int i;
*pgp = _bfd_get_gp_value (output_bfd);
if (*pgp)
return TRUE;
count = bfd_get_symcount (output_bfd);
sym = bfd_get_outsymbols (output_bfd);
if (sym == NULL)
i = count;
else
{
for (i = 0; i < count; i++, sym++)
{
register const char *name;
name = bfd_asymbol_name (*sym);
if (*name == '_' && strcmp (name, "_gp") == 0)
{
*pgp = bfd_asymbol_value (*sym);
_bfd_set_gp_value (output_bfd, *pgp);
break;
}
}
}
if (i >= count)
{
*pgp = 4;
_bfd_set_gp_value (output_bfd, *pgp);
return FALSE;
}
return TRUE;
}
static bfd_reloc_status_type
mips_elf_final_gp (bfd *output_bfd, asymbol *symbol, bfd_boolean relocatable,
char **error_message, bfd_vma *pgp)
{
if (bfd_is_und_section (symbol->section)
&& ! relocatable)
{
*pgp = 0;
return bfd_reloc_undefined;
}
*pgp = _bfd_get_gp_value (output_bfd);
if (*pgp == 0
&& (! relocatable
|| (symbol->flags & BSF_SECTION_SYM) != 0))
{
if (relocatable)
{
*pgp = symbol->section->output_section->vma + 0x4000;
_bfd_set_gp_value (output_bfd, *pgp);
}
else if (!mips_elf_assign_gp (output_bfd, pgp))
{
*error_message =
(char *) _("GP relative relocation when _gp not defined");
return bfd_reloc_dangerous;
}
}
return bfd_reloc_ok;
}
bfd_reloc_status_type
_bfd_mips_elf32_gprel16_reloc (bfd *abfd, arelent *reloc_entry,
asymbol *symbol, void *data,
asection *input_section, bfd *output_bfd,
char **error_message)
{
bfd_boolean relocatable;
bfd_reloc_status_type ret;
bfd_vma gp;
if (reloc_entry->howto->type == R_MIPS_LITERAL
&& output_bfd != NULL
&& (symbol->flags & BSF_SECTION_SYM) == 0
&& (symbol->flags & BSF_LOCAL) != 0)
{
*error_message = (char *)
_("literal relocation occurs for an external symbol");
return bfd_reloc_outofrange;
}
if (output_bfd != NULL)
relocatable = TRUE;
else
{
relocatable = FALSE;
output_bfd = symbol->section->output_section->owner;
}
ret = mips_elf_final_gp (output_bfd, symbol, relocatable, error_message,
&gp);
if (ret != bfd_reloc_ok)
return ret;
return _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry,
input_section, relocatable,
data, gp);
}
static bfd_reloc_status_type
mips_elf_gprel32_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
void *data, asection *input_section, bfd *output_bfd,
char **error_message)
{
bfd_boolean relocatable;
bfd_reloc_status_type ret;
bfd_vma gp;
if (output_bfd != NULL
&& (symbol->flags & BSF_SECTION_SYM) == 0
&& (symbol->flags & BSF_LOCAL) != 0)
{
*error_message = (char *)
_("32bits gp relative relocation occurs for an external symbol");
return bfd_reloc_outofrange;
}
if (output_bfd != NULL)
relocatable = TRUE;
else
{
relocatable = FALSE;
output_bfd = symbol->section->output_section->owner;
}
ret = mips_elf_final_gp (output_bfd, symbol, relocatable,
error_message, &gp);
if (ret != bfd_reloc_ok)
return ret;
return gprel32_with_gp (abfd, symbol, reloc_entry, input_section,
relocatable, data, gp);
}
static bfd_reloc_status_type
gprel32_with_gp (bfd *abfd, asymbol *symbol, arelent *reloc_entry,
asection *input_section, bfd_boolean relocatable,
void *data, bfd_vma gp)
{
bfd_vma relocation;
bfd_vma val;
if (bfd_is_com_section (symbol->section))
relocation = 0;
else
relocation = symbol->value;
relocation += symbol->section->output_section->vma;
relocation += symbol->section->output_offset;
if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
return bfd_reloc_outofrange;
val = reloc_entry->addend;
if (reloc_entry->howto->partial_inplace)
val += bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address);
if (! relocatable
|| (symbol->flags & BSF_SECTION_SYM) != 0)
val += relocation - gp;
if (reloc_entry->howto->partial_inplace)
bfd_put_32 (abfd, val, (bfd_byte *) data + reloc_entry->address);
else
reloc_entry->addend = val;
if (relocatable)
reloc_entry->address += input_section->output_offset;
return bfd_reloc_ok;
}
static bfd_reloc_status_type
mips32_64bit_reloc (bfd *abfd, arelent *reloc_entry,
asymbol *symbol ATTRIBUTE_UNUSED,
void *data, asection *input_section,
bfd *output_bfd, char **error_message)
{
bfd_reloc_status_type r;
arelent reloc32;
unsigned long val;
bfd_size_type addr;
reloc32 = *reloc_entry;
if (bfd_big_endian (abfd))
reloc32.address += 4;
reloc32.howto = &elf_mips_howto_table_rel[R_MIPS_32];
r = bfd_perform_relocation (abfd, &reloc32, data, input_section,
output_bfd, error_message);
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;
}
static bfd_reloc_status_type
mips16_jump_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
asymbol *symbol, void *data ATTRIBUTE_UNUSED,
asection *input_section, bfd *output_bfd,
char **error_message ATTRIBUTE_UNUSED)
{
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;
}
{
static bfd_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;
}
static bfd_reloc_status_type
mips16_gprel_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
void *data, asection *input_section, bfd *output_bfd,
char **error_message)
{
bfd_boolean relocatable;
bfd_reloc_status_type ret;
bfd_byte *location;
bfd_vma gp;
if (output_bfd != NULL
&& (symbol->flags & BSF_SECTION_SYM) == 0
&& (symbol->flags & BSF_LOCAL) != 0)
{
reloc_entry->address += input_section->output_offset;
return bfd_reloc_ok;
}
if (output_bfd != NULL)
relocatable = TRUE;
else
{
relocatable = FALSE;
output_bfd = symbol->section->output_section->owner;
}
ret = mips_elf_final_gp (output_bfd, symbol, relocatable, error_message,
&gp);
if (ret != bfd_reloc_ok)
return ret;
location = (bfd_byte *) data + reloc_entry->address;
_bfd_mips16_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, FALSE,
location);
ret = _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry,
input_section, relocatable,
data, gp);
_bfd_mips16_elf_reloc_shuffle (abfd, reloc_entry->howto->type, !relocatable,
location);
return ret;
}
struct elf_reloc_map {
bfd_reloc_code_real_type bfd_val;
enum elf_mips_reloc_type elf_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_64, R_MIPS_64 },
{ BFD_RELOC_MIPS_JMP, R_MIPS_26 },
{ BFD_RELOC_HI16_S, R_MIPS_HI16 },
{ BFD_RELOC_LO16, R_MIPS_LO16 },
{ BFD_RELOC_GPREL16, R_MIPS_GPREL16 },
{ BFD_RELOC_MIPS_LITERAL, R_MIPS_LITERAL },
{ BFD_RELOC_MIPS_GOT16, R_MIPS_GOT16 },
{ BFD_RELOC_16_PCREL, R_MIPS_PC16 },
{ BFD_RELOC_MIPS_CALL16, R_MIPS_CALL16 },
{ BFD_RELOC_GPREL32, R_MIPS_GPREL32 },
{ BFD_RELOC_MIPS_GOT_HI16, R_MIPS_GOT_HI16 },
{ BFD_RELOC_MIPS_GOT_LO16, R_MIPS_GOT_LO16 },
{ BFD_RELOC_MIPS_CALL_HI16, R_MIPS_CALL_HI16 },
{ BFD_RELOC_MIPS_CALL_LO16, R_MIPS_CALL_LO16 },
{ BFD_RELOC_MIPS_SUB, R_MIPS_SUB },
{ BFD_RELOC_MIPS_GOT_PAGE, R_MIPS_GOT_PAGE },
{ BFD_RELOC_MIPS_GOT_OFST, R_MIPS_GOT_OFST },
{ BFD_RELOC_MIPS_GOT_DISP, R_MIPS_GOT_DISP },
{ BFD_RELOC_MIPS_TLS_DTPMOD32, R_MIPS_TLS_DTPMOD32 },
{ BFD_RELOC_MIPS_TLS_DTPREL32, R_MIPS_TLS_DTPREL32 },
{ BFD_RELOC_MIPS_TLS_DTPMOD64, R_MIPS_TLS_DTPMOD64 },
{ BFD_RELOC_MIPS_TLS_DTPREL64, R_MIPS_TLS_DTPREL64 },
{ BFD_RELOC_MIPS_TLS_GD, R_MIPS_TLS_GD },
{ BFD_RELOC_MIPS_TLS_LDM, R_MIPS_TLS_LDM },
{ BFD_RELOC_MIPS_TLS_DTPREL_HI16, R_MIPS_TLS_DTPREL_HI16 },
{ BFD_RELOC_MIPS_TLS_DTPREL_LO16, R_MIPS_TLS_DTPREL_LO16 },
{ BFD_RELOC_MIPS_TLS_GOTTPREL, R_MIPS_TLS_GOTTPREL },
{ BFD_RELOC_MIPS_TLS_TPREL32, R_MIPS_TLS_TPREL32 },
{ BFD_RELOC_MIPS_TLS_TPREL64, R_MIPS_TLS_TPREL64 },
{ BFD_RELOC_MIPS_TLS_TPREL_HI16, R_MIPS_TLS_TPREL_HI16 },
{ BFD_RELOC_MIPS_TLS_TPREL_LO16, R_MIPS_TLS_TPREL_LO16 }
};
static const struct elf_reloc_map mips16_reloc_map[] =
{
{ BFD_RELOC_MIPS16_JMP, R_MIPS16_26 - R_MIPS16_min },
{ BFD_RELOC_MIPS16_GPREL, R_MIPS16_GPREL - R_MIPS16_min },
{ BFD_RELOC_MIPS16_HI16_S, R_MIPS16_HI16 - R_MIPS16_min },
{ BFD_RELOC_MIPS16_LO16, R_MIPS16_LO16 - R_MIPS16_min },
};
static reloc_howto_type *
bfd_elf32_bfd_reloc_type_lookup (bfd *abfd, bfd_reloc_code_real_type code)
{
unsigned int i;
reloc_howto_type *howto_table = elf_mips_howto_table_rel;
reloc_howto_type *howto16_table = elf_mips16_howto_table_rel;
for (i = 0; i < sizeof (mips_reloc_map) / sizeof (struct elf_reloc_map);
i++)
{
if (mips_reloc_map[i].bfd_val == code)
return &howto_table[(int) mips_reloc_map[i].elf_val];
}
for (i = 0; i < sizeof (mips16_reloc_map) / sizeof (struct elf_reloc_map);
i++)
{
if (mips16_reloc_map[i].bfd_val == code)
return &howto16_table[(int) mips16_reloc_map[i].elf_val];
}
switch (code)
{
default:
bfd_set_error (bfd_error_bad_value);
return NULL;
case BFD_RELOC_CTOR:
if ((elf_elfheader (abfd)->e_flags & (E_MIPS_ABI_O64
| E_MIPS_ABI_EABI64)) != 0)
return &elf_mips_ctor64_howto;
else
return &howto_table[(int) R_MIPS_32];
case BFD_RELOC_VTABLE_INHERIT:
return &elf_mips_gnu_vtinherit_howto;
case BFD_RELOC_VTABLE_ENTRY:
return &elf_mips_gnu_vtentry_howto;
case BFD_RELOC_16_PCREL_S2:
return &elf_mips_gnu_rel16_s2;
case BFD_RELOC_32_PCREL:
return &elf_mips_gnu_pcrel32;
}
}
static reloc_howto_type *
mips_elf32_rtype_to_howto (unsigned int r_type,
bfd_boolean rela_p ATTRIBUTE_UNUSED)
{
switch (r_type)
{
case R_MIPS_GNU_VTINHERIT:
return &elf_mips_gnu_vtinherit_howto;
case R_MIPS_GNU_VTENTRY:
return &elf_mips_gnu_vtentry_howto;
case R_MIPS_GNU_REL16_S2:
return &elf_mips_gnu_rel16_s2;
case R_MIPS_PC32:
return &elf_mips_gnu_pcrel32;
default:
if (r_type >= R_MIPS16_min && r_type < R_MIPS16_max)
return &elf_mips16_howto_table_rel[r_type - R_MIPS16_min];
BFD_ASSERT (r_type < (unsigned int) R_MIPS_max);
return &elf_mips_howto_table_rel[r_type];
}
}
static void
mips_info_to_howto_rel (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst)
{
unsigned int r_type;
r_type = ELF32_R_TYPE (dst->r_info);
cache_ptr->howto = mips_elf32_rtype_to_howto (r_type, FALSE);
if (((*cache_ptr->sym_ptr_ptr)->flags & BSF_SECTION_SYM) != 0
&& (r_type == (unsigned int) R_MIPS_GPREL16
|| r_type == (unsigned int) R_MIPS_LITERAL))
cache_ptr->addend = elf_gp (abfd);
}
static void
mips_info_to_howto_rela (bfd *abfd, arelent *cache_ptr, Elf_Internal_Rela *dst)
{
mips_info_to_howto_rel (abfd, cache_ptr, dst);
}
static bfd_boolean
mips_elf_sym_is_global (bfd *abfd ATTRIBUTE_UNUSED, asymbol *sym)
{
if (SGI_COMPAT (abfd))
return (sym->flags & BSF_SECTION_SYM) == 0;
else
return ((sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0
|| bfd_is_und_section (bfd_get_section (sym))
|| bfd_is_com_section (bfd_get_section (sym)));
}
static bfd_boolean
mips_elf32_object_p (bfd *abfd)
{
unsigned long mach;
if (SGI_COMPAT (abfd))
elf_bad_symtab (abfd) = TRUE;
if (ABI_N32_P (abfd))
return FALSE;
mach = _bfd_elf_mips_mach (elf_elfheader (abfd)->e_flags);
bfd_default_set_arch_mach (abfd, bfd_arch_mips, mach);
return TRUE;
}
static bfd_boolean
mips_elf_is_local_label_name (bfd *abfd, const char *name)
{
if (name[0] == '$')
return TRUE;
return _bfd_elf_is_local_label_name (abfd, name);
}
static bfd_boolean
elf32_mips_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
{
int offset;
unsigned int size;
switch (note->descsz)
{
default:
return FALSE;
case 256:
elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24);
offset = 72;
size = 180;
break;
}
return _bfd_elfcore_make_pseudosection (abfd, ".reg",
size, note->descpos + offset);
}
static bfd_boolean
elf32_mips_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
{
switch (note->descsz)
{
default:
return FALSE;
case 128:
elf_tdata (abfd)->core_program
= _bfd_elfcore_strndup (abfd, note->descdata + 32, 16);
elf_tdata (abfd)->core_command
= _bfd_elfcore_strndup (abfd, note->descdata + 48, 80);
}
{
char *command = elf_tdata (abfd)->core_command;
int n = strlen (command);
if (0 < n && command[n - 1] == ' ')
command[n - 1] = '\0';
}
return TRUE;
}
static irix_compat_t
elf32_mips_irix_compat (bfd *abfd)
{
if ((abfd->xvec == &bfd_elf32_bigmips_vec)
|| (abfd->xvec == &bfd_elf32_littlemips_vec))
return ict_irix5;
else
return ict_none;
}
static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = {
magicSym,
4,
sizeof (struct hdr_ext),
sizeof (struct dnr_ext),
sizeof (struct pdr_ext),
sizeof (struct sym_ext),
sizeof (struct opt_ext),
sizeof (struct fdr_ext),
sizeof (struct rfd_ext),
sizeof (struct ext_ext),
ecoff_swap_hdr_in,
ecoff_swap_dnr_in,
ecoff_swap_pdr_in,
ecoff_swap_sym_in,
ecoff_swap_opt_in,
ecoff_swap_fdr_in,
ecoff_swap_rfd_in,
ecoff_swap_ext_in,
_bfd_ecoff_swap_tir_in,
_bfd_ecoff_swap_rndx_in,
ecoff_swap_hdr_out,
ecoff_swap_dnr_out,
ecoff_swap_pdr_out,
ecoff_swap_sym_out,
ecoff_swap_opt_out,
ecoff_swap_fdr_out,
ecoff_swap_rfd_out,
ecoff_swap_ext_out,
_bfd_ecoff_swap_tir_out,
_bfd_ecoff_swap_rndx_out,
_bfd_mips_elf_read_ecoff_info
};
#define ELF_ARCH bfd_arch_mips
#define ELF_MACHINE_CODE EM_MIPS
#define elf_backend_collect TRUE
#define elf_backend_type_change_ok TRUE
#define elf_backend_can_gc_sections TRUE
#define elf_info_to_howto mips_info_to_howto_rela
#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_elf32_object_p
#define elf_backend_symbol_processing _bfd_mips_elf_symbol_processing
#define elf_backend_section_processing _bfd_mips_elf_section_processing
#define elf_backend_section_from_shdr _bfd_mips_elf_section_from_shdr
#define elf_backend_fake_sections _bfd_mips_elf_fake_sections
#define elf_backend_section_from_bfd_section \
_bfd_mips_elf_section_from_bfd_section
#define elf_backend_add_symbol_hook _bfd_mips_elf_add_symbol_hook
#define elf_backend_link_output_symbol_hook \
_bfd_mips_elf_link_output_symbol_hook
#define elf_backend_create_dynamic_sections \
_bfd_mips_elf_create_dynamic_sections
#define elf_backend_check_relocs _bfd_mips_elf_check_relocs
#define elf_backend_adjust_dynamic_symbol \
_bfd_mips_elf_adjust_dynamic_symbol
#define elf_backend_always_size_sections \
_bfd_mips_elf_always_size_sections
#define elf_backend_size_dynamic_sections \
_bfd_mips_elf_size_dynamic_sections
#define elf_backend_relocate_section _bfd_mips_elf_relocate_section
#define elf_backend_finish_dynamic_symbol \
_bfd_mips_elf_finish_dynamic_symbol
#define elf_backend_finish_dynamic_sections \
_bfd_mips_elf_finish_dynamic_sections
#define elf_backend_final_write_processing \
_bfd_mips_elf_final_write_processing
#define elf_backend_additional_program_headers \
_bfd_mips_elf_additional_program_headers
#define elf_backend_modify_segment_map _bfd_mips_elf_modify_segment_map
#define elf_backend_gc_mark_hook _bfd_mips_elf_gc_mark_hook
#define elf_backend_gc_sweep_hook _bfd_mips_elf_gc_sweep_hook
#define elf_backend_copy_indirect_symbol \
_bfd_mips_elf_copy_indirect_symbol
#define elf_backend_hide_symbol _bfd_mips_elf_hide_symbol
#define elf_backend_grok_prstatus elf32_mips_grok_prstatus
#define elf_backend_grok_psinfo elf32_mips_grok_psinfo
#define elf_backend_ecoff_debug_swap &mips_elf32_ecoff_debug_swap
#define elf_backend_got_header_size (4 * MIPS_RESERVED_GOTNO)
#define elf_backend_may_use_rel_p 1
#define elf_backend_may_use_rela_p 0
#define elf_backend_default_use_rela_p 0
#define elf_backend_sign_extend_vma TRUE
#define elf_backend_discard_info _bfd_mips_elf_discard_info
#define elf_backend_ignore_discarded_relocs \
_bfd_mips_elf_ignore_discarded_relocs
#define elf_backend_mips_irix_compat elf32_mips_irix_compat
#define elf_backend_mips_rtype_to_howto mips_elf32_rtype_to_howto
#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_find_inliner_info _bfd_mips_elf_find_inliner_info
#define bfd_elf32_new_section_hook _bfd_mips_elf_new_section_hook
#define bfd_elf32_set_section_contents _bfd_mips_elf_set_section_contents
#define bfd_elf32_bfd_get_relocated_section_contents \
_bfd_elf_mips_get_relocated_section_contents
#define bfd_elf32_bfd_link_hash_table_create \
_bfd_mips_elf_link_hash_table_create
#define bfd_elf32_bfd_final_link _bfd_mips_elf_final_link
#define bfd_elf32_bfd_merge_private_bfd_data \
_bfd_mips_elf_merge_private_bfd_data
#define bfd_elf32_bfd_set_private_flags _bfd_mips_elf_set_private_flags
#define bfd_elf32_bfd_print_private_bfd_data \
_bfd_mips_elf_print_private_bfd_data
#define TARGET_LITTLE_SYM bfd_elf32_littlemips_vec
#define TARGET_LITTLE_NAME "elf32-littlemips"
#define TARGET_BIG_SYM bfd_elf32_bigmips_vec
#define TARGET_BIG_NAME "elf32-bigmips"
#define ELF_MAXPAGESIZE 0x1000
#include "elf32-target.h"
#undef TARGET_LITTLE_SYM
#undef TARGET_LITTLE_NAME
#undef TARGET_BIG_SYM
#undef TARGET_BIG_NAME
#undef ELF_MAXPAGESIZE
#define TARGET_LITTLE_SYM bfd_elf32_tradlittlemips_vec
#define TARGET_LITTLE_NAME "elf32-tradlittlemips"
#define TARGET_BIG_SYM bfd_elf32_tradbigmips_vec
#define TARGET_BIG_NAME "elf32-tradbigmips"
#define ELF_MAXPAGESIZE 0x10000
#define elf32_bed elf32_tradbed
#include "elf32-target.h"