This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
2.10.91: Incorrect creation of function stubs by elf32-mips
- To: binutils at sourceware dot cygnus dot com
- Subject: 2.10.91: Incorrect creation of function stubs by elf32-mips
- From: "Maciej W. Rozycki" <macro at ds2 dot pg dot gda dot pl>
- Date: Fri, 17 Nov 2000 17:32:11 +0100 (MET)
- cc: Ralf Baechle <ralf at uni-koblenz dot de>, Ulf Carlsson <ulfc at engr dot sgi dot com>
- Organization: Technical University of Gdansk
- Reply-To: "Maciej W. Rozycki" <macro at ds2 dot pg dot gda dot pl>
Hi,
"MIPS ABI Supplement, 3rd Edition", figure 5-9 on page 5-10 states that
only if there are no relocations related to taking a function's address a
symbol can have a stub associated and thus lazy binding enabled. This is
a reasonable requirement as otherwise a function pointer will have
different values depending on which module it was obtained in and whether
the final binding already happened or not. As a result lazy binding
becomes non-transparent to the program.
On page 4-20 the specification further clarifies how to distinguish
whether there are relocations related to taking a function's address or
not. It reserves three special relocation types, namely R_MIPS_CALL16,
R_MIPS_CALL_HI16 and R_MIPS_CALL_LO16 for the purpose of loading the jump
register ($25 or t9) when performing position-independent function calls.
An occurence of any these relocations does not count as taking a
function's address as the contents of the jump register are not used for
accessing pointers in a compliant code. The relocations otherwise behave
in the same way as R_MIPS_GOT16, R_MIPS_GOT_HI16 and R_MIPS_GOT_LO16,
respectively. Any but these CALL relocations are treated as related to
taking a function's address.
Unfortunately BFD does not obey the above rules and builds stubs even if
there are relocations related to taking a function's address. The
following patch fixes it.
bfd/ChangeLog:
2000-11-05 Maciej W. Rozycki <macro@ds2.pg.gda.pl>
* elf32-mips.c (struct mips_elf_link_hash_entry): Added no_fn_stub
member to mark symbols that have non-CALL relocations against
them.
(mips_elf_link_hash_newfunc): Initialize no_fn_stub.
(mips_elf_calculate_relocation): Handle R_MIPS_CALL16 like
R_MIPS_GOT16.
(_bfd_mips_elf_check_relocs): Set no_fn_stub for a symbol if a
non-CALL relocation against it is encountered.
(_bfd_mips_elf_copy_indirect_symbol): Merge no_fn_stub as well.
(_bfd_mips_elf_adjust_dynamic_symbol): Only create a stub if
no_fn_stub is not set.
Maciej
--
+ Maciej W. Rozycki, Technical University of Gdansk, Poland +
+--------------------------------------------------------------+
+ e-mail: macro@ds2.pg.gda.pl, PGP key available +
diff -up --recursive --new-file binutils.macro/bfd/elf32-mips.c binutils/bfd/elf32-mips.c
--- binutils.macro/bfd/elf32-mips.c Sun Oct 15 03:25:28 2000
+++ binutils/bfd/elf32-mips.c Sun Nov 5 21:42:45 2000
@@ -79,6 +79,12 @@ struct mips_elf_link_hash_entry
section) against this symbol. */
unsigned int min_dyn_reloc_index;
+ /* We must not create a stub for a symbol that has relocations
+ related to taking the function's address, i.e. any but
+ R_MIPS_CALL*16 ones -- see "MIPS ABI Supplement, 3rd Edition",
+ p. 4-20. */
+ boolean no_fn_stub;
+
/* 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;
@@ -3891,6 +3897,7 @@ mips_elf_link_hash_newfunc (entry, table
ret->esym.ifd = -2;
ret->possibly_dynamic_relocs = 0;
ret->min_dyn_reloc_index = 0;
+ ret->no_fn_stub = false;
ret->fn_stub = NULL;
ret->need_fn_stub = false;
ret->call_stub = NULL;
@@ -6157,7 +6164,7 @@ mips_elf_calculate_relocation (abfd,
symbol + addend, sgot->contents + g);
}
}
- else if (r_type == R_MIPS_GOT16)
+ else if (r_type == R_MIPS_GOT16 || r_type == R_MIPS_CALL16)
/* There's no need to create a local GOT entry here; the
calculation for a local GOT16 entry does not involve G. */
break;
@@ -6325,6 +6332,7 @@ mips_elf_calculate_relocation (abfd,
break;
case R_MIPS_GOT16:
+ case R_MIPS_CALL16:
if (local_p)
{
boolean forced;
@@ -6347,7 +6355,6 @@ mips_elf_calculate_relocation (abfd,
/* Fall through. */
- case R_MIPS_CALL16:
case R_MIPS_GOT_DISP:
value = g;
overflowed_p = mips_elf_overflow_p (value, 16);
@@ -7662,10 +7669,10 @@ _bfd_mips_elf_check_relocs (abfd, info,
/* 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. 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.
+ the segment. Similar comments apply to R_MIPS_GOT16 and
+ R_MIPS_CALL16. 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.
This estimation is very conservative since we can merge
duplicate entries in the GOT. In order to be less
@@ -7797,6 +7804,25 @@ _bfd_mips_elf_check_relocs (abfd, info,
break;
}
+ /* We must not create a stub for a symbol that has relocations
+ related to taking the function's address. */
+ switch (r_type)
+ {
+ default:
+ if (h != NULL)
+ {
+ struct mips_elf_link_hash_entry *mh;
+
+ mh = (struct mips_elf_link_hash_entry *) h;
+ mh->no_fn_stub = true;
+ }
+ break;
+ case R_MIPS_CALL16:
+ case R_MIPS_CALL_HI16:
+ case R_MIPS_CALL_LO16:
+ 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. */
@@ -7932,6 +7958,8 @@ _bfd_mips_elf_copy_indirect_symbol (dir,
|| (indmips->min_dyn_reloc_index != 0
&& indmips->min_dyn_reloc_index < dirmips->min_dyn_reloc_index))
dirmips->min_dyn_reloc_index = indmips->min_dyn_reloc_index;
+ if (indmips->no_fn_stub)
+ dirmips->no_fn_stub = true;
}
/* Adjust a symbol defined by a dynamic object and referenced by a
@@ -7972,8 +8000,9 @@ _bfd_mips_elf_adjust_dynamic_symbol (inf
mips_elf_allocate_dynamic_relocations (dynobj,
hmips->possibly_dynamic_relocs);
- /* For a function, create a stub, if needed. */
- if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
+ /* For a function create a stub, if allowed. */
+ if (! hmips->no_fn_stub
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0)
{
if (! elf_hash_table (info)->dynamic_sections_created)
return true;