This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Properly align static TLS segments on Solaris 2
- From: Rainer Orth <ro at CeBiTec dot Uni-Bielefeld dot DE>
- To: binutils at sourceware dot org
- Date: Mon, 27 Sep 2010 19:35:16 +0200
- Subject: 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