aboutsummaryrefslogtreecommitdiff
path: root/bfd/elf32-i386.c
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2006-04-08 22:57:22 +0000
committerH.J. Lu <hjl.tools@gmail.com>2006-04-08 22:57:22 +0000
commitcb878726df95ae9effe3b5b06a519bf2f2786226 (patch)
treebe50e49bc285bc8cee79690a5aecdfbcd903add9 /bfd/elf32-i386.c
parent07c5f590ae27c60e498282c40414f6c77dccc39a (diff)
downloadgdb-cb878726df95ae9effe3b5b06a519bf2f2786226.zip
gdb-cb878726df95ae9effe3b5b06a519bf2f2786226.tar.gz
gdb-cb878726df95ae9effe3b5b06a519bf2f2786226.tar.bz2
2006-04-08 H.J. Lu <hongjiu.lu@intel.com>
PR ld/2513 * elf32-i386.c (GOT_TLS_MASK): New macro for tls_type. (GOT_TLS_IE_IE): Likewise. (GOT_TLS_IE_GD): Likewise. (GOT_TLS_IE_MASK): Likewise. (elf_i386_check_relocs): For global symbols, set GOT_TLS_IE_GD and GOT_TLS_IE_IE for R_386_TLS_GD and R_386_TLS_IE respectively. (allocate_dynrelocs): If both GOT_TLS_IE_IE and GOT_TLS_IE_GD are set, treat tls_type as GOT_TLS_IE_BOTH. (elf_i386_relocate_section): Likewise.
Diffstat (limited to 'bfd/elf32-i386.c')
-rw-r--r--bfd/elf32-i386.c39
1 files changed, 36 insertions, 3 deletions
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index bc44cba..754aa52 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -582,6 +582,10 @@ 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) \
@@ -1007,12 +1011,25 @@ 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;
}
@@ -1052,7 +1069,8 @@ 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))
{
@@ -1682,6 +1700,14 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
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. */
@@ -2685,6 +2711,13 @@ elf_i386_relocate_section (bfd *output_bfd,
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;
}