bfd/
* reloc.c (BFD_RELOC_MIPS16_GOT16, BFD_RELOC_MIPS16_CALL16): Declare. * libbfd.h, bfd-in2.h: Regenerate. * elf32-mips.c (elf_mips16_howto_table_rel): Fill in reserved R_MIPS16_GOT16 and R_MIPS16_CALL16 entries. (mips16_reloc_map): Add mappings. * elf64-mips.c (mips16_elf64_howto_table_rel): Fill in reserved R_MIPS16_GOT16 and R_MIPS16_CALL16 entries. (mips16_elf64_howto_table_rela): Likewise. (mips16_reloc_map): Add mappings. * elfn32-mips.c (elf_mips16_howto_table_rel): Fill in reserved R_MIPS16_GOT16 and R_MIPS16_CALL16 entries. (elf_mips16_howto_table_rela): Likewise. (mips16_reloc_map): Add mappings. * elfxx-mips.c (mips_elf_create_shadow_symbol): New function. (section_allows_mips16_refs_p): Likewise. (mips16_stub_symndx): Likewise. (mips_elf_check_mips16_stubs): Treat the data argument as a bfd_link_info. Mark every dynamic symbol as needing MIPS16 stubs and create a "shadow" symbol for the original MIPS16 definition. (mips16_reloc_p, got16_reloc_p, call16_reloc_p, hi16_reloc_p) (lo16_reloc_p, mips16_call_reloc_p): New functions. (_bfd_mips16_elf_reloc_unshuffle): Use mips16_reloc_p to generalize relocation checks. (_bfd_mips16_elf_reloc_shuffle): Likewise. (_bfd_mips_elf_lo16_reloc): Handle R_MIPS16_GOT16. (mips_elf_got16_entry): Add comment. (mips_elf_calculate_relocation): Use hi16_reloc_p, lo16_reloc_p, mips16_call_reloc_p, call16_reloc_p and got16_reloc_p to generalize relocation checks. Use section_allows_mips16_refs_p instead of mips16_stub_section_p. Handle R_MIPS16_CALL16 and R_MIPS16_GOT16, allowing the former to refer directly to a MIPS16 function if its stub is not needed. (mips16_stub_section_p): Delete. (_bfd_mips_elf_symbol_processing): Convert odd-valued function symbols into even MIPS16 symbols. (mips_elf_add_lo16_rel_addend): Use mips16_reloc_p to generalize a relocation check. (_bfd_mips_elf_check_relocs): Calculate "bed" and "rel_end" earlier in the function. Use mips16_stub_symndx to identify the target function. Avoid out-of-bounds accesses when the stub has no relocations; report an error instead. Use section_allows_mips16_refs_p instead of mips16_stub_section_p. Use mips16_call_reloc_p and got16_reloc_p to generalize relocation checks. Handle R_MIPS16_CALL16 and R_MIPS16_GOT16. Don't create dynamic relocations for absolute references to __gnu_local_gp. (_bfd_mips_elf_always_size_sections): Pass a bfd_link_info as the argument to mips_elf_check_mips16_stubs. Generalize comment. (_bfd_mips_elf_relocate_section): Use hi16_reloc_p and got16_reloc_p to generalize relocation checks. (_bfd_mips_elf_finish_dynamic_symbol): If a dynamic MIPS16 function symbol has a non-MIPS16 stub, redirect the symbol to the stub. Fix an overly long line. Don't give dynamic symbols type STO_MIPS16. (_bfd_mips_elf_gc_sweep_hook): Handle R_MIPS16_CALL16 and R_MIPS16_GOT16. gas/ * config/tc-mips.c (mips16_reloc_p, got16_reloc_p, hi16_reloc_p) (lo16_reloc_p): New functions. (reloc_needs_lo_p): Use hi16_reloc_p and got16_reloc_p to generalize relocation checks. (matching_lo_reloc): New function. (fixup_has_matching_lo_p): Use it. (mips16_mark_labels): Don't clobber a symbol's visibility. (append_insn): Use hi16_reloc_p and lo16_reloc_p. (mips16_ip): Handle BFD_RELOC_MIPS16_GOT16 and BFD_RELOC_MIPS16_CALL16. (md_apply_fix): Likewise. (mips16_percent_op): Add %got and %call16. (mips_frob_file): Use got16_reloc_p to generalize relocation checks. Use matching_lo_reloc. (mips_force_relocation): Use hi16_reloc_p and lo16_reloc_p to generalize relocation checks. (mips_fix_adjustable): Use lo16_reloc_p to generalize relocation checks. gas/testsuite/ * gas/mips/elf-rel8-mips16.d, gas/mips/elf-rel8-mips16.s, * gas/mips/elf-rel9-mips16.d, gas/mips/elf-rel9-mips16.s, * gas/mips/elf-rel13-mips16.d, gas/mips/elf-rel13-mips16.s: New tests. * gas/mips/mips.exp: Run them. ld/testsuite/ * ld-mips-elf/mips16-local-stubs-1.d: Remove stub_for_h3, which was only referenced by the .pdr section, and was not actually needed by code. * ld-mips-elf/mips16-intermix.d: Remove unused static function stubs. * ld-mips-elf/mips16-pic-1a.s, ld-mips-elf/mips16-pic-1b.s, ld-mips-elf/mips16-pic-1-dummy.s, ld-mips-elf/mips16-pic-1.dd, ld-mips-elf/mips16-pic-1.gd, ld-mips-elf/mips16-pic-1.inc, ld-mips-elf/mips16-pic-1.ld, ld-mips-elf/mips16-pic-2a.s, ld-mips-elf/mips16-pic-2b.s, ld-mips-elf/mips16-pic-2.ad, ld-mips-elf/mips16-pic-2.dd, ld-mips-elf/mips16-pic-2.gd, ld-mips-elf/mips16-pic-2.nd, ld-mips-elf/mips16-pic-2.rd: New tests. * ld-mips-elf/mips-elf.exp: Run them.
This commit is contained in:
parent
d57a3c85f6
commit
738e53487d
36 changed files with 2862 additions and 145 deletions
348
bfd/elfxx-mips.c
348
bfd/elfxx-mips.c
|
@ -525,8 +525,6 @@ static bfd_boolean mips_elf_sort_hash_table_f
|
|||
(struct mips_elf_link_hash_entry *, void *);
|
||||
static bfd_vma mips_elf_high
|
||||
(bfd_vma);
|
||||
static bfd_boolean mips16_stub_section_p
|
||||
(bfd *, asection *);
|
||||
static bfd_boolean mips_elf_create_dynamic_relocation
|
||||
(bfd *, struct bfd_link_info *, const Elf_Internal_Rela *,
|
||||
struct mips_elf_link_hash_entry *, asection *, bfd_vma,
|
||||
|
@ -1148,17 +1146,104 @@ mips_elf_create_procedure_table (void *handle, bfd *abfd,
|
|||
free (sv);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* We're about to redefine H. Create a symbol to represent H's
|
||||
current value and size, to help make the disassembly easier
|
||||
to read. */
|
||||
|
||||
static bfd_boolean
|
||||
mips_elf_create_shadow_symbol (struct bfd_link_info *info,
|
||||
struct mips_elf_link_hash_entry *h,
|
||||
const char *prefix)
|
||||
{
|
||||
struct bfd_link_hash_entry *bh;
|
||||
struct elf_link_hash_entry *elfh;
|
||||
const char *name;
|
||||
asection *s;
|
||||
bfd_vma value;
|
||||
|
||||
/* Read the symbol's value. */
|
||||
BFD_ASSERT (h->root.root.type == bfd_link_hash_defined
|
||||
|| h->root.root.type == bfd_link_hash_defweak);
|
||||
s = h->root.root.u.def.section;
|
||||
value = h->root.root.u.def.value;
|
||||
|
||||
/* Create a new symbol. */
|
||||
name = ACONCAT ((prefix, h->root.root.root.string, NULL));
|
||||
bh = NULL;
|
||||
if (!_bfd_generic_link_add_one_symbol (info, s->owner, name,
|
||||
BSF_LOCAL, s, value, NULL,
|
||||
TRUE, FALSE, &bh))
|
||||
return FALSE;
|
||||
|
||||
/* Make it local and copy the other attributes from H. */
|
||||
elfh = (struct elf_link_hash_entry *) bh;
|
||||
elfh->type = ELF_ST_INFO (STB_LOCAL, ELF_ST_TYPE (h->root.type));
|
||||
elfh->other = h->root.other;
|
||||
elfh->size = h->root.size;
|
||||
elfh->forced_local = 1;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Return TRUE if relocations in SECTION can refer directly to a MIPS16
|
||||
function rather than to a hard-float stub. */
|
||||
|
||||
static bfd_boolean
|
||||
section_allows_mips16_refs_p (asection *section)
|
||||
{
|
||||
const char *name;
|
||||
|
||||
name = bfd_get_section_name (section->owner, section);
|
||||
return (FN_STUB_P (name)
|
||||
|| CALL_STUB_P (name)
|
||||
|| CALL_FP_STUB_P (name)
|
||||
|| strcmp (name, ".pdr") == 0);
|
||||
}
|
||||
|
||||
/* [RELOCS, RELEND) are the relocations against SEC, which is a MIPS16
|
||||
stub section of some kind. Return the R_SYMNDX of the target
|
||||
function, or 0 if we can't decide which function that is. */
|
||||
|
||||
static unsigned long
|
||||
mips16_stub_symndx (asection *sec, const Elf_Internal_Rela *relocs,
|
||||
const Elf_Internal_Rela *relend)
|
||||
{
|
||||
const Elf_Internal_Rela *rel;
|
||||
|
||||
/* Trust the first R_MIPS_NONE relocation, if any. */
|
||||
for (rel = relocs; rel < relend; rel++)
|
||||
if (ELF_R_TYPE (sec->owner, rel->r_info) == R_MIPS_NONE)
|
||||
return ELF_R_SYM (sec->owner, rel->r_info);
|
||||
|
||||
/* Otherwise trust the first relocation, whatever its kind. This is
|
||||
the traditional behavior. */
|
||||
if (relocs < relend)
|
||||
return ELF_R_SYM (sec->owner, relocs->r_info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check the mips16 stubs for a particular symbol, and see if we can
|
||||
discard them. */
|
||||
|
||||
static bfd_boolean
|
||||
mips_elf_check_mips16_stubs (struct mips_elf_link_hash_entry *h,
|
||||
void *data ATTRIBUTE_UNUSED)
|
||||
mips_elf_check_mips16_stubs (struct mips_elf_link_hash_entry *h, void *data)
|
||||
{
|
||||
struct bfd_link_info *info;
|
||||
|
||||
info = (struct bfd_link_info *) data;
|
||||
if (h->root.root.type == bfd_link_hash_warning)
|
||||
h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link;
|
||||
|
||||
/* Dynamic symbols must use the standard call interface, in case other
|
||||
objects try to call them. */
|
||||
if (h->fn_stub != NULL
|
||||
&& h->root.dynindx != -1)
|
||||
{
|
||||
mips_elf_create_shadow_symbol (info, h, ".mips16.");
|
||||
h->need_fn_stub = TRUE;
|
||||
}
|
||||
|
||||
if (h->fn_stub != NULL
|
||||
&& ! h->need_fn_stub)
|
||||
{
|
||||
|
@ -1257,8 +1342,18 @@ mips_elf_check_mips16_stubs (struct mips_elf_link_hash_entry *h,
|
|||
let R = (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2)
|
||||
((R & 0x1f0000) << 5) | ((R & 0x3e00000) >> 5) | (R & 0xffff)
|
||||
|
||||
R_MIPS16_GPREL is used for GP-relative addressing in mips16
|
||||
mode. A typical instruction will have a format like this:
|
||||
The table below lists the other MIPS16 instruction relocations.
|
||||
Each one is calculated in the same way as the non-MIPS16 relocation
|
||||
given on the right, but using the extended MIPS16 layout of 16-bit
|
||||
immediate fields:
|
||||
|
||||
R_MIPS16_GPREL R_MIPS_GPREL16
|
||||
R_MIPS16_GOT16 R_MIPS_GOT16
|
||||
R_MIPS16_CALL16 R_MIPS_CALL16
|
||||
R_MIPS16_HI16 R_MIPS_HI16
|
||||
R_MIPS16_LO16 R_MIPS_LO16
|
||||
|
||||
A typical instruction will have a format like this:
|
||||
|
||||
+--------------+--------------------------------+
|
||||
| EXTEND | Imm 10:5 | Imm 15:11 |
|
||||
|
@ -1269,28 +1364,65 @@ mips_elf_check_mips16_stubs (struct mips_elf_link_hash_entry *h,
|
|||
EXTEND is the five bit value 11110. Major is the instruction
|
||||
opcode.
|
||||
|
||||
This is handled exactly like R_MIPS_GPREL16, except that the
|
||||
addend is retrieved and stored as shown in this diagram; that
|
||||
is, the Imm fields above replace the V-rel16 field.
|
||||
All we need to do here is shuffle the bits appropriately.
|
||||
As above, the two 16-bit halves must be swapped on a
|
||||
little-endian system. */
|
||||
|
||||
All we need to do here is shuffle the bits appropriately. As
|
||||
above, the two 16-bit halves must be swapped on a
|
||||
little-endian system.
|
||||
static inline bfd_boolean
|
||||
mips16_reloc_p (int r_type)
|
||||
{
|
||||
switch (r_type)
|
||||
{
|
||||
case R_MIPS16_26:
|
||||
case R_MIPS16_GPREL:
|
||||
case R_MIPS16_GOT16:
|
||||
case R_MIPS16_CALL16:
|
||||
case R_MIPS16_HI16:
|
||||
case R_MIPS16_LO16:
|
||||
return TRUE;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bfd_boolean
|
||||
got16_reloc_p (int r_type)
|
||||
{
|
||||
return r_type == R_MIPS_GOT16 || r_type == R_MIPS16_GOT16;
|
||||
}
|
||||
|
||||
static inline bfd_boolean
|
||||
call16_reloc_p (int r_type)
|
||||
{
|
||||
return r_type == R_MIPS_CALL16 || r_type == R_MIPS16_CALL16;
|
||||
}
|
||||
|
||||
static inline bfd_boolean
|
||||
hi16_reloc_p (int r_type)
|
||||
{
|
||||
return r_type == R_MIPS_HI16 || r_type == R_MIPS16_HI16;
|
||||
}
|
||||
|
||||
static inline bfd_boolean
|
||||
lo16_reloc_p (int r_type)
|
||||
{
|
||||
return r_type == R_MIPS_LO16 || r_type == R_MIPS16_LO16;
|
||||
}
|
||||
|
||||
static inline bfd_boolean
|
||||
mips16_call_reloc_p (int r_type)
|
||||
{
|
||||
return r_type == R_MIPS16_26 || r_type == R_MIPS16_CALL16;
|
||||
}
|
||||
|
||||
R_MIPS16_HI16 and R_MIPS16_LO16 are used in mips16 mode to
|
||||
access data when neither GP-relative nor PC-relative addressing
|
||||
can be used. They are handled like R_MIPS_HI16 and R_MIPS_LO16,
|
||||
except that the addend is retrieved and stored as shown above
|
||||
for R_MIPS16_GPREL.
|
||||
*/
|
||||
void
|
||||
_bfd_mips16_elf_reloc_unshuffle (bfd *abfd, int r_type,
|
||||
bfd_boolean jal_shuffle, bfd_byte *data)
|
||||
{
|
||||
bfd_vma extend, insn, val;
|
||||
|
||||
if (r_type != R_MIPS16_26 && r_type != R_MIPS16_GPREL
|
||||
&& r_type != R_MIPS16_HI16 && r_type != R_MIPS16_LO16)
|
||||
if (!mips16_reloc_p (r_type))
|
||||
return;
|
||||
|
||||
/* Pick up the mips16 extend instruction and the real instruction. */
|
||||
|
@ -1316,8 +1448,7 @@ _bfd_mips16_elf_reloc_shuffle (bfd *abfd, int r_type,
|
|||
{
|
||||
bfd_vma extend, insn, val;
|
||||
|
||||
if (r_type != R_MIPS16_26 && r_type != R_MIPS16_GPREL
|
||||
&& r_type != R_MIPS16_HI16 && r_type != R_MIPS16_LO16)
|
||||
if (!mips16_reloc_p (r_type))
|
||||
return;
|
||||
|
||||
val = bfd_get_32 (abfd, data);
|
||||
|
@ -1446,7 +1577,7 @@ _bfd_mips_elf_hi16_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry,
|
|||
return bfd_reloc_ok;
|
||||
}
|
||||
|
||||
/* A howto special_function for REL R_MIPS_GOT16 relocations. This is just
|
||||
/* A howto special_function for REL R_MIPS*_GOT16 relocations. This is just
|
||||
like any other 16-bit relocation when applied to global symbols, but is
|
||||
treated in the same as R_MIPS_HI16 when applied to local symbols. */
|
||||
|
||||
|
@ -1495,13 +1626,15 @@ _bfd_mips_elf_lo16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol,
|
|||
|
||||
hi = mips_hi16_list;
|
||||
|
||||
/* R_MIPS_GOT16 relocations are something of a special case. We
|
||||
want to install the addend in the same way as for a R_MIPS_HI16
|
||||
/* R_MIPS*_GOT16 relocations are something of a special case. We
|
||||
want to install the addend in the same way as for a R_MIPS*_HI16
|
||||
relocation (with a rightshift of 16). However, since GOT16
|
||||
relocations can also be used with global symbols, their howto
|
||||
has a rightshift of 0. */
|
||||
if (hi->rel.howto->type == R_MIPS_GOT16)
|
||||
hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MIPS_HI16, FALSE);
|
||||
else if (hi->rel.howto->type == R_MIPS16_GOT16)
|
||||
hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MIPS16_HI16, FALSE);
|
||||
|
||||
/* VALLO is a signed 16-bit number. Bias it by 0x8000 so that any
|
||||
carry or borrow will induce a change of +1 or -1 in the high part. */
|
||||
|
@ -2620,7 +2753,7 @@ mips_elf_got_page (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
|
|||
return index;
|
||||
}
|
||||
|
||||
/* Find a local GOT entry for an R_MIPS_GOT16 relocation against VALUE.
|
||||
/* Find a local GOT entry for an R_MIPS*_GOT16 relocation against VALUE.
|
||||
EXTERNAL is true if the relocation was against a global symbol
|
||||
that has been forced local. */
|
||||
|
||||
|
@ -2641,6 +2774,9 @@ mips_elf_got16_entry (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
|
|||
|
||||
g = mips_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
|
||||
|
||||
/* It doesn't matter whether the original relocation was R_MIPS_GOT16,
|
||||
R_MIPS16_GOT16, R_MIPS_CALL16, etc. The format of the entry is the
|
||||
same in all cases. */
|
||||
entry = mips_elf_create_local_got_entry (abfd, info, ibfd, g, sgot,
|
||||
value, 0, NULL, R_MIPS_GOT16);
|
||||
if (entry)
|
||||
|
@ -4216,8 +4352,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
|
|||
{
|
||||
/* Relocations against _gp_disp are permitted only with
|
||||
R_MIPS_HI16 and R_MIPS_LO16 relocations. */
|
||||
if (r_type != R_MIPS_HI16 && r_type != R_MIPS_LO16
|
||||
&& r_type != R_MIPS16_HI16 && r_type != R_MIPS16_LO16)
|
||||
if (!hi16_reloc_p (r_type) && !lo16_reloc_p (r_type))
|
||||
return bfd_reloc_notsupported;
|
||||
|
||||
gp_disp_p = TRUE;
|
||||
|
@ -4291,15 +4426,24 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
|
|||
target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (h->root.other);
|
||||
}
|
||||
|
||||
/* If this is a 32- or 64-bit call to a 16-bit function with a stub, we
|
||||
need to redirect the call to the stub, unless we're already *in*
|
||||
a stub. */
|
||||
if (r_type != R_MIPS16_26 && !info->relocatable
|
||||
&& ((h != NULL && h->fn_stub != NULL)
|
||||
/* If this is a reference to a 16-bit function with a stub, we need
|
||||
to redirect the relocation to the stub unless:
|
||||
|
||||
(a) the relocation is for a MIPS16 JAL;
|
||||
|
||||
(b) the relocation is for a MIPS16 PIC call, and there are no
|
||||
non-MIPS16 uses of the GOT slot; or
|
||||
|
||||
(c) the section allows direct references to MIPS16 functions. */
|
||||
if (r_type != R_MIPS16_26
|
||||
&& !info->relocatable
|
||||
&& ((h != NULL
|
||||
&& h->fn_stub != NULL
|
||||
&& (r_type != R_MIPS16_CALL16 || h->need_fn_stub))
|
||||
|| (local_p
|
||||
&& elf_tdata (input_bfd)->local_stubs != NULL
|
||||
&& elf_tdata (input_bfd)->local_stubs[r_symndx] != NULL))
|
||||
&& !mips16_stub_section_p (input_bfd, input_section))
|
||||
&& !section_allows_mips16_refs_p (input_section))
|
||||
{
|
||||
/* This is a 32- or 64-bit call to a 16-bit function. We should
|
||||
have already noticed that we were going to need the
|
||||
|
@ -4317,7 +4461,9 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
|
|||
target_is_16_bit_code_p = FALSE;
|
||||
}
|
||||
/* If this is a 16-bit call to a 32- or 64-bit function with a stub, we
|
||||
need to redirect the call to the stub. */
|
||||
need to redirect the call to the stub. Note that we specifically
|
||||
exclude R_MIPS16_CALL16 from this behavior; indirect calls should
|
||||
use an indirect stub instead. */
|
||||
else if (r_type == R_MIPS16_26 && !info->relocatable
|
||||
&& ((h != NULL && (h->call_stub != NULL || h->call_fp_stub != NULL))
|
||||
|| (local_p
|
||||
|
@ -4389,6 +4535,8 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
|
|||
break;
|
||||
/* Fall through. */
|
||||
|
||||
case R_MIPS16_CALL16:
|
||||
case R_MIPS16_GOT16:
|
||||
case R_MIPS_CALL16:
|
||||
case R_MIPS_GOT16:
|
||||
case R_MIPS_GOT_DISP:
|
||||
|
@ -4414,7 +4562,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
|
|||
if (htab->is_vxworks
|
||||
&& (r_type == R_MIPS_CALL_HI16
|
||||
|| r_type == R_MIPS_CALL_LO16
|
||||
|| r_type == R_MIPS_CALL16))
|
||||
|| call16_reloc_p (r_type)))
|
||||
{
|
||||
BFD_ASSERT (addend == 0);
|
||||
BFD_ASSERT (h->root.needs_plt);
|
||||
|
@ -4444,7 +4592,7 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
|
|||
}
|
||||
}
|
||||
else if (!htab->is_vxworks
|
||||
&& (r_type == R_MIPS_CALL16 || (r_type == R_MIPS_GOT16)))
|
||||
&& (call16_reloc_p (r_type) || got16_reloc_p (r_type)))
|
||||
/* The calculation below does not involve "g". */
|
||||
break;
|
||||
else
|
||||
|
@ -4674,10 +4822,12 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd,
|
|||
overflowed_p = mips_elf_overflow_p (value, 16);
|
||||
break;
|
||||
|
||||
case R_MIPS16_GOT16:
|
||||
case R_MIPS16_CALL16:
|
||||
case R_MIPS_GOT16:
|
||||
case R_MIPS_CALL16:
|
||||
/* VxWorks does not have separate local and global semantics for
|
||||
R_MIPS_GOT16; every relocation evaluates to "G". */
|
||||
R_MIPS*_GOT16; every relocation evaluates to "G". */
|
||||
if (!htab->is_vxworks && local_p)
|
||||
{
|
||||
bfd_boolean forced;
|
||||
|
@ -4921,16 +5071,6 @@ mips_elf_perform_relocation (struct bfd_link_info *info,
|
|||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Returns TRUE if SECTION is a MIPS16 stub section. */
|
||||
|
||||
static bfd_boolean
|
||||
mips16_stub_section_p (bfd *abfd ATTRIBUTE_UNUSED, asection *section)
|
||||
{
|
||||
const char *name = bfd_get_section_name (abfd, section);
|
||||
|
||||
return FN_STUB_P (name) || CALL_STUB_P (name) || CALL_FP_STUB_P (name);
|
||||
}
|
||||
|
||||
/* Add room for N relocations to the .rel(a).dyn section in ABFD. */
|
||||
|
||||
|
@ -5312,14 +5452,14 @@ static asection mips_elf_acom_section;
|
|||
static asymbol mips_elf_acom_symbol;
|
||||
static asymbol *mips_elf_acom_symbol_ptr;
|
||||
|
||||
/* Handle the special MIPS section numbers that a symbol may use.
|
||||
This is used for both the 32-bit and the 64-bit ABI. */
|
||||
/* This is used for both the 32-bit and the 64-bit ABI. */
|
||||
|
||||
void
|
||||
_bfd_mips_elf_symbol_processing (bfd *abfd, asymbol *asym)
|
||||
{
|
||||
elf_symbol_type *elfsym;
|
||||
|
||||
/* Handle the special MIPS section numbers that a symbol may use. */
|
||||
elfsym = (elf_symbol_type *) asym;
|
||||
switch (elfsym->internal_elf_sym.st_shndx)
|
||||
{
|
||||
|
@ -5407,6 +5547,15 @@ _bfd_mips_elf_symbol_processing (bfd *abfd, asymbol *asym)
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* If this is an odd-valued function symbol, assume it's a MIPS16 one. */
|
||||
if (ELF_ST_TYPE (elfsym->internal_elf_sym.st_info) == STT_FUNC
|
||||
&& (asym->value & 1) != 0)
|
||||
{
|
||||
asym->value--;
|
||||
elfsym->internal_elf_sym.st_other
|
||||
= ELF_ST_SET_MIPS16 (elfsym->internal_elf_sym.st_other);
|
||||
}
|
||||
}
|
||||
|
||||
/* Implement elf_backend_eh_frame_address_size. This differs from
|
||||
|
@ -6401,7 +6550,7 @@ mips_elf_add_lo16_rel_addend (bfd *abfd,
|
|||
bfd_vma l;
|
||||
|
||||
r_type = ELF_R_TYPE (abfd, rel->r_info);
|
||||
if (r_type == R_MIPS16_HI16)
|
||||
if (mips16_reloc_p (r_type))
|
||||
lo16_type = R_MIPS16_LO16;
|
||||
else
|
||||
lo16_type = R_MIPS_LO16;
|
||||
|
@ -6491,6 +6640,9 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
|||
sym_hashes = elf_sym_hashes (abfd);
|
||||
extsymoff = (elf_bad_symtab (abfd)) ? 0 : symtab_hdr->sh_info;
|
||||
|
||||
bed = get_elf_backend_data (abfd);
|
||||
rel_end = relocs + sec->reloc_count * bed->s->int_rels_per_ext_rel;
|
||||
|
||||
/* Check for the mips16 stub sections. */
|
||||
|
||||
name = bfd_get_section_name (abfd, sec);
|
||||
|
@ -6501,7 +6653,16 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
|||
/* Look at the relocation information to figure out which symbol
|
||||
this is for. */
|
||||
|
||||
r_symndx = ELF_R_SYM (abfd, relocs->r_info);
|
||||
r_symndx = mips16_stub_symndx (sec, relocs, rel_end);
|
||||
if (r_symndx == 0)
|
||||
{
|
||||
(*_bfd_error_handler)
|
||||
(_("%B: Warning: cannot determine the target function for"
|
||||
" stub section `%s'"),
|
||||
abfd, name);
|
||||
bfd_set_error (bfd_error_bad_value);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (r_symndx < extsymoff
|
||||
|| sym_hashes[r_symndx - extsymoff] == NULL)
|
||||
|
@ -6519,7 +6680,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
|||
/* We can ignore stub sections when looking for relocs. */
|
||||
if ((o->flags & SEC_RELOC) == 0
|
||||
|| o->reloc_count == 0
|
||||
|| mips16_stub_section_p (abfd, o))
|
||||
|| section_allows_mips16_refs_p (o))
|
||||
continue;
|
||||
|
||||
sec_relocs
|
||||
|
@ -6531,7 +6692,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
|||
rend = sec_relocs + o->reloc_count;
|
||||
for (r = sec_relocs; r < rend; r++)
|
||||
if (ELF_R_SYM (abfd, r->r_info) == r_symndx
|
||||
&& ELF_R_TYPE (abfd, r->r_info) != R_MIPS16_26)
|
||||
&& !mips16_call_reloc_p (ELF_R_TYPE (abfd, r->r_info)))
|
||||
break;
|
||||
|
||||
if (elf_section_data (o)->relocs != sec_relocs)
|
||||
|
@ -6617,7 +6778,16 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
|||
/* Look at the relocation information to figure out which symbol
|
||||
this is for. */
|
||||
|
||||
r_symndx = ELF_R_SYM (abfd, relocs->r_info);
|
||||
r_symndx = mips16_stub_symndx (sec, relocs, rel_end);
|
||||
if (r_symndx == 0)
|
||||
{
|
||||
(*_bfd_error_handler)
|
||||
(_("%B: Warning: cannot determine the target function for"
|
||||
" stub section `%s'"),
|
||||
abfd, name);
|
||||
bfd_set_error (bfd_error_bad_value);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (r_symndx < extsymoff
|
||||
|| sym_hashes[r_symndx - extsymoff] == NULL)
|
||||
|
@ -6635,7 +6805,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
|||
/* We can ignore stub sections when looking for relocs. */
|
||||
if ((o->flags & SEC_RELOC) == 0
|
||||
|| o->reloc_count == 0
|
||||
|| mips16_stub_section_p (abfd, o))
|
||||
|| section_allows_mips16_refs_p (o))
|
||||
continue;
|
||||
|
||||
sec_relocs
|
||||
|
@ -6743,8 +6913,6 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
|||
}
|
||||
|
||||
sreloc = NULL;
|
||||
bed = get_elf_backend_data (abfd);
|
||||
rel_end = relocs + sec->reloc_count * bed->s->int_rels_per_ext_rel;
|
||||
contents = NULL;
|
||||
for (rel = relocs; rel < rel_end; ++rel)
|
||||
{
|
||||
|
@ -6782,6 +6950,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
|||
{
|
||||
switch (r_type)
|
||||
{
|
||||
case R_MIPS16_GOT16:
|
||||
case R_MIPS16_CALL16:
|
||||
case R_MIPS_GOT16:
|
||||
case R_MIPS_CALL16:
|
||||
case R_MIPS_CALL_HI16:
|
||||
|
@ -6851,13 +7021,13 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
|||
else if (r_type == R_MIPS_CALL_LO16
|
||||
|| r_type == R_MIPS_GOT_LO16
|
||||
|| r_type == R_MIPS_GOT_DISP
|
||||
|| (r_type == R_MIPS_GOT16 && htab->is_vxworks))
|
||||
|| (got16_reloc_p (r_type) && htab->is_vxworks))
|
||||
{
|
||||
/* We may need a local GOT entry for this relocation. We
|
||||
don't count R_MIPS_GOT_PAGE because we can estimate the
|
||||
maximum number of pages needed by looking at the size of
|
||||
the segment. Similar comments apply to R_MIPS_GOT16 and
|
||||
R_MIPS_CALL16, except on VxWorks, where GOT relocations
|
||||
the segment. Similar comments apply to R_MIPS*_GOT16 and
|
||||
R_MIPS*_CALL16, except on VxWorks, where GOT relocations
|
||||
always evaluate to "G". We don't count R_MIPS_GOT_HI16, or
|
||||
R_MIPS_CALL_HI16 because these are always followed by an
|
||||
R_MIPS_GOT_LO16 or R_MIPS_CALL_LO16. */
|
||||
|
@ -6869,6 +7039,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
|||
switch (r_type)
|
||||
{
|
||||
case R_MIPS_CALL16:
|
||||
case R_MIPS16_CALL16:
|
||||
if (h == NULL)
|
||||
{
|
||||
(*_bfd_error_handler)
|
||||
|
@ -6919,6 +7090,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
|||
}
|
||||
/* Fall through. */
|
||||
|
||||
case R_MIPS16_GOT16:
|
||||
case R_MIPS_GOT16:
|
||||
case R_MIPS_GOT_HI16:
|
||||
case R_MIPS_GOT_LO16:
|
||||
|
@ -7003,6 +7175,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
|||
are handled using copy relocs or PLT stubs, so there's
|
||||
no need to add a .rela.dyn entry for this relocation. */
|
||||
if ((info->shared || (h != NULL && !htab->is_vxworks))
|
||||
&& !(h && strcmp (h->root.root.string, "__gnu_local_gp") == 0)
|
||||
&& (sec->flags & SEC_ALLOC) != 0)
|
||||
{
|
||||
if (sreloc == NULL)
|
||||
|
@ -7116,6 +7289,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
|||
default:
|
||||
((struct mips_elf_link_hash_entry *) h)->no_fn_stub = TRUE;
|
||||
break;
|
||||
case R_MIPS16_CALL16:
|
||||
case R_MIPS_CALL16:
|
||||
case R_MIPS_CALL_HI16:
|
||||
case R_MIPS_CALL_LO16:
|
||||
|
@ -7123,12 +7297,13 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
|
|||
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. */
|
||||
/* See if this reloc would need to refer to a MIPS16 hard-float stub,
|
||||
if there is one. We only need to handle global symbols here;
|
||||
we decide whether to keep or delete stubs for local symbols
|
||||
when processing the stub's relocations. */
|
||||
if (h != NULL
|
||||
&& r_type != R_MIPS16_26
|
||||
&& !mips16_stub_section_p (abfd, sec))
|
||||
&& !mips16_call_reloc_p (r_type)
|
||||
&& !section_allows_mips16_refs_p (sec))
|
||||
{
|
||||
struct mips_elf_link_hash_entry *mh;
|
||||
|
||||
|
@ -7638,7 +7813,7 @@ _bfd_mips_elf_always_size_sections (bfd *output_bfd,
|
|||
if (! (info->relocatable
|
||||
|| ! mips_elf_hash_table (info)->mips16_stubs_seen))
|
||||
mips_elf_link_hash_traverse (mips_elf_hash_table (info),
|
||||
mips_elf_check_mips16_stubs, NULL);
|
||||
mips_elf_check_mips16_stubs, info);
|
||||
|
||||
dynobj = elf_hash_table (info)->dynobj;
|
||||
if (dynobj == NULL)
|
||||
|
@ -7700,7 +7875,7 @@ _bfd_mips_elf_always_size_sections (bfd *output_bfd,
|
|||
loadable_size += htab->function_stub_size * (i + 1);
|
||||
|
||||
if (htab->is_vxworks)
|
||||
/* There's no need to allocate page entries for VxWorks; R_MIPS_GOT16
|
||||
/* There's no need to allocate page entries for VxWorks; R_MIPS*_GOT16
|
||||
relocations against local symbols evaluate to "G", and the EABI does
|
||||
not include R_MIPS_GOT_PAGE. */
|
||||
page_gotno = 0;
|
||||
|
@ -8248,9 +8423,8 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
|||
rela_relocation_p = FALSE;
|
||||
addend = mips_elf_read_rel_addend (input_bfd, rel,
|
||||
howto, contents);
|
||||
if (r_type == R_MIPS_HI16
|
||||
|| r_type == R_MIPS16_HI16
|
||||
|| (r_type == R_MIPS_GOT16
|
||||
if (hi16_reloc_p (r_type)
|
||||
|| (got16_reloc_p (r_type)
|
||||
&& mips_elf_local_relocation_p (input_bfd, rel,
|
||||
local_sections, FALSE)))
|
||||
{
|
||||
|
@ -8289,8 +8463,7 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
|
|||
if (!rela_relocation_p && rel->r_addend)
|
||||
{
|
||||
addend += rel->r_addend;
|
||||
if (r_type == R_MIPS_HI16
|
||||
|| r_type == R_MIPS_GOT16)
|
||||
if (hi16_reloc_p (r_type) || got16_reloc_p (r_type))
|
||||
addend = mips_elf_high (addend);
|
||||
else if (r_type == R_MIPS_HIGHER)
|
||||
addend = mips_elf_higher (addend);
|
||||
|
@ -8555,9 +8728,11 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
|
|||
const char *name;
|
||||
int idx;
|
||||
struct mips_elf_link_hash_table *htab;
|
||||
struct mips_elf_link_hash_entry *hmips;
|
||||
|
||||
htab = mips_elf_hash_table (info);
|
||||
dynobj = elf_hash_table (info)->dynobj;
|
||||
hmips = (struct mips_elf_link_hash_entry *) h;
|
||||
|
||||
if (h->plt.offset != MINUS_ONE)
|
||||
{
|
||||
|
@ -8620,6 +8795,18 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
|
|||
+ h->plt.offset);
|
||||
}
|
||||
|
||||
/* If we have a MIPS16 function with a stub, the dynamic symbol must
|
||||
refer to the stub, since only the stub uses the standard calling
|
||||
conventions. */
|
||||
if (h->dynindx != -1 && hmips->fn_stub != NULL)
|
||||
{
|
||||
BFD_ASSERT (hmips->need_fn_stub);
|
||||
sym->st_value = (hmips->fn_stub->output_section->vma
|
||||
+ hmips->fn_stub->output_offset);
|
||||
sym->st_size = hmips->fn_stub->size;
|
||||
sym->st_other = ELF_ST_VISIBILITY (sym->st_other);
|
||||
}
|
||||
|
||||
BFD_ASSERT (h->dynindx != -1
|
||||
|| h->forced_local);
|
||||
|
||||
|
@ -8638,7 +8825,8 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
|
|||
bfd_vma value;
|
||||
|
||||
value = sym->st_value;
|
||||
offset = mips_elf_global_got_index (dynobj, output_bfd, h, R_MIPS_GOT16, info);
|
||||
offset = mips_elf_global_got_index (dynobj, output_bfd, h,
|
||||
R_MIPS_GOT16, info);
|
||||
MIPS_ELF_PUT_WORD (output_bfd, value, sgot->contents + offset);
|
||||
}
|
||||
|
||||
|
@ -8652,7 +8840,7 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
|
|||
|
||||
e.abfd = output_bfd;
|
||||
e.symndx = -1;
|
||||
e.d.h = (struct mips_elf_link_hash_entry *)h;
|
||||
e.d.h = hmips;
|
||||
e.tls_type = 0;
|
||||
|
||||
for (g = g->next; g->next != gg; g = g->next)
|
||||
|
@ -8768,9 +8956,13 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd,
|
|||
}
|
||||
}
|
||||
|
||||
/* If this is a mips16 symbol, force the value to be even. */
|
||||
/* Keep dynamic MIPS16 symbols odd. This allows the dynamic linker to
|
||||
treat MIPS16 symbols like any other. */
|
||||
if (ELF_ST_IS_MIPS16 (sym->st_other))
|
||||
sym->st_value &= ~1;
|
||||
{
|
||||
BFD_ASSERT (sym->st_value & 1);
|
||||
sym->st_other -= STO_MIPS16;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -9998,6 +10190,8 @@ _bfd_mips_elf_gc_sweep_hook (bfd *abfd ATTRIBUTE_UNUSED,
|
|||
for (rel = relocs; rel < relend; rel++)
|
||||
switch (ELF_R_TYPE (abfd, rel->r_info))
|
||||
{
|
||||
case R_MIPS16_GOT16:
|
||||
case R_MIPS16_CALL16:
|
||||
case R_MIPS_GOT16:
|
||||
case R_MIPS_CALL16:
|
||||
case R_MIPS_CALL_HI16:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue