This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
PR ld/12637: reloc overflow for R_MIPS_TLS_LDM
- From: Richard Sandiford <rdsandiford at googlemail dot com>
- To: binutils at sourceware dot org
- Cc: gingold at adacore dot com
- Date: Sun, 10 Apr 2011 12:10:39 +0100
- Subject: PR ld/12637: reloc overflow for R_MIPS_TLS_LDM
This patch fixes PR ld/12637, which is about relocation overflow
in a libjava link. The problem is that we end up having TLS entries
in a primary GOT that is too big for them. There was code to try
to handle this case:
/* We place TLS GOT entries after both locals and globals. The globals
for the primary GOT may overflow the normal GOT size limit, so be
sure not to merge a GOT which requires TLS with the primary GOT in that
case. This doesn't affect non-primary GOTs. */
estimate += (g->tls_gotno > 0 ? arg->global_count : g->global_gotno);
if (estimate <= arg->max_count)
{
/* If we don't have a primary GOT, use it as
a starting point for the primary GOT. */
if (!arg->primary)
{
arg->primary = bfd2got->g;
return 1;
}
/* Try merging with the primary GOT. */
result = mips_elf_merge_got_with (bfd2got, arg->primary, arg);
if (result >= 0)
return result;
}
which works fine when the GOT we're adding has TLS entries. But we
also need to handle the case where we're adding a GOT that doesn't
have TLS entries to a primary GOT that already does.
The bug has been around for a long time (probably since the inception
of TLS), but 2.20 did not fail for this particular testcase.
In the testcase, the number of global GOT entries is pretty close to
the threshold beyond which the primary GOT can no longer be assigned
to input bfds. I think the changes to more accurately estimate the
other parts of the GOT (the non-global parts) mean that we are now able
to use the primary GOT for some bfds, whereas previously we couldn't.
One of the first GOTs we add has TLS entries. We correctly estimate
that it can be merged into the primary GOT. We then tried to add lots
of other GOTs that don't have TLS entries, and the number of local
entries we added then pushed the TLS entries out of range.
Tested on mips64-linux-gnu and applied. Tristan, is this OK for
the branch?
Richard
bfd/
PR ld/12637
* elfxx-mips.c (mips_elf_merge_got_with): Use arg->global_count
as the number of global entries when merging with the primary GOT.
Index: bfd/elfxx-mips.c
===================================================================
--- bfd/elfxx-mips.c 2011-04-10 10:36:57.000000000 +0100
+++ bfd/elfxx-mips.c 2011-04-10 11:39:41.000000000 +0100
@@ -4080,14 +4080,18 @@ mips_elf_merge_got_with (struct mips_elf
if (estimate >= from->page_gotno + to->page_gotno)
estimate = from->page_gotno + to->page_gotno;
- /* And conservatively estimate how many local, global and TLS entries
+ /* And conservatively estimate how many local and TLS entries
would be needed. */
- estimate += (from->local_gotno
- + from->global_gotno
- + from->tls_gotno
- + to->local_gotno
- + to->global_gotno
- + to->tls_gotno);
+ estimate += from->local_gotno + to->local_gotno;
+ estimate += from->tls_gotno + to->tls_gotno;
+
+ /* If we're merging with the primary got, we will always have
+ the full set of global entries. Otherwise estimate those
+ conservatively as well. */
+ if (to == arg->primary)
+ estimate += arg->global_count;
+ else
+ estimate += from->global_gotno + to->global_gotno;
/* Bail out if the combined GOT might be too big. */
if (estimate > arg->max_count)