[SH] TLS IE -> LE optimization issue

Thomas Schwinge thomas@codesourcery.com
Fri Apr 13 15:53:00 GMT 2012


I saw the GDB testcase gdb.threads/tls.exp failing to build due to the
following assertion at the end of sh_elf_finish_dynamic_sections:

    7395      if (htab->srelgot)
    7396        BFD_ASSERT (htab->srelgot->reloc_count * sizeof (Elf32_External_Rela)
    7397                    == htab->srelgot->size);

    (gdb) print htab->srelgot->reloc_count
    $2 = 0
    (gdb) print htab->srelgot->size
    $3 = 12

I distilled this C++/pthread test case into the following minimal

    $ cat < tls.c
    _start (void)
      extern __thread int x;
      return x;
    $ cat < tls2.c
    __thread int x;
    $ $ROOT/install/bin/*-gcc -O2 -c tls.c tls2.c
    $ $ROOT/install/bin/*-gcc -O2 -o null.o -c -x c /dev/null
    $ $ROOT/install/bin/*-ld -o tls3.so -shared null.o
    $ $ROOT/install/bin/*-ld -o tls tls.o tls2.o tls3.so
    [...]/sh-linux-gnu-ld: BFD (GNU Binutils) assertion fail [...]/bfd/elf32-sh.c:7397

That is, we need a __thread variable that is referenced from another
compilation unit; these two are linked into an executable; and we need a
(dummy) SO in order to trigger creation of the .dynamic section, etc.
What happens is the following.  GCC will emit x as TLS IE.  Called from
sh_elf_size_dynamic_sections, in allocate_dynrelocs the the linker will
therefore make a reservation in line 3111:

      3098        dyn = htab->root.dynamic_sections_created;
      3099        if (!dyn)
      3100          {
      3101            /* No dynamic relocations required.  */
      3102            if (htab->fdpic_p && !info->shared
      3103                && h->root.type != bfd_link_hash_undefweak
      3104                && (got_type == GOT_NORMAL || got_type == GOT_FUNCDESC))
      3105              htab->srofixup->size += 4;
      3106          }
      3107        /* R_SH_TLS_IE_32 needs one dynamic relocation if dynamic,
      3108           R_SH_TLS_GD needs one if local symbol and two if global.  */
      3109        else if ((got_type == GOT_TLS_GD && h->dynindx == -1)
      3110                 || got_type == GOT_TLS_IE)
      3111          htab->srelgot->size += sizeof (Elf32_External_Rela);

(This is also where the (dummy) SO comes into play: otherwise »dyn ==
NULL«.)  Back in sh_elf_size_dynamic_sections, »srelgot->size != 0«
(»sizeof (Elf32_External_Rela) == 12«), thus memory for this section will
be allocated (using bfd_zalloc).  Later on, in sh_elf_relocate_section,
the linker recognizes that TLS IE can here be optimized into TLS LE, and
does so; the relocation slot is now not needed anymore (so
srelgot->reloc_count is not incremented), but it is not reclaimed/the
size reservation remains (and due to using zalloc, it's a R_SH_NONE), and
thus the assertion is triggered.

Expectedly, weakening the assertion into using <= instead of == makes the
problem go away, but the empty slot in .rela.dyn remains (12 bytes

Or, instead, should the srelgot->size reservations be un-done as the TLS
optimizations are done (there may be other such cases, I didn't check)?
Can this actually be done at this stage?

Or, should there be another cleanup pass after the TLS optimizations have
been done?  Or, should one of the existing passes in fact be catching
this case, too?

Due to my lack of experience with BFD'S innards combined with its rather
monstrous appearance, I can't really tell which is preferable.  But I'm
willing to learn.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 489 bytes
Desc: not available
URL: <https://sourceware.org/pipermail/binutils/attachments/20120413/52d9a87a/attachment.sig>

More information about the Binutils mailing list