mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-21 02:24:17 +08:00
* elf32-mips.c (FN_STUB, CALL_STUB, CALL_FP_STUB): Define.
(struct mips_elf_link_hash_entry): Add new fields fn_stub, need_fn_sub, call_stub, and call_fp_stub. (struct mips_elf_link_hash_table): Add field mips16_stubs_seen. (mips_elf_link_hash_newfunc): Initialize new fields. (mips_elf_link_hash_table_create): Likewise. (mips_elf_relocate_section): Redirect relocations to use mips16 stubs when appropriate. (mips_elf_check_relocs): Attach stub sections to the appropriate symbol. Set need_fn_stub when appropriate. (mips_elf_always_size_sections): New static function. (mips_elf_check_mips16_stubs): New static function. (elf_backend_always_size_sections): Define. * elf-bfd.h (struct elf_obj_tdata): Add local_stubs field.
This commit is contained in:
@ -1,3 +1,23 @@
|
|||||||
|
Thu Feb 6 16:55:43 1997 Ian Lance Taylor <ian@cygnus.com>
|
||||||
|
|
||||||
|
* elf32-mips.c (FN_STUB, CALL_STUB, CALL_FP_STUB): Define.
|
||||||
|
(struct mips_elf_link_hash_entry): Add new fields fn_stub,
|
||||||
|
need_fn_sub, call_stub, and call_fp_stub.
|
||||||
|
(struct mips_elf_link_hash_table): Add field mips16_stubs_seen.
|
||||||
|
(mips_elf_link_hash_newfunc): Initialize new fields.
|
||||||
|
(mips_elf_link_hash_table_create): Likewise.
|
||||||
|
(mips_elf_relocate_section): Redirect relocations to use mips16
|
||||||
|
stubs when appropriate.
|
||||||
|
(mips_elf_check_relocs): Attach stub sections to the appropriate
|
||||||
|
symbol. Set need_fn_stub when appropriate.
|
||||||
|
(mips_elf_always_size_sections): New static function.
|
||||||
|
(mips_elf_check_mips16_stubs): New static function.
|
||||||
|
(elf_backend_always_size_sections): Define.
|
||||||
|
* elf-bfd.h (struct elf_obj_tdata): Add local_stubs field.
|
||||||
|
|
||||||
|
* elflink.h (elf_link_input_bfd): Discard local symbols that are
|
||||||
|
attached to sections which are not being included in the link.
|
||||||
|
|
||||||
Wed Feb 5 13:20:17 1997 Ian Lance Taylor <ian@cygnus.com>
|
Wed Feb 5 13:20:17 1997 Ian Lance Taylor <ian@cygnus.com>
|
||||||
|
|
||||||
* cofflink.c (_bfd_coff_generic_relocate_section): Ignore the
|
* cofflink.c (_bfd_coff_generic_relocate_section): Ignore the
|
||||||
|
417
bfd/elf32-mips.c
417
bfd/elf32-mips.c
@ -101,6 +101,8 @@ static boolean mips_elf_check_relocs
|
|||||||
const Elf_Internal_Rela *));
|
const Elf_Internal_Rela *));
|
||||||
static boolean mips_elf_adjust_dynamic_symbol
|
static boolean mips_elf_adjust_dynamic_symbol
|
||||||
PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *));
|
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
|
static boolean mips_elf_size_dynamic_sections
|
||||||
PARAMS ((bfd *, struct bfd_link_info *));
|
PARAMS ((bfd *, struct bfd_link_info *));
|
||||||
static boolean mips_elf_finish_dynamic_symbol
|
static boolean mips_elf_finish_dynamic_symbol
|
||||||
@ -2948,6 +2950,44 @@ _bfd_mips_elf_find_nearest_line (abfd, section, symbols, offset, filename_ptr,
|
|||||||
line_ptr);
|
line_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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 MIPS ELF linker needs additional information for each symbol in
|
||||||
the global hash table. */
|
the global hash table. */
|
||||||
|
|
||||||
@ -2960,6 +3000,22 @@ struct mips_elf_link_hash_entry
|
|||||||
|
|
||||||
/* Number of MIPS_32 or MIPS_REL32 relocs against this symbol. */
|
/* Number of MIPS_32 or MIPS_REL32 relocs against this symbol. */
|
||||||
unsigned int mips_32_relocs;
|
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. */
|
/* MIPS ELF linker hash table. */
|
||||||
@ -2978,6 +3034,8 @@ struct mips_elf_link_hash_table
|
|||||||
boolean use_rld_obj_head;
|
boolean use_rld_obj_head;
|
||||||
/* This is the value of the __rld_map or __rld_obj_head symbol. */
|
/* This is the value of the __rld_map or __rld_obj_head symbol. */
|
||||||
bfd_vma rld_value;
|
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. */
|
/* Look up an entry in a MIPS ELF linker hash table. */
|
||||||
@ -3035,6 +3093,10 @@ mips_elf_link_hash_newfunc (entry, table, string)
|
|||||||
not been set. -1 means there is no associated ifd. */
|
not been set. -1 means there is no associated ifd. */
|
||||||
ret->esym.ifd = -2;
|
ret->esym.ifd = -2;
|
||||||
ret->mips_32_relocs = 0;
|
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;
|
return (struct bfd_hash_entry *) ret;
|
||||||
@ -3067,6 +3129,7 @@ mips_elf_link_hash_table_create (abfd)
|
|||||||
ret->compact_rel_size = 0;
|
ret->compact_rel_size = 0;
|
||||||
ret->use_rld_obj_head = false;
|
ret->use_rld_obj_head = false;
|
||||||
ret->rld_value = 0;
|
ret->rld_value = 0;
|
||||||
|
ret->mips16_stubs_seen = false;
|
||||||
|
|
||||||
return &ret->root.root;
|
return &ret->root.root;
|
||||||
}
|
}
|
||||||
@ -4378,6 +4441,8 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
|
|||||||
struct elf_link_hash_entry *h;
|
struct elf_link_hash_entry *h;
|
||||||
asection *sec;
|
asection *sec;
|
||||||
Elf_Internal_Sym *sym;
|
Elf_Internal_Sym *sym;
|
||||||
|
struct mips_elf_link_hash_entry *mh;
|
||||||
|
int other;
|
||||||
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);
|
||||||
@ -4639,6 +4704,98 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
if (r_type == R_MIPS_HI16)
|
||||||
{
|
{
|
||||||
Elf_Internal_Rela *lorel;
|
Elf_Internal_Rela *lorel;
|
||||||
@ -4867,9 +5024,7 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
|
|||||||
addr += 4;
|
addr += 4;
|
||||||
bfd_put_32 (input_bfd, val, contents + addr);
|
bfd_put_32 (input_bfd, val, contents + addr);
|
||||||
}
|
}
|
||||||
else if (r_type == R_MIPS_26
|
else if (r_type == R_MIPS_26 && other == STO_MIPS16)
|
||||||
&& ((h != NULL && h->other == STO_MIPS16)
|
|
||||||
|| (sym != NULL && sym->st_other == STO_MIPS16)))
|
|
||||||
{
|
{
|
||||||
unsigned long insn;
|
unsigned long insn;
|
||||||
|
|
||||||
@ -4911,8 +5066,7 @@ mips_elf_relocate_section (output_bfd, info, input_bfd, input_section,
|
|||||||
| ((insn & 0x3e0) >> 5));
|
| ((insn & 0x3e0) >> 5));
|
||||||
/* If this is a jump to a 32 bit routine, then make
|
/* If this is a jump to a 32 bit routine, then make
|
||||||
it jalx. */
|
it jalx. */
|
||||||
if ((h != NULL && h->other != STO_MIPS16)
|
if (other != STO_MIPS16)
|
||||||
|| (sym != NULL && sym->st_other != STO_MIPS16))
|
|
||||||
insn |= 0x400;
|
insn |= 0x400;
|
||||||
bfd_put_16 (input_bfd, insn, contents + rel->r_offset);
|
bfd_put_16 (input_bfd, insn, contents + rel->r_offset);
|
||||||
}
|
}
|
||||||
@ -5264,6 +5418,7 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
|
|||||||
asection *sec;
|
asection *sec;
|
||||||
const Elf_Internal_Rela *relocs;
|
const Elf_Internal_Rela *relocs;
|
||||||
{
|
{
|
||||||
|
const char *name;
|
||||||
bfd *dynobj;
|
bfd *dynobj;
|
||||||
Elf_Internal_Shdr *symtab_hdr;
|
Elf_Internal_Shdr *symtab_hdr;
|
||||||
struct elf_link_hash_entry **sym_hashes;
|
struct elf_link_hash_entry **sym_hashes;
|
||||||
@ -5282,6 +5437,164 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
|
|||||||
sym_hashes = elf_sym_hashes (abfd);
|
sym_hashes = elf_sym_hashes (abfd);
|
||||||
extsymoff = (elf_bad_symtab (abfd)) ? 0 : symtab_hdr->sh_info;
|
extsymoff = (elf_bad_symtab (abfd)) ? 0 : symtab_hdr->sh_info;
|
||||||
|
|
||||||
|
/* 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)
|
if (dynobj == NULL)
|
||||||
{
|
{
|
||||||
sgot = NULL;
|
sgot = NULL;
|
||||||
@ -5488,6 +5801,24 @@ mips_elf_check_relocs (abfd, info, sec, relocs)
|
|||||||
default:
|
default:
|
||||||
break;
|
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 true;
|
||||||
@ -5591,6 +5922,80 @@ mips_elf_adjust_dynamic_symbol (info, h)
|
|||||||
return true;
|
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. */
|
/* Set the sizes of the dynamic sections. */
|
||||||
|
|
||||||
static boolean
|
static boolean
|
||||||
@ -6706,6 +7111,8 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap =
|
|||||||
#define elf_backend_check_relocs mips_elf_check_relocs
|
#define elf_backend_check_relocs mips_elf_check_relocs
|
||||||
#define elf_backend_adjust_dynamic_symbol \
|
#define elf_backend_adjust_dynamic_symbol \
|
||||||
mips_elf_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 \
|
#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
|
||||||
|
Reference in New Issue
Block a user