* 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:
Ian Lance Taylor
1996-12-17 18:58:59 +00:00
parent 69e2ff181d
commit e4f4813f9c
2 changed files with 257 additions and 8 deletions

View File

@ -1,5 +1,12 @@
Tue Dec 17 11:09:36 1996 Ian Lance Taylor <ian@cygnus.com> 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 * elf.c (bfd_elf_print_symbol): Print the st_other field if it is
not zero. not zero.

View File

@ -41,6 +41,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#define ECOFF_32 #define ECOFF_32
#include "ecoffswap.h" #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 static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
PARAMS ((bfd *, bfd_reloc_code_real_type)); PARAMS ((bfd *, bfd_reloc_code_real_type));
static void mips_info_to_howto_rel 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)); Elf_Internal_Rela *, bfd_byte *, bfd_vma));
static void mips_elf_relocate_global_got static void mips_elf_relocate_global_got
PARAMS ((bfd *, Elf_Internal_Rela *, bfd_byte *, bfd_vma)); 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 static boolean mips_elf_adjust_dynindx
PARAMS ((struct elf_link_hash_entry *, PTR)); PARAMS ((struct elf_link_hash_entry *, PTR));
static boolean mips_elf_relocate_section static boolean mips_elf_relocate_section
PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)); 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 static boolean mips_elf_create_dynamic_sections
PARAMS ((bfd *, struct bfd_link_info *)); PARAMS ((bfd *, struct bfd_link_info *));
static boolean mips_elf_create_compact_rel_section static boolean mips_elf_create_compact_rel_section
@ -296,7 +303,9 @@ enum reloc_type
R_MIPS_INSERT_B, R_MIPS_DELETE, R_MIPS_INSERT_B, R_MIPS_DELETE,
R_MIPS_HIGHER, R_MIPS_HIGHEST, R_MIPS_HIGHER, R_MIPS_HIGHEST,
R_MIPS_CALL_HI16, R_MIPS_CALL_LO16, 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[] = static reloc_howto_type elf_mips_howto_table[] =
@ -538,8 +547,23 @@ static reloc_howto_type elf_mips_howto_table[] =
0x000007c4, /* dst_mask */ 0x000007c4, /* dst_mask */
false), /* pcrel_offset */ false), /* pcrel_offset */
/* A 64 bit relocation. Presumably not used in 32 bit ELF. */ /* A 64 bit relocation. This is used in 32 bit ELF when addresses
{ R_MIPS_64 }, 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. */ /* Displacement in the global offset table. */
/* FIXME: Not handled correctly. */ /* FIXME: Not handled correctly. */
@ -667,6 +691,25 @@ static reloc_howto_type elf_mips_howto_table[] =
false) /* pcrel_offset */ 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 /* 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 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 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; 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. */ /* A mapping from BFD reloc types to MIPS ELF reloc types. */
struct elf_reloc_map { 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_16, R_MIPS_16 },
{ BFD_RELOC_32, R_MIPS_32 }, { BFD_RELOC_32, R_MIPS_32 },
{ BFD_RELOC_CTOR, R_MIPS_32 }, { BFD_RELOC_CTOR, R_MIPS_32 },
{ BFD_RELOC_64, R_MIPS_64 },
{ BFD_RELOC_MIPS_JMP, R_MIPS_26 }, { BFD_RELOC_MIPS_JMP, R_MIPS_26 },
{ BFD_RELOC_HI16_S, R_MIPS_HI16 }, { BFD_RELOC_HI16_S, R_MIPS_HI16 },
{ BFD_RELOC_LO16, R_MIPS_LO16 }, { 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) if (mips_reloc_map[i].bfd_reloc_val == code)
return &elf_mips_howto_table[(int) mips_reloc_map[i].elf_reloc_val]; 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; return NULL;
} }
@ -1282,8 +1404,13 @@ mips_info_to_howto_rel (abfd, cache_ptr, dst)
unsigned int r_type; unsigned int r_type;
r_type = ELF32_R_TYPE (dst->r_info); r_type = ELF32_R_TYPE (dst->r_info);
if (r_type == R_MIPS16_26)
cache_ptr->howto = &elf_mips16_jump_howto;
else
{
BFD_ASSERT (r_type < (unsigned int) R_MIPS_max); BFD_ASSERT (r_type < (unsigned int) R_MIPS_max);
cache_ptr->howto = &elf_mips_howto_table[r_type]; cache_ptr->howto = &elf_mips_howto_table[r_type];
}
/* The addend for a GPREL16 or LITERAL relocation comes from the GP /* The addend for a GPREL16 or LITERAL relocation comes from the GP
value for the object file. We get the addend now, rather than 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; 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; return true;
} }
@ -4225,12 +4358,15 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
bfd_reloc_status_type r; bfd_reloc_status_type r;
r_type = ELF32_R_TYPE (rel->r_info); 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); bfd_set_error (bfd_error_bad_value);
return false; return false;
} }
if (r_type != R_MIPS16_26)
howto = elf_mips_howto_table + r_type; howto = elf_mips_howto_table + r_type;
else
howto = &elf_mips16_jump_howto;
if (dynobj != NULL if (dynobj != NULL
&& (r_type == R_MIPS_CALL16 && (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, /* If this is HI16 or GOT16 with an associated LO16,
adjust the addend accordingly. Otherwise, just adjust the addend accordingly. Otherwise, just
relocate. */ 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, r = _bfd_relocate_contents (howto, input_bfd,
addend, addend,
contents + rel->r_offset); contents + rel->r_offset);
@ -4394,6 +4534,10 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
value. */ value. */
if (ELF_ST_TYPE (sym->st_info) != STT_SECTION) if (ELF_ST_TYPE (sym->st_info) != STT_SECTION)
relocation += sym->st_value; relocation += sym->st_value;
/* mips16 text labels should be treated as odd. */
if (sym->st_other == STO_MIPS16)
++relocation;
} }
else else
{ {
@ -4678,6 +4822,78 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
contents, rel->r_offset, contents, rel->r_offset,
relocation, addend); 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 else
r = _bfd_final_link_relocate (howto, input_bfd, input_section, r = _bfd_final_link_relocate (howto, input_bfd, input_section,
contents, rel->r_offset, contents, rel->r_offset,
@ -4764,6 +4980,25 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
return true; 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. */ /* 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; return true;
} }
@ -6440,6 +6680,8 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap =
#define elf_backend_size_dynamic_sections \ #define elf_backend_size_dynamic_sections \
mips_elf_size_dynamic_sections mips_elf_size_dynamic_sections
#define elf_backend_relocate_section mips_elf_relocate_section #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 \ #define elf_backend_finish_dynamic_symbol \
mips_elf_finish_dynamic_symbol mips_elf_finish_dynamic_symbol
#define elf_backend_finish_dynamic_sections \ #define elf_backend_finish_dynamic_sections \