This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Properly align static TLS segments on Solaris 2


When comparing GCC mainline testsuite results with Sun ld vs. CVS GNU
ld, a large number of TLS execution tests failed when using gld.  The
problem can be seen with the following minimal testcase:

$ cat thr.c
static __thread int i = 2;

int
main (void)
{
  return i;
}

If you disassemble the resulting executables, you find:

$ dis -F main {sld,gld}/thr
disassembly for sld/thr

main()
    main:                   55                 pushl  %ebp
    main+0x1:               89 e5              movl   %esp,%ebp
    main+0x3:               65 a1 00 00 00 00  movl   %gs:0x0,%eax
    main+0x9:               8b 80 f8 ff ff ff  movl   -0x8(%eax),%eax
    main+0xf:               5d                 popl   %ebp
    main+0x10:              c3                 ret    
disassembly for gld/thr

main()
    main:                   55                 pushl  %ebp
    main+0x1:               89 e5              movl   %esp,%ebp
    main+0x3:               65 a1 00 00 00 00  movl   %gs:0x0,%eax
    main+0x9:               8b 80 fc ff ff ff  movl   -0x4(%eax),%eax
    main+0xf:               5d                 popl   %ebp
    main+0x10:              c3                 ret    

This difference stems from the ntpoff relocation used: thr.s uses

    movl    i@ntpoff(%eax), %eax

and the two linkers calculate two different offsets from that.

After some searching, I've found the following in the OpenSolaris ld
sources:

http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/cmd/sgs/libld/common/machrel.intel.c#997

		} else if ((arsp->rel_flags & FLG_REL_STLS) &&
		    ((flags & FLG_OF_RELOBJ) == 0)) {
			Xword	tlsstatsize;

			/*
			 * This is the LE TLS reference model.  Static
			 * offset is hard-coded.
			 */
			tlsstatsize = S_ROUND(ofl->ofl_tlsphdr->p_memsz,
			    M_TLSSTATALIGN);
			value = tlsstatsize - value;

together with

http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/cmd/sgs/include/i386/machdep_x86.h#94

/*
 * TLS static segments must be rounded to the following requirements,
 * due to libthread stack allocation.
 */
#if	defined(_ELF64)
#define	M_TLSSTATALIGN	0x10
#else
#define	M_TLSSTATALIGN	0x08
#endif

The following patch (not yet ready as is) implements this in bfd:

Index: bfd/elf32-i386.c
===================================================================
RCS file: /vol/gnu/src/binutils/src-cvs/src/bfd/elf32-i386.c,v
retrieving revision 1.239
diff -u -p -r1.239 elf32-i386.c
--- bfd/elf32-i386.c	25 Aug 2010 14:53:42 -0000	1.239
+++ bfd/elf32-i386.c	23 Sep 2010 18:21:03 -0000
@@ -2817,15 +2817,36 @@ elf_i386_dtpoff_base (struct bfd_link_in
 /* Return the relocation value for @tpoff relocation
    if STT_TLS virtual address is ADDRESS.  */
 
 static bfd_vma
 elf_i386_tpoff (struct bfd_link_info *info, bfd_vma address)
 {
   struct elf_link_hash_table *htab = elf_hash_table (info);
+  bfd_vma tlsstatsize;
+
+#define TLSSTATALIGN 8
 
   /* If tls_sec is NULL, we should have signalled an error already.  */
   if (htab->tls_sec == NULL)
     return 0;
-  return htab->tls_size + htab->tls_sec->vma - address;
+  tlsstatsize = BFD_ALIGN (htab->tls_size, TLSSTATALIGN);
+  return tlsstatsize + htab->tls_sec->vma - address;
 }
 
 /* Relocate an i386 ELF section.  */

This patch (and a corresponding one in bfd/elf64-x86-64.c
(elf64_x86_64_tpoff) allowed all failing GCC TLS tests to succeed up to
-O2.  At -O3, they started failing again.  This happens because (for yet
unknown reasons) gcc starts to change the .tdata alignment from 4 to 32
bytes.  This interferes with the alignment done in bfd/elflink.c
(bfd_elf_final_link).  If I disable that as well, all GCC TLS testcases
pass at all optimization levels.

Index: bfd/elflink.c
===================================================================
RCS file: /vol/gnu/src/binutils/src-cvs/src/bfd/elflink.c,v
retrieving revision 1.379
diff -u -p -r1.379 elflink.c
--- bfd/elflink.c	16 Sep 2010 00:06:11 -0000	1.379
+++ bfd/elflink.c	23 Sep 2010 18:19:29 -0000
@@ -10644,7 +10644,9 @@ bfd_elf_final_link (bfd *abfd, struct bf
 	  end = sec->vma + size;
 	}
       base = elf_hash_table (info)->tls_sec->vma;
+#if 0
       end = align_power (end, elf_hash_table (info)->tls_sec->alignment_power);
+#endif
       elf_hash_table (info)->tls_size = end - base;
     }

Obviously such a patch is not appropriate as is:

* It lacks 32 and 64-bit SPARC support.

* Most importantly, the change affects all i386/x86-64 ELF targets.
  Unfortunately, I haven't been able to figure out how in the maze of
  code that is BFD to make such a target OS-specific change.  Any
  suggestions how to properly handle this?

Thanks.
	Rainer

-- 
-----------------------------------------------------------------------------
Rainer Orth, Center for Biotechnology, Bielefeld University


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]