* elf32-mips.c (mips_elf_add_symbol_hook): Add 1 to the value of a
mips16 symbol during the link. (mips_elf_finish_dynamic_symbol): Subtract 1 from the value of a mips16 symbol. (mips_elf_link_output_symbol_hook): New static function. (elf_backend_link_output_symbol_hook): Define.
This commit is contained in:
parent
69e2ff181d
commit
e4f4813f9c
2 changed files with 257 additions and 8 deletions
|
@ -1,5 +1,12 @@
|
|||
Tue Dec 17 11:09:36 1996 Ian Lance Taylor <ian@cygnus.com>
|
||||
|
||||
* elf32-mips.c (mips_elf_add_symbol_hook): Add 1 to the value of a
|
||||
mips16 symbol during the link.
|
||||
(mips_elf_finish_dynamic_symbol): Subtract 1 from the value of a
|
||||
mips16 symbol.
|
||||
(mips_elf_link_output_symbol_hook): New static function.
|
||||
(elf_backend_link_output_symbol_hook): Define.
|
||||
|
||||
* elf.c (bfd_elf_print_symbol): Print the st_other field if it is
|
||||
not zero.
|
||||
|
||||
|
|
258
bfd/elf32-mips.c
258
bfd/elf32-mips.c
|
@ -41,6 +41,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|||
#define ECOFF_32
|
||||
#include "ecoffswap.h"
|
||||
|
||||
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
|
||||
|
@ -78,11 +80,16 @@ static void mips_elf_relocate_got_local
|
|||
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 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
|
||||
|
@ -296,7 +303,9 @@ enum reloc_type
|
|||
R_MIPS_INSERT_B, R_MIPS_DELETE,
|
||||
R_MIPS_HIGHER, R_MIPS_HIGHEST,
|
||||
R_MIPS_CALL_HI16, R_MIPS_CALL_LO16,
|
||||
R_MIPS_max
|
||||
R_MIPS_max,
|
||||
/* This reloc is used for the mips16. */
|
||||
R_MIPS16_26 = 100
|
||||
};
|
||||
|
||||
static reloc_howto_type elf_mips_howto_table[] =
|
||||
|
@ -538,8 +547,23 @@ static reloc_howto_type elf_mips_howto_table[] =
|
|||
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. */
|
||||
|
@ -667,6 +691,25 @@ static reloc_howto_type elf_mips_howto_table[] =
|
|||
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 */
|
||||
|
||||
/* 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
|
||||
|
@ -1226,6 +1269,78 @@ gprel32_with_gp (abfd, symbol, reloc_entry, input_section, relocateable, data,
|
|||
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. */
|
||||
abort ();
|
||||
}
|
||||
|
||||
/* A mapping from BFD reloc types to MIPS ELF reloc types. */
|
||||
|
||||
struct elf_reloc_map {
|
||||
|
@ -1239,6 +1354,7 @@ static CONST struct elf_reloc_map mips_reloc_map[] =
|
|||
{ BFD_RELOC_16, R_MIPS_16 },
|
||||
{ BFD_RELOC_32, R_MIPS_32 },
|
||||
{ BFD_RELOC_CTOR, 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 },
|
||||
|
@ -1268,6 +1384,12 @@ bfd_elf32_bfd_reloc_type_lookup (abfd, code)
|
|||
if (mips_reloc_map[i].bfd_reloc_val == code)
|
||||
return &elf_mips_howto_table[(int) mips_reloc_map[i].elf_reloc_val];
|
||||
}
|
||||
|
||||
/* Special handling for the MIPS16 jump, since it is a made up reloc
|
||||
type with a large value. */
|
||||
if (code == BFD_RELOC_MIPS16_JMP)
|
||||
return &elf_mips16_jump_howto;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1282,8 +1404,13 @@ mips_info_to_howto_rel (abfd, cache_ptr, dst)
|
|||
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];
|
||||
if (r_type == R_MIPS16_26)
|
||||
cache_ptr->howto = &elf_mips16_jump_howto;
|
||||
else
|
||||
{
|
||||
BFD_ASSERT (r_type < (unsigned int) R_MIPS_max);
|
||||
cache_ptr->howto = &elf_mips_howto_table[r_type];
|
||||
}
|
||||
|
||||
/* The addend for a GPREL16 or LITERAL relocation comes from the GP
|
||||
value for the object file. We get the addend now, rather than
|
||||
|
@ -3036,6 +3163,12 @@ mips_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp)
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -4225,12 +4358,15 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
|
|||
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 < 0 || r_type >= (int) R_MIPS_max) && r_type != R_MIPS16_26)
|
||||
{
|
||||
bfd_set_error (bfd_error_bad_value);
|
||||
return false;
|
||||
}
|
||||
howto = elf_mips_howto_table + r_type;
|
||||
if (r_type != R_MIPS16_26)
|
||||
howto = elf_mips_howto_table + r_type;
|
||||
else
|
||||
howto = &elf_mips16_jump_howto;
|
||||
|
||||
if (dynobj != NULL
|
||||
&& (r_type == R_MIPS_CALL16
|
||||
|
@ -4334,7 +4470,11 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
|
|||
/* 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);
|
||||
|
@ -4394,6 +4534,10 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
|
|||
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
|
||||
{
|
||||
|
@ -4678,6 +4822,78 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
|
|||
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
|
||||
&& ((h != NULL && h->other == STO_MIPS16)
|
||||
|| (sym != NULL && sym->st_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. */
|
||||
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
|
||||
contents, rel->r_offset,
|
||||
relocation, addend);
|
||||
if (r == bfd_reloc_ok)
|
||||
{
|
||||
unsigned long insn;
|
||||
|
||||
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 ((h != NULL && h->other != STO_MIPS16)
|
||||
|| (sym != NULL && sym->st_other != STO_MIPS16))
|
||||
insn |= 0x400;
|
||||
bfd_put_16 (input_bfd, insn, contents + rel->r_offset);
|
||||
}
|
||||
}
|
||||
else
|
||||
r = _bfd_final_link_relocate (howto, input_bfd, input_section,
|
||||
contents, rel->r_offset,
|
||||
|
@ -4764,6 +4980,25 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* This hook function is called before the linker writes out a global
|
||||
symbol. This is 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 (sym->st_other == STO_MIPS16
|
||||
&& (sym->st_value & 1) != 0)
|
||||
--sym->st_value;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Functions for the dynamic linker. */
|
||||
|
||||
|
@ -5845,6 +6080,11 @@ mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym)
|
|||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
@ -6440,6 +6680,8 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap =
|
|||
#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 \
|
||||
|
|
Loading…
Reference in a new issue