This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH] Handle mixing mips16/mips32 functions in BFD
- From: Thiemo Seufer <ths at networkno dot de>
- To: binutils at sourceware dot org
- Date: Tue, 25 Jul 2006 10:45:57 +0100
- Subject: [PATCH] Handle mixing mips16/mips32 functions in BFD
Hello All,
this patch add support for mixing mips16 and mips32 code in the
same source file.
I lacks some assembler-based testcase :-)
Otherwise ok?
Thiemo
2006-07-25 Thiemo Seufer <ths@mips.com>
David Ung <davidu@mips.com>
* elf-bfd.h (local_call_stubs): New member.
* elfxx-mips.c (mips_elf_calculate_relocation): Handle local
mips16 call stubs.
(_bfd_mips_elf_check_relocs): Handle call stubs for code which
mixes mips16 and mips32 functions.
Index: bfd/elf-bfd.h
===================================================================
RCS file: /cvs/src/src/bfd/elf-bfd.h,v
retrieving revision 1.211
diff -u -p -r1.211 elf-bfd.h
--- bfd/elf-bfd.h 10 Jul 2006 21:40:22 -0000 1.211
+++ bfd/elf-bfd.h 24 Jul 2006 11:21:00 -0000
@@ -1339,6 +1339,7 @@ struct elf_obj_tdata
MIPS ELF linker. FIXME: We should figure out some way to only
include this field for a MIPS ELF target. */
asection **local_stubs;
+ asection **local_call_stubs;
/* Used to determine if PT_GNU_EH_FRAME segment header should be
created. */
Index: bfd/elfxx-mips.c
===================================================================
RCS file: /cvs/src/src/bfd/elfxx-mips.c,v
retrieving revision 1.175
diff -u -p -r1.175 elfxx-mips.c
--- bfd/elfxx-mips.c 18 Jul 2006 08:56:44 -0000 1.175
+++ bfd/elfxx-mips.c 24 Jul 2006 11:21:01 -0000
@@ -4082,33 +4085,41 @@ mips_elf_calculate_relocation (bfd *abfd
need to redirect the call to the stub. */
else if (r_type == R_MIPS16_26 && !info->relocatable
&& h != NULL
- && (h->call_stub != NULL || h->call_fp_stub != NULL)
+ && ((h->call_stub != NULL || h->call_fp_stub != NULL)
+ || (local_p
+ && elf_tdata (input_bfd)->local_call_stubs != NULL
+ && elf_tdata (input_bfd)->local_call_stubs[r_symndx] != NULL))
&& !target_is_16_bit_code_p)
{
- /* 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 (h->call_stub != NULL && h->call_fp_stub != NULL)
+ if (local_p)
+ sec = elf_tdata (input_bfd)->local_call_stubs[r_symndx];
+ else
{
- asection *o;
-
- sec = 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)
+ /* If both call_stub and call_fp_stub are defined, we can figure
+ out which one to use by checking which one appears in the input
+ file. */
+ if (h->call_stub != NULL && h->call_fp_stub != NULL)
+ {
+ asection *o;
+
+ sec = NULL;
+ for (o = input_bfd->sections; o != NULL; o = o->next)
{
- sec = h->call_fp_stub;
- break;
+ if (strncmp (bfd_get_section_name (input_bfd, o),
+ CALL_FP_STUB, sizeof CALL_FP_STUB - 1) == 0)
+ {
+ sec = h->call_fp_stub;
+ break;
+ }
}
+ if (sec == NULL)
+ sec = h->call_stub;
}
- if (sec == NULL)
+ else if (h->call_stub != NULL)
sec = h->call_stub;
+ else
+ sec = h->call_fp_stub;
}
- else if (h->call_stub != NULL)
- sec = h->call_stub;
- else
- sec = h->call_fp_stub;
BFD_ASSERT (sec->size > 0);
symbol = sec->output_section->vma + sec->output_offset;
@@ -6233,42 +6244,112 @@ _bfd_mips_elf_check_relocs (bfd *abfd, s
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;
- }
+ asection *o;
- h = ((struct mips_elf_link_hash_entry *)
- sym_hashes[r_symndx - extsymoff]);
+ /* This stub is for a local symbol. This stub will only be
+ needed if there is some relocation (R_MIPS16_26) in this BFD
+ that 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;
- /* H is the symbol this stub is for. */
+ sec_relocs
+ = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL,
+ info->keep_memory);
+ if (sec_relocs == NULL)
+ return FALSE;
- if (strncmp (name, CALL_FP_STUB, sizeof CALL_FP_STUB - 1) == 0)
- loc = &h->call_fp_stub;
- else
- loc = &h->call_stub;
+ 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)
+ break;
+
+ if (elf_section_data (o)->relocs != sec_relocs)
+ 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 call_stubs for
+ this BFD. */
+ if (elf_tdata (abfd)->local_call_stubs == NULL)
+ {
+ unsigned long symcount;
+ asection **n;
+ bfd_size_type amt;
+
+ if (elf_bad_symtab (abfd))
+ symcount = NUM_SHDR_ENTRIES (symtab_hdr);
+ else
+ symcount = symtab_hdr->sh_info;
+ amt = symcount * sizeof (asection *);
+ n = bfd_zalloc (abfd, amt);
+ if (n == NULL)
+ return FALSE;
+ elf_tdata (abfd)->local_call_stubs = n;
+ }
+
+ elf_tdata (abfd)->local_call_stubs[r_symndx] = sec;
- /* 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)
+ /* 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
{
- 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;
}
-
- *loc = sec;
- mips_elf_hash_table (info)->mips16_stubs_seen = TRUE;
}
if (dynobj == NULL)