TLS support for MIPS
Daniel Jacobowitz
drow@false.org
Tue Feb 8 09:30:00 GMT 2005
This patch implements thread-local storage for MIPS. The ABI can be found
at <http://www.linux-mips.org/wiki/index.php/NPTL>; GCC, Linux kernel, and
glibc bits will be along shortly.
First, there's one architecture independent fix in here (sorry). While
writing testcases I discovered that if the first object on the command line
was a shared library with a .reginfo section, then the resulting object
would not contain .reginfo. We'd select the copy from the shared library
as the only one to hold on to, and obligingly exclude all the others. Oops!
The bulk of the code is dealing with the unique MIPS GOT infrastructure.
I've tried to parallel the existing design as closely as possible. TLS
symbols are placed after the global and local entries for each GOT, to avoid
automatic relocation by the dynamic linker. There may be multiple
mips_got_info structures for each global TLS symbol while in single-GOT
mode, just as for normal symbols. We record the relevant TLS access types
on each GOT entry, and their union on the global symbol if applicable.
I had a lot of trouble with the GOT support, so I wrote exhaustive
(exhausting) test cases. I am especially proud of tls-multi-got-1.
No linker relaxations are supported, mostly because the MIPS linker didn't
have an existing framework for same. There may be some in the future,
though I anticipate that new marker relocations would be introduced to
support them.
Tested via cross builds to mips-elf, mips-linux, mips64-linux, and little
endian versions of same. Also tested using NPTL patches for GCC and glibc
on mips-linux.
OK? Comments, questions, things I failed to explain?
--
Daniel Jacobowitz
CodeSourcery, LLC
2005-02-07 Daniel Jacobowitz <dan@codesourcery.com>
* elflink.c: Don't exclude sections based on a shared library input.
* elfxx-mips.c (struct mips_got_entry): Add tls_type.
(struct mips_got_info): Add tls_gotno, tls_assigned_gotno,
and tls_ldm_offset.
(struct mips_elf_got_per_bfd_arg): Add global_count.
(struct mips_elf_count_tls_arg): New.
(struct mips_elf_hash_sort_data): Update comment for min_got_dynindx.
(struct mips_elf_link_hash_entry): Add tls_type and tls_got_offset.
(GOT_NORMAL, GOT_TLS_GD, GOT_TLS_LDM, GOT_TLS_IE)
(GOT_TLS_OFFSET_DONE, GOT_TLS_DONE): Define.
(IS_TLS_RELOC): Define.
(TP_OFFSET, DTP_OFFSET): Define.
(dtpoff_base, tpoff_base): New functions.
(mips_elf_link_hash_newfunc): Initialize tls_type.
(mips_elf_got_entry_hash, mips_elf_got_entry_eq)
(mips_elf_multi_got_entry_hash, mips_elf_multi_got_entry_eq): Handle
TLS entries.
(mips_tls_got_relocs, mips_elf_count_local_tls_relocs)
(mips_elf_count_global_tls_entries, mips_elf_count_global_tls_relocs)
(mips_elf_initialize_tls_slots, mips_tls_got_index): New functions.
(mips_elf_local_got_index): Add new R_SYMNDX, H, and R_TYPE
arguments. Pass them to mips_elf_create_local_got_entry. Use
mips_tls_got_index.
(mips_elf_global_got_index): Add new R_TYPE and INFO arguments.
Handle TLS entries.
(mips_elf_got_page, mips_elf_got16_entry): Update calls to
mips_elf_create_local_got_entry.
(mips_elf_create_local_got_entry): Add new R_SYMNDX, H, and R_TYPE
arguments. Handle TLS entries.
(mips_elf_sort_hash_table_f): Add non-TLS assertions.
(mips_elf_record_local_got_symbol): Add new TLS_FLAG argument. Handle
TLS entries.
(mips_elf_record_global_got_symbol): Likewise.
(mips_elf_make_got_per_bfd): Initialize new mips_got_info members.
Count TLS entries.
(mips_elf_merge_gots): Handle TLS entries when merging.
(mips_elf_initialize_tls_index): New function.
(mips_elf_set_global_got_offset): Handle TLS entries.
(mips_elf_adjust_gp): Handle TLS.
(mips_elf_multi_got): Remove redundant call to
mips_elf_resolve_final_got_entries. Initialize global_count.
Correct a comment. Initialize new TLS members of mips_got_info.
Assign TLS GOT indexes for new GOTs.
(mips_elf_create_got_section): Initialize new TLS members of
mips_got_info.
(mips_elf_calculate_relocation): Handle TLS relocs.
(_bfd_mips_elf_check_relocs): Likewise. Update calls to changed
functions.
(_bfd_mips_elf_always_size_sections): Handle TLS.
(_bfd_mips_elf_size_dynamic_sections): Likewise.
(_bfd_mips_elf_finish_dynamic_symbol): Likewise. Update calls to
changed functions.
(_bfd_mips_elf_copy_indirect_symbol): Copy tls_type.
(_bfd_mips_elf_hide_symbol): Handle TLS.
* elfn32-mips.c (elf_mips_howto_table_rel, elf_mips_howto_table_rela)
(mips_reloc_map): Add TLS relocs.
* elf32-mips.c (elf_mips_howto_table_rel, mips_reloc_map): Likewise.
* elf64-mips.c (mips_elf64_howto_table_rel)
(mips_elf64_howto_table_rela, mips_reloc_map): Likewise.
* reloc.c: Define new MIPS TLS relocations.
* libbfd.h, bfd-in2.h: Regenerated.
2005-02-07 Daniel Jacobowitz <dan@codesourcery.com>
* ld-mips-elf/tlsbin-o32.s, ld-mips-elf/mips-dyn.ld,
ld-mips-elf/tlslib-o32.got, ld-mips-elf/tlslib-o32.d,
ld-mips-elf/tlslib-o32.s, ld-mips-elf/mips-lib.ld,
ld-mips-elf/tlsbin-o32.got, ld-mips-elf/tlsdyn-o32.d,
ld-mips-elf/tlsdyn-o32.got, ld-mips-elf/tlsbin-o32.d,
ld-mips-elf/tlsdyn-o32.s, ld-mips-elf/tls-multi-got-1.got,
ld-mips-elf/tls-multi-got-1-1.s, ld-mips-elf/tls-multi-got-1.d,
ld-mips-elf/tls-multi-got-1.r, ld-mips-elf/tls-multi-got-1-2.s,
ld-mips-elf/tlslib-o32-ver.got, ld-mips-elf/tlslib.ver,
ld-mips-elf/tlslib-o32-hidden.got, ld-mips-elf/tlslib-hidden.ver,
ld-mips-elf/tlsdyn-o32-1.d, ld-mips-elf/tlsdyn-o32-3.got,
ld-mips-elf/tlsdyn-o32-2.d, ld-mips-elf/tlsdyn-o32-2.s,
ld-mips-elf/tlsdyn-o32-3.d, ld-mips-elf/tlsdyn-o32-1.got,
ld-mips-elf/tlsdyn-o32-2.got: New files.
* ld-mips-elf/mips-elf.exp: Run the new tests.
2005-02-07 Daniel Jacobowitz <dan@codesourcery.com>
* elf/mips.h: Define MIPS TLS relocations.
2005-02-07 Daniel Jacobowitz <dan@codesourcery.com>
* config/tc-mips.c (percent_op): Add %tlsgd, %tlsldm, %dtpoff,
%tpoff, and %gottpoff.
(parse_relocation): Check for a word break after a relocation
operator.
(my_getSmallExpression): Handle TLS relocations.
(md_apply_fix3): Handle TLS relocations, and mark thread-local
symbols.
2005-02-07 Daniel Jacobowitz <dan@codesourcery.com>
* gas/mips/tls-o32.d, gas/mips/tls-o32.s, gas/mips/tls-ill.l,
gas/mips/tls-ill.s: New files.
* gas/mips/mips.exp: Run TLS tests.
Index: binutils/bfd/elfxx-mips.c
===================================================================
--- binutils.orig/bfd/elfxx-mips.c 2005-02-01 16:59:39.000000000 -0500
+++ binutils/bfd/elfxx-mips.c 2005-02-07 16:21:35.253461706 -0500
@@ -64,6 +64,14 @@ struct mips_got_entry
h->forced_local). */
struct mips_elf_link_hash_entry *h;
} d;
+
+ /* The TLS types included in this GOT entry (specifically, GD and
+ IE). The GD and IE flags can be added as we encounter new
+ relocations. LDM can also be set; it will always be alone, not
+ combined with any GD or IE flags. An LDM GOT entry will be
+ a local symbol entry with r_symndx == 0. */
+ unsigned char tls_type;
+
/* The offset from the beginning of the .got section to the entry
corresponding to this symbol+addend. If it's a global symbol
whose offset is yet to be decided, it's going to be -1. */
@@ -79,6 +87,11 @@ struct mips_got_info
struct elf_link_hash_entry *global_gotsym;
/* The number of global .got entries. */
unsigned int global_gotno;
+ /* The number of .got slots used for TLS. */
+ unsigned int tls_gotno;
+ /* The first unused TLS .got entry. Used only during
+ mips_elf_initialize_tls_index. */
+ unsigned int tls_assigned_gotno;
/* The number of local .got entries. */
unsigned int local_gotno;
/* The number of local .got entries we have used. */
@@ -91,6 +104,11 @@ struct mips_got_info
/* In multi-got links, a pointer to the next got (err, rather, most
of the time, it points to the previous got). */
struct mips_got_info *next;
+ /* This is the GOT index of the TLS LDM entry for the GOT, MINUS_ONE
+ for none, or MINUS_TWO for not yet assigned. This is needed
+ because a single-GOT link may have multiple hash table entries
+ for the LDM. It does not get initialized in multi-GOT mode. */
+ bfd_vma tls_ldm_offset;
};
/* Map an input bfd to a got in a multi-got link. */
@@ -125,6 +143,11 @@ struct mips_elf_got_per_bfd_arg
unsigned int primary_count;
/* The number of local and global entries in the current got. */
unsigned int current_count;
+ /* The total number of global entries which will live in the
+ primary got and be automatically relocated. This includes
+ those not referenced by the primary GOT but included in
+ the "master" GOT. */
+ unsigned int global_count;
};
/* Another structure used to pass arguments for got entries traversal. */
@@ -137,6 +160,15 @@ struct mips_elf_set_global_got_offset_ar
struct bfd_link_info *info;
};
+/* A structure used to count TLS relocations or GOT entries, for GOT
+ entry or ELF symbol table traversal. */
+
+struct mips_elf_count_tls_arg
+{
+ struct bfd_link_info *info;
+ unsigned int needed;
+};
+
struct _mips_elf_section_data
{
struct bfd_elf_section_data elf;
@@ -158,8 +190,8 @@ struct mips_elf_hash_sort_data
/* The symbol in the global GOT with the lowest dynamic symbol table
index. */
struct elf_link_hash_entry *low;
- /* The least dynamic symbol table index corresponding to a symbol
- with a GOT entry. */
+ /* The least dynamic symbol table index corresponding to a non-TLS
+ symbol with a GOT entry. */
long min_got_dynindx;
/* The greatest dynamic symbol table index corresponding to a symbol
with a GOT entry that is not referenced (e.g., a dynamic symbol
@@ -212,6 +244,21 @@ struct mips_elf_link_hash_entry
/* Are we forced local? .*/
bfd_boolean forced_local;
+
+#define GOT_NORMAL 0
+#define GOT_TLS_GD 1
+#define GOT_TLS_LDM 2
+#define GOT_TLS_IE 4
+#define GOT_TLS_OFFSET_DONE 0x40
+#define GOT_TLS_DONE 0x80
+ unsigned char tls_type;
+ /* This is only used in single-GOT mode; in multi-GOT mode there
+ is one mips_got_entry per GOT entry, so the offset is stored
+ there. In single-GOT mode there may be many mips_got_entry
+ structures all referring to the same GOT slot. It might be
+ possible to use root.got.offset instead, but that field is
+ overloaded already. */
+ bfd_vma tls_got_offset;
};
/* MIPS ELF linker hash table. */
@@ -237,6 +284,21 @@ struct mips_elf_link_hash_table
bfd_boolean mips16_stubs_seen;
};
+#define IS_TLS_RELOC(r_type) \
+ (r_type == R_MIPS_TLS_DTPMOD32 \
+ || r_type == R_MIPS_TLS_DTPMOD64 \
+ || r_type == R_MIPS_TLS_DTPOFF32 \
+ || r_type == R_MIPS_TLS_DTPOFF64 \
+ || r_type == R_MIPS_TLS_GD \
+ || r_type == R_MIPS_TLS_LDM \
+ || r_type == R_MIPS_TLS_LDO_HI16 \
+ || r_type == R_MIPS_TLS_LDO_LO16 \
+ || r_type == R_MIPS_TLS_TPOFF \
+ || r_type == R_MIPS_TLS_TPOFF32 \
+ || r_type == R_MIPS_TLS_TPOFF64 \
+ || r_type == R_MIPS_TLS_TPOFF_HI16 \
+ || r_type == R_MIPS_TLS_TPOFF_LO16)
+
/* Structure used to pass information to mips_elf_output_extsym. */
struct extsym_info
@@ -401,9 +463,10 @@ static asection *mips_elf_got_section
static struct mips_got_info *mips_elf_got_info
(bfd *, asection **);
static bfd_vma mips_elf_local_got_index
- (bfd *, bfd *, struct bfd_link_info *, bfd_vma);
+ (bfd *, bfd *, struct bfd_link_info *, bfd_vma, unsigned long,
+ struct mips_elf_link_hash_entry *, int);
static bfd_vma mips_elf_global_got_index
- (bfd *, bfd *, struct elf_link_hash_entry *);
+ (bfd *, bfd *, struct elf_link_hash_entry *, int, struct bfd_link_info *);
static bfd_vma mips_elf_got_page
(bfd *, bfd *, struct bfd_link_info *, bfd_vma, bfd_vma *);
static bfd_vma mips_elf_got16_entry
@@ -411,16 +474,17 @@ static bfd_vma mips_elf_got16_entry
static bfd_vma mips_elf_got_offset_from_index
(bfd *, bfd *, bfd *, bfd_vma);
static struct mips_got_entry *mips_elf_create_local_got_entry
- (bfd *, bfd *, struct mips_got_info *, asection *, bfd_vma);
+ (bfd *, bfd *, struct mips_got_info *, asection *, bfd_vma, unsigned long,
+ struct mips_elf_link_hash_entry *, int);
static bfd_boolean mips_elf_sort_hash_table
(struct bfd_link_info *, unsigned long);
static bfd_boolean mips_elf_sort_hash_table_f
(struct mips_elf_link_hash_entry *, void *);
static bfd_boolean mips_elf_record_local_got_symbol
- (bfd *, long, bfd_vma, struct mips_got_info *);
+ (bfd *, long, bfd_vma, struct mips_got_info *, unsigned char);
static bfd_boolean mips_elf_record_global_got_symbol
(struct elf_link_hash_entry *, bfd *, struct bfd_link_info *,
- struct mips_got_info *);
+ struct mips_got_info *, unsigned char);
static const Elf_Internal_Rela *mips_elf_next_relocation
(bfd *, unsigned int, const Elf_Internal_Rela *, const Elf_Internal_Rela *);
static bfd_boolean mips_elf_local_relocation_p
@@ -700,6 +764,30 @@ static bfd *reldyn_sorting_bfd;
#define mips_elf_hash_table(p) \
((struct mips_elf_link_hash_table *) ((p)->hash))
+/* Find the base offsets for thread-local storage in this object,
+ for GD/LD and IE/LE respectively. */
+
+#define TP_OFFSET 0x7000
+#define DTP_OFFSET 0x8000
+
+static bfd_vma
+dtpoff_base (struct bfd_link_info *info)
+{
+ /* If tls_sec is NULL, we should have signalled an error already. */
+ if (elf_hash_table (info)->tls_sec == NULL)
+ return 0;
+ return elf_hash_table (info)->tls_sec->vma + DTP_OFFSET;
+}
+
+static bfd_vma
+tpoff_base (struct bfd_link_info *info)
+{
+ /* If tls_sec is NULL, we should have signalled an error already. */
+ if (elf_hash_table (info)->tls_sec == NULL)
+ return 0;
+ return elf_hash_table (info)->tls_sec->vma + TP_OFFSET;
+}
+
/* Create an entry in a MIPS ELF linker hash table. */
static struct bfd_hash_entry *
@@ -735,6 +823,7 @@ mips_elf_link_hash_newfunc (struct bfd_h
ret->call_stub = NULL;
ret->call_fp_stub = NULL;
ret->forced_local = FALSE;
+ ret->tls_type = GOT_NORMAL;
}
return (struct bfd_hash_entry *) ret;
@@ -1693,6 +1782,7 @@ mips_elf_got_entry_hash (const void *ent
const struct mips_got_entry *entry = (struct mips_got_entry *)entry_;
return entry->symndx
+ + ((entry->tls_type & GOT_TLS_LDM) << 17)
+ (! entry->abfd ? mips_elf_hash_bfd_vma (entry->d.address)
: entry->abfd->id
+ (entry->symndx >= 0 ? mips_elf_hash_bfd_vma (entry->d.addend)
@@ -1705,6 +1795,10 @@ mips_elf_got_entry_eq (const void *entry
const struct mips_got_entry *e1 = (struct mips_got_entry *)entry1;
const struct mips_got_entry *e2 = (struct mips_got_entry *)entry2;
+ /* An LDM entry can only match another LDM entry. */
+ if ((e1->tls_type ^ e2->tls_type) & GOT_TLS_LDM)
+ return 0;
+
return e1->abfd == e2->abfd && e1->symndx == e2->symndx
&& (! e1->abfd ? e1->d.address == e2->d.address
: e1->symndx >= 0 ? e1->d.addend == e2->d.addend
@@ -1725,8 +1819,10 @@ mips_elf_multi_got_entry_hash (const voi
+ (! entry->abfd
? mips_elf_hash_bfd_vma (entry->d.address)
: entry->symndx >= 0
- ? (entry->abfd->id
- + mips_elf_hash_bfd_vma (entry->d.addend))
+ ? ((entry->tls_type & GOT_TLS_LDM)
+ ? (GOT_TLS_LDM << 17)
+ : (entry->abfd->id
+ + mips_elf_hash_bfd_vma (entry->d.addend)))
: entry->d.h->root.root.root.hash);
}
@@ -1736,6 +1832,14 @@ mips_elf_multi_got_entry_eq (const void
const struct mips_got_entry *e1 = (struct mips_got_entry *)entry1;
const struct mips_got_entry *e2 = (struct mips_got_entry *)entry2;
+ /* Any two LDM entries match. */
+ if (e1->tls_type & e2->tls_type & GOT_TLS_LDM)
+ return 1;
+
+ /* Nothing else matches an LDM entry. */
+ if ((e1->tls_type ^ e2->tls_type) & GOT_TLS_LDM)
+ return 0;
+
return e1->symndx == e2->symndx
&& (e1->symndx >= 0 ? e1->abfd == e2->abfd && e1->d.addend == e2->d.addend
: e1->abfd == NULL || e2->abfd == NULL
@@ -1804,13 +1908,356 @@ mips_elf_got_info (bfd *abfd, asection *
return g;
}
+/* Count the number of relocations needed for a TLS GOT entry, with
+ access types from TLS_TYPE, and symbol H (or a local symbol if H
+ is NULL). */
+
+static int
+mips_tls_got_relocs (struct bfd_link_info *info, unsigned char tls_type,
+ struct elf_link_hash_entry *h)
+{
+ int indx = 0;
+ int ret = 0;
+ bfd_boolean need_relocs = FALSE;
+ bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created;
+
+ if (h && WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
+ && (!info->shared || !SYMBOL_REFERENCES_LOCAL (info, h)))
+ indx = h->dynindx;
+
+ if ((info->shared || indx != 0)
+ && (h == NULL
+ || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak))
+ need_relocs = TRUE;
+
+ if (!need_relocs)
+ return FALSE;
+
+ if (tls_type & GOT_TLS_GD)
+ {
+ ret++;
+ if (indx != 0)
+ ret++;
+ }
+
+ if (tls_type & GOT_TLS_IE)
+ ret++;
+
+ if ((tls_type & GOT_TLS_LDM) && info->shared)
+ ret++;
+
+ return ret;
+}
+
+/* Count the number of TLS relocations required for the GOT entry in
+ ARG1, if it describes a local symbol. */
+
+static int
+mips_elf_count_local_tls_relocs (void **arg1, void *arg2)
+{
+ struct mips_got_entry *entry = * (struct mips_got_entry **) arg1;
+ struct mips_elf_count_tls_arg *arg = arg2;
+
+ if (entry->abfd != NULL && entry->symndx != -1)
+ arg->needed += mips_tls_got_relocs (arg->info, entry->tls_type, NULL);
+
+ return 1;
+}
+
+/* Count the number of TLS GOT entries required for the global (or
+ forced-local) symbol in ARG1. */
+
+static int
+mips_elf_count_global_tls_entries (void *arg1, void *arg2)
+{
+ struct mips_elf_link_hash_entry *hm
+ = (struct mips_elf_link_hash_entry *) arg1;
+ struct mips_elf_count_tls_arg *arg = arg2;
+
+ if (hm->tls_type & GOT_TLS_GD)
+ arg->needed += 2;
+ if (hm->tls_type & GOT_TLS_IE)
+ arg->needed += 1;
+
+ return 1;
+}
+
+/* Count the number of TLS relocations required for the global (or
+ forced-local) symbol in ARG1. */
+
+static int
+mips_elf_count_global_tls_relocs (void *arg1, void *arg2)
+{
+ struct mips_elf_link_hash_entry *hm
+ = (struct mips_elf_link_hash_entry *) arg1;
+ struct mips_elf_count_tls_arg *arg = arg2;
+
+ arg->needed += mips_tls_got_relocs (arg->info, hm->tls_type, &hm->root);
+
+ return 1;
+}
+
+/* Initialize a set of TLS GOT entries for one symbol. */
+
+static void
+mips_elf_initialize_tls_slots (bfd *abfd, bfd_vma got_offset,
+ unsigned char *tls_type_p,
+ struct bfd_link_info *info,
+ struct mips_elf_link_hash_entry *h,
+ bfd_vma value)
+{
+ int indx;
+ Elf_Internal_Rela rel[3];
+ asection *sreloc, *sgot;
+ bfd_vma offset, offset2;
+ bfd *dynobj;
+ bfd_boolean need_relocs = FALSE;
+
+ dynobj = elf_hash_table (info)->dynobj;
+ sgot = mips_elf_got_section (dynobj, FALSE);
+
+ indx = 0;
+ if (h != NULL)
+ {
+ bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created;
+
+ if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, &h->root)
+ && (!info->shared || !SYMBOL_REFERENCES_LOCAL (info, &h->root)))
+ indx = h->root.dynindx;
+ }
+
+ if (*tls_type_p & GOT_TLS_DONE)
+ return;
+
+ if ((info->shared || indx != 0)
+ && (h == NULL
+ || ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT
+ || h->root.type != bfd_link_hash_undefweak))
+ need_relocs = TRUE;
+
+ /* MINUS_ONE means the symbol is not defined in this object. It may not
+ be defined at all; assume that the value doesn't matter in that
+ case. Otherwise complain if we would use the value. */
+ BFD_ASSERT (value != MINUS_ONE || (indx != 0 && need_relocs)
+ || h->root.root.type == bfd_link_hash_undefweak);
+
+ /* Emit necessary relocations. */
+ sreloc = mips_elf_rel_dyn_section (dynobj, FALSE);
+
+ /* General Dynamic. */
+ if (*tls_type_p & GOT_TLS_GD)
+ {
+ offset = got_offset;
+ offset2 = offset + MIPS_ELF_GOT_SIZE (abfd);
+
+ if (need_relocs)
+ {
+ memset (rel, 0, sizeof (rel));
+ if (ABI_64_P (abfd))
+ rel[0].r_info = ELF_R_INFO (abfd, (unsigned long) indx,
+ R_MIPS_TLS_DTPMOD64);
+ else
+ rel[0].r_info = ELF_R_INFO (abfd, (unsigned long) indx,
+ R_MIPS_TLS_DTPMOD32);
+ rel[0].r_offset = rel[1].r_offset = rel[2].r_offset
+ = sgot->output_offset + sgot->output_section->vma + offset;
+ rel[1].r_info = ELF_R_INFO (abfd, 0, R_MIPS_NONE);
+ rel[2].r_info = ELF_R_INFO (abfd, 0, R_MIPS_NONE);
+ if (ABI_64_P (abfd))
+ {
+ (*get_elf_backend_data (abfd)->s->swap_reloc_out)
+ (abfd, &rel[0],
+ (sreloc->contents
+ + sreloc->reloc_count * sizeof (Elf64_Mips_External_Rel)));
+ }
+ else
+ bfd_elf32_swap_reloc_out
+ (abfd, &rel[0],
+ (sreloc->contents
+ + sreloc->reloc_count * sizeof (Elf32_External_Rel)));
+ ++sreloc->reloc_count;
+
+ if (indx)
+ {
+ memset (rel, 0, sizeof (rel));
+ if (ABI_64_P (abfd))
+ rel[0].r_info = ELF_R_INFO (abfd, (unsigned long) indx,
+ R_MIPS_TLS_DTPOFF64);
+ else
+ rel[0].r_info = ELF_R_INFO (abfd, (unsigned long) indx,
+ R_MIPS_TLS_DTPOFF32);
+ rel[0].r_offset = rel[1].r_offset = rel[2].r_offset
+ = sgot->output_offset + sgot->output_section->vma + offset2;
+ rel[1].r_info = ELF_R_INFO (abfd, 0, R_MIPS_NONE);
+ rel[2].r_info = ELF_R_INFO (abfd, 0, R_MIPS_NONE);
+ if (ABI_64_P (abfd))
+ {
+ (*get_elf_backend_data (abfd)->s->swap_reloc_out)
+ (abfd, &rel[0],
+ (sreloc->contents
+ + sreloc->reloc_count * sizeof (Elf64_Mips_External_Rel)));
+ }
+ else
+ bfd_elf32_swap_reloc_out
+ (abfd, &rel[0],
+ (sreloc->contents
+ + sreloc->reloc_count * sizeof (Elf32_External_Rel)));
+ ++sreloc->reloc_count;
+ }
+ else
+ MIPS_ELF_PUT_WORD (abfd, value - dtpoff_base (info),
+ sgot->contents + offset2);
+ }
+ else
+ {
+ MIPS_ELF_PUT_WORD (abfd, 1,
+ sgot->contents + offset);
+ MIPS_ELF_PUT_WORD (abfd, value - dtpoff_base (info),
+ sgot->contents + offset2);
+ }
+
+ got_offset += 2 * MIPS_ELF_GOT_SIZE (abfd);
+ }
+
+ /* Initial Exec model. */
+ if (*tls_type_p & GOT_TLS_IE)
+ {
+ offset = got_offset;
+
+ if (need_relocs)
+ {
+ if (indx == 0)
+ MIPS_ELF_PUT_WORD (abfd, value - elf_hash_table (info)->tls_sec->vma,
+ sgot->contents + offset);
+ else
+ MIPS_ELF_PUT_WORD (abfd, 0,
+ sgot->contents + offset);
+
+ memset (rel, 0, sizeof (rel));
+ if (ABI_64_P (abfd))
+ rel[0].r_info = ELF_R_INFO (abfd, (unsigned long) indx,
+ R_MIPS_TLS_TPOFF64);
+ else
+ rel[0].r_info = ELF_R_INFO (abfd, (unsigned long) indx,
+ R_MIPS_TLS_TPOFF32);
+ rel[0].r_offset = rel[1].r_offset = rel[2].r_offset
+ = sgot->output_offset + sgot->output_section->vma + offset;
+ rel[1].r_info = ELF_R_INFO (abfd, 0, R_MIPS_NONE);
+ rel[2].r_info = ELF_R_INFO (abfd, 0, R_MIPS_NONE);
+ if (ABI_64_P (abfd))
+ {
+ (*get_elf_backend_data (abfd)->s->swap_reloc_out)
+ (abfd, &rel[0],
+ (sreloc->contents
+ + sreloc->reloc_count * sizeof (Elf64_Mips_External_Rel)));
+ }
+ else
+ bfd_elf32_swap_reloc_out
+ (abfd, &rel[0],
+ (sreloc->contents
+ + sreloc->reloc_count * sizeof (Elf32_External_Rel)));
+ ++sreloc->reloc_count;
+ }
+ else
+ {
+ MIPS_ELF_PUT_WORD (abfd, value - tpoff_base (info),
+ sgot->contents + offset);
+ }
+ }
+
+ if (*tls_type_p & GOT_TLS_LDM)
+ {
+ /* The initial offset is zero, and the LD offsets will include the
+ bias by DTP_OFFSET. */
+ MIPS_ELF_PUT_WORD (abfd, 0,
+ sgot->contents + got_offset
+ + MIPS_ELF_GOT_SIZE (abfd));
+
+ if (!info->shared)
+ MIPS_ELF_PUT_WORD (abfd, 1,
+ sgot->contents + got_offset);
+ else
+ {
+ sreloc = mips_elf_rel_dyn_section (dynobj, FALSE);
+ memset (rel, 0, sizeof (rel));
+ if (ABI_64_P (abfd))
+ rel[0].r_info = ELF_R_INFO (abfd, (unsigned long) 0,
+ R_MIPS_TLS_DTPMOD64);
+ else
+ rel[0].r_info = ELF_R_INFO (abfd, (unsigned long) 0,
+ R_MIPS_TLS_DTPMOD32);
+ rel[0].r_offset = rel[1].r_offset = rel[2].r_offset
+ = sgot->output_offset + sgot->output_section->vma + got_offset;
+ rel[1].r_info = ELF_R_INFO (abfd, 0, R_MIPS_NONE);
+ rel[2].r_info = ELF_R_INFO (abfd, 0, R_MIPS_NONE);
+ if (ABI_64_P (abfd))
+ {
+ (*get_elf_backend_data (abfd)->s->swap_reloc_out)
+ (abfd, &rel[0],
+ (sreloc->contents
+ + sreloc->reloc_count * sizeof (Elf64_Mips_External_Rel)));
+ }
+ else
+ bfd_elf32_swap_reloc_out
+ (abfd, &rel[0],
+ (sreloc->contents
+ + sreloc->reloc_count * sizeof (Elf32_External_Rel)));
+ ++sreloc->reloc_count;
+ }
+ }
+
+ *tls_type_p |= GOT_TLS_DONE;
+}
+
+/* Return the GOT index to use for a relocation of type R_TYPE against
+ a symbol accessed using TLS_TYPE models. The GOT entries for this
+ symbol in this GOT start at GOT_INDEX. This function initializes the
+ GOT entries and corresponding relocations. */
+
+static bfd_vma
+mips_tls_got_index (bfd *abfd, bfd_vma got_index, unsigned char *tls_type,
+ int r_type, struct bfd_link_info *info,
+ struct mips_elf_link_hash_entry *h, bfd_vma symbol)
+{
+ BFD_ASSERT (r_type == R_MIPS_TLS_TPOFF || r_type == R_MIPS_TLS_GD
+ || r_type == R_MIPS_TLS_LDM);
+
+ mips_elf_initialize_tls_slots (abfd, got_index, tls_type, info, h, symbol);
+
+ if (r_type == R_MIPS_TLS_TPOFF)
+ {
+ BFD_ASSERT (*tls_type & GOT_TLS_IE);
+ if (*tls_type & GOT_TLS_GD)
+ return got_index + 2 * MIPS_ELF_GOT_SIZE (abfd);
+ else
+ return got_index;
+ }
+
+ if (r_type == R_MIPS_TLS_GD)
+ {
+ BFD_ASSERT (*tls_type & GOT_TLS_GD);
+ return got_index;
+ }
+
+ if (r_type == R_MIPS_TLS_LDM)
+ {
+ BFD_ASSERT (*tls_type & GOT_TLS_LDM);
+ return got_index;
+ }
+
+ return got_index;
+}
+
/* Returns the GOT offset at which the indicated address can be found.
- If there is not yet a GOT entry for this value, create one. Returns
- -1 if no satisfactory GOT offset can be found. */
+ If there is not yet a GOT entry for this value, create one. If
+ R_SYMNDX refers to a TLS symbol, create a TLS GOT entry instead.
+ Returns -1 if no satisfactory GOT offset can be found. */
static bfd_vma
mips_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info,
- bfd_vma value)
+ bfd_vma value, unsigned long r_symndx,
+ struct mips_elf_link_hash_entry *h, int r_type)
{
asection *sgot;
struct mips_got_info *g;
@@ -1818,17 +2265,23 @@ mips_elf_local_got_index (bfd *abfd, bfd
g = mips_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
- entry = mips_elf_create_local_got_entry (abfd, ibfd, g, sgot, value);
- if (entry)
- return entry->gotidx;
- else
+ entry = mips_elf_create_local_got_entry (abfd, ibfd, g, sgot, value,
+ r_symndx, h, r_type);
+ if (!entry)
return MINUS_ONE;
+
+ if (IS_TLS_RELOC (r_type))
+ return mips_tls_got_index (abfd, entry->gotidx, &entry->tls_type, r_type,
+ info, h, value);
+ else
+ return entry->gotidx;
}
/* Returns the GOT index for the global symbol indicated by H. */
static bfd_vma
-mips_elf_global_got_index (bfd *abfd, bfd *ibfd, struct elf_link_hash_entry *h)
+mips_elf_global_got_index (bfd *abfd, bfd *ibfd, struct elf_link_hash_entry *h,
+ int r_type, struct bfd_link_info *info)
{
bfd_vma index;
asection *sgot;
@@ -1843,29 +2296,64 @@ mips_elf_global_got_index (bfd *abfd, bf
BFD_ASSERT (h->dynindx >= 0);
g = mips_elf_got_for_ibfd (g, ibfd);
- if (g->next != gg)
+ if (g->next != gg || IS_TLS_RELOC (r_type))
{
e.abfd = ibfd;
e.symndx = -1;
e.d.h = (struct mips_elf_link_hash_entry *)h;
+ e.tls_type = 0;
p = htab_find (g->got_entries, &e);
BFD_ASSERT (p->gotidx > 0);
- return p->gotidx;
+
+ if (IS_TLS_RELOC (r_type))
+ {
+ bfd_vma value = MINUS_ONE;
+ if ((h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && h->root.u.def.section->output_section)
+ value = (h->root.u.def.value
+ + h->root.u.def.section->output_offset
+ + h->root.u.def.section->output_section->vma);
+
+ return mips_tls_got_index (abfd, p->gotidx, &p->tls_type, r_type,
+ info, e.d.h, value);
+ }
+ else
+ return p->gotidx;
}
}
if (gg->global_gotsym != NULL)
global_got_dynindx = gg->global_gotsym->dynindx;
- /* Once we determine the global GOT entry with the lowest dynamic
- symbol table index, we must put all dynamic symbols with greater
- indices into the GOT. That makes it easy to calculate the GOT
- offset. */
- BFD_ASSERT (h->dynindx >= global_got_dynindx);
- index = ((h->dynindx - global_got_dynindx + g->local_gotno)
- * MIPS_ELF_GOT_SIZE (abfd));
+ if (IS_TLS_RELOC (r_type))
+ {
+ struct mips_elf_link_hash_entry *hm
+ = (struct mips_elf_link_hash_entry *) h;
+ bfd_vma value = MINUS_ONE;
+
+ if ((h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && h->root.u.def.section->output_section)
+ value = (h->root.u.def.value
+ + h->root.u.def.section->output_offset
+ + h->root.u.def.section->output_section->vma);
+
+ index = mips_tls_got_index (abfd, hm->tls_got_offset, &hm->tls_type,
+ r_type, info, hm, value);
+ }
+ else
+ {
+ /* Once we determine the global GOT entry with the lowest dynamic
+ symbol table index, we must put all dynamic symbols with greater
+ indices into the GOT. That makes it easy to calculate the GOT
+ offset. */
+ BFD_ASSERT (h->dynindx >= global_got_dynindx);
+ index = ((h->dynindx - global_got_dynindx + g->local_gotno)
+ * MIPS_ELF_GOT_SIZE (abfd));
+ }
BFD_ASSERT (index < sgot->size);
return index;
@@ -1890,7 +2378,8 @@ mips_elf_got_page (bfd *abfd, bfd *ibfd,
entry = mips_elf_create_local_got_entry (abfd, ibfd, g, sgot,
(value + 0x8000)
- & (~(bfd_vma)0xffff));
+ & (~(bfd_vma)0xffff), 0,
+ NULL, R_MIPS_GOT_PAGE);
if (!entry)
return MINUS_ONE;
@@ -1925,7 +2414,8 @@ mips_elf_got16_entry (bfd *abfd, bfd *ib
g = mips_elf_got_info (elf_hash_table (info)->dynobj, &sgot);
- entry = mips_elf_create_local_got_entry (abfd, ibfd, g, sgot, value);
+ entry = mips_elf_create_local_got_entry (abfd, ibfd, g, sgot, value, 0, NULL,
+ R_MIPS_GOT16);
if (entry)
return entry->gotidx;
else
@@ -1951,12 +2441,16 @@ mips_elf_got_offset_from_index (bfd *dyn
}
/* Create a local GOT entry for VALUE. Return the index of the entry,
- or -1 if it could not be created. */
+ or -1 if it could not be created. If R_SYMNDX refers to a TLS symbol,
+ create a TLS entry instead. */
static struct mips_got_entry *
mips_elf_create_local_got_entry (bfd *abfd, bfd *ibfd,
struct mips_got_info *gg,
- asection *sgot, bfd_vma value)
+ asection *sgot, bfd_vma value,
+ unsigned long r_symndx,
+ struct mips_elf_link_hash_entry *h,
+ int r_type)
{
struct mips_got_entry entry, **loc;
struct mips_got_info *g;
@@ -1964,6 +2458,7 @@ mips_elf_create_local_got_entry (bfd *ab
entry.abfd = NULL;
entry.symndx = -1;
entry.d.address = value;
+ entry.tls_type = 0;
g = mips_elf_got_for_ibfd (gg, ibfd);
if (g == NULL)
@@ -1972,12 +2467,44 @@ mips_elf_create_local_got_entry (bfd *ab
BFD_ASSERT (g != NULL);
}
+ /* We might have a symbol, H, if it has been forced local. Use the
+ global entry then. It doesn't matter whether an entry is local
+ or global for TLS, since the dynamic linker does not
+ automatically relocate TLS GOT entries. */
+ BFD_ASSERT (h == NULL || h->forced_local);
+ if (IS_TLS_RELOC (r_type))
+ {
+ struct mips_got_entry *p;
+
+ entry.abfd = ibfd;
+ if (r_type == R_MIPS_TLS_LDM)
+ {
+ entry.tls_type = GOT_TLS_LDM;
+ entry.symndx = 0;
+ entry.d.addend = 0;
+ }
+ else if (h == NULL)
+ {
+ entry.symndx = r_symndx;
+ entry.d.addend = 0;
+ }
+ else
+ entry.d.h = h;
+
+ p = (struct mips_got_entry *)
+ htab_find (g->got_entries, &entry);
+
+ BFD_ASSERT (p);
+ return p;
+ }
+
loc = (struct mips_got_entry **) htab_find_slot (g->got_entries, &entry,
INSERT);
if (*loc)
return *loc;
entry.gotidx = MIPS_ELF_GOT_SIZE (abfd) * g->assigned_gotno++;
+ entry.tls_type = 0;
*loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry);
@@ -2073,6 +2600,8 @@ mips_elf_sort_hash_table_f (struct mips_
-1. */
if (h->root.got.offset == 2)
{
+ BFD_ASSERT (h->tls_type == GOT_NORMAL);
+
if (hsd->max_unref_got_dynindx == hsd->min_got_dynindx)
hsd->low = (struct elf_link_hash_entry *) h;
h->root.dynindx = hsd->max_unref_got_dynindx++;
@@ -2081,6 +2610,8 @@ mips_elf_sort_hash_table_f (struct mips_
h->root.dynindx = hsd->max_non_got_dynindx++;
else
{
+ BFD_ASSERT (h->tls_type == GOT_NORMAL);
+
h->root.dynindx = --hsd->min_got_dynindx;
hsd->low = (struct elf_link_hash_entry *) h;
}
@@ -2095,7 +2626,8 @@ mips_elf_sort_hash_table_f (struct mips_
static bfd_boolean
mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h,
bfd *abfd, struct bfd_link_info *info,
- struct mips_got_info *g)
+ struct mips_got_info *g,
+ unsigned char tls_flag)
{
struct mips_got_entry entry, **loc;
@@ -2117,6 +2649,7 @@ mips_elf_record_global_got_symbol (struc
entry.abfd = abfd;
entry.symndx = -1;
entry.d.h = (struct mips_elf_link_hash_entry *) h;
+ entry.tls_type = 0;
loc = (struct mips_got_entry **) htab_find_slot (g->got_entries, &entry,
INSERT);
@@ -2124,7 +2657,10 @@ mips_elf_record_global_got_symbol (struc
/* If we've already marked this entry as needing GOT space, we don't
need to do it again. */
if (*loc)
- return TRUE;
+ {
+ (*loc)->tls_type |= tls_flag;
+ return TRUE;
+ }
*loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry);
@@ -2132,6 +2668,8 @@ mips_elf_record_global_got_symbol (struc
return FALSE;
entry.gotidx = -1;
+ entry.tls_type = tls_flag;
+
memcpy (*loc, &entry, sizeof entry);
if (h->got.offset != MINUS_ONE)
@@ -2140,7 +2678,8 @@ mips_elf_record_global_got_symbol (struc
/* By setting this to a value other than -1, we are indicating that
there needs to be a GOT entry for H. Avoid using zero, as the
generic ELF copy_indirect_symbol tests for <= 0. */
- h->got.offset = 1;
+ if (tls_flag == 0)
+ h->got.offset = 1;
return TRUE;
}
@@ -2150,20 +2689,52 @@ mips_elf_record_global_got_symbol (struc
static bfd_boolean
mips_elf_record_local_got_symbol (bfd *abfd, long symndx, bfd_vma addend,
- struct mips_got_info *g)
+ struct mips_got_info *g,
+ unsigned char tls_flag)
{
struct mips_got_entry entry, **loc;
entry.abfd = abfd;
entry.symndx = symndx;
entry.d.addend = addend;
+ entry.tls_type = tls_flag;
loc = (struct mips_got_entry **)
htab_find_slot (g->got_entries, &entry, INSERT);
if (*loc)
- return TRUE;
+ {
+ if (tls_flag == GOT_TLS_GD && !((*loc)->tls_type & GOT_TLS_GD))
+ {
+ g->tls_gotno += 2;
+ (*loc)->tls_type |= tls_flag;
+ }
+ else if (tls_flag == GOT_TLS_IE && !((*loc)->tls_type & GOT_TLS_IE))
+ {
+ g->tls_gotno += 1;
+ (*loc)->tls_type |= tls_flag;
+ }
+ return TRUE;
+ }
- entry.gotidx = g->local_gotno++;
+ if (tls_flag != 0)
+ {
+ entry.gotidx = -1;
+ entry.tls_type = tls_flag;
+ if (tls_flag == GOT_TLS_IE)
+ g->tls_gotno += 1;
+ else if (tls_flag == GOT_TLS_GD)
+ g->tls_gotno += 2;
+ else if (g->tls_ldm_offset == MINUS_ONE)
+ {
+ g->tls_ldm_offset = MINUS_TWO;
+ g->tls_gotno += 2;
+ }
+ }
+ else
+ {
+ entry.gotidx = g->local_gotno++;
+ entry.tls_type = 0;
+ }
*loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry);
@@ -2263,6 +2834,9 @@ mips_elf_make_got_per_bfd (void **entryp
g->global_gotno = 0;
g->local_gotno = 0;
g->assigned_gotno = -1;
+ g->tls_gotno = 0;
+ g->tls_assigned_gotno = 0;
+ g->tls_ldm_offset = MINUS_ONE;
g->got_entries = htab_try_create (1, mips_elf_multi_got_entry_hash,
mips_elf_multi_got_entry_eq, NULL);
if (g->got_entries == NULL)
@@ -2282,7 +2856,14 @@ mips_elf_make_got_per_bfd (void **entryp
*entryp = entry;
- if (entry->symndx >= 0 || entry->d.h->forced_local)
+ if (entry->tls_type)
+ {
+ if (entry->tls_type & (GOT_TLS_GD | GOT_TLS_LDM))
+ g->tls_gotno += 2;
+ if (entry->tls_type & GOT_TLS_IE)
+ g->tls_gotno += 1;
+ }
+ else if (entry->symndx >= 0 || entry->d.h->forced_local)
++g->local_gotno;
else
++g->global_gotno;
@@ -2305,11 +2886,26 @@ mips_elf_merge_gots (void **bfd2got_, vo
struct mips_elf_got_per_bfd_arg *arg = (struct mips_elf_got_per_bfd_arg *)p;
unsigned int lcount = bfd2got->g->local_gotno;
unsigned int gcount = bfd2got->g->global_gotno;
+ unsigned int tcount = bfd2got->g->tls_gotno;
unsigned int maxcnt = arg->max_count;
+ bfd_boolean too_many_for_tls = FALSE;
+
+ /* We place TLS GOT entries after both locals and globals. The globals
+ for the primary GOT may overflow the normal GOT size limit, so be
+ sure not to merge a GOT which requires TLS with the primary GOT in that
+ case. This doesn't affect non-primary GOTs. */
+ if (tcount > 0)
+ {
+ unsigned int primary_total = lcount + tcount + arg->global_count;
+ if (primary_total * MIPS_ELF_GOT_SIZE (bfd2got->bfd)
+ >= MIPS_ELF_GOT_MAX_SIZE (bfd2got->bfd))
+ too_many_for_tls = TRUE;
+ }
/* If we don't have a primary GOT and this is not too big, use it as
a starting point for the primary GOT. */
- if (! arg->primary && lcount + gcount <= maxcnt)
+ if (! arg->primary && lcount + gcount + tcount <= maxcnt
+ && ! too_many_for_tls)
{
arg->primary = bfd2got->g;
arg->primary_count = lcount + gcount;
@@ -2317,12 +2913,13 @@ mips_elf_merge_gots (void **bfd2got_, vo
/* If it looks like we can merge this bfd's entries with those of
the primary, merge them. The heuristics is conservative, but we
don't have to squeeze it too hard. */
- else if (arg->primary
- && (arg->primary_count + lcount + gcount) <= maxcnt)
+ else if (arg->primary && ! too_many_for_tls
+ && (arg->primary_count + lcount + gcount + tcount) <= maxcnt)
{
struct mips_got_info *g = bfd2got->g;
int old_lcount = arg->primary->local_gotno;
int old_gcount = arg->primary->global_gotno;
+ int old_tcount = arg->primary->tls_gotno;
bfd2got->g = arg->primary;
@@ -2339,17 +2936,19 @@ mips_elf_merge_gots (void **bfd2got_, vo
BFD_ASSERT (old_lcount + lcount >= arg->primary->local_gotno);
BFD_ASSERT (old_gcount + gcount >= arg->primary->global_gotno);
+ BFD_ASSERT (old_tcount + tcount >= arg->primary->tls_gotno);
arg->primary_count = arg->primary->local_gotno
- + arg->primary->global_gotno;
+ + arg->primary->global_gotno + arg->primary->tls_gotno;
}
/* If we can merge with the last-created got, do it. */
else if (arg->current
- && arg->current_count + lcount + gcount <= maxcnt)
+ && arg->current_count + lcount + gcount + tcount <= maxcnt)
{
struct mips_got_info *g = bfd2got->g;
int old_lcount = arg->current->local_gotno;
int old_gcount = arg->current->global_gotno;
+ int old_tcount = arg->current->tls_gotno;
bfd2got->g = arg->current;
@@ -2363,9 +2962,10 @@ mips_elf_merge_gots (void **bfd2got_, vo
BFD_ASSERT (old_lcount + lcount >= arg->current->local_gotno);
BFD_ASSERT (old_gcount + gcount >= arg->current->global_gotno);
+ BFD_ASSERT (old_tcount + tcount >= arg->current->tls_gotno);
arg->current_count = arg->current->local_gotno
- + arg->current->global_gotno;
+ + arg->current->global_gotno + arg->current->tls_gotno;
}
/* Well, we couldn't merge, so create a new GOT. Don't check if it
fits; if it turns out that it doesn't, we'll get relocation
@@ -2375,12 +2975,61 @@ mips_elf_merge_gots (void **bfd2got_, vo
bfd2got->g->next = arg->current;
arg->current = bfd2got->g;
- arg->current_count = lcount + gcount;
+ arg->current_count = lcount + gcount + 2 * tcount;
}
return 1;
}
+/* Set the TLS GOT index for the GOT entry in ENTRYP. */
+
+static int
+mips_elf_initialize_tls_index (void **entryp, void *p)
+{
+ struct mips_got_entry *entry = (struct mips_got_entry *)*entryp;
+ struct mips_got_info *g = p;
+
+ /* We're only interested in TLS symbols. */
+ if (entry->tls_type == 0)
+ return 1;
+
+ if (entry->symndx == -1)
+ {
+ /* There may be multiple mips_got_entry structs for a global variable
+ if there is just one GOT. Just do this once. */
+ if (g->next == NULL)
+ {
+ if (entry->d.h->tls_type & GOT_TLS_OFFSET_DONE)
+ return 1;
+ entry->d.h->tls_type |= GOT_TLS_OFFSET_DONE;
+ }
+ }
+ else if (entry->tls_type & GOT_TLS_LDM)
+ {
+ /* Similarly, there may be multiple structs for the LDM entry. */
+ if (g->tls_ldm_offset != MINUS_TWO && g->tls_ldm_offset != MINUS_ONE)
+ {
+ entry->gotidx = g->tls_ldm_offset;
+ return 1;
+ }
+ }
+
+ /* Initialize the GOT offset. */
+ entry->gotidx = MIPS_ELF_GOT_SIZE (entry->abfd) * (long) g->tls_assigned_gotno;
+ if (g->next == NULL && entry->symndx == -1)
+ entry->d.h->tls_got_offset = entry->gotidx;
+
+ if (entry->tls_type & (GOT_TLS_GD | GOT_TLS_LDM))
+ g->tls_assigned_gotno += 2;
+ if (entry->tls_type & GOT_TLS_IE)
+ g->tls_assigned_gotno += 1;
+
+ if (entry->tls_type & GOT_TLS_LDM)
+ g->tls_ldm_offset = entry->gotidx;
+
+ return 1;
+}
+
/* If passed a NULL mips_got_info in the argument, set the marker used
to tell whether a global symbol needs a got entry (in the primary
got) to the given VALUE.
@@ -2402,8 +3051,14 @@ mips_elf_set_global_got_offset (void **e
= (struct mips_elf_set_global_got_offset_arg *)p;
struct mips_got_info *g = arg->g;
+ if (g && entry->tls_type != GOT_NORMAL)
+ arg->needed_relocs +=
+ mips_tls_got_relocs (arg->info, entry->tls_type,
+ entry->symndx == -1 ? &entry->d.h->root : NULL);
+
if (entry->abfd != NULL && entry->symndx == -1
- && entry->d.h->root.dynindx != -1)
+ && entry->d.h->root.dynindx != -1
+ && entry->d.h->tls_type == GOT_NORMAL)
{
if (g)
{
@@ -2518,7 +3173,8 @@ mips_elf_adjust_gp (bfd *abfd, struct mi
g = g->next;
- return (g->local_gotno + g->global_gotno) * MIPS_ELF_GOT_SIZE (abfd);
+ return (g->local_gotno + g->global_gotno + g->tls_gotno)
+ * MIPS_ELF_GOT_SIZE (abfd);
}
/* Turn a single GOT that is too big for 16-bit addressing into
@@ -2545,7 +3201,6 @@ mips_elf_multi_got (bfd *abfd, struct bf
/* Count how many GOT entries each input bfd requires, creating a
map from bfd to got info while at that. */
- mips_elf_resolve_final_got_entries (g);
htab_traverse (g->got_entries, mips_elf_make_got_per_bfd, &got_per_bfd_arg);
if (got_per_bfd_arg.obfd == NULL)
return FALSE;
@@ -2558,6 +3213,10 @@ mips_elf_multi_got (bfd *abfd, struct bf
got_per_bfd_arg.max_count = ((MIPS_ELF_GOT_MAX_SIZE (abfd)
/ MIPS_ELF_GOT_SIZE (abfd))
- MIPS_RESERVED_GOTNO - pages);
+ /* The number of globals that will be included in the primary GOT.
+ See the calls to mips_elf_set_global_got_offset below for more
+ information. */
+ got_per_bfd_arg.global_count = g->global_gotno;
/* Try to merge the GOTs of input bfds together, as long as they
don't seem to exceed the maximum GOT size, choosing one of them
@@ -2566,7 +3225,7 @@ mips_elf_multi_got (bfd *abfd, struct bf
if (got_per_bfd_arg.obfd == NULL)
return FALSE;
- /* If we find any suitable primary GOT, create an empty one. */
+ /* If we do not find any suitable primary GOT, create an empty one. */
if (got_per_bfd_arg.primary == NULL)
{
g->next = (struct mips_got_info *)
@@ -2577,7 +3236,10 @@ mips_elf_multi_got (bfd *abfd, struct bf
g->next->global_gotsym = NULL;
g->next->global_gotno = 0;
g->next->local_gotno = 0;
+ g->next->tls_gotno = 0;
g->next->assigned_gotno = 0;
+ g->next->tls_assigned_gotno = 0;
+ g->next->tls_ldm_offset = MINUS_ONE;
g->next->got_entries = htab_try_create (1, mips_elf_multi_got_entry_hash,
mips_elf_multi_got_entry_eq,
NULL);
@@ -2677,6 +3339,7 @@ mips_elf_multi_got (bfd *abfd, struct bf
points back to the master GOT. */
gg->local_gotno = -g->global_gotno;
gg->global_gotno = g->global_gotno;
+ gg->tls_gotno = 0;
assign = 0;
gg->next = gg;
@@ -2687,7 +3350,12 @@ mips_elf_multi_got (bfd *abfd, struct bf
assign += MIPS_RESERVED_GOTNO;
g->assigned_gotno = assign;
g->local_gotno += assign + pages;
- assign = g->local_gotno + g->global_gotno;
+ assign = g->local_gotno + g->global_gotno + g->tls_gotno;
+
+ /* Set up any TLS entries. We always place the TLS entries after
+ all non-TLS entries. */
+ g->tls_assigned_gotno = g->local_gotno + g->global_gotno;
+ htab_traverse (g->got_entries, mips_elf_initialize_tls_index, g);
/* Take g out of the direct list, and push it onto the reversed
list that gg points to. */
@@ -2704,7 +3372,8 @@ mips_elf_multi_got (bfd *abfd, struct bf
while (g);
got->size = (gg->next->local_gotno
- + gg->next->global_gotno) * MIPS_ELF_GOT_SIZE (abfd);
+ + gg->next->global_gotno
+ + gg->next->tls_gotno) * MIPS_ELF_GOT_SIZE (abfd);
return TRUE;
}
@@ -2923,10 +3592,12 @@ mips_elf_create_got_section (bfd *abfd,
return FALSE;
g->global_gotsym = NULL;
g->global_gotno = 0;
+ g->tls_gotno = 0;
g->local_gotno = MIPS_RESERVED_GOTNO;
g->assigned_gotno = MIPS_RESERVED_GOTNO;
g->bfd2got = NULL;
g->next = NULL;
+ g->tls_ldm_offset = MINUS_ONE;
g->got_entries = htab_try_create (1, mips_elf_got_entry_hash,
mips_elf_got_entry_eq, NULL);
if (g->got_entries == NULL)
@@ -3222,8 +3893,18 @@ mips_elf_calculate_relocation (bfd *abfd
case R_MIPS_CALL_HI16:
case R_MIPS_GOT_LO16:
case R_MIPS_CALL_LO16:
+ case R_MIPS_TLS_GD:
+ case R_MIPS_TLS_TPOFF:
+ case R_MIPS_TLS_LDM:
/* Find the index into the GOT where this value is located. */
- if (!local_p)
+ if (r_type == R_MIPS_TLS_LDM)
+ {
+ g = mips_elf_local_got_index (abfd, input_bfd, info, 0, 0, NULL,
+ r_type);
+ if (g == MINUS_ONE)
+ return bfd_reloc_outofrange;
+ }
+ else if (!local_p)
{
/* GOT_PAGE may take a non-zero addend, that is ignored in a
GOT_PAGE relocation that decays to GOT_DISP because the
@@ -3232,11 +3913,13 @@ mips_elf_calculate_relocation (bfd *abfd
BFD_ASSERT (addend == 0 || r_type == R_MIPS_GOT_PAGE);
g = mips_elf_global_got_index (elf_hash_table (info)->dynobj,
input_bfd,
- (struct elf_link_hash_entry *) h);
- if (! elf_hash_table(info)->dynamic_sections_created
- || (info->shared
- && (info->symbolic || h->root.dynindx == -1)
- && h->root.def_regular))
+ (struct elf_link_hash_entry *) h,
+ r_type, info);
+ if (h->tls_type == GOT_NORMAL
+ && (! elf_hash_table(info)->dynamic_sections_created
+ || (info->shared
+ && (info->symbolic || h->root.dynindx == -1)
+ && h->root.def_regular)))
{
/* This is a static link or a -Bsymbolic link. The
symbol is defined locally, or was forced to be local.
@@ -3253,7 +3936,8 @@ mips_elf_calculate_relocation (bfd *abfd
else
{
g = mips_elf_local_got_index (abfd, input_bfd,
- info, symbol + addend);
+ info, symbol + addend, r_symndx, h,
+ r_type);
if (g == MINUS_ONE)
return bfd_reloc_outofrange;
}
@@ -3359,6 +4043,24 @@ mips_elf_calculate_relocation (bfd *abfd
value &= howto->dst_mask;
break;
+ case R_MIPS_TLS_LDO_HI16:
+ value = (mips_elf_high (addend + symbol - dtpoff_base (info))
+ & howto->dst_mask);
+ break;
+
+ case R_MIPS_TLS_LDO_LO16:
+ value = (symbol + addend - dtpoff_base (info)) & howto->dst_mask;
+ break;
+
+ case R_MIPS_TLS_TPOFF_HI16:
+ value = (mips_elf_high (addend + symbol - tpoff_base (info))
+ & howto->dst_mask);
+ break;
+
+ case R_MIPS_TLS_TPOFF_LO16:
+ value = (symbol + addend - tpoff_base (info)) & howto->dst_mask;
+ break;
+
case R_MIPS_HI16:
if (!gp_disp_p)
{
@@ -3451,6 +4153,9 @@ mips_elf_calculate_relocation (bfd *abfd
/* Fall through. */
+ case R_MIPS_TLS_GD:
+ case R_MIPS_TLS_TPOFF:
+ case R_MIPS_TLS_LDM:
case R_MIPS_GOT_DISP:
got_disp:
value = g;
@@ -5346,6 +6051,8 @@ _bfd_mips_elf_check_relocs (bfd *abfd, s
case R_MIPS_GOT_PAGE:
case R_MIPS_GOT_OFST:
case R_MIPS_GOT_DISP:
+ case R_MIPS_TLS_GD:
+ case R_MIPS_TLS_LDM:
if (dynobj == NULL)
elf_hash_table (info)->dynobj = dynobj = abfd;
if (! mips_elf_create_got_section (dynobj, info, FALSE))
@@ -5379,7 +6086,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, s
R_MIPS_CALL_HI16 because these are always followed by an
R_MIPS_GOT_LO16 or R_MIPS_CALL_LO16. */
if (! mips_elf_record_local_got_symbol (abfd, r_symndx,
- rel->r_addend, g))
+ rel->r_addend, g, 0))
return FALSE;
}
@@ -5401,7 +6108,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, s
if (h != NULL)
{
/* This symbol requires a global offset table entry. */
- if (! mips_elf_record_global_got_symbol (h, abfd, info, g))
+ if (! mips_elf_record_global_got_symbol (h, abfd, info, g, 0))
return FALSE;
/* We need a stub, not a plt entry for the undefined
@@ -5438,11 +6145,52 @@ _bfd_mips_elf_check_relocs (bfd *abfd, s
case R_MIPS_GOT_HI16:
case R_MIPS_GOT_LO16:
case R_MIPS_GOT_DISP:
- /* This symbol requires a global offset table entry. */
- if (h && ! mips_elf_record_global_got_symbol (h, abfd, info, g))
+ if (h && ! mips_elf_record_global_got_symbol (h, abfd, info, g, 0))
return FALSE;
break;
+ case R_MIPS_TLS_TPOFF:
+ if (info->shared)
+ info->flags |= DF_STATIC_TLS;
+ /* Fall through */
+
+ case R_MIPS_TLS_LDM:
+ if (r_type == R_MIPS_TLS_LDM)
+ {
+ r_symndx = 0;
+ h = NULL;
+ }
+ /* Fall through */
+
+ case R_MIPS_TLS_GD:
+ /* This symbol requires a global offset table entry, or two
+ for TLS GD relocations. */
+ {
+ unsigned char flag = (r_type == R_MIPS_TLS_GD
+ ? GOT_TLS_GD
+ : r_type == R_MIPS_TLS_LDM
+ ? GOT_TLS_LDM
+ : GOT_TLS_IE);
+ if (h != NULL)
+ {
+ struct mips_elf_link_hash_entry *hmips =
+ (struct mips_elf_link_hash_entry *) h;
+ hmips->tls_type |= flag;
+
+ if (h && ! mips_elf_record_global_got_symbol (h, abfd, info, g, flag))
+ return FALSE;
+ }
+ else
+ {
+ BFD_ASSERT (flag == GOT_TLS_LDM || r_symndx != 0);
+
+ if (! mips_elf_record_local_got_symbol (abfd, r_symndx,
+ rel->r_addend, g, flag))
+ return FALSE;
+ }
+ }
+ break;
+
case R_MIPS_32:
case R_MIPS_REL32:
case R_MIPS_64:
@@ -5495,7 +6243,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, s
if (! mips_elf_create_got_section (dynobj, info, TRUE))
return FALSE;
g = mips_elf_got_info (dynobj, &sgot);
- if (! mips_elf_record_global_got_symbol (h, abfd, info, g))
+ if (! mips_elf_record_global_got_symbol (h, abfd, info, g, 0))
return FALSE;
}
}
@@ -5861,6 +6609,7 @@ _bfd_mips_elf_always_size_sections (bfd
bfd_size_type loadable_size = 0;
bfd_size_type local_gotno;
bfd *sub;
+ struct mips_elf_count_tls_arg count_tls_arg;
/* The .reginfo section has a fixed size. */
ri = bfd_get_section_by_name (output_bfd, ".reginfo");
@@ -5929,9 +6678,30 @@ _bfd_mips_elf_always_size_sections (bfd
g->global_gotno = i;
s->size += i * MIPS_ELF_GOT_SIZE (output_bfd);
- if (s->size > MIPS_ELF_GOT_MAX_SIZE (output_bfd)
- && ! mips_elf_multi_got (output_bfd, info, g, s, local_gotno))
- return FALSE;
+ /* We need to calculate tls_gotno for global symbols at this point
+ instead of building it up earlier, to avoid doublecounting
+ entries for one global symbol from multiple input files. */
+ count_tls_arg.info = info;
+ count_tls_arg.needed = 0;
+ elf_link_hash_traverse (elf_hash_table (info),
+ mips_elf_count_global_tls_entries,
+ &count_tls_arg);
+ g->tls_gotno += count_tls_arg.needed;
+ s->size += g->tls_gotno * MIPS_ELF_GOT_SIZE (output_bfd);
+
+ mips_elf_resolve_final_got_entries (g);
+
+ if (s->size > MIPS_ELF_GOT_MAX_SIZE (output_bfd))
+ {
+ if (! mips_elf_multi_got (output_bfd, info, g, s, local_gotno))
+ return FALSE;
+ }
+ else
+ {
+ /* Set up TLS entries for the first GOT. */
+ g->tls_assigned_gotno = g->global_gotno + g->local_gotno;
+ htab_traverse (g->got_entries, mips_elf_initialize_tls_index, g);
+ }
return TRUE;
}
@@ -6046,6 +6816,9 @@ _bfd_mips_elf_size_dynamic_sections (bfd
set_got_offset_arg.value = MIPS_ELF_GOT_SIZE (output_bfd);
set_got_offset_arg.info = info;
+ /* NOTE 2005-02-03: How can this call, or the next, ever
+ find any indirect entries to resolve? They were all
+ resolved in mips_elf_multi_got. */
mips_elf_resolve_final_got_entries (gg);
for (g = gg->next; g && g->next != gg; g = g->next)
{
@@ -6071,13 +6844,28 @@ _bfd_mips_elf_size_dynamic_sections (bfd
needed_relocs += g->local_gotno - g->assigned_gotno;
BFD_ASSERT (g->assigned_gotno == g->next->local_gotno
+ g->next->global_gotno
+ + g->next->tls_gotno
+ MIPS_RESERVED_GOTNO);
}
}
+ }
+ else
+ {
+ struct mips_elf_count_tls_arg arg;
+ arg.info = info;
+ arg.needed = 0;
- if (needed_relocs)
- mips_elf_allocate_dynamic_relocations (dynobj, needed_relocs);
+ htab_traverse (gg->got_entries, mips_elf_count_local_tls_relocs,
+ &arg);
+ elf_link_hash_traverse (elf_hash_table (info),
+ mips_elf_count_global_tls_relocs,
+ &arg);
+
+ needed_relocs += arg.needed;
}
+
+ if (needed_relocs)
+ mips_elf_allocate_dynamic_relocations (dynobj, needed_relocs);
}
else if (strcmp (name, MIPS_ELF_STUB_SECTION_NAME (output_bfd)) == 0)
{
@@ -6709,11 +7497,11 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd
bfd_vma value;
value = sym->st_value;
- offset = mips_elf_global_got_index (dynobj, output_bfd, h);
+ offset = mips_elf_global_got_index (dynobj, output_bfd, h, R_MIPS_GOT16, info);
MIPS_ELF_PUT_WORD (output_bfd, value, sgot->contents + offset);
}
- if (g->next && h->dynindx != -1)
+ if (g->next && h->dynindx != -1 && h->type != STT_TLS)
{
struct mips_got_entry e, *p;
bfd_vma entry;
@@ -6724,6 +7512,7 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd
e.abfd = output_bfd;
e.symndx = -1;
e.d.h = (struct mips_elf_link_hash_entry *)h;
+ e.tls_type = 0;
for (g = g->next; g->next != gg; g = g->next)
{
@@ -7036,7 +7825,8 @@ _bfd_mips_elf_finish_dynamic_sections (b
for (g = gg->next; g->next != gg; g = g->next)
{
- bfd_vma index = g->next->local_gotno + g->next->global_gotno;
+ bfd_vma index = g->next->local_gotno + g->next->global_gotno
+ + g->next->tls_gotno;
MIPS_ELF_PUT_WORD (output_bfd, 0, sgot->contents
+ index++ * MIPS_ELF_GOT_SIZE (output_bfd));
@@ -7650,6 +8440,11 @@ _bfd_mips_elf_copy_indirect_symbol (cons
dirmips->readonly_reloc = TRUE;
if (indmips->no_fn_stub)
dirmips->no_fn_stub = TRUE;
+
+ if (dirmips->tls_type == 0)
+ dirmips->tls_type = indmips->tls_type;
+ else
+ BFD_ASSERT (indmips->tls_type == 0);
}
void
@@ -7668,7 +8463,7 @@ _bfd_mips_elf_hide_symbol (struct bfd_li
h->forced_local = force_local;
dynobj = elf_hash_table (info)->dynobj;
- if (dynobj != NULL && force_local)
+ if (dynobj != NULL && force_local && h->root.type != STT_TLS)
{
got = mips_elf_got_section (dynobj, FALSE);
g = mips_elf_section_data (got)->u.got_info;
@@ -7686,6 +8481,7 @@ _bfd_mips_elf_hide_symbol (struct bfd_li
e.abfd = dynobj;
e.symndx = -1;
e.d.h = h;
+ e.tls_type = 0;
for (g = g->next; g != gg; g = g->next)
if (htab_find (g->got_entries, &e))
Index: binutils/bfd/elfn32-mips.c
===================================================================
--- binutils.orig/bfd/elfn32-mips.c 2004-12-09 01:32:41.000000000 -0500
+++ binutils/bfd/elfn32-mips.c 2005-02-07 16:21:54.871598869 -0500
@@ -1,6 +1,6 @@
/* MIPS-specific support for 32-bit ELF
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004 Free Software Foundation, Inc.
+ 2003, 2004, 2005 Free Software Foundation, Inc.
Most of the information added by Ian Lance Taylor, Cygnus Support,
<ian@cygnus.com>.
@@ -600,6 +600,160 @@ static reloc_howto_type elf_mips_howto_t
0x00000000, /* src_mask */
0x00000000, /* dst_mask */
FALSE), /* pcrel_offset */
+
+ /* TLS GD/LD dynamic relocations. */
+ HOWTO (R_MIPS_TLS_DTPMOD32, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_DTPMOD32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_MIPS_TLS_DTPOFF32, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_DTPOFF32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ EMPTY_HOWTO (R_MIPS_TLS_DTPMOD64),
+ EMPTY_HOWTO (R_MIPS_TLS_DTPOFF64),
+
+ /* TLS general dynamic variable reference. */
+ HOWTO (R_MIPS_TLS_GD, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_GD", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS local dynamic variable reference. */
+ HOWTO (R_MIPS_TLS_LDM, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_LDM", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS local dynamic offset. */
+ HOWTO (R_MIPS_TLS_LDO_HI16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_LDO_HI16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS local dynamic offset. */
+ HOWTO (R_MIPS_TLS_LDO_LO16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_LDO_LO16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS thread pointer offset. */
+ HOWTO (R_MIPS_TLS_TPOFF, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_TPOFF", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS IE dynamic relocations. */
+ HOWTO (R_MIPS_TLS_TPOFF32, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_TPOFF32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ EMPTY_HOWTO (R_MIPS_TLS_TPOFF64),
+
+ /* TLS thread pointer offset. */
+ HOWTO (R_MIPS_TLS_TPOFF_HI16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_TPOFF_HI16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS thread pointer offset. */
+ HOWTO (R_MIPS_TLS_TPOFF_LO16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_TPOFF_LO16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
};
/* The relocation table used for SHT_RELA sections. */
@@ -1117,6 +1271,160 @@ static reloc_howto_type elf_mips_howto_t
0, /* src_mask */
0, /* dst_mask */
FALSE), /* pcrel_offset */
+
+ /* TLS GD/LD dynamic relocations. */
+ HOWTO (R_MIPS_TLS_DTPMOD32, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_DTPMOD32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_MIPS_TLS_DTPOFF32, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_DTPOFF32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ EMPTY_HOWTO (R_MIPS_TLS_DTPMOD64),
+ EMPTY_HOWTO (R_MIPS_TLS_DTPOFF64),
+
+ /* TLS general dynamic variable reference. */
+ HOWTO (R_MIPS_TLS_GD, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_GD", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS local dynamic variable reference. */
+ HOWTO (R_MIPS_TLS_LDM, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_LDM", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS local dynamic offset. */
+ HOWTO (R_MIPS_TLS_LDO_HI16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_LDO_HI16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS local dynamic offset. */
+ HOWTO (R_MIPS_TLS_LDO_LO16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_LDO_LO16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS thread pointer offset. */
+ HOWTO (R_MIPS_TLS_TPOFF, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_TPOFF", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS IE dynamic relocations. */
+ HOWTO (R_MIPS_TLS_TPOFF32, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_TPOFF32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ EMPTY_HOWTO (R_MIPS_TLS_TPOFF64),
+
+ /* TLS thread pointer offset. */
+ HOWTO (R_MIPS_TLS_TPOFF_HI16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_TPOFF_HI16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS thread pointer offset. */
+ HOWTO (R_MIPS_TLS_TPOFF_LO16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_TPOFF_LO16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
};
/* The reloc used for the mips16 jump instruction. */
@@ -1614,7 +1922,20 @@ static const struct elf_reloc_map mips_r
{ BFD_RELOC_MIPS_REL16, R_MIPS_REL16 },
/* Use of R_MIPS_ADD_IMMEDIATE and R_MIPS_PJUMP is deprecated. */
{ BFD_RELOC_MIPS_RELGOT, R_MIPS_RELGOT },
- { BFD_RELOC_MIPS_JALR, R_MIPS_JALR }
+ { BFD_RELOC_MIPS_JALR, R_MIPS_JALR },
+ { BFD_RELOC_MIPS_TLS_DTPMOD32, R_MIPS_TLS_DTPMOD32 },
+ { BFD_RELOC_MIPS_TLS_DTPOFF32, R_MIPS_TLS_DTPOFF32 },
+ { BFD_RELOC_MIPS_TLS_DTPMOD64, R_MIPS_TLS_DTPMOD64 },
+ { BFD_RELOC_MIPS_TLS_DTPOFF64, R_MIPS_TLS_DTPOFF64 },
+ { BFD_RELOC_MIPS_TLS_GD, R_MIPS_TLS_GD },
+ { BFD_RELOC_MIPS_TLS_LDM, R_MIPS_TLS_LDM },
+ { BFD_RELOC_MIPS_TLS_LDO_HI16, R_MIPS_TLS_LDO_HI16 },
+ { BFD_RELOC_MIPS_TLS_LDO_LO16, R_MIPS_TLS_LDO_LO16 },
+ { BFD_RELOC_MIPS_TLS_TPOFF, R_MIPS_TLS_TPOFF },
+ { BFD_RELOC_MIPS_TLS_TPOFF32, R_MIPS_TLS_TPOFF32 },
+ { BFD_RELOC_MIPS_TLS_TPOFF64, R_MIPS_TLS_TPOFF64 },
+ { BFD_RELOC_MIPS_TLS_TPOFF_HI16, R_MIPS_TLS_TPOFF_HI16 },
+ { BFD_RELOC_MIPS_TLS_TPOFF_LO16, R_MIPS_TLS_TPOFF_LO16 }
};
/* Given a BFD reloc type, return a howto structure. */
Index: binutils/bfd/elf32-mips.c
===================================================================
--- binutils.orig/bfd/elf32-mips.c 2004-06-29 09:46:30.000000000 -0400
+++ binutils/bfd/elf32-mips.c 2005-02-07 16:22:06.120815728 -0500
@@ -1,6 +1,6 @@
/* MIPS-specific support for 32-bit ELF
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004 Free Software Foundation, Inc.
+ 2003, 2004, 2005 Free Software Foundation, Inc.
Most of the information added by Ian Lance Taylor, Cygnus Support,
<ian@cygnus.com>.
@@ -545,6 +545,160 @@ static reloc_howto_type elf_mips_howto_t
0x00000000, /* src_mask */
0x00000000, /* dst_mask */
FALSE), /* pcrel_offset */
+
+ /* TLS GD/LD dynamic relocations. */
+ HOWTO (R_MIPS_TLS_DTPMOD32, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_DTPMOD32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_MIPS_TLS_DTPOFF32, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_DTPOFF32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ EMPTY_HOWTO (R_MIPS_TLS_DTPMOD64),
+ EMPTY_HOWTO (R_MIPS_TLS_DTPOFF64),
+
+ /* TLS general dynamic variable reference. */
+ HOWTO (R_MIPS_TLS_GD, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_GD", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS local dynamic variable reference. */
+ HOWTO (R_MIPS_TLS_LDM, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_LDM", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS local dynamic offset. */
+ HOWTO (R_MIPS_TLS_LDO_HI16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_LDO_HI16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS local dynamic offset. */
+ HOWTO (R_MIPS_TLS_LDO_LO16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_LDO_LO16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS thread pointer offset. */
+ HOWTO (R_MIPS_TLS_TPOFF, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_TPOFF", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS IE dynamic relocations. */
+ HOWTO (R_MIPS_TLS_TPOFF32, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_TPOFF32", /* name */
+ TRUE, /* partial_inplace */
+ 0xffffffff, /* src_mask */
+ 0xffffffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ EMPTY_HOWTO (R_MIPS_TLS_TPOFF64),
+
+ /* TLS thread pointer offset. */
+ HOWTO (R_MIPS_TLS_TPOFF_HI16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_TPOFF_HI16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS thread pointer offset. */
+ HOWTO (R_MIPS_TLS_TPOFF_LO16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_TPOFF_LO16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
};
/* The reloc used for BFD_RELOC_CTOR when doing a 64 bit link. This
@@ -1046,7 +1200,20 @@ static const struct elf_reloc_map mips_r
{ BFD_RELOC_MIPS_SUB, R_MIPS_SUB },
{ BFD_RELOC_MIPS_GOT_PAGE, R_MIPS_GOT_PAGE },
{ BFD_RELOC_MIPS_GOT_OFST, R_MIPS_GOT_OFST },
- { BFD_RELOC_MIPS_GOT_DISP, R_MIPS_GOT_DISP }
+ { BFD_RELOC_MIPS_GOT_DISP, R_MIPS_GOT_DISP },
+ { BFD_RELOC_MIPS_TLS_DTPMOD32, R_MIPS_TLS_DTPMOD32 },
+ { BFD_RELOC_MIPS_TLS_DTPOFF32, R_MIPS_TLS_DTPOFF32 },
+ { BFD_RELOC_MIPS_TLS_DTPMOD64, R_MIPS_TLS_DTPMOD64 },
+ { BFD_RELOC_MIPS_TLS_DTPOFF64, R_MIPS_TLS_DTPOFF64 },
+ { BFD_RELOC_MIPS_TLS_GD, R_MIPS_TLS_GD },
+ { BFD_RELOC_MIPS_TLS_LDM, R_MIPS_TLS_LDM },
+ { BFD_RELOC_MIPS_TLS_LDO_HI16, R_MIPS_TLS_LDO_HI16 },
+ { BFD_RELOC_MIPS_TLS_LDO_LO16, R_MIPS_TLS_LDO_LO16 },
+ { BFD_RELOC_MIPS_TLS_TPOFF, R_MIPS_TLS_TPOFF },
+ { BFD_RELOC_MIPS_TLS_TPOFF32, R_MIPS_TLS_TPOFF32 },
+ { BFD_RELOC_MIPS_TLS_TPOFF64, R_MIPS_TLS_TPOFF64 },
+ { BFD_RELOC_MIPS_TLS_TPOFF_HI16, R_MIPS_TLS_TPOFF_HI16 },
+ { BFD_RELOC_MIPS_TLS_TPOFF_LO16, R_MIPS_TLS_TPOFF_LO16 }
};
/* Given a BFD reloc type, return a howto structure. */
Index: binutils/ld/testsuite/ld-mips-elf/tlsbin-o32.s
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/tlsbin-o32.s 2005-02-07 16:21:35.255461210 -0500
@@ -0,0 +1,89 @@
+ .file 1 "tlsbin-o32.s"
+ .abicalls
+ .text
+ .align 2
+ .globl __start
+ .ent __start
+ .type __start,@function
+__start:
+ .frame $fp,16,$31
+ .mask 0x40000000,-8
+ .fmask 0x00000000,0
+ .set noreorder
+ .cpload $25
+ .set reorder
+ addiu $sp,$sp,-16
+ sw $fp,8($sp)
+ move $fp,$sp
+ .cprestore 0
+
+ # General Dynamic
+ lw $25,%call16(__tls_get_addr)($28)
+ addiu $4,$28,%tlsgd(tlsvar_gd)
+ jal $25
+
+ # Local Dynamic
+ lw $25,%call16(__tls_get_addr)($28)
+ addiu $4,$28,%tlsldm(tlsvar_ld)
+ jal $25
+
+ move $2,$2 # Arbitrary instructions
+
+ lui $3,%hi(%dtpoff(tlsvar_ld))
+ addiu $3,$3,%lo(%dtpoff(tlsvar_ld))
+ addu $3,$3,$2
+
+ # Initial Exec
+ .set push
+ .set mips32r2
+ rdhwr $2, $5
+ .set pop
+ lw $3,%gottpoff(tlsvar_ie)($28)
+ addu $3,$3,$2
+
+ # Local Exec
+ .set push
+ .set mips32r2
+ rdhwr $2, $5
+ .set pop
+ lui $3,%hi(%tpoff(tlsvar_le))
+ addiu $3,$3,%lo(%tpoff(tlsvar_le))
+ addu $3,$3,$2
+
+ move $sp,$fp
+ lw $fp,8($sp)
+ addiu $sp,$sp,16
+ j $31
+ .end __start
+
+ .globl __tls_get_addr
+__tls_get_addr:
+ j $31
+
+ .section .tbss,"awT",@nobits
+ .align 2
+ .global tlsvar_gd
+ .type tlsvar_gd,@object
+ .size tlsvar_gd,4
+tlsvar_gd:
+ .space 4
+ .global tlsvar_ie
+ .type tlsvar_ie,@object
+ .size tlsvar_ie,4
+tlsvar_ie:
+ .space 4
+
+ .section .tdata,"awT"
+ .align 2
+ .global tlsvar_ld
+ .hidden tlsvar_ld
+ .type tlsvar_ld,@object
+ .size tlsvar_ld,4
+tlsvar_ld:
+ .word 1
+ .global tlsvar_le
+ .hidden tlsvar_le
+ .type tlsvar_le,@object
+ .size tlsvar_le,4
+tlsvar_le:
+ .word 1
Index: binutils/ld/testsuite/ld-mips-elf/mips-dyn.ld
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/mips-dyn.ld 2005-02-07 16:21:35.256460962 -0500
@@ -0,0 +1,223 @@
+/* Script for -z combreloc: combine and sort reloc sections */
+OUTPUT_FORMAT("elf32-tradbigmips", "elf32-tradbigmips",
+ "elf32-tradlittlemips")
+OUTPUT_ARCH(mips)
+ENTRY(__start)
+SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib");
+/* Do we need any of these for elf?
+ __DYNAMIC = 0; */
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ PROVIDE (__executable_start = 0x0400000); . = 0x0400000 + SIZEOF_HEADERS;
+ .interp : { *(.interp) }
+ .reginfo : { *(.reginfo) }
+ .dynamic : { *(.dynamic) }
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+ .rel.dyn :
+ {
+ *(.rel.init)
+ *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
+ *(.rel.fini)
+ *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
+ *(.rel.data.rel.ro*)
+ *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
+ *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
+ *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
+ *(.rel.ctors)
+ *(.rel.dtors)
+ *(.rel.got)
+ *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*)
+ *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*)
+ *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*)
+ *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*)
+ *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
+ }
+ .rela.dyn :
+ {
+ *(.rela.init)
+ *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+ *(.rela.fini)
+ *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+ *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+ *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+ *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+ *(.rela.ctors)
+ *(.rela.dtors)
+ *(.rela.got)
+ *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*)
+ *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*)
+ *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*)
+ *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*)
+ *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+ }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+ .init :
+ {
+ KEEP (*(.init))
+ } =0
+ .plt : { *(.plt) }
+ .text :
+ {
+ _ftext = . ;
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ KEEP (*(.text.*personality*))
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ *(.mips16.fn.*) *(.mips16.call.*)
+ } =0
+ .fini :
+ {
+ KEEP (*(.fini))
+ } =0
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+ .rodata1 : { *(.rodata1) }
+ .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) }
+ .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
+ .eh_frame_hdr : { *(.eh_frame_hdr) }
+ .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }
+ .gcc_except_table : ONLY_IF_RO { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) }
+ /* Adjust the address for the data segment. We want to adjust up to
+ the same address within the page on the next page up. */
+ . = 0x10000000;
+ /* Exception handling */
+ .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }
+ .gcc_except_table : ONLY_IF_RW { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) }
+ /* Thread Local Storage sections */
+ .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+ .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+ /* Ensure the __preinit_array_start label is properly aligned. We
+ could instead move the label definition inside the section, but
+ the linker would then create the section even if it turns out to
+ be empty, which isn't pretty. */
+ . = ALIGN(32 / 8);
+ PROVIDE (__preinit_array_start = .);
+ .preinit_array : { KEEP (*(.preinit_array)) }
+ PROVIDE (__preinit_array_end = .);
+ PROVIDE (__init_array_start = .);
+ .init_array : { KEEP (*(.init_array)) }
+ PROVIDE (__init_array_end = .);
+ PROVIDE (__fini_array_start = .);
+ .fini_array : { KEEP (*(.fini_array)) }
+ PROVIDE (__fini_array_end = .);
+ .ctors :
+ {
+ /* gcc uses crtbegin.o to find the start of
+ the constructors, so we make sure it is
+ first. Because this is a wildcard, it
+ doesn't matter if the user does not
+ actually link against crtbegin.o; the
+ linker won't look for a file to match a
+ wildcard. The wildcard also means that it
+ doesn't matter which directory crtbegin.o
+ is in. */
+ KEEP (*crtbegin*.o(.ctors))
+ /* We don't want to include the .ctor section from
+ from the crtend.o file until after the sorted ctors.
+ The .ctor section from the crtend file contains the
+ end of ctors marker and it must be last */
+ KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ }
+ .dtors :
+ {
+ KEEP (*crtbegin*.o(.dtors))
+ KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ }
+ .jcr : { KEEP (*(.jcr)) }
+ .data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro*) }
+ .data :
+ {
+ _fdata = . ;
+ *(.data .data.* .gnu.linkonce.d.*)
+ KEEP (*(.gnu.linkonce.d.*personality*))
+ SORT(CONSTRUCTORS)
+ }
+ .data1 : { *(.data1) }
+ _gp = ALIGN(16) + 0x7ff0;
+ .got : { *(.got.plt) *(.got) }
+ /* We want the small data sections together, so single-instruction offsets
+ can access them all, and initialized data all before uninitialized, so
+ we can shorten the on-disk segment size. */
+ .sdata :
+ {
+ *(.sdata .sdata.* .gnu.linkonce.s.*)
+ }
+ .lit8 : { *(.lit8) }
+ .lit4 : { *(.lit4) }
+ _edata = .;
+ PROVIDE (edata = .);
+ __bss_start = .;
+ _fbss = .;
+ .sbss :
+ {
+ PROVIDE (__sbss_start = .);
+ PROVIDE (___sbss_start = .);
+ *(.dynsbss)
+ *(.sbss .sbss.* .gnu.linkonce.sb.*)
+ *(.scommon)
+ PROVIDE (__sbss_end = .);
+ PROVIDE (___sbss_end = .);
+ }
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ /* Align here to ensure that the .bss section occupies space up to
+ _end. Align after .bss to ensure correct alignment even if the
+ .bss section disappears because there are no input sections. */
+ . = ALIGN(32 / 8);
+ }
+ . = ALIGN(32 / 8);
+ _end = .;
+ PROVIDE (end = .);
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
+ .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
+ /DISCARD/ : { *(.note.GNU-stack) }
+}
Index: binutils/bfd/libbfd.h
===================================================================
--- binutils.orig/bfd/libbfd.h 2005-01-28 10:21:21.000000000 -0500
+++ binutils/bfd/libbfd.h 2005-02-07 16:21:35.257460714 -0500
@@ -924,6 +924,19 @@ static const char *const bfd_reloc_code_
"BFD_RELOC_MIPS_REL16",
"BFD_RELOC_MIPS_RELGOT",
"BFD_RELOC_MIPS_JALR",
+ "BFD_RELOC_MIPS_TLS_DTPMOD32",
+ "BFD_RELOC_MIPS_TLS_DTPOFF32",
+ "BFD_RELOC_MIPS_TLS_DTPMOD64",
+ "BFD_RELOC_MIPS_TLS_DTPOFF64",
+ "BFD_RELOC_MIPS_TLS_GD",
+ "BFD_RELOC_MIPS_TLS_LDM",
+ "BFD_RELOC_MIPS_TLS_LDO_HI16",
+ "BFD_RELOC_MIPS_TLS_LDO_LO16",
+ "BFD_RELOC_MIPS_TLS_TPOFF",
+ "BFD_RELOC_MIPS_TLS_TPOFF32",
+ "BFD_RELOC_MIPS_TLS_TPOFF64",
+ "BFD_RELOC_MIPS_TLS_TPOFF_HI16",
+ "BFD_RELOC_MIPS_TLS_TPOFF_LO16",
"BFD_RELOC_FRV_LABEL16",
"BFD_RELOC_FRV_LABEL24",
Index: binutils/bfd/elf64-mips.c
===================================================================
--- binutils.orig/bfd/elf64-mips.c 2005-02-01 16:59:32.000000000 -0500
+++ binutils/bfd/elf64-mips.c 2005-02-07 16:23:39.084950987 -0500
@@ -1,5 +1,5 @@
/* MIPS-specific support for 64-bit ELF
- Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
Free Software Foundation, Inc.
Ian Lance Taylor, Cygnus Support
Linker support added by Mark Mitchell, CodeSourcery, LLC.
@@ -635,6 +635,160 @@ static reloc_howto_type mips_elf64_howto
0, /* src_mask */
0x00000000, /* dst_mask */
FALSE), /* pcrel_offset */
+
+ /* TLS relocations. */
+ EMPTY_HOWTO (R_MIPS_TLS_DTPMOD32),
+ EMPTY_HOWTO (R_MIPS_TLS_DTPOFF32),
+
+ HOWTO (R_MIPS_TLS_DTPMOD64, /* type */
+ 0, /* rightshift */
+ 4, /* size (0 = byte, 1 = short, 2 = long) */
+ 64, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_DTPMOD64", /* name */
+ TRUE, /* partial_inplace */
+ MINUS_ONE, /* src_mask */
+ MINUS_ONE, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_MIPS_TLS_DTPOFF64, /* type */
+ 0, /* rightshift */
+ 4, /* size (0 = byte, 1 = short, 2 = long) */
+ 64, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_DTPOFF64", /* name */
+ TRUE, /* partial_inplace */
+ MINUS_ONE, /* src_mask */
+ MINUS_ONE, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS general dynamic variable reference. */
+ HOWTO (R_MIPS_TLS_GD, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_GD", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS local dynamic variable reference. */
+ HOWTO (R_MIPS_TLS_LDM, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_LDM", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS local dynamic offset. */
+ HOWTO (R_MIPS_TLS_LDO_HI16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_LDO_HI16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS local dynamic offset. */
+ HOWTO (R_MIPS_TLS_LDO_LO16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_LDO_LO16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS thread pointer offset. */
+ HOWTO (R_MIPS_TLS_TPOFF, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_TPOFF", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS IE dynamic relocations. */
+ EMPTY_HOWTO (R_MIPS_TLS_TPOFF32),
+
+ HOWTO (R_MIPS_TLS_TPOFF64, /* type */
+ 0, /* rightshift */
+ 4, /* size (0 = byte, 1 = short, 2 = long) */
+ 64, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_TPOFF64", /* name */
+ TRUE, /* partial_inplace */
+ MINUS_ONE, /* src_mask */
+ MINUS_ONE, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS thread pointer offset. */
+ HOWTO (R_MIPS_TLS_TPOFF_HI16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_TPOFF_HI16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS thread pointer offset. */
+ HOWTO (R_MIPS_TLS_TPOFF_LO16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_TPOFF_LO16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
};
/* The relocation table used for SHT_RELA sections. */
@@ -1151,6 +1305,120 @@ static reloc_howto_type mips_elf64_howto
0, /* src_mask */
0x00000000, /* dst_mask */
FALSE), /* pcrel_offset */
+
+ /* TLS relocations. */
+ EMPTY_HOWTO (R_MIPS_TLS_DTPMOD32),
+ EMPTY_HOWTO (R_MIPS_TLS_DTPOFF32),
+ EMPTY_HOWTO (R_MIPS_TLS_DTPMOD64),
+ EMPTY_HOWTO (R_MIPS_TLS_DTPOFF64),
+
+ /* TLS general dynamic variable reference. */
+ HOWTO (R_MIPS_TLS_GD, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_GD", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS local dynamic variable reference. */
+ HOWTO (R_MIPS_TLS_LDM, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_LDM", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS local dynamic offset. */
+ HOWTO (R_MIPS_TLS_LDO_HI16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_LDO_HI16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS local dynamic offset. */
+ HOWTO (R_MIPS_TLS_LDO_LO16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_LDO_LO16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS thread pointer offset. */
+ HOWTO (R_MIPS_TLS_TPOFF, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_TPOFF", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ EMPTY_HOWTO (R_MIPS_TLS_TPOFF32),
+ EMPTY_HOWTO (R_MIPS_TLS_TPOFF64),
+
+ /* TLS thread pointer offset. */
+ HOWTO (R_MIPS_TLS_TPOFF_HI16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_TPOFF_HI16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ /* TLS thread pointer offset. */
+ HOWTO (R_MIPS_TLS_TPOFF_LO16, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 16, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ _bfd_mips_elf_generic_reloc, /* special_function */
+ "R_MIPS_TLS_TPOFF_LO16", /* name */
+ TRUE, /* partial_inplace */
+ 0x0000ffff, /* src_mask */
+ 0x0000ffff, /* dst_mask */
+ FALSE), /* pcrel_offset */
};
/* The reloc used for the mips16 jump instruction. */
@@ -1827,7 +2095,20 @@ static const struct elf_reloc_map mips_r
{ BFD_RELOC_MIPS_REL16, R_MIPS_REL16 },
/* Use of R_MIPS_ADD_IMMEDIATE and R_MIPS_PJUMP is deprecated. */
{ BFD_RELOC_MIPS_RELGOT, R_MIPS_RELGOT },
- { BFD_RELOC_MIPS_JALR, R_MIPS_JALR }
+ { BFD_RELOC_MIPS_JALR, R_MIPS_JALR },
+ { BFD_RELOC_MIPS_TLS_DTPMOD32, R_MIPS_TLS_DTPMOD32 },
+ { BFD_RELOC_MIPS_TLS_DTPOFF32, R_MIPS_TLS_DTPOFF32 },
+ { BFD_RELOC_MIPS_TLS_DTPMOD64, R_MIPS_TLS_DTPMOD64 },
+ { BFD_RELOC_MIPS_TLS_DTPOFF64, R_MIPS_TLS_DTPOFF64 },
+ { BFD_RELOC_MIPS_TLS_GD, R_MIPS_TLS_GD },
+ { BFD_RELOC_MIPS_TLS_LDM, R_MIPS_TLS_LDM },
+ { BFD_RELOC_MIPS_TLS_LDO_HI16, R_MIPS_TLS_LDO_HI16 },
+ { BFD_RELOC_MIPS_TLS_LDO_LO16, R_MIPS_TLS_LDO_LO16 },
+ { BFD_RELOC_MIPS_TLS_TPOFF, R_MIPS_TLS_TPOFF },
+ { BFD_RELOC_MIPS_TLS_TPOFF32, R_MIPS_TLS_TPOFF32 },
+ { BFD_RELOC_MIPS_TLS_TPOFF64, R_MIPS_TLS_TPOFF64 },
+ { BFD_RELOC_MIPS_TLS_TPOFF_HI16, R_MIPS_TLS_TPOFF_HI16 },
+ { BFD_RELOC_MIPS_TLS_TPOFF_LO16, R_MIPS_TLS_TPOFF_LO16 }
};
/* Given a BFD reloc type, return a howto structure. */
Index: binutils/ld/testsuite/ld-mips-elf/tlslib-o32.got
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/tlslib-o32.got 2005-02-07 16:21:35.259460217 -0500
@@ -0,0 +1,17 @@
+
+tmpdir/tlslib-o32.so: file format elf32-tradbigmips
+
+DYNAMIC RELOCATION RECORDS
+OFFSET TYPE VALUE
+00000000 R_MIPS_NONE \*ABS\*
+00040534 R_MIPS_TLS_DTPMOD32 \*ABS\*
+0004053c R_MIPS_TLS_DTPMOD32 tlsvar_gd
+00040540 R_MIPS_TLS_DTPOFF32 tlsvar_gd
+00040530 R_MIPS_TLS_TPOFF32 tlsvar_ie
+
+
+Contents of section .got:
+ 40510 00000000 80000000 00000000 00000000 ................
+ 40520 00000000 00000000 00000000 000004e0 ................
+ 40530 00000000 00000000 00000000 00000000 ................
+ 40540 00000000 ....
Index: binutils/ld/testsuite/ld-mips-elf/tlslib-o32.d
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/tlslib-o32.d 2005-02-07 16:21:35.259460217 -0500
@@ -0,0 +1,45 @@
+
+.*: file format elf32-tradbigmips
+
+Disassembly of section .text:
+
+.* <fn>:
+ .*: 3c1c0005 lui gp,0x5
+ .*: 279c80a0 addiu gp,gp,-32608
+ .*: 0399e021 addu gp,gp,t9
+ .*: 27bdfff0 addiu sp,sp,-16
+ .*: afbe0008 sw s8,8\(sp\)
+ .*: 03a0f021 move s8,sp
+ .*: afbc0000 sw gp,0\(sp\)
+ .*: 8f99802c lw t9,-32724\(gp\)
+ .*: 2784803c addiu a0,gp,-32708
+ .*: 0320f809 jalr t9
+ .*: 00000000 nop
+ .*: 8fdc0000 lw gp,0\(s8\)
+ .*: 00000000 nop
+ .*: 8f99802c lw t9,-32724\(gp\)
+ .*: 27848034 addiu a0,gp,-32716
+ .*: 0320f809 jalr t9
+ .*: 00000000 nop
+ .*: 8fdc0000 lw gp,0\(s8\)
+ .*: 00401021 move v0,v0
+ .*: 3c030000 lui v1,0x0
+ .*: 24638000 addiu v1,v1,-32768
+ .*: 00621821 addu v1,v1,v0
+ .*: 7c02283b rdhwr v0,\$5
+ .*: 8f838030 lw v1,-32720\(gp\)
+ .*: 00000000 nop
+ .*: 00621821 addu v1,v1,v0
+ .*: 03c0e821 move sp,s8
+ .*: 8fbe0008 lw s8,8\(sp\)
+ .*: 03e00008 jr ra
+ .*: 27bd0010 addiu sp,sp,16
+ ...
+Disassembly of section .MIPS.stubs:
+
+.* <.MIPS.stubs>:
+ .*: 8f998010 lw t9,-32752\(gp\)
+ .*: 03e07821 move t7,ra
+ .*: 0320f809 jalr t9
+ .*: 241800.* li t8,.*
+ ...
Index: binutils/ld/testsuite/ld-mips-elf/tlslib-o32.s
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/tlslib-o32.s 2005-02-07 16:21:35.259460217 -0500
@@ -0,0 +1,70 @@
+ .file 1 "tlslib-o32.s"
+ .abicalls
+ .text
+ .align 2
+ .globl fn
+ .ent fn
+ .type fn,@function
+fn:
+ .frame $fp,16,$31
+ .mask 0x40000000,-8
+ .fmask 0x00000000,0
+ .set noreorder
+ .cpload $25
+ .set reorder
+ addiu $sp,$sp,-16
+ sw $fp,8($sp)
+ move $fp,$sp
+ .cprestore 0
+
+ # General Dynamic
+ lw $25,%call16(__tls_get_addr)($28)
+ addiu $4,$28,%tlsgd(tlsvar_gd)
+ jal $25
+
+ # Local Dynamic
+ lw $25,%call16(__tls_get_addr)($28)
+ addiu $4,$28,%tlsldm(tlsvar_ld)
+ jal $25
+
+ move $2,$2 # Arbitrary instructions
+
+ lui $3,%hi(%dtpoff(tlsvar_ld))
+ addiu $3,$3,%lo(%dtpoff(tlsvar_ld))
+ addu $3,$3,$2
+
+ # Initial Exec
+ .set push
+ .set mips32r2
+ rdhwr $2, $5
+ .set pop
+ lw $3,%gottpoff(tlsvar_ie)($28)
+ addu $3,$3,$2
+
+ move $sp,$fp
+ lw $fp,8($sp)
+ addiu $sp,$sp,16
+ j $31
+ .end fn
+
+ .section .tbss,"awT",@nobits
+ .align 2
+ .global tlsvar_gd
+ .type tlsvar_gd,@object
+ .size tlsvar_gd,4
+tlsvar_gd:
+ .space 4
+ .global tlsvar_ie
+ .type tlsvar_ie,@object
+ .size tlsvar_ie,4
+tlsvar_ie:
+ .space 4
+
+ .section .tdata,"awT"
+ .align 2
+ .global tlsvar_ld
+ .hidden tlsvar_ld
+ .type tlsvar_ld,@object
+ .size tlsvar_ld,4
+tlsvar_ld:
+ .word 1
Index: binutils/ld/testsuite/ld-mips-elf/mips-elf.exp
===================================================================
--- binutils.orig/ld/testsuite/ld-mips-elf/mips-elf.exp 2005-02-07 16:21:35.225468653 -0500
+++ binutils/ld/testsuite/ld-mips-elf/mips-elf.exp 2005-02-07 16:24:01.379500645 -0500
@@ -1,5 +1,5 @@
# Expect script for MIPS ELF linker tests
-# Copyright 2002, 2003 Free Software Foundation, Inc.
+# Copyright 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -94,3 +94,67 @@ run_dump_test "jaloverflow-2"
if {$has_newabi} {
run_dump_test "jalbal"
}
+
+# For tests which may involve multiple files, use run_ld_link_tests.
+
+# List contains test-items with 3 items followed by 2 lists:
+# 0:name 1:ld options 2:assembler options
+# 3:filenames of assembler files 4: action and options. 5: name of output file
+
+# Actions:
+# objdump: Apply objdump options on result. Compare with regex (last arg).
+# nm: Apply nm options on result. Compare with regex (last arg).
+# readelf: Apply readelf options on result. Compare with regex (last arg).
+
+set mips_tls_tests {
+ {"Static executable with TLS" "-static -melf32btsmip -T mips-dyn.ld"
+ "-EB -march=mips1 -32 -KPIC" {tlsbin-o32.s}
+ {{objdump {-dr -m mips:isa32r2} tlsbin-o32.d} {objdump -srj.got tlsbin-o32.got}}
+ "tls-static-o32"}
+ {"Shared library with TLS" "-shared -melf32btsmip -T mips-lib.ld"
+ "-EB -march=mips1 -32 -KPIC" {tlslib-o32.s}
+ {{objdump {-dr -m mips:isa32r2} tlslib-o32.d} {objdump -Rsj.got tlslib-o32.got}}
+ "tlslib-o32.so"}
+ {"Dynamic executable with TLS"
+ "-melf32btsmip -T mips-dyn.ld tmpdir/tlslib-o32.so"
+ "-EB -march=mips1 -32 -KPIC" {tlsdyn-o32.s}
+ {{objdump {-dr -m mips:isa32r2} tlsdyn-o32.d} {objdump -Rsj.got tlsdyn-o32.got}}
+ "tls-dynamic-o32"}
+ {"Shared library with multiple GOTs and TLS"
+ "-shared -melf32btsmip -T mips-lib.ld"
+ "-EB -march=mips1 -32 -KPIC" {tls-multi-got-1-1.s tls-multi-got-1-2.s}
+ {{readelf {-d -r} tls-multi-got-1.r}
+ {objdump {-dr -m mips:isa32r2} tls-multi-got-1.d}
+ {objdump -Rsj.got tls-multi-got-1.got}}
+ "tlslib-multi.so"}
+ {"Shared library with TLS and versioning"
+ "-shared -melf32btsmip -T mips-lib.ld --version-script tlslib.ver"
+ "-EB -march=mips1 -32 -KPIC" {tlslib-o32.s}
+ {{objdump {-dr -m mips:isa32r2} tlslib-o32.d} {objdump -Rsj.got tlslib-o32-ver.got}}
+ "tlslib-o32-ver.so"}
+ {"Dynamic executable with TLS and versioning"
+ "-melf32btsmip -T mips-dyn.ld tmpdir/tlslib-o32-ver.so"
+ "-EB -march=mips1 -32 -KPIC" {tlsdyn-o32.s tlsdyn-o32-2.s}
+ {{objdump {-dr -m mips:isa32r2} tlsdyn-o32-1.d} {objdump -Rsj.got tlsdyn-o32-1.got}}
+ "tls-dynamic-o32-ver"}
+ {"Dynamic executable with TLS and versioning (order 2)"
+ "-melf32btsmip -T mips-dyn.ld tmpdir/tlsdyn-o32.o tmpdir/tlslib-o32-ver.so tmpdir/tlsdyn-o32-2.o"
+ "-EB -march=mips1 -32 -KPIC" {}
+ {{objdump {-dr -m mips:isa32r2} tlsdyn-o32-2.d} {objdump -Rsj.got tlsdyn-o32-2.got}}
+ "tls-dynamic-o32-ver-2"}
+ {"Dynamic executable with TLS and versioning (order 3)"
+ "-melf32btsmip -T mips-dyn.ld tmpdir/tlsdyn-o32-2.o tmpdir/tlslib-o32-ver.so tmpdir/tlsdyn-o32.o"
+ "-EB -march=mips1 -32 -KPIC" {}
+ {{objdump {-dr -m mips:isa32r2} tlsdyn-o32-3.d} {objdump -Rsj.got tlsdyn-o32-3.got}}
+ "tls-dynamic-o32-ver-3"}
+ {"Shared library with TLS and hidden symbols"
+ "-shared -melf32btsmip -T mips-lib.ld --version-script tlslib-hidden.ver"
+ "-EB -march=mips1 -32 -KPIC" {tlslib-o32.s}
+ {{objdump {-dr -m mips:isa32r2} tlslib-o32.d} {objdump -Rsj.got tlslib-o32-hidden.got}}
+ "tlslib-o32-hidden.so"}
+}
+
+if {[istarget mips*-*-linux*]} {
+ run_ld_link_tests $mips_tls_tests
+}
+
Index: binutils/gas/testsuite/gas/mips/tls-o32.d
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/gas/testsuite/gas/mips/tls-o32.d 2005-02-07 16:21:35.260459969 -0500
@@ -0,0 +1,55 @@
+#as: -EB -march=mips1 -mabi=32
+#objdump: -dr
+#name: MIPS ELF TLS o32
+
+dump.o: file format elf32-.*bigmips
+
+Disassembly of section .text:
+
+00000000 <fn>:
+ 0: 3c1c0000 lui gp,0x0
+ 0: R_MIPS_HI16 _gp_disp
+ 4: 279c0000 addiu gp,gp,0
+ 4: R_MIPS_LO16 _gp_disp
+ 8: 0399e021 addu gp,gp,t9
+ c: 27bdfff0 addiu sp,sp,-16
+ 10: afbe0008 sw s8,8\(sp\)
+ 14: 03a0f021 move s8,sp
+ 18: afbc0000 sw gp,0\(sp\)
+ 1c: 8f990000 lw t9,0\(gp\)
+ 1c: R_MIPS_CALL16 __tls_get_addr
+ 20: 27840000 addiu a0,gp,0
+ 20: R_MIPS_TLS_GD tlsvar_gd
+ 24: 0320f809 jalr t9
+ 28: 00000000 nop
+ 2c: 8fdc0000 lw gp,0\(s8\)
+ 30: 00000000 nop
+ 34: 8f990000 lw t9,0\(gp\)
+ 34: R_MIPS_CALL16 __tls_get_addr
+ 38: 27840000 addiu a0,gp,0
+ 38: R_MIPS_TLS_LDM tlsvar_ld
+ 3c: 0320f809 jalr t9
+ 40: 00000000 nop
+ 44: 8fdc0000 lw gp,0\(s8\)
+ 48: 00401021 move v0,v0
+ 4c: 3c030000 lui v1,0x0
+ 4c: R_MIPS_TLS_LDO_HI16 tlsvar_ld
+ 50: 24630000 addiu v1,v1,0
+ 50: R_MIPS_TLS_LDO_LO16 tlsvar_ld
+ 54: 00621821 addu v1,v1,v0
+ 58: 7c02283b 0x7c02283b
+ 5c: 8f830000 lw v1,0\(gp\)
+ 5c: R_MIPS_TLS_TPOFF tlsvar_ie
+ 60: 00000000 nop
+ 64: 00621821 addu v1,v1,v0
+ 68: 7c02283b 0x7c02283b
+ 6c: 3c030000 lui v1,0x0
+ 6c: R_MIPS_TLS_TPOFF_HI16 tlsvar_le
+ 70: 34630000 ori v1,v1,0x0
+ 70: R_MIPS_TLS_TPOFF_LO16 tlsvar_le
+ 74: 00621821 addu v1,v1,v0
+ 78: 03c0e821 move sp,s8
+ 7c: 8fbe0008 lw s8,8\(sp\)
+ 80: 03e00008 jr ra
+ 84: 27bd0010 addiu sp,sp,16
+#pass
Index: binutils/gas/testsuite/gas/mips/tls-o32.s
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/gas/testsuite/gas/mips/tls-o32.s 2005-02-07 16:21:35.260459969 -0500
@@ -0,0 +1,85 @@
+ .file 1 "tls.s"
+ .abicalls
+ .text
+ .align 2
+ .globl fn
+ .ent fn
+ .type fn,@function
+fn:
+ .frame $fp,16,$31
+ .mask 0x40000000,-8
+ .fmask 0x00000000,0
+ .set noreorder
+ .cpload $25
+ .set reorder
+ addiu $sp,$sp,-16
+ sw $fp,8($sp)
+ move $fp,$sp
+ .cprestore 0
+
+ # General Dynamic
+ lw $25,%call16(__tls_get_addr)($28)
+ addiu $4,$28,%tlsgd(tlsvar_gd)
+ jal $25
+
+ # Local Dynamic
+ lw $25,%call16(__tls_get_addr)($28)
+ addiu $4,$28,%tlsldm(tlsvar_ld)
+ jal $25
+
+ move $2,$2 # Arbitrary instructions
+
+ lui $3,%hi(%dtpoff(tlsvar_ld))
+ addiu $3,$3,%lo(%dtpoff(tlsvar_ld))
+ addu $3,$3,$2
+
+ # Initial Exec
+ .set push
+ .set mips32r2
+ rdhwr $2, $5
+ .set pop
+ lw $3,%gottpoff(tlsvar_ie)($28)
+ addu $3,$3,$2
+
+ # Local Exec
+ .set push
+ .set mips32r2
+ rdhwr $2, $5
+ .set pop
+ lui $3,%hi(%tpoff(tlsvar_le))
+ ori $3,$3,%lo(%tpoff(tlsvar_le))
+ addu $3,$3,$2
+
+ move $sp,$fp
+ lw $fp,8($sp)
+ addiu $sp,$sp,16
+ j $31
+ .end fn
+
+ .section .tbss,"awT",@nobits
+ .align 2
+ .global tlsvar_gd
+ .type tlsvar_gd,@object
+ .size tlsvar_gd,4
+tlsvar_gd:
+ .space 4
+ .global tlsvar_ie
+ .type tlsvar_ie,@object
+ .size tlsvar_ie,4
+tlsvar_ie:
+ .space 4
+
+ .section .tdata,"awT"
+ .align 2
+ .global tlsvar_ld
+ .hidden tlsvar_ld
+ .type tlsvar_ld,@object
+ .size tlsvar_ld,4
+tlsvar_ld:
+ .word 1
+ .global tlsvar_le
+ .hidden tlsvar_le
+ .type tlsvar_le,@object
+ .size tlsvar_le,4
+tlsvar_le:
+ .word 1
Index: binutils/bfd/reloc.c
===================================================================
--- binutils.orig/bfd/reloc.c 2005-02-01 16:59:44.000000000 -0500
+++ binutils/bfd/reloc.c 2005-02-07 16:24:09.004639231 -0500
@@ -1,6 +1,6 @@
/* BFD support for handling relocation entries.
Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004
+ 2000, 2001, 2002, 2003, 2004, 2005
Free Software Foundation, Inc.
Written by Cygnus Support.
@@ -2109,6 +2109,32 @@ ENUMX
BFD_RELOC_MIPS_RELGOT
ENUMX
BFD_RELOC_MIPS_JALR
+ENUMX
+ BFD_RELOC_MIPS_TLS_DTPMOD32
+ENUMX
+ BFD_RELOC_MIPS_TLS_DTPOFF32
+ENUMX
+ BFD_RELOC_MIPS_TLS_DTPMOD64
+ENUMX
+ BFD_RELOC_MIPS_TLS_DTPOFF64
+ENUMX
+ BFD_RELOC_MIPS_TLS_GD
+ENUMX
+ BFD_RELOC_MIPS_TLS_LDM
+ENUMX
+ BFD_RELOC_MIPS_TLS_LDO_HI16
+ENUMX
+ BFD_RELOC_MIPS_TLS_LDO_LO16
+ENUMX
+ BFD_RELOC_MIPS_TLS_TPOFF
+ENUMX
+ BFD_RELOC_MIPS_TLS_TPOFF32
+ENUMX
+ BFD_RELOC_MIPS_TLS_TPOFF64
+ENUMX
+ BFD_RELOC_MIPS_TLS_TPOFF_HI16
+ENUMX
+ BFD_RELOC_MIPS_TLS_TPOFF_LO16
ENUMDOC
MIPS ELF relocations.
COMMENT
Index: binutils/bfd/bfd-in2.h
===================================================================
--- binutils.orig/bfd/bfd-in2.h 2005-02-01 16:59:11.000000000 -0500
+++ binutils/bfd/bfd-in2.h 2005-02-07 16:21:35.263459225 -0500
@@ -2383,6 +2383,19 @@ to compensate for the borrow when the lo
BFD_RELOC_MIPS_REL16,
BFD_RELOC_MIPS_RELGOT,
BFD_RELOC_MIPS_JALR,
+ BFD_RELOC_MIPS_TLS_DTPMOD32,
+ BFD_RELOC_MIPS_TLS_DTPOFF32,
+ BFD_RELOC_MIPS_TLS_DTPMOD64,
+ BFD_RELOC_MIPS_TLS_DTPOFF64,
+ BFD_RELOC_MIPS_TLS_GD,
+ BFD_RELOC_MIPS_TLS_LDM,
+ BFD_RELOC_MIPS_TLS_LDO_HI16,
+ BFD_RELOC_MIPS_TLS_LDO_LO16,
+ BFD_RELOC_MIPS_TLS_TPOFF,
+ BFD_RELOC_MIPS_TLS_TPOFF32,
+ BFD_RELOC_MIPS_TLS_TPOFF64,
+ BFD_RELOC_MIPS_TLS_TPOFF_HI16,
+ BFD_RELOC_MIPS_TLS_TPOFF_LO16,
/* Fujitsu Frv Relocations. */
Index: binutils/ld/testsuite/ld-mips-elf/mips-lib.ld
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/mips-lib.ld 2005-02-07 16:21:35.264458977 -0500
@@ -0,0 +1,218 @@
+/* Script for --shared -z combreloc: shared library, combine & sort relocs */
+OUTPUT_FORMAT("elf32-tradbigmips", "elf32-tradbigmips",
+ "elf32-tradlittlemips")
+OUTPUT_ARCH(mips)
+ENTRY(__start)
+SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib");
+/* Do we need any of these for elf?
+ __DYNAMIC = 0; */
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = 0 + SIZEOF_HEADERS;
+ .reginfo : { *(.reginfo) }
+ .dynamic : { *(.dynamic) }
+ .hash : { *(.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+ .rel.dyn :
+ {
+ *(.rel.init)
+ *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
+ *(.rel.fini)
+ *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
+ *(.rel.data.rel.ro*)
+ *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
+ *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
+ *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
+ *(.rel.ctors)
+ *(.rel.dtors)
+ *(.rel.got)
+ *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*)
+ *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*)
+ *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*)
+ *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*)
+ *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
+ }
+ .rela.dyn :
+ {
+ *(.rela.init)
+ *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+ *(.rela.fini)
+ *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+ *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+ *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+ *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+ *(.rela.ctors)
+ *(.rela.dtors)
+ *(.rela.got)
+ *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*)
+ *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*)
+ *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*)
+ *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*)
+ *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+ }
+ .rel.plt : { *(.rel.plt) }
+ .rela.plt : { *(.rela.plt) }
+ .init :
+ {
+ KEEP (*(.init))
+ } =0
+ .plt : { *(.plt) }
+ .text :
+ {
+ _ftext = . ;
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ KEEP (*(.text.*personality*))
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ *(.mips16.fn.*) *(.mips16.call.*)
+ } =0
+ .fini :
+ {
+ KEEP (*(.fini))
+ } =0
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+ .rodata1 : { *(.rodata1) }
+ .eh_frame_hdr : { *(.eh_frame_hdr) }
+ .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }
+ .gcc_except_table : ONLY_IF_RO { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) }
+ /* Adjust the address for the data segment. We want to adjust up to
+ the same address within the page on the next page up. */
+ . = ALIGN (0x40000) - ((0x40000 - .) & (0x40000 - 1)); . = DATA_SEGMENT_ALIGN (0x40000, 0x1000);
+ /* Exception handling */
+ .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }
+ .gcc_except_table : ONLY_IF_RW { KEEP (*(.gcc_except_table)) *(.gcc_except_table.*) }
+ /* Thread Local Storage sections */
+ .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+ .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+ /* Ensure the __preinit_array_start label is properly aligned. We
+ could instead move the label definition inside the section, but
+ the linker would then create the section even if it turns out to
+ be empty, which isn't pretty. */
+ . = ALIGN(32 / 8);
+ .preinit_array : { KEEP (*(.preinit_array)) }
+ .init_array : { KEEP (*(.init_array)) }
+ .fini_array : { KEEP (*(.fini_array)) }
+ .ctors :
+ {
+ /* gcc uses crtbegin.o to find the start of
+ the constructors, so we make sure it is
+ first. Because this is a wildcard, it
+ doesn't matter if the user does not
+ actually link against crtbegin.o; the
+ linker won't look for a file to match a
+ wildcard. The wildcard also means that it
+ doesn't matter which directory crtbegin.o
+ is in. */
+ KEEP (*crtbegin*.o(.ctors))
+ /* We don't want to include the .ctor section from
+ from the crtend.o file until after the sorted ctors.
+ The .ctor section from the crtend file contains the
+ end of ctors marker and it must be last */
+ KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ }
+ .dtors :
+ {
+ KEEP (*crtbegin*.o(.dtors))
+ KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ }
+ .jcr : { KEEP (*(.jcr)) }
+ .data.rel.ro : { *(.data.rel.ro.local) *(.data.rel.ro*) }
+ . = DATA_SEGMENT_RELRO_END (0, .);
+ .data :
+ {
+ _fdata = . ;
+ *(.data .data.* .gnu.linkonce.d.*)
+ KEEP (*(.gnu.linkonce.d.*personality*))
+ SORT(CONSTRUCTORS)
+ }
+ .data1 : { *(.data1) }
+ _gp = ALIGN(16) + 0x7ff0;
+ .got : { *(.got.plt) *(.got) }
+ .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) }
+ .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
+ /* We want the small data sections together, so single-instruction offsets
+ can access them all, and initialized data all before uninitialized, so
+ we can shorten the on-disk segment size. */
+ .sdata :
+ {
+ *(.sdata .sdata.* .gnu.linkonce.s.*)
+ }
+ .lit8 : { *(.lit8) }
+ .lit4 : { *(.lit4) }
+ _edata = .;
+ PROVIDE (edata = .);
+ __bss_start = .;
+ _fbss = .;
+ .sbss :
+ {
+ PROVIDE (__sbss_start = .);
+ PROVIDE (___sbss_start = .);
+ *(.dynsbss)
+ *(.sbss .sbss.* .gnu.linkonce.sb.*)
+ *(.scommon)
+ PROVIDE (__sbss_end = .);
+ PROVIDE (___sbss_end = .);
+ }
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ /* Align here to ensure that the .bss section occupies space up to
+ _end. Align after .bss to ensure correct alignment even if the
+ .bss section disappears because there are no input sections. */
+ . = ALIGN(32 / 8);
+ }
+ . = ALIGN(32 / 8);
+ _end = .;
+ PROVIDE (end = .);
+ . = DATA_SEGMENT_END (.);
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
+ .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
+ /DISCARD/ : { *(.note.GNU-stack) }
+}
Index: binutils/gas/testsuite/gas/mips/mips.exp
===================================================================
--- binutils.orig/gas/testsuite/gas/mips/mips.exp 2004-12-10 14:48:42.000000000 -0500
+++ binutils/gas/testsuite/gas/mips/mips.exp 2005-02-07 16:21:35.264458977 -0500
@@ -733,4 +733,9 @@ if { [istarget mips*-*-*] } then {
run_dump_test "macro-warn-1-n32"
run_dump_test "macro-warn-2-n32"
}
+
+ if $elf {
+ run_list_test "tls-ill" "-32"
+ run_dump_test "tls-o32"
+ }
}
Index: binutils/ld/testsuite/ld-mips-elf/tlsbin-o32.got
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/tlsbin-o32.got 2005-02-07 16:21:35.264458977 -0500
@@ -0,0 +1,8 @@
+
+.*: file format elf32-tradbigmips
+
+Contents of section .got:
+ 10000010 00000000 80000000 00000000 00000000 ................
+ 10000020 00000000 00000000 00000000 00400158 .............@.X
+ 10000030 ffff900c 00000001 00000000 00000001 ................
+ 10000040 ffff8008 ....
Index: binutils/ld/testsuite/ld-mips-elf/tlsdyn-o32.d
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/tlsdyn-o32.d 2005-02-07 16:21:35.265458729 -0500
@@ -0,0 +1,58 @@
+
+.*: file format elf32-tradbigmips
+
+Disassembly of section .text:
+
+.* <__start>:
+ .*: 3c1c0fc0 lui gp,0xfc0
+ .*: 279c7b50 addiu gp,gp,31568
+ .*: 0399e021 addu gp,gp,t9
+ .*: 27bdfff0 addiu sp,sp,-16
+ .*: afbe0008 sw s8,8\(sp\)
+ .*: 03a0f021 move s8,sp
+ .*: afbc0000 sw gp,0\(sp\)
+ .*: 8f99802c lw t9,-32724\(gp\)
+ .*: 27848038 addiu a0,gp,-32712
+ .*: 0320f809 jalr t9
+ .*: 00000000 nop
+ .*: 8fdc0000 lw gp,0\(s8\)
+ .*: 00000000 nop
+ .*: 8f99802c lw t9,-32724\(gp\)
+ .*: 27848048 addiu a0,gp,-32696
+ .*: 0320f809 jalr t9
+ .*: 00000000 nop
+ .*: 8fdc0000 lw gp,0\(s8\)
+ .*: 00000000 nop
+ .*: 8f99802c lw t9,-32724\(gp\)
+ .*: 27848030 addiu a0,gp,-32720
+ .*: 0320f809 jalr t9
+ .*: 00000000 nop
+ .*: 8fdc0000 lw gp,0\(s8\)
+ .*: 00401021 move v0,v0
+ .*: 3c030000 lui v1,0x0
+ .*: 24638000 addiu v1,v1,-32768
+ .*: 00621821 addu v1,v1,v0
+ .*: 7c02283b rdhwr v0,\$5
+ .*: 8f838044 lw v1,-32700\(gp\)
+ .*: 00000000 nop
+ .*: 00621821 addu v1,v1,v0
+ .*: 8f838040 lw v1,-32704\(gp\)
+ .*: 00000000 nop
+ .*: 00621821 addu v1,v1,v0
+ .*: 7c02283b rdhwr v0,\$5
+ .*: 3c030000 lui v1,0x0
+ .*: 24639004 addiu v1,v1,-28668
+ .*: 00621821 addu v1,v1,v0
+ .*: 03c0e821 move sp,s8
+ .*: 8fbe0008 lw s8,8\(sp\)
+ .*: 03e00008 jr ra
+ .*: 27bd0010 addiu sp,sp,16
+
+.* <__tls_get_addr>:
+ .*: 03e00008 jr ra
+ .*: 00000000 nop
+ ...
+Disassembly of section .MIPS.stubs:
+
+.* <.MIPS.stubs>:
+ ...
Index: binutils/ld/testsuite/ld-mips-elf/tlsdyn-o32.got
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/tlsdyn-o32.got 2005-02-07 16:21:35.265458729 -0500
@@ -0,0 +1,19 @@
+
+tmpdir/tls-dynamic-o32: file format elf32-tradbigmips
+
+DYNAMIC RELOCATION RECORDS
+OFFSET TYPE VALUE
+00000000 R_MIPS_NONE \*ABS\*
+10000048 R_MIPS_TLS_DTPMOD32 tlsbin_gd
+1000004c R_MIPS_TLS_DTPOFF32 tlsbin_gd
+10000058 R_MIPS_TLS_DTPMOD32 tlsvar_gd
+1000005c R_MIPS_TLS_DTPOFF32 tlsvar_gd
+10000054 R_MIPS_TLS_TPOFF32 tlsbin_ie
+10000050 R_MIPS_TLS_TPOFF32 tlsvar_ie
+
+
+Contents of section .got:
+ 10000020 00000000 80000000 00000000 00000000 ................
+ 10000030 00000000 00000000 00000000 0040056c ................
+ 10000040 00000001 00000000 00000000 00000000 ................
+ 10000050 00000000 00000000 00000000 00000000 ................
Index: binutils/ld/testsuite/ld-mips-elf/tlsbin-o32.d
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/tlsbin-o32.d 2005-02-07 16:21:35.265458729 -0500
@@ -0,0 +1,43 @@
+.*: file format elf32-tradbigmips
+
+Disassembly of section .text:
+
+004000d0 <__start>:
+ 4000d0: 3c1c0fc0 lui gp,0xfc0
+ 4000d4: 279c7f30 addiu gp,gp,32560
+ 4000d8: 0399e021 addu gp,gp,t9
+ 4000dc: 27bdfff0 addiu sp,sp,-16
+ 4000e0: afbe0008 sw s8,8\(sp\)
+ 4000e4: 03a0f021 move s8,sp
+ 4000e8: afbc0000 sw gp,0\(sp\)
+ 4000ec: 8f99802c lw t9,-32724\(gp\)
+ 4000f0: 2784803c addiu a0,gp,-32708
+ 4000f4: 0320f809 jalr t9
+ 4000f8: 00000000 nop
+ 4000fc: 8fdc0000 lw gp,0\(s8\)
+ 400100: 00000000 nop
+ 400104: 8f99802c lw t9,-32724\(gp\)
+ 400108: 27848034 addiu a0,gp,-32716
+ 40010c: 0320f809 jalr t9
+ 400110: 00000000 nop
+ 400114: 8fdc0000 lw gp,0\(s8\)
+ 400118: 00401021 move v0,v0
+ 40011c: 3c030000 lui v1,0x0
+ 400120: 24638000 addiu v1,v1,-32768
+ 400124: 00621821 addu v1,v1,v0
+ 400128: 7c02283b rdhwr v0,\$5
+ 40012c: 8f838030 lw v1,-32720\(gp\)
+ 400130: 00000000 nop
+ 400134: 00621821 addu v1,v1,v0
+ 400138: 7c02283b rdhwr v0,\$5
+ 40013c: 3c030000 lui v1,0x0
+ 400140: 24639004 addiu v1,v1,-28668
+ 400144: 00621821 addu v1,v1,v0
+ 400148: 03c0e821 move sp,s8
+ 40014c: 8fbe0008 lw s8,8\(sp\)
+ 400150: 03e00008 jr ra
+ 400154: 27bd0010 addiu sp,sp,16
+
+00400158 <__tls_get_addr>:
+ 400158: 03e00008 jr ra
+ 40015c: 00000000 nop
Index: binutils/include/elf/mips.h
===================================================================
--- binutils.orig/include/elf/mips.h 2004-12-09 01:02:45.000000000 -0500
+++ binutils/include/elf/mips.h 2005-02-07 16:25:12.916088506 -0500
@@ -1,5 +1,6 @@
/* MIPS ELF support for BFD.
- Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003
+ Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2003,
+ 2004, 2005
Free Software Foundation, Inc.
By Ian Lance Taylor, Cygnus Support, <ian@cygnus.com>, from
@@ -72,7 +73,21 @@ START_RELOC_NUMBERS (elf_mips_reloc_type
RELOC_NUMBER (R_MIPS_PJUMP, 35)
RELOC_NUMBER (R_MIPS_RELGOT, 36)
RELOC_NUMBER (R_MIPS_JALR, 37)
- RELOC_NUMBER (R_MIPS_max, 38)
+ /* TLS relocs <http://www.linux-mips.org/wiki/index.php/NPTL>. */
+ RELOC_NUMBER (R_MIPS_TLS_DTPMOD32, 38)
+ RELOC_NUMBER (R_MIPS_TLS_DTPOFF32, 39)
+ RELOC_NUMBER (R_MIPS_TLS_DTPMOD64, 40)
+ RELOC_NUMBER (R_MIPS_TLS_DTPOFF64, 41)
+ RELOC_NUMBER (R_MIPS_TLS_GD, 42)
+ RELOC_NUMBER (R_MIPS_TLS_LDM, 43)
+ RELOC_NUMBER (R_MIPS_TLS_LDO_HI16, 44)
+ RELOC_NUMBER (R_MIPS_TLS_LDO_LO16, 45)
+ RELOC_NUMBER (R_MIPS_TLS_TPOFF, 46)
+ RELOC_NUMBER (R_MIPS_TLS_TPOFF32, 47)
+ RELOC_NUMBER (R_MIPS_TLS_TPOFF64, 48)
+ RELOC_NUMBER (R_MIPS_TLS_TPOFF_HI16, 49)
+ RELOC_NUMBER (R_MIPS_TLS_TPOFF_LO16, 50)
+ RELOC_NUMBER (R_MIPS_max, 51)
/* These relocs are used for the mips16. */
RELOC_NUMBER (R_MIPS16_26, 100)
RELOC_NUMBER (R_MIPS16_GPREL, 101)
Index: binutils/gas/config/tc-mips.c
===================================================================
--- binutils.orig/gas/config/tc-mips.c 2005-02-01 17:00:04.000000000 -0500
+++ binutils/gas/config/tc-mips.c 2005-02-07 16:25:18.556720211 -0500
@@ -1,6 +1,6 @@
/* tc-mips.c -- assemble code for a MIPS chip.
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004 Free Software Foundation, Inc.
+ 2003, 2004, 2005 Free Software Foundation, Inc.
Contributed by the OSF and Ralph Campbell.
Written by Keith Knowles and Ralph Campbell, working independently.
Modified for ECOFF and R4000 support by Ian Lance Taylor of Cygnus
@@ -9819,6 +9819,13 @@ static const struct percent_op_match
{"%highest", BFD_RELOC_MIPS_HIGHEST},
{"%higher", BFD_RELOC_MIPS_HIGHER},
{"%neg", BFD_RELOC_MIPS_SUB},
+ {"%tlsgd", BFD_RELOC_MIPS_TLS_GD},
+ {"%tlsldm", BFD_RELOC_MIPS_TLS_LDM},
+ /* These must always be used with %lo or %hi (for now). */
+ {"%dtpoff", BFD_RELOC_MIPS_TLS_LDO_LO16},
+ {"%tpoff", BFD_RELOC_MIPS_TLS_TPOFF_LO16},
+ /* This one must be used without %lo or %hi (for now). */
+ {"%gottpoff", BFD_RELOC_MIPS_TLS_TPOFF},
#endif
{"%hi", BFD_RELOC_HI16_S}
};
@@ -9836,6 +9843,11 @@ parse_relocation (char **str, bfd_reloc_
for (i = 0; i < ARRAY_SIZE (percent_op); i++)
if (strncasecmp (*str, percent_op[i].str, strlen (percent_op[i].str)) == 0)
{
+ int len = strlen (percent_op[i].str);
+
+ if (!ISSPACE ((*str)[len]) && (*str)[len] != '(')
+ continue;
+
*str += strlen (percent_op[i].str);
*reloc = percent_op[i].reloc;
@@ -9887,9 +9899,61 @@ my_getSmallExpression (expressionS *ep,
str_depth++;
}
while (*str == '%'
- && reloc_index < (HAVE_NEWABI ? 3 : 1)
+ && reloc_index < 3
&& parse_relocation (&str, &reversed_reloc[reloc_index]));
+ /* %dtpoff may only be used immediately inside %hi or %lo, with no
+ other relocations. However, use inside %hi and %lo is valid even
+ with the old ABI which permits only a single relocation.
+ Similarly, %tpoff may be used inside %hi and %lo even with the
+ old ABI, but may also be used on its own. Convert these uses to
+ a single relocation and give an error for other uses. */
+ for (i = 0; i < reloc_index; i++)
+ {
+ if (reversed_reloc[i] == BFD_RELOC_MIPS_TLS_LDO_LO16)
+ {
+ if (i != 1
+ || reloc_index != 2
+ || (reversed_reloc[i - 1] != BFD_RELOC_LO16
+ && reversed_reloc[i - 1] != BFD_RELOC_HI16_S))
+ {
+ as_bad (_("bad use of %%dtpoff"));
+ reloc_index = 0;
+ break;
+ }
+ i--;
+ reloc_index--;
+ if (reversed_reloc[i] == BFD_RELOC_LO16)
+ reversed_reloc[i] = BFD_RELOC_MIPS_TLS_LDO_LO16;
+ else
+ reversed_reloc[i] = BFD_RELOC_MIPS_TLS_LDO_HI16;
+ }
+ if (reversed_reloc[i] == BFD_RELOC_MIPS_TLS_TPOFF_LO16)
+ {
+ if (i != 1
+ || reloc_index != 2
+ || (reversed_reloc[i - 1] != BFD_RELOC_LO16
+ && reversed_reloc[i - 1] != BFD_RELOC_HI16_S))
+ {
+ as_bad (_("bad use of %%tpoff"));
+ reloc_index = 0;
+ break;
+ }
+ i--;
+ reloc_index--;
+ if (reversed_reloc[i] == BFD_RELOC_LO16)
+ reversed_reloc[i] = BFD_RELOC_MIPS_TLS_TPOFF_LO16;
+ else
+ reversed_reloc[i] = BFD_RELOC_MIPS_TLS_TPOFF_HI16;
+ }
+ }
+
+ if (reloc_index > 1 && !HAVE_NEWABI)
+ {
+ as_bad (_("multiple relocations not supported by current ABI"));
+ reloc_index = 0;
+ }
+
my_getExpression (ep, crux);
str = expr_end;
@@ -10972,6 +11036,16 @@ md_apply_fix3 (fixS *fixP, valueT *valP,
switch (fixP->fx_r_type)
{
+ case BFD_RELOC_MIPS_TLS_GD:
+ case BFD_RELOC_MIPS_TLS_LDM:
+ case BFD_RELOC_MIPS_TLS_LDO_HI16:
+ case BFD_RELOC_MIPS_TLS_LDO_LO16:
+ case BFD_RELOC_MIPS_TLS_TPOFF:
+ case BFD_RELOC_MIPS_TLS_TPOFF_HI16:
+ case BFD_RELOC_MIPS_TLS_TPOFF_LO16:
+ S_SET_THREAD_LOCAL (fixP->fx_addsy);
+ /* fall through */
+
case BFD_RELOC_MIPS_JMP:
case BFD_RELOC_MIPS_SHIFT5:
case BFD_RELOC_MIPS_SHIFT6:
Index: binutils/ld/testsuite/ld-mips-elf/tlsdyn-o32.s
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/tlsdyn-o32.s 2005-02-07 16:21:35.272456992 -0500
@@ -0,0 +1,96 @@
+ .file 1 "tlsbin-o32.s"
+ .abicalls
+ .text
+ .align 2
+ .globl __start
+ .ent __start
+ .type __start,@function
+__start:
+ .frame $fp,16,$31
+ .mask 0x40000000,-8
+ .fmask 0x00000000,0
+ .set noreorder
+ .cpload $25
+ .set reorder
+ addiu $sp,$sp,-16
+ sw $fp,8($sp)
+ move $fp,$sp
+ .cprestore 0
+
+ # General Dynamic
+ lw $25,%call16(__tls_get_addr)($28)
+ addiu $4,$28,%tlsgd(tlsbin_gd)
+ jal $25
+
+ lw $25,%call16(__tls_get_addr)($28)
+ addiu $4,$28,%tlsgd(tlsvar_gd)
+ jal $25
+
+ # Local Dynamic
+ lw $25,%call16(__tls_get_addr)($28)
+ addiu $4,$28,%tlsldm(tlsbin_ld)
+ jal $25
+
+ move $2,$2 # Arbitrary instructions
+
+ lui $3,%hi(%dtpoff(tlsbin_ld))
+ addiu $3,$3,%lo(%dtpoff(tlsbin_ld))
+ addu $3,$3,$2
+
+ # Initial Exec
+ .set push
+ .set mips32r2
+ rdhwr $2, $5
+ .set pop
+ lw $3,%gottpoff(tlsbin_ie)($28)
+ addu $3,$3,$2
+
+ lw $3,%gottpoff(tlsvar_ie)($28)
+ addu $3,$3,$2
+
+ # Local Exec
+ .set push
+ .set mips32r2
+ rdhwr $2, $5
+ .set pop
+ lui $3,%hi(%tpoff(tlsbin_le))
+ addiu $3,$3,%lo(%tpoff(tlsbin_le))
+ addu $3,$3,$2
+
+ move $sp,$fp
+ lw $fp,8($sp)
+ addiu $sp,$sp,16
+ j $31
+ .end __start
+
+ .globl __tls_get_addr
+__tls_get_addr:
+ j $31
+
+ .section .tbss,"awT",@nobits
+ .align 2
+ .global tlsbin_gd
+ .type tlsbin_gd,@object
+ .size tlsbin_gd,4
+tlsbin_gd:
+ .space 4
+ .global tlsbin_ie
+ .type tlsbin_ie,@object
+ .size tlsbin_ie,4
+tlsbin_ie:
+ .space 4
+
+ .section .tdata,"awT"
+ .align 2
+ .global tlsbin_ld
+ .hidden tlsbin_ld
+ .type tlsbin_ld,@object
+ .size tlsbin_ld,4
+tlsbin_ld:
+ .word 1
+ .global tlsbin_le
+ .hidden tlsbin_le
+ .type tlsbin_le,@object
+ .size tlsbin_le,4
+tlsbin_le:
+ .word 1
Index: binutils/ld/testsuite/ld-mips-elf/tls-multi-got-1.got
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/tls-multi-got-1.got 2005-02-07 16:21:35.273456744 -0500
@@ -0,0 +1,58 @@
+
+.*: file format elf32-tradbigmips
+
+DYNAMIC RELOCATION RECORDS
+OFFSET TYPE VALUE
+00000000 R_MIPS_NONE \*ABS\*
+00149630 R_MIPS_TLS_DTPMOD32 \*ABS\*
+0013f9a8 R_MIPS_TLS_DTPMOD32 \*ABS\*
+0014963c R_MIPS_TLS_DTPMOD32 tlsvar_gd
+00149640 R_MIPS_TLS_DTPOFF32 tlsvar_gd
+0013f9b4 R_MIPS_TLS_DTPMOD32 tlsvar_gd
+0013f9b8 R_MIPS_TLS_DTPOFF32 tlsvar_gd
+00149638 R_MIPS_TLS_TPOFF32 tlsvar_ie
+0013f9b0 R_MIPS_TLS_TPOFF32 tlsvar_ie
+0013602c R_MIPS_REL32 sym_2_8355
+#...
+00142d4c R_MIPS_REL32 sym_1_0945
+00000000 R_MIPS_NONE \*ABS\*
+00000000 R_MIPS_NONE \*ABS\*
+00000000 R_MIPS_NONE \*ABS\*
+00000000 R_MIPS_NONE \*ABS\*
+00000000 R_MIPS_NONE \*ABS\*
+00000000 R_MIPS_NONE \*ABS\*
+00000000 R_MIPS_NONE \*ABS\*
+00000000 R_MIPS_NONE \*ABS\*
+00000000 R_MIPS_NONE \*ABS\*
+00000000 R_MIPS_NONE \*ABS\*
+00000000 R_MIPS_NONE \*ABS\*
+00000000 R_MIPS_NONE \*ABS\*
+00000000 R_MIPS_NONE \*ABS\*
+00000000 R_MIPS_NONE \*ABS\*
+00000000 R_MIPS_NONE \*ABS\*
+00000000 R_MIPS_NONE \*ABS\*
+00000000 R_MIPS_NONE \*ABS\*
+00000000 R_MIPS_NONE \*ABS\*
+00000000 R_MIPS_NONE \*ABS\*
+00000000 R_MIPS_NONE \*ABS\*
+00000000 R_MIPS_NONE \*ABS\*
+00000000 R_MIPS_NONE \*ABS\*
+
+
+Contents of section .got:
+ 122480 00000000 80000000 00000000 00000000 ................
+ 122490 00000000 00000000 00000000 00000000 ................
+ 1224a0 00000000 00000000 00000000 00000000 ................
+ 1224b0 00000000 000e0aac 000d35f4 000d35e4 ..........5...5.
+#...
+ 13f990 00000000 00000000 00000000 00000000 ................
+ 13f9a0 00000000 00000000 00000000 00000000 ................
+ 13f9b0 00000000 00000000 00000000 00000000 ................
+ 13f9c0 80000000 00000000 00000000 00000000 ................
+#...
+ 149600 00000000 00000000 00000000 00000000 ................
+ 149610 00000000 00000000 00000000 00000000 ................
+ 149620 00000000 00000000 00000000 00000000 ................
+ 149630 00000000 00000000 00000000 00000000 ................
+ 149640 00000000 ....
+#pass
Index: binutils/ld/testsuite/ld-mips-elf/tls-multi-got-1-1.s
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/tls-multi-got-1-1.s 2005-02-07 16:21:35.273456744 -0500
@@ -0,0 +1,39 @@
+.macro one_sym count
+.globl sym_1_\count
+sym_1_\count:
+ la $2, sym_1_\count
+.endm
+
+.irp thou,0,1,2,3,4,5,6,7,8,9
+.irp hund,0,1,2,3,4,5,6,7,8,9
+.irp tens,0,1,2,3,4,5,6,7,8,9
+.irp ones,0,1,2,3,4,5,6,7,8,9
+one_sym \thou\hund\tens\ones
+.endr
+.endr
+.endr
+.endr
+
+tls_bits_1:
+ addiu $4,$28,%tlsgd(tlsvar_gd)
+ addiu $4,$28,%tlsldm(tlsvar_ld)
+ addiu $4,$2,%gottpoff(tlsvar_ie)
+
+ .section .tbss,"awT",@nobits
+ .align 2
+ .global tlsvar_gd
+ .type tlsvar_gd,@object
+ .size tlsvar_gd,4
+tlsvar_gd:
+ .space 4
+ .global tlsvar_ie
+ .type tlsvar_ie,@object
+ .size tlsvar_ie,4
+tlsvar_ie:
+ .space 4
+ .global tlsvar_ld
+ .hidden tlsvar_ld
+ .type tlsvar_ld,@object
+ .size tlsvar_ld,4
+tlsvar_ld:
+ .word 1
Index: binutils/ld/testsuite/ld-mips-elf/tls-multi-got-1.d
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/tls-multi-got-1.d 2005-02-07 16:21:35.273456744 -0500
@@ -0,0 +1,20 @@
+
+.*: file format elf32-tradbigmips
+
+Disassembly of section .text:
+
+#...
+[0-9a-f]+ <tls_bits_1>:
+ [0-9a-f]+: 27841c90 addiu a0,gp,7312
+ [0-9a-f]+: 27841c84 addiu a0,gp,7300
+ [0-9a-f]+: 24441c8c addiu a0,v0,7308
+ [0-9a-f]+: 00000000 nop
+
+[0-9a-f]+ <sym_2_0000>:
+#...
+[0-9a-f]+ <tls_bits_2>:
+ [0-9a-f]+: 27841c90 addiu a0,gp,7312
+ [0-9a-f]+: 27841c84 addiu a0,gp,7300
+ [0-9a-f]+: 24441c8c addiu a0,v0,7308
+ [0-9a-f]+: 00000000 nop
+#pass
Index: binutils/ld/testsuite/ld-mips-elf/tls-multi-got-1.r
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/tls-multi-got-1.r 2005-02-07 16:21:35.273456744 -0500
@@ -0,0 +1,61 @@
+
+Dynamic section at offset 0xec contains 19 entries:
+ Tag Type Name/Value
+ 0x00000004 \(HASH\) 0x1ac
+ 0x00000005 \(STRTAB\) 0x71e08
+ 0x00000006 \(SYMTAB\) 0x23ae8
+ 0x0000000a \(STRSZ\) 220100 \(bytes\)
+ 0x0000000b \(SYMENT\) 16 \(bytes\)
+ 0x00000015 \(DEBUG\) 0x0
+ 0x00000003 \(PLTGOT\) 0x122480
+ 0x00000011 \(REL\) 0xa79cc
+ 0x00000012 \(RELSZ\) 160072 \(bytes\)
+ 0x00000013 \(RELENT\) 8 \(bytes\)
+ 0x70000001 \(MIPS_RLD_VERSION\) 1
+ 0x70000005 \(MIPS_FLAGS\) NOTPOT
+ 0x70000006 \(MIPS_BASE_ADDRESS\) 0
+ 0x7000000a \(MIPS_LOCAL_GOTNO\) 13
+ 0x70000011 \(MIPS_SYMTABNO\) 20018
+ 0x70000012 \(MIPS_UNREFEXTNO\) 15
+ 0x70000013 \(MIPS_GOTSYM\) 0x12
+ 0x0000001e \(FLAGS\) STATIC_TLS
+ 0x00000000 \(NULL\) 0x0
+
+Relocation section '\.rel\.dyn' at offset 0x[0-9a-f]+ contains 20031 entries:
+ Offset Info Type Sym.Value Sym. Name
+00000000 00000000 R_MIPS_NONE
+00149630 00000026 R_MIPS_TLS_DTPMOD
+0013f9a8 00000026 R_MIPS_TLS_DTPMOD
+0014963c 00000a26 R_MIPS_TLS_DTPMOD 00000000 tlsvar_gd
+00149640 00000a27 R_MIPS_TLS_DTPOFF 00000000 tlsvar_gd
+0013f9b4 00000a26 R_MIPS_TLS_DTPMOD 00000000 tlsvar_gd
+0013f9b8 00000a27 R_MIPS_TLS_DTPOFF 00000000 tlsvar_gd
+00149638 0000102f R_MIPS_TLS_TPOFF3 00000004 tlsvar_ie
+0013f9b0 0000102f R_MIPS_TLS_TPOFF3 00000004 tlsvar_ie
+0013602c 00001203 R_MIPS_REL32 000e0aac sym_2_8355
+0014250c 00001303 R_MIPS_REL32 000d35f4 sym_1_4745
+#...
+00136a10 004e3003 R_MIPS_REL32 000da990 sym_2_2140
+00142d4c 004e3103 R_MIPS_REL32 000cfa94 sym_1_0945
+00000000 00000000 R_MIPS_NONE
+00000000 00000000 R_MIPS_NONE
+00000000 00000000 R_MIPS_NONE
+00000000 00000000 R_MIPS_NONE
+00000000 00000000 R_MIPS_NONE
+00000000 00000000 R_MIPS_NONE
+00000000 00000000 R_MIPS_NONE
+00000000 00000000 R_MIPS_NONE
+00000000 00000000 R_MIPS_NONE
+00000000 00000000 R_MIPS_NONE
+00000000 00000000 R_MIPS_NONE
+00000000 00000000 R_MIPS_NONE
+00000000 00000000 R_MIPS_NONE
+00000000 00000000 R_MIPS_NONE
+00000000 00000000 R_MIPS_NONE
+00000000 00000000 R_MIPS_NONE
+00000000 00000000 R_MIPS_NONE
+00000000 00000000 R_MIPS_NONE
+00000000 00000000 R_MIPS_NONE
+00000000 00000000 R_MIPS_NONE
+00000000 00000000 R_MIPS_NONE
+00000000 00000000 R_MIPS_NONE
Index: binutils/ld/testsuite/ld-mips-elf/tls-multi-got-1-2.s
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/tls-multi-got-1-2.s 2005-02-07 16:21:35.274456496 -0500
@@ -0,0 +1,20 @@
+.macro one_sym count
+.globl sym_2_\count
+sym_2_\count:
+ la $2, sym_2_\count
+.endm
+
+.irp thou,0,1,2,3,4,5,6,7,8,9
+.irp hund,0,1,2,3,4,5,6,7,8,9
+.irp tens,0,1,2,3,4,5,6,7,8,9
+.irp ones,0,1,2,3,4,5,6,7,8,9
+one_sym \thou\hund\tens\ones
+.endr
+.endr
+.endr
+.endr
+
+tls_bits_2:
+ addiu $4,$28,%tlsgd(tlsvar_gd)
+ addiu $4,$28,%tlsldm(tlsvar_ld)
+ addiu $4,$2,%gottpoff(tlsvar_ie)
Index: binutils/gas/testsuite/gas/mips/tls-ill.l
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/gas/testsuite/gas/mips/tls-ill.l 2005-02-07 16:21:35.274456496 -0500
@@ -0,0 +1,5 @@
+.*: Assembler messages:
+.*:6: Error: bad use of %dtpoff
+.*:7: Error: bad use of %tpoff
+.*:8: Error: multiple relocations not supported by current ABI
+.*:9: Error: multiple relocations not supported by current ABI
Index: binutils/gas/testsuite/gas/mips/tls-ill.s
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/gas/testsuite/gas/mips/tls-ill.s 2005-02-07 16:21:35.274456496 -0500
@@ -0,0 +1,9 @@
+ .abicalls
+ .text
+
+ /* These have obvious meanings, but we don't have currently defined
+ relocations for them. */
+ addiu $4,$28,%dtpoff(tlsvar)
+ addiu $4,$28,%tpoff(tlsvar)
+ addiu $4,$28,%lo(%gottpoff(tlsvar))
+ addiu $4,$28,%hi(%gottpoff(tlsvar))
Index: binutils/ld/testsuite/ld-mips-elf/tlslib-o32-ver.got
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/tlslib-o32-ver.got 2005-02-07 16:21:35.274456496 -0500
@@ -0,0 +1,17 @@
+
+.*: file format elf32-tradbigmips
+
+DYNAMIC RELOCATION RECORDS
+OFFSET TYPE VALUE
+00000000 R_MIPS_NONE \*ABS\*
+000405e4 R_MIPS_TLS_DTPMOD32 \*ABS\*
+000405ec R_MIPS_TLS_DTPMOD32 tlsvar_gd
+000405f0 R_MIPS_TLS_DTPOFF32 tlsvar_gd
+000405e0 R_MIPS_TLS_TPOFF32 tlsvar_ie
+
+
+Contents of section .got:
+ 405c0 00000000 80000000 00000000 00000000 ................
+ 405d0 00000000 00000000 00000000 00000590 ................
+ 405e0 00000000 00000000 00000000 00000000 ................
+ 405f0 00000000 ....
Index: binutils/ld/testsuite/ld-mips-elf/tlslib.ver
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/tlslib.ver 2005-02-07 16:21:35.274456496 -0500
@@ -0,0 +1,3 @@
+VER_1 {
+ global: *;
+};
Index: binutils/bfd/elflink.c
===================================================================
--- binutils.orig/bfd/elflink.c 2005-02-01 16:59:37.000000000 -0500
+++ binutils/bfd/elflink.c 2005-02-07 16:21:35.278455503 -0500
@@ -9461,6 +9461,10 @@ _bfd_elf_section_already_linked (bfd *ab
if ((flags & SEC_LINK_ONCE) == 0 && group == NULL)
return;
+ /* Don't exclude sections based on what we see in shared libraries. */
+ if (sec->owner->flags & DYNAMIC)
+ return;
+
if (group)
{
/* If this is the member of a single member comdat group, check if
Index: binutils/ld/testsuite/ld-mips-elf/tlslib-o32-hidden.got
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/tlslib-o32-hidden.got 2005-02-07 16:21:35.278455503 -0500
@@ -0,0 +1,16 @@
+
+.*: file format elf32-tradbigmips
+
+DYNAMIC RELOCATION RECORDS
+OFFSET TYPE VALUE
+00000000 R_MIPS_NONE \*ABS\*
+0004043c R_MIPS_TLS_DTPMOD32 \*ABS\*
+00040434 R_MIPS_TLS_DTPMOD32 \*ABS\*
+00040430 R_MIPS_TLS_TPOFF32 \*ABS\*
+
+
+Contents of section .got:
+ 40410 00000000 80000000 00000000 00000000 ................
+ 40420 00000000 00000000 00000000 000003e0 ................
+ 40430 00000008 00000000 00000000 00000000 ................
+ 40440 ffff8004 ....
Index: binutils/ld/testsuite/ld-mips-elf/tlslib-hidden.ver
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/tlslib-hidden.ver 2005-02-07 16:21:35.278455503 -0500
@@ -0,0 +1,3 @@
+VER_1 {
+ local: *;
+};
Index: binutils/ld/testsuite/ld-mips-elf/tlsdyn-o32-1.d
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/tlsdyn-o32-1.d 2005-02-07 16:21:35.278455503 -0500
@@ -0,0 +1,104 @@
+
+.*: file format elf32-tradbigmips
+
+Disassembly of section .text:
+
+.* <__start>:
+ .*: 3c1c0fc0 lui gp,0xfc0
+ .*: 279c7b60 addiu gp,gp,31584
+ .*: 0399e021 addu gp,gp,t9
+ .*: 27bdfff0 addiu sp,sp,-16
+ .*: afbe0008 sw s8,8\(sp\)
+ .*: 03a0f021 move s8,sp
+ .*: afbc0000 sw gp,0\(sp\)
+ .*: 8f99802c lw t9,-32724\(gp\)
+ .*: 27848044 addiu a0,gp,-32700
+ .*: 0320f809 jalr t9
+ .*: 00000000 nop
+ .*: 8fdc0000 lw gp,0\(s8\)
+ .*: 00000000 nop
+ .*: 8f99802c lw t9,-32724\(gp\)
+ .*: 27848038 addiu a0,gp,-32712
+ .*: 0320f809 jalr t9
+ .*: 00000000 nop
+ .*: 8fdc0000 lw gp,0\(s8\)
+ .*: 00000000 nop
+ .*: 8f99802c lw t9,-32724\(gp\)
+ .*: 27848030 addiu a0,gp,-32720
+ .*: 0320f809 jalr t9
+ .*: 00000000 nop
+ .*: 8fdc0000 lw gp,0\(s8\)
+ .*: 00401021 move v0,v0
+ .*: 3c030000 lui v1,0x0
+ .*: 24638000 addiu v1,v1,-32768
+ .*: 00621821 addu v1,v1,v0
+ .*: 7c02283b rdhwr v0,\$5
+ .*: 8f83804c lw v1,-32692\(gp\)
+ .*: 00000000 nop
+ .*: 00621821 addu v1,v1,v0
+ .*: 8f838040 lw v1,-32704\(gp\)
+ .*: 00000000 nop
+ .*: 00621821 addu v1,v1,v0
+ .*: 7c02283b rdhwr v0,\$5
+ .*: 3c030000 lui v1,0x0
+ .*: 24639004 addiu v1,v1,-28668
+ .*: 00621821 addu v1,v1,v0
+ .*: 03c0e821 move sp,s8
+ .*: 8fbe0008 lw s8,8\(sp\)
+ .*: 03e00008 jr ra
+ .*: 27bd0010 addiu sp,sp,16
+
+.* <__tls_get_addr>:
+ .*: 03e00008 jr ra
+ .*: 00000000 nop
+ ...
+
+.* <other>:
+ .*: 3c1c0fc0 lui gp,0xfc0
+ .*: 279c7aa0 addiu gp,gp,31392
+ .*: 0399e021 addu gp,gp,t9
+ .*: 27bdfff0 addiu sp,sp,-16
+ .*: afbe0008 sw s8,8\(sp\)
+ .*: 03a0f021 move s8,sp
+ .*: afbc0000 sw gp,0\(sp\)
+ .*: 8f99802c lw t9,-32724\(gp\)
+ .*: 27848044 addiu a0,gp,-32700
+ .*: 0320f809 jalr t9
+ .*: 00000000 nop
+ .*: 8fdc0000 lw gp,0\(s8\)
+ .*: 00000000 nop
+ .*: 8f99802c lw t9,-32724\(gp\)
+ .*: 27848038 addiu a0,gp,-32712
+ .*: 0320f809 jalr t9
+ .*: 00000000 nop
+ .*: 8fdc0000 lw gp,0\(s8\)
+ .*: 00000000 nop
+ .*: 8f99802c lw t9,-32724\(gp\)
+ .*: 27848030 addiu a0,gp,-32720
+ .*: 0320f809 jalr t9
+ .*: 00000000 nop
+ .*: 8fdc0000 lw gp,0\(s8\)
+ .*: 00401021 move v0,v0
+ .*: 3c030000 lui v1,0x0
+ .*: 24638000 addiu v1,v1,-32768
+ .*: 00621821 addu v1,v1,v0
+ .*: 7c02283b rdhwr v0,\$5
+ .*: 8f83804c lw v1,-32692\(gp\)
+ .*: 00000000 nop
+ .*: 00621821 addu v1,v1,v0
+ .*: 8f838040 lw v1,-32704\(gp\)
+ .*: 00000000 nop
+ .*: 00621821 addu v1,v1,v0
+ .*: 7c02283b rdhwr v0,\$5
+ .*: 3c030000 lui v1,0x0
+ .*: 24639004 addiu v1,v1,-28668
+ .*: 00621821 addu v1,v1,v0
+ .*: 03c0e821 move sp,s8
+ .*: 8fbe0008 lw s8,8\(sp\)
+ .*: 03e00008 jr ra
+ .*: 27bd0010 addiu sp,sp,16
+ .*: 00000000 nop
+Disassembly of section .MIPS.stubs:
+
+.* <.MIPS.stubs>:
+ ...
Index: binutils/ld/testsuite/ld-mips-elf/tlsdyn-o32-3.got
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/tlsdyn-o32-3.got 2005-02-07 16:21:35.279455255 -0500
@@ -0,0 +1,20 @@
+
+.*: file format elf32-tradbigmips
+
+DYNAMIC RELOCATION RECORDS
+OFFSET TYPE VALUE
+00000000 R_MIPS_NONE \*ABS\*
+10000060 R_MIPS_TLS_DTPMOD32 tlsbin_gd
+10000064 R_MIPS_TLS_DTPOFF32 tlsbin_gd
+10000054 R_MIPS_TLS_DTPMOD32 tlsvar_gd
+10000058 R_MIPS_TLS_DTPOFF32 tlsvar_gd
+1000005c R_MIPS_TLS_TPOFF32 tlsvar_ie
+10000068 R_MIPS_TLS_TPOFF32 tlsbin_ie
+
+
+Contents of section .got:
+ 10000020 00000000 80000000 00000000 00000000 ................
+ 10000030 00000000 00000000 00000000 0040060c .............@..
+ 10000040 00000000 00000001 00000000 00000000 ................
+ 10000050 00000000 00000000 00000000 00000000 ................
+ 10000060 00000000 00000000 00000000 ............
Index: binutils/ld/testsuite/ld-mips-elf/tlsdyn-o32-2.d
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/tlsdyn-o32-2.d 2005-02-07 16:21:35.279455255 -0500
@@ -0,0 +1,104 @@
+
+.*: file format elf32-tradbigmips
+
+Disassembly of section .text:
+
+.* <__start>:
+ .*: 3c1c0fc0 lui gp,0xfc0
+ .*: 279c7b60 addiu gp,gp,31584
+ .*: 0399e021 addu gp,gp,t9
+ .*: 27bdfff0 addiu sp,sp,-16
+ .*: afbe0008 sw s8,8\(sp\)
+ .*: 03a0f021 move s8,sp
+ .*: afbc0000 sw gp,0\(sp\)
+ .*: 8f99802c lw t9,-32724\(gp\)
+ .*: 27848050 addiu a0,gp,-32688
+ .*: 0320f809 jalr t9
+ .*: 00000000 nop
+ .*: 8fdc0000 lw gp,0\(s8\)
+ .*: 00000000 nop
+ .*: 8f99802c lw t9,-32724\(gp\)
+ .*: 27848044 addiu a0,gp,-32700
+ .*: 0320f809 jalr t9
+ .*: 00000000 nop
+ .*: 8fdc0000 lw gp,0\(s8\)
+ .*: 00000000 nop
+ .*: 8f99802c lw t9,-32724\(gp\)
+ .*: 27848034 addiu a0,gp,-32716
+ .*: 0320f809 jalr t9
+ .*: 00000000 nop
+ .*: 8fdc0000 lw gp,0\(s8\)
+ .*: 00401021 move v0,v0
+ .*: 3c030000 lui v1,0x0
+ .*: 24638000 addiu v1,v1,-32768
+ .*: 00621821 addu v1,v1,v0
+ .*: 7c02283b rdhwr v0,\$5
+ .*: 8f838058 lw v1,-32680\(gp\)
+ .*: 00000000 nop
+ .*: 00621821 addu v1,v1,v0
+ .*: 8f83804c lw v1,-32692\(gp\)
+ .*: 00000000 nop
+ .*: 00621821 addu v1,v1,v0
+ .*: 7c02283b rdhwr v0,\$5
+ .*: 3c030000 lui v1,0x0
+ .*: 24639004 addiu v1,v1,-28668
+ .*: 00621821 addu v1,v1,v0
+ .*: 03c0e821 move sp,s8
+ .*: 8fbe0008 lw s8,8\(sp\)
+ .*: 03e00008 jr ra
+ .*: 27bd0010 addiu sp,sp,16
+
+.* <__tls_get_addr>:
+ .*: 03e00008 jr ra
+ .*: 00000000 nop
+ ...
+
+.* <other>:
+ .*: 3c1c0fc0 lui gp,0xfc0
+ .*: 279c7aa0 addiu gp,gp,31392
+ .*: 0399e021 addu gp,gp,t9
+ .*: 27bdfff0 addiu sp,sp,-16
+ .*: afbe0008 sw s8,8\(sp\)
+ .*: 03a0f021 move s8,sp
+ .*: afbc0000 sw gp,0\(sp\)
+ .*: 8f99802c lw t9,-32724\(gp\)
+ .*: 27848050 addiu a0,gp,-32688
+ .*: 0320f809 jalr t9
+ .*: 00000000 nop
+ .*: 8fdc0000 lw gp,0\(s8\)
+ .*: 00000000 nop
+ .*: 8f99802c lw t9,-32724\(gp\)
+ .*: 27848044 addiu a0,gp,-32700
+ .*: 0320f809 jalr t9
+ .*: 00000000 nop
+ .*: 8fdc0000 lw gp,0\(s8\)
+ .*: 00000000 nop
+ .*: 8f99802c lw t9,-32724\(gp\)
+ .*: 27848034 addiu a0,gp,-32716
+ .*: 0320f809 jalr t9
+ .*: 00000000 nop
+ .*: 8fdc0000 lw gp,0\(s8\)
+ .*: 00401021 move v0,v0
+ .*: 3c030000 lui v1,0x0
+ .*: 24638000 addiu v1,v1,-32768
+ .*: 00621821 addu v1,v1,v0
+ .*: 7c02283b rdhwr v0,\$5
+ .*: 8f838058 lw v1,-32680\(gp\)
+ .*: 00000000 nop
+ .*: 00621821 addu v1,v1,v0
+ .*: 8f83804c lw v1,-32692\(gp\)
+ .*: 00000000 nop
+ .*: 00621821 addu v1,v1,v0
+ .*: 7c02283b rdhwr v0,\$5
+ .*: 3c030000 lui v1,0x0
+ .*: 24639004 addiu v1,v1,-28668
+ .*: 00621821 addu v1,v1,v0
+ .*: 03c0e821 move sp,s8
+ .*: 8fbe0008 lw s8,8\(sp\)
+ .*: 03e00008 jr ra
+ .*: 27bd0010 addiu sp,sp,16
+ .*: 00000000 nop
+Disassembly of section .MIPS.stubs:
+
+.* <.MIPS.stubs>:
+ ...
Index: binutils/ld/testsuite/ld-mips-elf/tlsdyn-o32-2.s
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/tlsdyn-o32-2.s 2005-02-07 16:21:35.279455255 -0500
@@ -0,0 +1,64 @@
+ .file 1 "tlsbin-o32.s"
+ .abicalls
+ .text
+ .align 2
+ .globl other
+ .ent other
+ .type other,@function
+other:
+ .frame $fp,16,$31
+ .mask 0x40000000,-8
+ .fmask 0x00000000,0
+ .set noreorder
+ .cpload $25
+ .set reorder
+ addiu $sp,$sp,-16
+ sw $fp,8($sp)
+ move $fp,$sp
+ .cprestore 0
+
+ # General Dynamic
+ lw $25,%call16(__tls_get_addr)($28)
+ addiu $4,$28,%tlsgd(tlsbin_gd)
+ jal $25
+
+ lw $25,%call16(__tls_get_addr)($28)
+ addiu $4,$28,%tlsgd(tlsvar_gd)
+ jal $25
+
+ # Local Dynamic
+ lw $25,%call16(__tls_get_addr)($28)
+ addiu $4,$28,%tlsldm(tlsbin_ld)
+ jal $25
+
+ move $2,$2 # Arbitrary instructions
+
+ lui $3,%hi(%dtpoff(tlsbin_ld))
+ addiu $3,$3,%lo(%dtpoff(tlsbin_ld))
+ addu $3,$3,$2
+
+ # Initial Exec
+ .set push
+ .set mips32r2
+ rdhwr $2, $5
+ .set pop
+ lw $3,%gottpoff(tlsbin_ie)($28)
+ addu $3,$3,$2
+
+ lw $3,%gottpoff(tlsvar_ie)($28)
+ addu $3,$3,$2
+
+ # Local Exec
+ .set push
+ .set mips32r2
+ rdhwr $2, $5
+ .set pop
+ lui $3,%hi(%tpoff(tlsbin_le))
+ addiu $3,$3,%lo(%tpoff(tlsbin_le))
+ addu $3,$3,$2
+
+ move $sp,$fp
+ lw $fp,8($sp)
+ addiu $sp,$sp,16
+ j $31
+ .end other
Index: binutils/ld/testsuite/ld-mips-elf/tlsdyn-o32-3.d
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/tlsdyn-o32-3.d 2005-02-07 16:21:35.279455255 -0500
@@ -0,0 +1,104 @@
+
+.*: file format elf32-tradbigmips
+
+Disassembly of section .text:
+
+.* <other>:
+ .*: 3c1c0fc0 lui gp,0xfc0
+ .*: 279c7b60 addiu gp,gp,31584
+ .*: 0399e021 addu gp,gp,t9
+ .*: 27bdfff0 addiu sp,sp,-16
+ .*: afbe0008 sw s8,8\(sp\)
+ .*: 03a0f021 move s8,sp
+ .*: afbc0000 sw gp,0\(sp\)
+ .*: 8f99802c lw t9,-32724\(gp\)
+ .*: 27848050 addiu a0,gp,-32688
+ .*: 0320f809 jalr t9
+ .*: 00000000 nop
+ .*: 8fdc0000 lw gp,0\(s8\)
+ .*: 00000000 nop
+ .*: 8f99802c lw t9,-32724\(gp\)
+ .*: 27848044 addiu a0,gp,-32700
+ .*: 0320f809 jalr t9
+ .*: 00000000 nop
+ .*: 8fdc0000 lw gp,0\(s8\)
+ .*: 00000000 nop
+ .*: 8f99802c lw t9,-32724\(gp\)
+ .*: 27848034 addiu a0,gp,-32716
+ .*: 0320f809 jalr t9
+ .*: 00000000 nop
+ .*: 8fdc0000 lw gp,0\(s8\)
+ .*: 00401021 move v0,v0
+ .*: 3c030000 lui v1,0x0
+ .*: 24638000 addiu v1,v1,-32768
+ .*: 00621821 addu v1,v1,v0
+ .*: 7c02283b rdhwr v0,\$5
+ .*: 8f838058 lw v1,-32680\(gp\)
+ .*: 00000000 nop
+ .*: 00621821 addu v1,v1,v0
+ .*: 8f83804c lw v1,-32692\(gp\)
+ .*: 00000000 nop
+ .*: 00621821 addu v1,v1,v0
+ .*: 7c02283b rdhwr v0,\$5
+ .*: 3c030000 lui v1,0x0
+ .*: 24639004 addiu v1,v1,-28668
+ .*: 00621821 addu v1,v1,v0
+ .*: 03c0e821 move sp,s8
+ .*: 8fbe0008 lw s8,8\(sp\)
+ .*: 03e00008 jr ra
+ .*: 27bd0010 addiu sp,sp,16
+ .*: 00000000 nop
+
+.* <__start>:
+ .*: 3c1c0fc0 lui gp,0xfc0
+ .*: 279c7ab0 addiu gp,gp,31408
+ .*: 0399e021 addu gp,gp,t9
+ .*: 27bdfff0 addiu sp,sp,-16
+ .*: afbe0008 sw s8,8\(sp\)
+ .*: 03a0f021 move s8,sp
+ .*: afbc0000 sw gp,0\(sp\)
+ .*: 8f99802c lw t9,-32724\(gp\)
+ .*: 27848050 addiu a0,gp,-32688
+ .*: 0320f809 jalr t9
+ .*: 00000000 nop
+ .*: 8fdc0000 lw gp,0\(s8\)
+ .*: 00000000 nop
+ .*: 8f99802c lw t9,-32724\(gp\)
+ .*: 27848044 addiu a0,gp,-32700
+ .*: 0320f809 jalr t9
+ .*: 00000000 nop
+ .*: 8fdc0000 lw gp,0\(s8\)
+ .*: 00000000 nop
+ .*: 8f99802c lw t9,-32724\(gp\)
+ .*: 27848034 addiu a0,gp,-32716
+ .*: 0320f809 jalr t9
+ .*: 00000000 nop
+ .*: 8fdc0000 lw gp,0\(s8\)
+ .*: 00401021 move v0,v0
+ .*: 3c030000 lui v1,0x0
+ .*: 24638000 addiu v1,v1,-32768
+ .*: 00621821 addu v1,v1,v0
+ .*: 7c02283b rdhwr v0,\$5
+ .*: 8f838058 lw v1,-32680\(gp\)
+ .*: 00000000 nop
+ .*: 00621821 addu v1,v1,v0
+ .*: 8f83804c lw v1,-32692\(gp\)
+ .*: 00000000 nop
+ .*: 00621821 addu v1,v1,v0
+ .*: 7c02283b rdhwr v0,\$5
+ .*: 3c030000 lui v1,0x0
+ .*: 24639004 addiu v1,v1,-28668
+ .*: 00621821 addu v1,v1,v0
+ .*: 03c0e821 move sp,s8
+ .*: 8fbe0008 lw s8,8\(sp\)
+ .*: 03e00008 jr ra
+ .*: 27bd0010 addiu sp,sp,16
+
+.* <__tls_get_addr>:
+ .*: 03e00008 jr ra
+ .*: 00000000 nop
+ ...
+Disassembly of section .MIPS.stubs:
+
+.* <.MIPS.stubs>:
+ ...
Index: binutils/ld/testsuite/ld-mips-elf/tlsdyn-o32-1.got
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/tlsdyn-o32-1.got 2005-02-07 16:21:35.279455255 -0500
@@ -0,0 +1,19 @@
+
+.*: file format elf32-tradbigmips
+
+DYNAMIC RELOCATION RECORDS
+OFFSET TYPE VALUE
+00000000 R_MIPS_NONE \*ABS\*
+10000054 R_MIPS_TLS_DTPMOD32 tlsbin_gd
+10000058 R_MIPS_TLS_DTPOFF32 tlsbin_gd
+10000048 R_MIPS_TLS_DTPMOD32 tlsvar_gd
+1000004c R_MIPS_TLS_DTPOFF32 tlsvar_gd
+10000050 R_MIPS_TLS_TPOFF32 tlsvar_ie
+1000005c R_MIPS_TLS_TPOFF32 tlsbin_ie
+
+
+Contents of section .got:
+ 10000020 00000000 80000000 00000000 00000000 ................
+ 10000030 00000000 00000000 00000000 0040055c .............@..
+ 10000040 00000001 00000000 00000000 00000000 ................
+ 10000050 00000000 00000000 00000000 00000000 ................
Index: binutils/ld/testsuite/ld-mips-elf/tlsdyn-o32-2.got
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ binutils/ld/testsuite/ld-mips-elf/tlsdyn-o32-2.got 2005-02-07 16:21:35.280455007 -0500
@@ -0,0 +1,20 @@
+
+.*: file format elf32-tradbigmips
+
+DYNAMIC RELOCATION RECORDS
+OFFSET TYPE VALUE
+00000000 R_MIPS_NONE \*ABS\*
+10000060 R_MIPS_TLS_DTPMOD32 tlsbin_gd
+10000064 R_MIPS_TLS_DTPOFF32 tlsbin_gd
+10000054 R_MIPS_TLS_DTPMOD32 tlsvar_gd
+10000058 R_MIPS_TLS_DTPOFF32 tlsvar_gd
+1000005c R_MIPS_TLS_TPOFF32 tlsvar_ie
+10000068 R_MIPS_TLS_TPOFF32 tlsbin_ie
+
+
+Contents of section .got:
+ 10000020 00000000 80000000 00000000 00000000 ................
+ 10000030 00000000 00000000 00000000 0040055c .............@..
+ 10000040 00000000 00000001 00000000 00000000 ................
+ 10000050 00000000 00000000 00000000 00000000 ................
+ 10000060 00000000 00000000 00000000 ............
More information about the Binutils
mailing list