aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
Diffstat (limited to 'bfd')
-rw-r--r--bfd/ChangeLog26
-rw-r--r--bfd/bfd-in2.h3
-rw-r--r--bfd/elf32-i386.c371
-rw-r--r--bfd/libbfd.h3
-rw-r--r--bfd/reloc.c6
5 files changed, 334 insertions, 75 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index cb06a25..e697ce3 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,29 @@
+2002-09-19 Jakub Jelinek <jakub@redhat.com>
+
+ * reloc.c (BFD_RELOC_386_TLS_TPOFF, BFD_RELOC_386_TLS_IE,
+ BFD_RELOC_386_TLS_GOTIE): Add.
+ * bfd-in2.h, libbfd.h: Rebuilt.
+ * elf32-i386.c (elf_howto_table): Add R_386_TLS_TPOFF, R_386_TLS_IE
+ and R_386_TLS_GOTIE.
+ (elf_i386_reloc_type_lookup): Handle it.
+ (struct elf_i386_link_hash_entry): Change tls_type type to unsigned
+ char instead of enum, change GOT_* into defines.
+ (GOT_TLS_IE_POS, GOT_TLS_IE_NEG, GOT_TLS_IE_BOTH): Define.
+ (elf_i386_tls_transition): Handle R_386_TLS_IE and R_386_TLS_GOTIE.
+ (elf_i386_check_relocs): Likewise. Avoid crash if local symbol is
+ accessed both as normal and TLS symbol. Move R_386_TLS_LDM and
+ R_386_PLT32 cases so that R_386_TLS_IE can fall through.
+ Handle R_386_TLS_LE_32 and R_386_TLS_LE in shared libs.
+ (elf_i386_gc_sweep_hook): Handle R_386_TLS_IE and R_386_TLS_GOTIE.
+ Handle R_386_TLS_LE_32 and R_386_TLS_LE in shared libs.
+ (allocate_dynrelocs): Allocate 2 .got and 2 .rel.got entries if
+ tls_type is GOT_TLS_IE_BOTH.
+ (elf_i386_size_dynamic_sections): Likewise.
+ (elf_i386_relocate_section): Handle R_386_TLS_IE and R_386_TLS_GOTIE.
+ Handle R_386_TLS_LE_32 and R_386_TLS_LE in shared libs.
+ (elf_i386_finish_dynamic_symbol): Use tls_type & GOT_TLS_IE to catch
+ all 4 GOT_TLS_* TLS types.
+
2002-09-19 Nick Clifton <nickc@redhat.com>
* elflink.h (elf_fix_symbol_flags): When examining weak symbols,
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index b6edd0a..0525594 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -2264,6 +2264,9 @@ to compensate for the borrow when the low bits are added. */
BFD_RELOC_386_RELATIVE,
BFD_RELOC_386_GOTOFF,
BFD_RELOC_386_GOTPC,
+ BFD_RELOC_386_TLS_TPOFF,
+ BFD_RELOC_386_TLS_IE,
+ BFD_RELOC_386_TLS_GOTIE,
BFD_RELOC_386_TLS_LE,
BFD_RELOC_386_TLS_GD,
BFD_RELOC_386_TLS_LDM,
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c
index ef22e68..d52d5a7 100644
--- a/bfd/elf32-i386.c
+++ b/bfd/elf32-i386.c
@@ -133,9 +133,18 @@ static reloc_howto_type elf_howto_table[]=
R_386_ext_offset is the value to subtract from a reloc type of
R_386_16 thru R_386_PC8 to form an index into this table. */
#define R_386_standard ((unsigned int) R_386_GOTPC + 1)
-#define R_386_ext_offset ((unsigned int) R_386_TLS_LE - R_386_standard)
+#define R_386_ext_offset ((unsigned int) R_386_TLS_TPOFF - R_386_standard)
- /* The remaining relocs are a GNU extension. */
+ /* These relocs are a GNU extension. */
+ HOWTO(R_386_TLS_TPOFF, 0, 2, 32, false, 0, complain_overflow_bitfield,
+ bfd_elf_generic_reloc, "R_386_TLS_TPOFF",
+ true, 0xffffffff, 0xffffffff, false),
+ HOWTO(R_386_TLS_IE, 0, 2, 32, false, 0, complain_overflow_bitfield,
+ bfd_elf_generic_reloc, "R_386_TLS_IE",
+ true, 0xffffffff, 0xffffffff, false),
+ HOWTO(R_386_TLS_GOTIE, 0, 2, 32, false, 0, complain_overflow_bitfield,
+ bfd_elf_generic_reloc, "R_386_TLS_GOTIE",
+ true, 0xffffffff, 0xffffffff, false),
HOWTO(R_386_TLS_LE, 0, 2, 32, false, 0, complain_overflow_bitfield,
bfd_elf_generic_reloc, "R_386_TLS_LE",
true, 0xffffffff, 0xffffffff, false),
@@ -279,7 +288,19 @@ elf_i386_reloc_type_lookup (abfd, code)
TRACE ("BFD_RELOC_386_GOTPC");
return &elf_howto_table[(unsigned int) R_386_GOTPC ];
- /* The remaining relocs are a GNU extension. */
+ /* These relocs are a GNU extension. */
+ case BFD_RELOC_386_TLS_TPOFF:
+ TRACE ("BFD_RELOC_386_TLS_TPOFF");
+ return &elf_howto_table[(unsigned int) R_386_TLS_TPOFF - R_386_ext_offset];
+
+ case BFD_RELOC_386_TLS_IE:
+ TRACE ("BFD_RELOC_386_TLS_IE");
+ return &elf_howto_table[(unsigned int) R_386_TLS_IE - R_386_ext_offset];
+
+ case BFD_RELOC_386_TLS_GOTIE:
+ TRACE ("BFD_RELOC_386_TLS_GOTIE");
+ return &elf_howto_table[(unsigned int) R_386_TLS_GOTIE - R_386_ext_offset];
+
case BFD_RELOC_386_TLS_LE:
TRACE ("BFD_RELOC_386_TLS_LE");
return &elf_howto_table[(unsigned int) R_386_TLS_LE - R_386_ext_offset];
@@ -564,9 +585,14 @@ struct elf_i386_link_hash_entry
/* Track dynamic relocs copied for this symbol. */
struct elf_i386_dyn_relocs *dyn_relocs;
- enum {
- GOT_UNKNOWN = 0, GOT_NORMAL, GOT_TLS_GD, GOT_TLS_IE
- } tls_type;
+#define GOT_UNKNOWN 0
+#define GOT_NORMAL 1
+#define GOT_TLS_GD 2
+#define GOT_TLS_IE 4
+#define GOT_TLS_IE_POS 5
+#define GOT_TLS_IE_NEG 6
+#define GOT_TLS_IE_BOTH 7
+ unsigned char tls_type;
};
#define elf_i386_hash_entry(ent) ((struct elf_i386_link_hash_entry *)(ent))
@@ -836,6 +862,11 @@ elf_i386_tls_transition (info, r_type, is_local)
if (is_local)
return R_386_TLS_LE_32;
return R_386_TLS_IE_32;
+ case R_386_TLS_IE:
+ case R_386_TLS_GOTIE:
+ if (is_local)
+ return R_386_TLS_LE_32;
+ return r_type;
case R_386_TLS_LDM:
return R_386_TLS_LE_32;
}
@@ -897,10 +928,34 @@ elf_i386_check_relocs (abfd, info, sec, relocs)
switch (r_type)
{
+ case R_386_TLS_LDM:
+ htab->tls_ldm_got.refcount += 1;
+ goto create_got;
+
+ case R_386_PLT32:
+ /* This symbol requires a procedure linkage table entry. We
+ actually build the entry in adjust_dynamic_symbol,
+ because this might be a case of linking PIC code which is
+ never referenced by a dynamic object, in which case we
+ don't need to generate a procedure linkage table entry
+ after all. */
+
+ /* If this is a local symbol, we resolve it directly without
+ creating a procedure linkage table entry. */
+ if (h == NULL)
+ continue;
+
+ h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
+ h->plt.refcount += 1;
+ break;
+
case R_386_TLS_IE_32:
+ case R_386_TLS_IE:
+ case R_386_TLS_GOTIE:
if (info->shared)
info->flags |= DF_STATIC_TLS;
- /* FALLTHROUGH */
+ /* Fall through */
+
case R_386_GOT32:
case R_386_TLS_GD:
/* This symbol requires a global offset table entry. */
@@ -912,7 +967,17 @@ elf_i386_check_relocs (abfd, info, sec, relocs)
default:
case R_386_GOT32: tls_type = GOT_NORMAL; break;
case R_386_TLS_GD: tls_type = GOT_TLS_GD; break;
- case R_386_TLS_IE_32: tls_type = GOT_TLS_IE; break;
+ case R_386_TLS_IE_32:
+ if (ELF32_R_TYPE (rel->r_info) == r_type)
+ tls_type = GOT_TLS_IE_NEG;
+ 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:
+ case R_386_TLS_GOTIE:
+ tls_type = GOT_TLS_IE_POS; break;
}
if (h != NULL)
@@ -944,18 +1009,22 @@ elf_i386_check_relocs (abfd, info, sec, relocs)
old_tls_type = elf_i386_local_got_tls_type (abfd) [r_symndx];
}
+ if ((old_tls_type & GOT_TLS_IE) && (tls_type & GOT_TLS_IE))
+ 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. */
- if (old_tls_type != tls_type && old_tls_type != GOT_UNKNOWN
- && (old_tls_type != GOT_TLS_GD || tls_type != GOT_TLS_IE))
+ else if (old_tls_type != tls_type && old_tls_type != GOT_UNKNOWN
+ && (old_tls_type != GOT_TLS_GD
+ || (tls_type & GOT_TLS_IE) == 0))
{
- if (old_tls_type == GOT_TLS_IE && tls_type == GOT_TLS_GD)
- tls_type = GOT_TLS_IE;
+ if ((old_tls_type & GOT_TLS_IE) && tls_type == GOT_TLS_GD)
+ tls_type = old_tls_type;
else
{
(*_bfd_error_handler)
(_("%s: `%s' accessed both as normal and thread local symbol"),
- bfd_archive_filename (abfd), h->root.root.string);
+ bfd_archive_filename (abfd),
+ h ? h->root.root.string : "<local>");
return false;
}
}
@@ -980,28 +1049,15 @@ elf_i386_check_relocs (abfd, info, sec, relocs)
if (!create_got_section (htab->elf.dynobj, info))
return false;
}
- break;
-
- case R_386_TLS_LDM:
- htab->tls_ldm_got.refcount += 1;
- goto create_got;
-
- case R_386_PLT32:
- /* This symbol requires a procedure linkage table entry. We
- actually build the entry in adjust_dynamic_symbol,
- because this might be a case of linking PIC code which is
- never referenced by a dynamic object, in which case we
- don't need to generate a procedure linkage table entry
- after all. */
-
- /* If this is a local symbol, we resolve it directly without
- creating a procedure linkage table entry. */
- if (h == NULL)
- continue;
+ if (r_type != R_386_TLS_IE)
+ break;
+ /* Fall through */
- h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT;
- h->plt.refcount += 1;
- break;
+ case R_386_TLS_LE_32:
+ case R_386_TLS_LE:
+ if (!info->shared)
+ break;
+ /* Fall through */
case R_386_32:
case R_386_PC32:
@@ -1161,16 +1217,6 @@ elf_i386_check_relocs (abfd, info, sec, relocs)
return false;
break;
- case R_386_TLS_LE_32:
- case R_386_TLS_LE:
- if (info->shared)
- {
- (*_bfd_error_handler) (_("%s: TLS local exec code cannot be linked into shared objects"),
- bfd_archive_filename (abfd));
- return false;
- }
- break;
-
default:
break;
}
@@ -1233,6 +1279,7 @@ elf_i386_gc_sweep_hook (abfd, info, sec, relocs)
bfd_signed_vma *local_got_refcounts;
const Elf_Internal_Rela *rel, *relend;
unsigned long r_symndx;
+ int r_type;
struct elf_link_hash_entry *h;
elf_section_data (sec)->local_dynrel = NULL;
@@ -1243,9 +1290,10 @@ elf_i386_gc_sweep_hook (abfd, info, sec, relocs)
relend = relocs + sec->reloc_count;
for (rel = relocs; rel < relend; rel++)
- switch (elf_i386_tls_transition (info, ELF32_R_TYPE (rel->r_info),
- ELF32_R_SYM (rel->r_info)
- >= symtab_hdr->sh_info))
+ switch ((r_type = elf_i386_tls_transition (info,
+ ELF32_R_TYPE (rel->r_info),
+ ELF32_R_SYM (rel->r_info)
+ >= symtab_hdr->sh_info)))
{
case R_386_TLS_LDM:
if (elf_i386_hash_table (info)->tls_ldm_got.refcount > 0)
@@ -1254,6 +1302,8 @@ elf_i386_gc_sweep_hook (abfd, info, sec, relocs)
case R_386_TLS_GD:
case R_386_TLS_IE_32:
+ case R_386_TLS_IE:
+ case R_386_TLS_GOTIE:
case R_386_GOT32:
r_symndx = ELF32_R_SYM (rel->r_info);
if (r_symndx >= symtab_hdr->sh_info)
@@ -1267,7 +1317,15 @@ elf_i386_gc_sweep_hook (abfd, info, sec, relocs)
if (local_got_refcounts[r_symndx] > 0)
local_got_refcounts[r_symndx] -= 1;
}
- break;
+ if (r_type != R_386_TLS_IE)
+ break;
+ /* Fall through */
+
+ case R_386_TLS_LE_32:
+ case R_386_TLS_LE:
+ if (!info->shared)
+ break;
+ /* Fall through */
case R_386_32:
case R_386_PC32:
@@ -1553,12 +1611,12 @@ allocate_dynrelocs (h, inf)
h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT;
}
- /* If R_386_TLS_IE_32 symbol is now local to the binary,
+ /* If R_386_TLS_{IE_32,IE,GOTIE} symbol is now local to the binary,
make it a R_386_TLS_LE_32 requiring no TLS entry. */
if (h->got.refcount > 0
&& !info->shared
&& h->dynindx == -1
- && elf_i386_hash_entry(h)->tls_type == GOT_TLS_IE)
+ && (elf_i386_hash_entry(h)->tls_type & GOT_TLS_IE))
h->got.offset = (bfd_vma) -1;
else if (h->got.refcount > 0)
{
@@ -1579,13 +1637,18 @@ allocate_dynrelocs (h, inf)
h->got.offset = s->_raw_size;
s->_raw_size += 4;
/* R_386_TLS_GD needs 2 consecutive GOT slots. */
- if (tls_type == GOT_TLS_GD)
+ if (tls_type == GOT_TLS_GD || tls_type == GOT_TLS_IE_BOTH)
s->_raw_size += 4;
dyn = htab->elf.dynamic_sections_created;
/* R_386_TLS_IE_32 needs one dynamic relocation,
- R_386_TLS_GD needs one if local symbol and two if global. */
- if ((tls_type == GOT_TLS_GD && h->dynindx == -1)
- || tls_type == GOT_TLS_IE)
+ R_386_TLS_IE resp. R_386_TLS_GOTIE needs one dynamic relocation,
+ (but if both R_386_TLS_IE_32 and R_386_TLS_IE is present, we
+ need two), R_386_TLS_GD needs one if local symbol and two if
+ global. */
+ if (tls_type == GOT_TLS_IE_BOTH)
+ htab->srelgot->_raw_size += 2 * sizeof (Elf32_External_Rel);
+ else if ((tls_type == GOT_TLS_GD && h->dynindx == -1)
+ || (tls_type & GOT_TLS_IE))
htab->srelgot->_raw_size += sizeof (Elf32_External_Rel);
else if (tls_type == GOT_TLS_GD)
htab->srelgot->_raw_size += 2 * sizeof (Elf32_External_Rel);
@@ -1786,12 +1849,18 @@ elf_i386_size_dynamic_sections (output_bfd, info)
{
*local_got = s->_raw_size;
s->_raw_size += 4;
- if (*local_tls_type == GOT_TLS_GD)
+ if (*local_tls_type == GOT_TLS_GD
+ || *local_tls_type == GOT_TLS_IE_BOTH)
s->_raw_size += 4;
if (info->shared
|| *local_tls_type == GOT_TLS_GD
- || *local_tls_type == GOT_TLS_IE)
- srel->_raw_size += sizeof (Elf32_External_Rel);
+ || (*local_tls_type & GOT_TLS_IE))
+ {
+ if (*local_tls_type == GOT_TLS_IE_BOTH)
+ srel->_raw_size += 2 * sizeof (Elf32_External_Rel);
+ else
+ srel->_raw_size += sizeof (Elf32_External_Rel);
+ }
}
else
*local_got = (bfd_vma) -1;
@@ -2422,8 +2491,29 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
}
break;
+ case R_386_TLS_IE:
+ if (info->shared)
+ {
+ Elf_Internal_Rel outrel;
+ asection *sreloc;
+ Elf32_External_Rel *loc;
+
+ outrel.r_offset = rel->r_offset
+ + input_section->output_section->vma
+ + input_section->output_offset;
+ outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE);
+ sreloc = elf_section_data (input_section)->sreloc;
+ if (sreloc == NULL)
+ abort ();
+ loc = (Elf32_External_Rel *) sreloc->contents;
+ loc += sreloc->reloc_count++;
+ bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+ }
+ /* Fall through */
+
case R_386_TLS_GD:
case R_386_TLS_IE_32:
+ case R_386_TLS_GOTIE:
r_type = elf_i386_tls_transition (info, r_type, h == NULL);
tls_type = GOT_UNKNOWN;
if (h == NULL && local_got_offsets)
@@ -2431,11 +2521,18 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
else if (h != NULL)
{
tls_type = elf_i386_hash_entry(h)->tls_type;
- if (!info->shared && h->dynindx == -1 && tls_type == GOT_TLS_IE)
+ if (!info->shared && h->dynindx == -1 && (tls_type & GOT_TLS_IE))
r_type = R_386_TLS_LE_32;
}
- if (r_type == R_386_TLS_GD && tls_type == GOT_TLS_IE)
- r_type = R_386_TLS_IE_32;
+ if (tls_type == GOT_TLS_IE)
+ tls_type = GOT_TLS_IE_NEG;
+ if (r_type == R_386_TLS_GD)
+ {
+ 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;
+ }
if (r_type == R_386_TLS_LE_32)
{
@@ -2503,27 +2600,77 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
rel++;
continue;
}
- else
+ else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_IE)
{
unsigned int val, type;
/* IE->LE transition:
- Originally it can be either:
+ Originally it can be one of:
+ movl foo, %eax
+ movl foo, %reg
+ addl foo, %reg
+ We change it into:
+ movl $foo, %eax
+ movl $foo, %reg
+ addl $foo, %reg. */
+ BFD_ASSERT (rel->r_offset >= 1);
+ val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1);
+ BFD_ASSERT (rel->r_offset + 4 <= input_section->_raw_size);
+ if (val != 0xa1)
+ {
+ BFD_ASSERT (rel->r_offset >= 2);
+ type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2);
+ }
+ if (val == 0xa1)
+ {
+ /* movl foo, %eax. */
+ bfd_put_8 (output_bfd, 0xb8, contents + rel->r_offset - 2);
+ }
+ else if (type == 0x8b)
+ {
+ /* movl */
+ BFD_ASSERT ((val & 0xc7) == 0x05);
+ bfd_put_8 (output_bfd, 0xc7,
+ contents + rel->r_offset - 2);
+ bfd_put_8 (output_bfd, 0xc0 | ((val >> 3) & 7),
+ contents + rel->r_offset - 1);
+ }
+ else if (type == 0x03)
+ {
+ /* addl */
+ BFD_ASSERT ((val & 0xc7) == 0x05);
+ bfd_put_8 (output_bfd, 0x81,
+ contents + rel->r_offset - 2);
+ bfd_put_8 (output_bfd, 0xc0 | ((val >> 3) & 7),
+ contents + rel->r_offset - 1);
+ }
+ else
+ BFD_FAIL ();
+ bfd_put_32 (output_bfd, -tpoff (info, relocation),
+ contents + rel->r_offset);
+ continue;
+ }
+ else
+ {
+ unsigned int val, type;
+
+ /* {IE_32,GOTIE}->LE transition:
+ Originally it can be one of:
subl foo(%reg1), %reg2
- or
movl foo(%reg1), %reg2
+ addl foo(%reg1), %reg2
We change it into:
subl $foo, %reg2
- or
- movl $foo, %reg2 (6 byte form) */
+ movl $foo, %reg2 (6 byte form)
+ addl $foo, %reg2. */
BFD_ASSERT (rel->r_offset >= 2);
type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2);
val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1);
BFD_ASSERT (rel->r_offset + 4 <= input_section->_raw_size);
+ BFD_ASSERT ((val & 0xc0) == 0x80 && (val & 7) != 4);
if (type == 0x8b)
{
/* movl */
- BFD_ASSERT ((val & 0xc0) == 0x80 && (val & 7) != 4);
bfd_put_8 (output_bfd, 0xc7,
contents + rel->r_offset - 2);
bfd_put_8 (output_bfd, 0xc0 | ((val >> 3) & 7),
@@ -2532,16 +2679,27 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
else if (type == 0x2b)
{
/* subl */
- BFD_ASSERT ((val & 0xc0) == 0x80 && (val & 7) != 4);
bfd_put_8 (output_bfd, 0x81,
contents + rel->r_offset - 2);
bfd_put_8 (output_bfd, 0xe8 | ((val >> 3) & 7),
contents + rel->r_offset - 1);
}
+ else if (type == 0x03)
+ {
+ /* addl */
+ bfd_put_8 (output_bfd, 0x81,
+ contents + rel->r_offset - 2);
+ bfd_put_8 (output_bfd, 0xc0 | ((val >> 3) & 7),
+ contents + rel->r_offset - 1);
+ }
else
BFD_FAIL ();
- bfd_put_32 (output_bfd, tpoff (info, relocation),
- contents + rel->r_offset);
+ if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GOTIE)
+ bfd_put_32 (output_bfd, -tpoff (info, relocation),
+ contents + rel->r_offset);
+ else
+ bfd_put_32 (output_bfd, tpoff (info, relocation),
+ contents + rel->r_offset);
continue;
}
}
@@ -2576,9 +2734,14 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
indx = h && h->dynindx != -1 ? h->dynindx : 0;
if (r_type == R_386_TLS_GD)
dr_type = R_386_TLS_DTPMOD32;
+ else if (tls_type == GOT_TLS_IE_POS)
+ dr_type = R_386_TLS_TPOFF;
else
dr_type = R_386_TLS_TPOFF32;
- if (dr_type == R_386_TLS_TPOFF32 && indx == 0)
+ if (dr_type == R_386_TLS_TPOFF && indx == 0)
+ bfd_put_32 (output_bfd, relocation - dtpoff_base (info),
+ htab->sgot->contents + off);
+ else if (dr_type == R_386_TLS_TPOFF32 && indx == 0)
bfd_put_32 (output_bfd, dtpoff_base (info) - relocation,
htab->sgot->contents + off);
else
@@ -2611,6 +2774,17 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
loc);
}
}
+ else if (tls_type == GOT_TLS_IE_BOTH)
+ {
+ bfd_put_32 (output_bfd,
+ indx == 0 ? relocation - dtpoff_base (info) : 0,
+ htab->sgot->contents + off + 4);
+ outrel.r_info = ELF32_R_INFO (indx, R_386_TLS_TPOFF);
+ outrel.r_offset += 4;
+ htab->srelgot->reloc_count++;
+ loc++;
+ bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+ }
if (h != NULL)
h->got.offset |= 1;
@@ -2623,6 +2797,11 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
if (r_type == ELF32_R_TYPE (rel->r_info))
{
relocation = htab->sgot->output_offset + off;
+ if ((r_type == R_386_TLS_IE || r_type == R_386_TLS_GOTIE)
+ && tls_type == GOT_TLS_IE_BOTH)
+ relocation += 4;
+ if (r_type == R_386_TLS_IE)
+ relocation += htab->sgot->output_section->vma;
unresolved_reloc = false;
}
else
@@ -2668,6 +2847,17 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
memcpy (contents + roff,
"\x65\xa1\0\0\0\0\x2b\x80\0\0\0", 12);
contents[roff + 7] = 0x80 | (val & 7);
+ /* If foo is used only with foo@gotntpoff(%reg) and
+ foo@indntpoff, but not with foo@gottpoff(%reg), change
+ 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;
+ }
bfd_put_32 (output_bfd, htab->sgot->output_offset + off,
contents + roff + 8);
/* Skip R_386_PLT32. */
@@ -2743,11 +2933,42 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section,
break;
case R_386_TLS_LE_32:
- relocation = tpoff (info, relocation);
- break;
-
case R_386_TLS_LE:
- relocation = -tpoff (info, relocation);
+ if (info->shared)
+ {
+ Elf_Internal_Rel outrel;
+ asection *sreloc;
+ Elf32_External_Rel *loc;
+ int indx;
+
+ outrel.r_offset = rel->r_offset
+ + input_section->output_section->vma
+ + input_section->output_offset;
+ if (h != NULL && h->dynindx != -1)
+ indx = h->dynindx;
+ else
+ indx = 0;
+ if (r_type == R_386_TLS_LE_32)
+ outrel.r_info = ELF32_R_INFO (indx, R_386_TLS_TPOFF32);
+ else
+ outrel.r_info = ELF32_R_INFO (indx, R_386_TLS_TPOFF);
+ sreloc = elf_section_data (input_section)->sreloc;
+ if (sreloc == NULL)
+ abort ();
+ loc = (Elf32_External_Rel *) sreloc->contents;
+ loc += sreloc->reloc_count++;
+ bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc);
+ if (indx)
+ continue;
+ else if (r_type == R_386_TLS_LE_32)
+ relocation = dtpoff_base (info) - relocation;
+ else
+ relocation -= dtpoff_base (info);
+ }
+ else if (r_type == R_386_TLS_LE_32)
+ relocation = tpoff (info, relocation);
+ else
+ relocation = -tpoff (info, relocation);
break;
default:
@@ -2907,7 +3128,7 @@ elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym)
if (h->got.offset != (bfd_vma) -1
&& elf_i386_hash_entry(h)->tls_type != GOT_TLS_GD
- && elf_i386_hash_entry(h)->tls_type != GOT_TLS_IE)
+ && (elf_i386_hash_entry(h)->tls_type & GOT_TLS_IE) == 0)
{
Elf_Internal_Rel rel;
Elf32_External_Rel *loc;
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index e855db1..3971ea6 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -799,6 +799,9 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_RELOC_386_RELATIVE",
"BFD_RELOC_386_GOTOFF",
"BFD_RELOC_386_GOTPC",
+ "BFD_RELOC_386_TLS_TPOFF",
+ "BFD_RELOC_386_TLS_IE",
+ "BFD_RELOC_386_TLS_GOTIE",
"BFD_RELOC_386_TLS_LE",
"BFD_RELOC_386_TLS_GD",
"BFD_RELOC_386_TLS_LDM",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index e60c26e..504359f 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -2123,6 +2123,12 @@ ENUMX
ENUMX
BFD_RELOC_386_GOTPC
ENUMX
+ BFD_RELOC_386_TLS_TPOFF
+ENUMX
+ BFD_RELOC_386_TLS_IE
+ENUMX
+ BFD_RELOC_386_TLS_GOTIE
+ENUMX
BFD_RELOC_386_TLS_LE
ENUMX
BFD_RELOC_386_TLS_GD