* [PATCH] Fix i386 GD->IE TLS transition
@ 2006-06-23 14:32 Jakub Jelinek
2006-06-23 16:30 ` H. J. Lu
0 siblings, 1 reply; 3+ messages in thread
From: Jakub Jelinek @ 2006-06-23 14:32 UTC (permalink / raw)
To: binutils
Hi!
#!/bin/sh
CFLAGS="-g -m32 -O2"
gcc $CFLAGS -fpic -c -o a.o -xc - <<EOF
extern __thread int data; extern int *foo (void); extern void abort (void);
int main (void) { if (foo () != &data) abort (); return 0; }
EOF
gcc $CFLAGS -c -o b.o -xc - <<EOF
extern __thread int data;
int *foo (void) { return &data; }
EOF
echo '__thread int data;' | gcc $CFLAGS -c -o c.o -xc -
gcc $CFLAGS -Wl,--export-dynamic -o test a.o b.o c.o
./test; echo $?
is mis-linked, as the GOT slot contains R_386_TPOFF value (0xfffffffc),
but the code in main subtracts this value from %gs:0 rather than adds to it.
Apparently H.J. was trying to fix this two months ago, but the fix was both
insufficient and flawed.
If we only have R_386_TLS_GOTIE/R_386_TLS_IE/R_386_TLS_GD relocations
for some symbols, we don't need 2 got slots and 2 dynamic
relocations, one is enough and the pre-2006-04-08 code was correctly
assuming that. The only bug is that the subl -> addl change was keyed off
the r_type value and so did the right thing only if -shared
(if -shared, elf_i386_tls_transition always return the r_type passed to it
unchanged and the
if (r_type == R_386_TLS_GD
|| r_type == R_386_TLS_GOTDESC
|| r_type == R_386_TLS_DESC_CALL)
{
if (tls_type == GOT_TLS_IE_POS)
r_type = R_386_TLS_GOTIE;
else if (tls_type & GOT_TLS_IE)
r_type = R_386_TLS_IE_32;
}
hunk in that case fired and set r_type to R_386_TLS_GOTIE (which means
subl was correctly changed into addl)). For executables though
elf_i386_tls_transition returns R_386_TLS_IE_32 though (assuming the symbol
is not local), the r_type = R_386_TLS_GOTIE; statement is not executed
(eventhough tls_type == GOT_TLS_IE_POS) and subl is unchanged.
The following patch reverts the 2006-04-08 change and instead
replaces in GD->IE transition
- if (r_type == R_386_TLS_GOTIE)
- {
- contents[roff + 6] = 0x03;
- if (tls_type == GOT_TLS_IE_BOTH)
- off += 4;
- }
with:
+ if (tls_type == GOT_TLS_IE_POS)
+ contents[roff + 6] = 0x03;
(clearly, if tls_type is GOT_TLS_IE_BOTH, r_type would never be
R_386_TLS_GOTIE here and we really should adjust according to the exact
TLS type of the GOT slot).
Ok for trunk?
Alternatively, we could revert the 2006-04-08 patch and replace
if (r_type == R_386_TLS_GD
|| r_type == R_386_TLS_GOTDESC
|| r_type == R_386_TLS_DESC_CALL)
{
if (tls_type == GOT_TLS_IE_POS)
r_type = R_386_TLS_GOTIE;
else if (tls_type & GOT_TLS_IE)
r_type = R_386_TLS_IE_32;
}
with:
if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GD
|| ELF32_R_TYPE (rel->r_info) == R_386_TLS_GOTDESC
|| ELF32_R_TYPE (rel->r_info) == R_386_TLS_DESC_CALL)
{
if (tls_type == GOT_TLS_IE_POS)
r_type = R_386_TLS_GOTIE;
else if (tls_type & GOT_TLS_IE)
r_type = R_386_TLS_IE_32;
}
(and remove the unneeded:
- if (tls_type == GOT_TLS_IE_BOTH)
- off += 4;
), but as GOTDESC and DESC_CALL code only look at tls_type and not
at r_type, this seems more consistent with it.
2006-06-23 Jakub Jelinek <jakub@redhat.com>
PR ld/2513
* elf32-i386.c (GOT_TLS_MASK, GOT_TLS_IE_IE, GOT_TLS_IE_GD,
GOT_TLS_IE_MASK, elf_i386_check_relocs, allocate_dynrelocs): Revert
2006-04-08 changes.
(elf_i386_relocate_section): Likewise. For GD->IE transition
change subl into addl whenever tls_type is GOT_TLS_IE_POS.
* ld-i386/tlsbin.dd: Fix expected output.
--- ld/testsuite/ld-i386/tlsbin.dd.jj 2004-05-11 19:02:12.000000000 +0200
+++ ld/testsuite/ld-i386/tlsbin.dd 2006-06-23 15:10:54.000000000 +0200
@@ -50,7 +50,7 @@ Disassembly of section .text:
# GD -> IE because variable is not defined in executable where
# the variable is referenced through @gotntpoff too
8049035: 65 a1 00 00 00 00[ ]+mov %gs:0x0,%eax
- 804903b: 2b 83 dc ff ff ff[ ]+sub 0xffffffdc\(%ebx\),%eax
+ 804903b: 03 83 dc ff ff ff[ ]+add 0xffffffdc\(%ebx\),%eax
# ->R_386_TLS_TPOFF sG3
8049041: 90[ ]+nop *
8049042: 90[ ]+nop *
--- bfd/elf32-i386.c.jj 2006-06-19 10:33:41.000000000 +0200
+++ bfd/elf32-i386.c 2006-06-23 15:01:39.000000000 +0200
@@ -582,10 +582,6 @@ struct elf_i386_link_hash_entry
#define GOT_TLS_IE_NEG 6
#define GOT_TLS_IE_BOTH 7
#define GOT_TLS_GDESC 8
-#define GOT_TLS_MASK 0x0f
-#define GOT_TLS_IE_IE 0x10
-#define GOT_TLS_IE_GD 0x20
-#define GOT_TLS_IE_MASK 0x30
#define GOT_TLS_GD_BOTH_P(type) \
((type) == (GOT_TLS_GD | GOT_TLS_GDESC))
#define GOT_TLS_GD_P(type) \
@@ -1011,25 +1007,12 @@ elf_i386_check_relocs (bfd *abfd,
case R_386_TLS_IE_32:
if (ELF32_R_TYPE (rel->r_info) == r_type)
tls_type = GOT_TLS_IE_NEG;
- else if (h
- && ELF32_R_TYPE (rel->r_info) == R_386_TLS_GD)
- /* If this is a GD->IE transition, we may use either
- of R_386_TLS_TPOFF and R_386_TLS_TPOFF32. But if
- we may have both R_386_TLS_IE and R_386_TLS_GD,
- we can't share the same R_386_TLS_TPOFF since
- they require different offsets. So we remember
- it comes from R_386_TLS_GD. */
- tls_type = GOT_TLS_IE | GOT_TLS_IE_GD;
else
+ /* If this is a GD->IE transition, we may use either of
+ R_386_TLS_TPOFF and R_386_TLS_TPOFF32. */
tls_type = GOT_TLS_IE;
break;
case R_386_TLS_IE:
- if (h)
- {
- /* We remember it comes from R_386_TLS_IE. */
- tls_type = GOT_TLS_IE_POS | GOT_TLS_IE_IE;
- break;
- }
case R_386_TLS_GOTIE:
tls_type = GOT_TLS_IE_POS; break;
}
@@ -1069,8 +1052,7 @@ elf_i386_check_relocs (bfd *abfd,
tls_type |= old_tls_type;
/* If a TLS symbol is accessed using IE at least once,
there is no point to use dynamic model for it. */
- else if (old_tls_type != tls_type
- && old_tls_type != GOT_UNKNOWN
+ else if (old_tls_type != tls_type && old_tls_type != GOT_UNKNOWN
&& (! GOT_TLS_GD_ANY_P (old_tls_type)
|| (tls_type & GOT_TLS_IE) == 0))
{
@@ -1700,14 +1682,6 @@ allocate_dynrelocs (struct elf_link_hash
asection *s;
bfd_boolean dyn;
int tls_type = elf_i386_hash_entry(h)->tls_type;
-
- /* If we have both R_386_TLS_IE and R_386_TLS_GD, GOT_TLS_IE_BOTH
- should be used. */
- if ((tls_type & GOT_TLS_IE_MASK)
- == (GOT_TLS_IE_IE | GOT_TLS_IE_GD))
- tls_type = GOT_TLS_IE_BOTH;
- else
- tls_type &= GOT_TLS_MASK;
/* Make sure this symbol is output as a dynamic symbol.
Undefined weak syms won't yet be marked as dynamic. */
@@ -2711,13 +2685,6 @@ elf_i386_relocate_section (bfd *output_b
else if (h != NULL)
{
tls_type = elf_i386_hash_entry(h)->tls_type;
- /* If we have both R_386_TLS_IE and R_386_TLS_GD,
- GOT_TLS_IE_BOTH should be used. */
- if ((tls_type & GOT_TLS_IE_MASK)
- == (GOT_TLS_IE_IE | GOT_TLS_IE_GD))
- tls_type = GOT_TLS_IE_BOTH;
- else
- tls_type &= GOT_TLS_MASK;
if (!info->shared && h->dynindx == -1 && (tls_type & GOT_TLS_IE))
r_type = R_386_TLS_LE_32;
}
@@ -3172,12 +3139,8 @@ elf_i386_relocate_section (bfd *output_b
subl $foo@gottpoff(%reg), %eax
into:
addl $foo@gotntpoff(%reg), %eax. */
- if (r_type == R_386_TLS_GOTIE)
- {
- contents[roff + 6] = 0x03;
- if (tls_type == GOT_TLS_IE_BOTH)
- off += 4;
- }
+ if (tls_type == GOT_TLS_IE_POS)
+ contents[roff + 6] = 0x03;
bfd_put_32 (output_bfd,
htab->sgot->output_section->vma
+ htab->sgot->output_offset + off
Jakub
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] Fix i386 GD->IE TLS transition
2006-06-23 14:32 [PATCH] Fix i386 GD->IE TLS transition Jakub Jelinek
@ 2006-06-23 16:30 ` H. J. Lu
2006-06-23 17:34 ` H. J. Lu
0 siblings, 1 reply; 3+ messages in thread
From: H. J. Lu @ 2006-06-23 16:30 UTC (permalink / raw)
To: Jakub Jelinek; +Cc: binutils
On Fri, Jun 23, 2006 at 04:00:51PM +0200, Jakub Jelinek wrote:
> Hi!
>
> #!/bin/sh
> CFLAGS="-g -m32 -O2"
> gcc $CFLAGS -fpic -c -o a.o -xc - <<EOF
> extern __thread int data; extern int *foo (void); extern void abort (void);
> int main (void) { if (foo () != &data) abort (); return 0; }
> EOF
> gcc $CFLAGS -c -o b.o -xc - <<EOF
> extern __thread int data;
> int *foo (void) { return &data; }
> EOF
> echo '__thread int data;' | gcc $CFLAGS -c -o c.o -xc -
> gcc $CFLAGS -Wl,--export-dynamic -o test a.o b.o c.o
> ./test; echo $?
>
> is mis-linked, as the GOT slot contains R_386_TPOFF value (0xfffffffc),
> but the code in main subtracts this value from %gs:0 rather than adds to it.
>
> Apparently H.J. was trying to fix this two months ago, but the fix was both
> insufficient and flawed.
I can't duplicate the failure with the testcase above.
H.J.
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] Fix i386 GD->IE TLS transition
2006-06-23 16:30 ` H. J. Lu
@ 2006-06-23 17:34 ` H. J. Lu
0 siblings, 0 replies; 3+ messages in thread
From: H. J. Lu @ 2006-06-23 17:34 UTC (permalink / raw)
To: Jakub Jelinek; +Cc: binutils
On Fri, Jun 23, 2006 at 09:26:52AM -0700, H. J. Lu wrote:
> On Fri, Jun 23, 2006 at 04:00:51PM +0200, Jakub Jelinek wrote:
> > Hi!
> >
> > #!/bin/sh
> > CFLAGS="-g -m32 -O2"
> > gcc $CFLAGS -fpic -c -o a.o -xc - <<EOF
> > extern __thread int data; extern int *foo (void); extern void abort (void);
> > int main (void) { if (foo () != &data) abort (); return 0; }
> > EOF
> > gcc $CFLAGS -c -o b.o -xc - <<EOF
> > extern __thread int data;
> > int *foo (void) { return &data; }
> > EOF
> > echo '__thread int data;' | gcc $CFLAGS -c -o c.o -xc -
> > gcc $CFLAGS -Wl,--export-dynamic -o test a.o b.o c.o
> > ./test; echo $?
> >
> > is mis-linked, as the GOT slot contains R_386_TPOFF value (0xfffffffc),
> > but the code in main subtracts this value from %gs:0 rather than adds to it.
> >
> > Apparently H.J. was trying to fix this two months ago, but the fix was both
> > insufficient and flawed.
>
> I can't duplicate the failure with the testcase above.
The correct testcase is ld-i386/tlsbin.dd. The patch looks good to me.
H.J.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2006-06-23 17:30 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-06-23 14:32 [PATCH] Fix i386 GD->IE TLS transition Jakub Jelinek
2006-06-23 16:30 ` H. J. Lu
2006-06-23 17:34 ` H. J. Lu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).