From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 19695 invoked by alias); 24 Feb 2005 19:03:12 -0000 Mailing-List: contact binutils-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: binutils-owner@sources.redhat.com Received: (qmail 19226 invoked from network); 24 Feb 2005 19:02:18 -0000 Received: from unknown (HELO nevyn.them.org) (66.93.172.17) by sourceware.org with SMTP; 24 Feb 2005 19:02:18 -0000 Received: from drow by nevyn.them.org with local (Exim 4.44 #1 (Debian)) id 1D4OFd-0002MX-PO for ; Thu, 24 Feb 2005 14:02:17 -0500 Date: Thu, 24 Feb 2005 21:56:00 -0000 From: Daniel Jacobowitz To: binutils@sources.redhat.com Subject: Re: TLS support for MIPS Message-ID: <20050224190217.GB8974@nevyn.them.org> Mail-Followup-To: binutils@sources.redhat.com References: <20050207230014.GA32655@nevyn.them.org> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20050207230014.GA32655@nevyn.them.org> User-Agent: Mutt/1.5.6+20040907i X-SW-Source: 2005-02/txt/msg00615.txt.bz2 On Mon, Feb 07, 2005 at 06:00:14PM -0500, Daniel Jacobowitz wrote: > This patch implements thread-local storage for MIPS. The ABI can be found > at ; 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? Here's a revised patch. The changes are: - *blush* I forgot to add Joseph to most of the changelog entries. He wrote the first version of this patch. - Operator names and relocation names updated. They're basically consistent now. - A couple of code cleanups in BFD. Retested using NPTL patches for GCC and glibc on mips-linux. OK? -- Daniel Jacobowitz CodeSourcery, LLC 2005-02-24 Daniel Jacobowitz Joseph Myers * 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. (TLS_RELOC_P): Define. (TP_OFFSET, DTP_OFFSET): Define. (dtprel_base, tprel_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_output_dynamic_relocation, 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-24 Daniel Jacobowitz * 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-24 Daniel Jacobowitz Joseph Myers * elf/mips.h: Define MIPS TLS relocations. 2005-02-24 Daniel Jacobowitz Joseph Myers * config/tc-mips.c (percent_op): Add %tlsgd, %tlsldm, %dtprel_hi, %dtprel_lo, %tprel_hi, %tprel_lo, and %gottprel. (parse_relocation): Check for a word break after a relocation operator. (md_apply_fix3): Handle TLS relocations, and mark thread-local symbols. 2005-02-24 Daniel Jacobowitz * 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-24 13:47:21.387287019 -0500 +++ binutils/bfd/elfxx-mips.c 2005-02-24 13:48:44.985881160 -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 TLS_RELOC_P(r_type) \ + (r_type == R_MIPS_TLS_DTPMOD32 \ + || r_type == R_MIPS_TLS_DTPMOD64 \ + || r_type == R_MIPS_TLS_DTPREL32 \ + || r_type == R_MIPS_TLS_DTPREL64 \ + || r_type == R_MIPS_TLS_GD \ + || r_type == R_MIPS_TLS_LDM \ + || r_type == R_MIPS_TLS_DTPREL_HI16 \ + || r_type == R_MIPS_TLS_DTPREL_LO16 \ + || r_type == R_MIPS_TLS_GOTTPREL \ + || r_type == R_MIPS_TLS_TPREL32 \ + || r_type == R_MIPS_TLS_TPREL64 \ + || r_type == R_MIPS_TLS_TPREL_HI16 \ + || r_type == R_MIPS_TLS_TPREL_LO16) + /* Structure used to pass information to mips_elf_output_extsym. */ struct extsym_info @@ -370,7 +432,8 @@ typedef struct runtime_pdr { #define rpdNil ((pRPDR) 0) 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_f (struct mips_elf_link_hash_entry *, void *); static bfd_vma mips_elf_high @@ -588,6 +651,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 +dtprel_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 +tprel_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 * @@ -623,6 +710,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; @@ -1738,6 +1826,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) @@ -1750,6 +1839,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 @@ -1770,8 +1863,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); } @@ -1781,6 +1876,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 @@ -1849,13 +1952,299 @@ 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; +} + +/* Output a simple dynamic relocation into SRELOC. */ + +static void +mips_elf_output_dynamic_relocation (bfd *output_bfd, + asection *sreloc, + unsigned long indx, + int r_type, + bfd_vma offset) +{ + Elf_Internal_Rela rel[3]; + + memset (rel, 0, sizeof (rel)); + + rel[0].r_info = ELF_R_INFO (output_bfd, indx, r_type); + rel[0].r_offset = rel[1].r_offset = rel[2].r_offset = offset; + + if (ABI_64_P (output_bfd)) + { + (*get_elf_backend_data (output_bfd)->s->swap_reloc_out) + (output_bfd, &rel[0], + (sreloc->contents + + sreloc->reloc_count * sizeof (Elf64_Mips_External_Rel))); + } + else + bfd_elf32_swap_reloc_out + (output_bfd, &rel[0], + (sreloc->contents + + sreloc->reloc_count * sizeof (Elf32_External_Rel))); + ++sreloc->reloc_count; +} + +/* 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; + 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) + { + mips_elf_output_dynamic_relocation + (abfd, sreloc, indx, + ABI_64_P (abfd) ? R_MIPS_TLS_DTPMOD64 : R_MIPS_TLS_DTPMOD32, + sgot->output_offset + sgot->output_section->vma + offset); + + if (indx) + mips_elf_output_dynamic_relocation + (abfd, sreloc, indx, + ABI_64_P (abfd) ? R_MIPS_TLS_DTPREL64 : R_MIPS_TLS_DTPREL32, + sgot->output_offset + sgot->output_section->vma + offset2); + else + MIPS_ELF_PUT_WORD (abfd, value - dtprel_base (info), + sgot->contents + offset2); + } + else + { + MIPS_ELF_PUT_WORD (abfd, 1, + sgot->contents + offset); + MIPS_ELF_PUT_WORD (abfd, value - dtprel_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); + + mips_elf_output_dynamic_relocation + (abfd, sreloc, indx, + ABI_64_P (abfd) ? R_MIPS_TLS_TPREL64 : R_MIPS_TLS_TPREL32, + sgot->output_offset + sgot->output_section->vma + offset); + } + else + MIPS_ELF_PUT_WORD (abfd, value - tprel_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 + mips_elf_output_dynamic_relocation + (abfd, sreloc, indx, + ABI_64_P (abfd) ? R_MIPS_TLS_DTPMOD64 : R_MIPS_TLS_DTPMOD32, + sgot->output_offset + sgot->output_section->vma + got_offset); + } + + *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_GOTTPREL || 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_GOTTPREL) + { + 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; @@ -1863,17 +2252,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 (TLS_RELOC_P (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; @@ -1888,29 +2283,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 || TLS_RELOC_P (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 (TLS_RELOC_P (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 (TLS_RELOC_P (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; @@ -1935,7 +2365,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; @@ -1970,7 +2401,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 @@ -1996,12 +2428,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; @@ -2009,6 +2445,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) @@ -2017,12 +2454,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 (TLS_RELOC_P (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); @@ -2118,6 +2587,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++; @@ -2126,6 +2597,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; } @@ -2140,7 +2613,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; @@ -2162,6 +2636,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); @@ -2169,7 +2644,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); @@ -2177,6 +2655,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) @@ -2185,7 +2665,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; } @@ -2195,20 +2676,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); @@ -2308,6 +2821,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) @@ -2327,7 +2843,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; @@ -2350,11 +2873,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; @@ -2362,12 +2900,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; @@ -2384,17 +2923,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; @@ -2408,9 +2949,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 @@ -2420,12 +2962,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. @@ -2447,8 +3038,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) { @@ -2563,7 +3160,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 @@ -2590,7 +3188,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; @@ -2603,6 +3200,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 @@ -2611,7 +3212,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 *) @@ -2622,7 +3223,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); @@ -2722,6 +3326,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; @@ -2732,7 +3337,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. */ @@ -2749,7 +3359,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; } @@ -2968,10 +3579,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) @@ -3268,8 +3881,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_GOTTPREL: + 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 @@ -3278,11 +3901,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. @@ -3299,7 +3924,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; } @@ -3407,6 +4033,24 @@ mips_elf_calculate_relocation (bfd *abfd value &= howto->dst_mask; break; + case R_MIPS_TLS_DTPREL_HI16: + value = (mips_elf_high (addend + symbol - dtprel_base (info)) + & howto->dst_mask); + break; + + case R_MIPS_TLS_DTPREL_LO16: + value = (symbol + addend - dtprel_base (info)) & howto->dst_mask; + break; + + case R_MIPS_TLS_TPREL_HI16: + value = (mips_elf_high (addend + symbol - tprel_base (info)) + & howto->dst_mask); + break; + + case R_MIPS_TLS_TPREL_LO16: + value = (symbol + addend - tprel_base (info)) & howto->dst_mask; + break; + case R_MIPS_HI16: case R_MIPS16_HI16: if (!gp_disp_p) @@ -3518,6 +4162,9 @@ mips_elf_calculate_relocation (bfd *abfd /* Fall through. */ + case R_MIPS_TLS_GD: + case R_MIPS_TLS_GOTTPREL: + case R_MIPS_TLS_LDM: case R_MIPS_GOT_DISP: got_disp: value = g; @@ -5288,6 +5935,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)) @@ -5321,7 +5970,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; } @@ -5343,7 +5992,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 @@ -5380,11 +6029,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_GOTTPREL: + 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: @@ -5437,7 +6127,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; } } @@ -5803,6 +6493,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"); @@ -5871,9 +6562,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; } @@ -5988,6 +6700,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) { @@ -6013,13 +6728,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) { @@ -6646,11 +7376,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; @@ -6661,6 +7391,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) { @@ -6973,7 +7704,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)); @@ -7587,6 +8319,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 @@ -7605,7 +8342,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; @@ -7623,6 +8360,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 2005-02-21 09:36:33.000000000 -0500 +++ binutils/bfd/elfn32-mips.c 2005-02-24 13:48:44.986880916 -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, . @@ -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_DTPREL32, /* 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_DTPREL32", /* name */ + TRUE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + EMPTY_HOWTO (R_MIPS_TLS_DTPMOD64), + EMPTY_HOWTO (R_MIPS_TLS_DTPREL64), + + /* 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_DTPREL_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_DTPREL_HI16", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* TLS local dynamic offset. */ + HOWTO (R_MIPS_TLS_DTPREL_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_DTPREL_LO16", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* TLS thread pointer offset. */ + HOWTO (R_MIPS_TLS_GOTTPREL, /* 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_GOTTPREL", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* TLS IE dynamic relocations. */ + HOWTO (R_MIPS_TLS_TPREL32, /* 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_TPREL32", /* name */ + TRUE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + EMPTY_HOWTO (R_MIPS_TLS_TPREL64), + + /* TLS thread pointer offset. */ + HOWTO (R_MIPS_TLS_TPREL_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_TPREL_HI16", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* TLS thread pointer offset. */ + HOWTO (R_MIPS_TLS_TPREL_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_TPREL_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_DTPREL32, /* 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_DTPREL32", /* name */ + TRUE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + EMPTY_HOWTO (R_MIPS_TLS_DTPMOD64), + EMPTY_HOWTO (R_MIPS_TLS_DTPREL64), + + /* 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_DTPREL_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_DTPREL_HI16", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* TLS local dynamic offset. */ + HOWTO (R_MIPS_TLS_DTPREL_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_DTPREL_LO16", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* TLS thread pointer offset. */ + HOWTO (R_MIPS_TLS_GOTTPREL, /* 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_GOTTPREL", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* TLS IE dynamic relocations. */ + HOWTO (R_MIPS_TLS_TPREL32, /* 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_TPREL32", /* name */ + TRUE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + EMPTY_HOWTO (R_MIPS_TLS_TPREL64), + + /* TLS thread pointer offset. */ + HOWTO (R_MIPS_TLS_TPREL_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_TPREL_HI16", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* TLS thread pointer offset. */ + HOWTO (R_MIPS_TLS_TPREL_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_TPREL_LO16", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ }; static reloc_howto_type elf_mips16_howto_table_rel[] = @@ -1701,7 +2009,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_DTPREL32, R_MIPS_TLS_DTPREL32 }, + { BFD_RELOC_MIPS_TLS_DTPMOD64, R_MIPS_TLS_DTPMOD64 }, + { BFD_RELOC_MIPS_TLS_DTPREL64, R_MIPS_TLS_DTPREL64 }, + { BFD_RELOC_MIPS_TLS_GD, R_MIPS_TLS_GD }, + { BFD_RELOC_MIPS_TLS_LDM, R_MIPS_TLS_LDM }, + { BFD_RELOC_MIPS_TLS_DTPREL_HI16, R_MIPS_TLS_DTPREL_HI16 }, + { BFD_RELOC_MIPS_TLS_DTPREL_LO16, R_MIPS_TLS_DTPREL_LO16 }, + { BFD_RELOC_MIPS_TLS_GOTTPREL, R_MIPS_TLS_GOTTPREL }, + { BFD_RELOC_MIPS_TLS_TPREL32, R_MIPS_TLS_TPREL32 }, + { BFD_RELOC_MIPS_TLS_TPREL64, R_MIPS_TLS_TPREL64 }, + { BFD_RELOC_MIPS_TLS_TPREL_HI16, R_MIPS_TLS_TPREL_HI16 }, + { BFD_RELOC_MIPS_TLS_TPREL_LO16, R_MIPS_TLS_TPREL_LO16 } }; static const struct elf_reloc_map mips16_reloc_map[] = Index: binutils/bfd/elf32-mips.c =================================================================== --- binutils.orig/bfd/elf32-mips.c 2005-02-21 09:36:26.000000000 -0500 +++ binutils/bfd/elf32-mips.c 2005-02-24 13:48:44.987880672 -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, . @@ -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_DTPREL32, /* 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_DTPREL32", /* name */ + TRUE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + EMPTY_HOWTO (R_MIPS_TLS_DTPMOD64), + EMPTY_HOWTO (R_MIPS_TLS_DTPREL64), + + /* 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_DTPREL_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_DTPREL_HI16", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* TLS local dynamic offset. */ + HOWTO (R_MIPS_TLS_DTPREL_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_DTPREL_LO16", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* TLS thread pointer offset. */ + HOWTO (R_MIPS_TLS_GOTTPREL, /* 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_GOTTPREL", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* TLS IE dynamic relocations. */ + HOWTO (R_MIPS_TLS_TPREL32, /* 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_TPREL32", /* name */ + TRUE, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + EMPTY_HOWTO (R_MIPS_TLS_TPREL64), + + /* TLS thread pointer offset. */ + HOWTO (R_MIPS_TLS_TPREL_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_TPREL_HI16", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* TLS thread pointer offset. */ + HOWTO (R_MIPS_TLS_TPREL_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_TPREL_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 @@ -1062,7 +1216,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_DTPREL32, R_MIPS_TLS_DTPREL32 }, + { BFD_RELOC_MIPS_TLS_DTPMOD64, R_MIPS_TLS_DTPMOD64 }, + { BFD_RELOC_MIPS_TLS_DTPREL64, R_MIPS_TLS_DTPREL64 }, + { BFD_RELOC_MIPS_TLS_GD, R_MIPS_TLS_GD }, + { BFD_RELOC_MIPS_TLS_LDM, R_MIPS_TLS_LDM }, + { BFD_RELOC_MIPS_TLS_DTPREL_HI16, R_MIPS_TLS_DTPREL_HI16 }, + { BFD_RELOC_MIPS_TLS_DTPREL_LO16, R_MIPS_TLS_DTPREL_LO16 }, + { BFD_RELOC_MIPS_TLS_GOTTPREL, R_MIPS_TLS_GOTTPREL }, + { BFD_RELOC_MIPS_TLS_TPREL32, R_MIPS_TLS_TPREL32 }, + { BFD_RELOC_MIPS_TLS_TPREL64, R_MIPS_TLS_TPREL64 }, + { BFD_RELOC_MIPS_TLS_TPREL_HI16, R_MIPS_TLS_TPREL_HI16 }, + { BFD_RELOC_MIPS_TLS_TPREL_LO16, R_MIPS_TLS_TPREL_LO16 } }; static const struct elf_reloc_map mips16_reloc_map[] = 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-24 13:48:44.988880429 -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,%dtprel_hi(tlsvar_ld) + addiu $3,$3,%dtprel_lo(tlsvar_ld) + addu $3,$3,$2 + + # Initial Exec + .set push + .set mips32r2 + rdhwr $2, $5 + .set pop + lw $3,%gottprel(tlsvar_ie)($28) + addu $3,$3,$2 + + # Local Exec + .set push + .set mips32r2 + rdhwr $2, $5 + .set pop + lui $3,%tprel_hi(tlsvar_le) + addiu $3,$3,%tprel_lo(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-24 13:48:45.003876771 -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-02-21 09:36:37.000000000 -0500 +++ binutils/bfd/libbfd.h 2005-02-24 13:48:45.004876527 -0500 @@ -928,6 +928,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_DTPREL32", + "BFD_RELOC_MIPS_TLS_DTPMOD64", + "BFD_RELOC_MIPS_TLS_DTPREL64", + "BFD_RELOC_MIPS_TLS_GD", + "BFD_RELOC_MIPS_TLS_LDM", + "BFD_RELOC_MIPS_TLS_DTPREL_HI16", + "BFD_RELOC_MIPS_TLS_DTPREL_LO16", + "BFD_RELOC_MIPS_TLS_GOTTPREL", + "BFD_RELOC_MIPS_TLS_TPREL32", + "BFD_RELOC_MIPS_TLS_TPREL64", + "BFD_RELOC_MIPS_TLS_TPREL_HI16", + "BFD_RELOC_MIPS_TLS_TPREL_LO16", "BFD_RELOC_FRV_LABEL16", "BFD_RELOC_FRV_LABEL24", Index: binutils/bfd/elf64-mips.c =================================================================== --- binutils.orig/bfd/elf64-mips.c 2005-02-21 09:36:29.000000000 -0500 +++ binutils/bfd/elf64-mips.c 2005-02-24 13:48:45.005876283 -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_DTPREL32), + + 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_DTPREL64, /* 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_DTPREL64", /* 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_DTPREL_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_DTPREL_HI16", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* TLS local dynamic offset. */ + HOWTO (R_MIPS_TLS_DTPREL_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_DTPREL_LO16", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* TLS thread pointer offset. */ + HOWTO (R_MIPS_TLS_GOTTPREL, /* 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_GOTTPREL", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* TLS IE dynamic relocations. */ + EMPTY_HOWTO (R_MIPS_TLS_TPREL32), + + HOWTO (R_MIPS_TLS_TPREL64, /* 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_TPREL64", /* name */ + TRUE, /* partial_inplace */ + MINUS_ONE, /* src_mask */ + MINUS_ONE, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* TLS thread pointer offset. */ + HOWTO (R_MIPS_TLS_TPREL_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_TPREL_HI16", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* TLS thread pointer offset. */ + HOWTO (R_MIPS_TLS_TPREL_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_TPREL_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_DTPREL32), + EMPTY_HOWTO (R_MIPS_TLS_DTPMOD64), + EMPTY_HOWTO (R_MIPS_TLS_DTPREL64), + + /* 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_DTPREL_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_DTPREL_HI16", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* TLS local dynamic offset. */ + HOWTO (R_MIPS_TLS_DTPREL_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_DTPREL_LO16", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* TLS thread pointer offset. */ + HOWTO (R_MIPS_TLS_GOTTPREL, /* 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_GOTTPREL", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + EMPTY_HOWTO (R_MIPS_TLS_TPREL32), + EMPTY_HOWTO (R_MIPS_TLS_TPREL64), + + /* TLS thread pointer offset. */ + HOWTO (R_MIPS_TLS_TPREL_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_TPREL_HI16", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* TLS thread pointer offset. */ + HOWTO (R_MIPS_TLS_TPREL_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_TPREL_LO16", /* name */ + TRUE, /* partial_inplace */ + 0x0000ffff, /* src_mask */ + 0x0000ffff, /* dst_mask */ + FALSE), /* pcrel_offset */ }; static reloc_howto_type mips16_elf64_howto_table_rel[] = @@ -1893,7 +2161,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_DTPREL32, R_MIPS_TLS_DTPREL32 }, + { BFD_RELOC_MIPS_TLS_DTPMOD64, R_MIPS_TLS_DTPMOD64 }, + { BFD_RELOC_MIPS_TLS_DTPREL64, R_MIPS_TLS_DTPREL64 }, + { BFD_RELOC_MIPS_TLS_GD, R_MIPS_TLS_GD }, + { BFD_RELOC_MIPS_TLS_LDM, R_MIPS_TLS_LDM }, + { BFD_RELOC_MIPS_TLS_DTPREL_HI16, R_MIPS_TLS_DTPREL_HI16 }, + { BFD_RELOC_MIPS_TLS_DTPREL_LO16, R_MIPS_TLS_DTPREL_LO16 }, + { BFD_RELOC_MIPS_TLS_GOTTPREL, R_MIPS_TLS_GOTTPREL }, + { BFD_RELOC_MIPS_TLS_TPREL32, R_MIPS_TLS_TPREL32 }, + { BFD_RELOC_MIPS_TLS_TPREL64, R_MIPS_TLS_TPREL64 }, + { BFD_RELOC_MIPS_TLS_TPREL_HI16, R_MIPS_TLS_TPREL_HI16 }, + { BFD_RELOC_MIPS_TLS_TPREL_LO16, R_MIPS_TLS_TPREL_LO16 } }; static const struct elf_reloc_map mips16_reloc_map[] = 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-24 13:48:45.005876283 -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_DTPREL32 tlsvar_gd +00040530 R_MIPS_TLS_TPREL32 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-24 13:48:45.006876039 -0500 @@ -0,0 +1,45 @@ + +.*: file format elf32-tradbigmips + +Disassembly of section .text: + +.* : + .*: 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-24 13:48:45.006876039 -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,%dtprel_hi(tlsvar_ld) + addiu $3,$3,%dtprel_lo(tlsvar_ld) + addu $3,$3,$2 + + # Initial Exec + .set push + .set mips32r2 + rdhwr $2, $5 + .set pop + lw $3,%gottprel(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-21 09:37:20.000000000 -0500 +++ binutils/ld/testsuite/ld-mips-elf/mips-elf.exp 2005-02-24 13:48:45.006876039 -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 @@ -99,3 +99,67 @@ run_dump_test "mips16-hilo" if {$has_newabi} { run_dump_test "mips16-hilo-n32" } + +# 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-24 13:48:45.006876039 -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 : + 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_DTPREL_HI16 tlsvar_ld + 50: 24630000 addiu v1,v1,0 + 50: R_MIPS_TLS_DTPREL_LO16 tlsvar_ld + 54: 00621821 addu v1,v1,v0 + 58: 7c02283b 0x7c02283b + 5c: 8f830000 lw v1,0\(gp\) + 5c: R_MIPS_TLS_GOTTPREL tlsvar_ie + 60: 00000000 nop + 64: 00621821 addu v1,v1,v0 + 68: 7c02283b 0x7c02283b + 6c: 3c030000 lui v1,0x0 + 6c: R_MIPS_TLS_TPREL_HI16 tlsvar_le + 70: 34630000 ori v1,v1,0x0 + 70: R_MIPS_TLS_TPREL_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-24 13:48:45.007875796 -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,%dtprel_hi(tlsvar_ld) + addiu $3,$3,%dtprel_lo(tlsvar_ld) + addu $3,$3,$2 + + # Initial Exec + .set push + .set mips32r2 + rdhwr $2, $5 + .set pop + lw $3,%gottprel(tlsvar_ie)($28) + addu $3,$3,$2 + + # Local Exec + .set push + .set mips32r2 + rdhwr $2, $5 + .set pop + lui $3,%tprel_hi(tlsvar_le) + ori $3,$3,%tprel_lo(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-21 09:36:39.000000000 -0500 +++ binutils/bfd/reloc.c 2005-02-24 13:48:45.019872870 -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. @@ -2125,6 +2125,32 @@ ENUMX BFD_RELOC_MIPS_RELGOT ENUMX BFD_RELOC_MIPS_JALR +ENUMX + BFD_RELOC_MIPS_TLS_DTPMOD32 +ENUMX + BFD_RELOC_MIPS_TLS_DTPREL32 +ENUMX + BFD_RELOC_MIPS_TLS_DTPMOD64 +ENUMX + BFD_RELOC_MIPS_TLS_DTPREL64 +ENUMX + BFD_RELOC_MIPS_TLS_GD +ENUMX + BFD_RELOC_MIPS_TLS_LDM +ENUMX + BFD_RELOC_MIPS_TLS_DTPREL_HI16 +ENUMX + BFD_RELOC_MIPS_TLS_DTPREL_LO16 +ENUMX + BFD_RELOC_MIPS_TLS_GOTTPREL +ENUMX + BFD_RELOC_MIPS_TLS_TPREL32 +ENUMX + BFD_RELOC_MIPS_TLS_TPREL64 +ENUMX + BFD_RELOC_MIPS_TLS_TPREL_HI16 +ENUMX + BFD_RELOC_MIPS_TLS_TPREL_LO16 ENUMDOC MIPS ELF relocations. COMMENT Index: binutils/bfd/bfd-in2.h =================================================================== --- binutils.orig/bfd/bfd-in2.h 2005-02-24 13:47:20.352539809 -0500 +++ binutils/bfd/bfd-in2.h 2005-02-24 13:48:45.021872382 -0500 @@ -2388,6 +2388,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_DTPREL32, + BFD_RELOC_MIPS_TLS_DTPMOD64, + BFD_RELOC_MIPS_TLS_DTPREL64, + BFD_RELOC_MIPS_TLS_GD, + BFD_RELOC_MIPS_TLS_LDM, + BFD_RELOC_MIPS_TLS_DTPREL_HI16, + BFD_RELOC_MIPS_TLS_DTPREL_LO16, + BFD_RELOC_MIPS_TLS_GOTTPREL, + BFD_RELOC_MIPS_TLS_TPREL32, + BFD_RELOC_MIPS_TLS_TPREL64, + BFD_RELOC_MIPS_TLS_TPREL_HI16, + BFD_RELOC_MIPS_TLS_TPREL_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-24 13:48:45.021872382 -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 2005-02-24 13:47:29.486308610 -0500 +++ binutils/gas/testsuite/gas/mips/mips.exp 2005-02-24 13:48:45.022872138 -0500 @@ -336,6 +336,11 @@ proc run_list_test_arches { name opts ar foreach arch $arch_list { run_list_test_arch "$name" "$opts" "$arch" } + + 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-24 13:48:45.022872138 -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-24 13:48:45.022872138 -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-24 13:48:45.022872138 -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_DTPREL32 tlsbin_gd +10000058 R_MIPS_TLS_DTPMOD32 tlsvar_gd +1000005c R_MIPS_TLS_DTPREL32 tlsvar_gd +10000054 R_MIPS_TLS_TPREL32 tlsbin_ie +10000050 R_MIPS_TLS_TPREL32 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-24 13:48:45.022872138 -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 2005-02-21 09:36:43.000000000 -0500 +++ binutils/include/elf/mips.h 2005-02-24 13:56:56.718770094 -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, , 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) - FAKE_RELOC (R_MIPS_max, 38) + /* TLS relocations. */ + RELOC_NUMBER (R_MIPS_TLS_DTPMOD32, 38) + RELOC_NUMBER (R_MIPS_TLS_DTPREL32, 39) + RELOC_NUMBER (R_MIPS_TLS_DTPMOD64, 40) + RELOC_NUMBER (R_MIPS_TLS_DTPREL64, 41) + RELOC_NUMBER (R_MIPS_TLS_GD, 42) + RELOC_NUMBER (R_MIPS_TLS_LDM, 43) + RELOC_NUMBER (R_MIPS_TLS_DTPREL_HI16, 44) + RELOC_NUMBER (R_MIPS_TLS_DTPREL_LO16, 45) + RELOC_NUMBER (R_MIPS_TLS_GOTTPREL, 46) + RELOC_NUMBER (R_MIPS_TLS_TPREL32, 47) + RELOC_NUMBER (R_MIPS_TLS_TPREL64, 48) + RELOC_NUMBER (R_MIPS_TLS_TPREL_HI16, 49) + RELOC_NUMBER (R_MIPS_TLS_TPREL_LO16, 50) + FAKE_RELOC (R_MIPS_max, 51) /* These relocs are used for the mips16. */ FAKE_RELOC (R_MIPS16_min, 100) RELOC_NUMBER (R_MIPS16_26, 100) Index: binutils/gas/config/tc-mips.c =================================================================== --- binutils.orig/gas/config/tc-mips.c 2005-02-24 13:47:26.545027060 -0500 +++ binutils/gas/config/tc-mips.c 2005-02-24 13:48:45.028870675 -0500 @@ -9856,6 +9856,13 @@ static const struct percent_op_match mip {"%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}, + {"%dtprel_hi", BFD_RELOC_MIPS_TLS_DTPREL_HI16}, + {"%dtprel_lo", BFD_RELOC_MIPS_TLS_DTPREL_LO16}, + {"%tprel_hi", BFD_RELOC_MIPS_TLS_TPREL_HI16}, + {"%tprel_lo", BFD_RELOC_MIPS_TLS_TPREL_LO16}, + {"%gottprel", BFD_RELOC_MIPS_TLS_GOTTPREL}, #endif {"%hi", BFD_RELOC_HI16_S} }; @@ -9892,6 +9899,11 @@ parse_relocation (char **str, bfd_reloc_ for (i = 0; i < limit; 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; @@ -11028,6 +11040,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_DTPREL_HI16: + case BFD_RELOC_MIPS_TLS_DTPREL_LO16: + case BFD_RELOC_MIPS_TLS_GOTTPREL: + case BFD_RELOC_MIPS_TLS_TPREL_HI16: + case BFD_RELOC_MIPS_TLS_TPREL_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-24 13:48:45.029870431 -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,%dtprel_hi(tlsbin_ld) + addiu $3,$3,%dtprel_lo(tlsbin_ld) + addu $3,$3,$2 + + # Initial Exec + .set push + .set mips32r2 + rdhwr $2, $5 + .set pop + lw $3,%gottprel(tlsbin_ie)($28) + addu $3,$3,$2 + + lw $3,%gottprel(tlsvar_ie)($28) + addu $3,$3,$2 + + # Local Exec + .set push + .set mips32r2 + rdhwr $2, $5 + .set pop + lui $3,%tprel_hi(tlsbin_le) + addiu $3,$3,%tprel_lo(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-24 13:48:45.029870431 -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_DTPREL32 tlsvar_gd +0013f9b4 R_MIPS_TLS_DTPMOD32 tlsvar_gd +0013f9b8 R_MIPS_TLS_DTPREL32 tlsvar_gd +00149638 R_MIPS_TLS_TPREL32 tlsvar_ie +0013f9b0 R_MIPS_TLS_TPREL32 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-24 13:48:45.029870431 -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,%gottprel(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-24 13:48:45.029870431 -0500 @@ -0,0 +1,20 @@ + +.*: file format elf32-tradbigmips + +Disassembly of section .text: + +#... +[0-9a-f]+ : + [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]+ : +#... +[0-9a-f]+ : + [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-24 13:48:45.030870187 -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_DTPREL 00000000 tlsvar_gd +0013f9b4 00000a26 R_MIPS_TLS_DTPMOD 00000000 tlsvar_gd +0013f9b8 00000a27 R_MIPS_TLS_DTPREL 00000000 tlsvar_gd +00149638 0000102f R_MIPS_TLS_TPREL3 00000004 tlsvar_ie +0013f9b0 0000102f R_MIPS_TLS_TPREL3 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-24 13:48:45.030870187 -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,%gottprel(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-24 13:48:45.030870187 -0500 @@ -0,0 +1,11 @@ +.*: Assembler messages: +.*:6: Error: bad expression +.*:6: Error: illegal operands `addiu' +.*:7: Error: bad expression +.*:7: Error: illegal operands `addiu' +.*:8: Error: bad expression +.*:8: Error: missing '\)' +.*:8: Error: illegal operands `addiu' +.*:9: Error: bad expression +.*:9: Error: missing '\)' +.*:9: Error: illegal operands `addiu' 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-24 13:48:45.030870187 -0500 @@ -0,0 +1,9 @@ + .abicalls + .text + + /* These have obvious meanings, but we don't have currently defined + relocations for them. */ + addiu $4,$28,%dtprel(tlsvar) + addiu $4,$28,%tprel(tlsvar) + addiu $4,$28,%lo(%gottprel(tlsvar)) + addiu $4,$28,%hi(%gottprel(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-24 13:48:45.031869944 -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_DTPREL32 tlsvar_gd +000405e0 R_MIPS_TLS_TPREL32 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-24 13:48:45.031869944 -0500 @@ -0,0 +1,3 @@ +VER_1 { + global: *; +}; 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-24 13:48:45.031869944 -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_TPREL32 \*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-24 13:48:45.031869944 -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-24 13:48:45.031869944 -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 + ... + +.* : + .*: 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-24 13:48:45.032869700 -0500 @@ -0,0 +1,20 @@ + +.*: 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_DTPREL32 tlsbin_gd +10000048 R_MIPS_TLS_DTPMOD32 tlsvar_gd +1000004c R_MIPS_TLS_DTPREL32 tlsvar_gd +10000050 R_MIPS_TLS_TPREL32 tlsvar_ie +1000005c R_MIPS_TLS_TPREL32 tlsbin_ie + + +Contents of section .got: + 10000020 00000000 80000000 00000000 00000000 ................ + 10000030 00000000 00000000 00000000 0040060c .............@.. + 10000040 00000001 00000000 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-24 13:48:45.032869700 -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 + ... + +.* : + .*: 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-2.s =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ binutils/ld/testsuite/ld-mips-elf/tlsdyn-o32-2.s 2005-02-24 13:48:45.032869700 -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,%dtprel_hi(tlsbin_ld) + addiu $3,$3,%dtprel_lo(tlsbin_ld) + addu $3,$3,$2 + + # Initial Exec + .set push + .set mips32r2 + rdhwr $2, $5 + .set pop + lw $3,%gottprel(tlsbin_ie)($28) + addu $3,$3,$2 + + lw $3,%gottprel(tlsvar_ie)($28) + addu $3,$3,$2 + + # Local Exec + .set push + .set mips32r2 + rdhwr $2, $5 + .set pop + lui $3,%tprel_hi(tlsbin_le) + addiu $3,$3,%tprel_lo(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-24 13:48:45.032869700 -0500 @@ -0,0 +1,104 @@ + +.*: file format elf32-tradbigmips + +Disassembly of section .text: + +.* : + .*: 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 + .*: 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\) + .*: 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 + ... +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-24 13:48:45.033869456 -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_DTPREL32 tlsbin_gd +10000048 R_MIPS_TLS_DTPMOD32 tlsvar_gd +1000004c R_MIPS_TLS_DTPREL32 tlsvar_gd +10000050 R_MIPS_TLS_TPREL32 tlsvar_ie +1000005c R_MIPS_TLS_TPREL32 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-24 13:48:45.033869456 -0500 @@ -0,0 +1,20 @@ + +.*: 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_DTPREL32 tlsbin_gd +10000048 R_MIPS_TLS_DTPMOD32 tlsvar_gd +1000004c R_MIPS_TLS_DTPREL32 tlsvar_gd +10000050 R_MIPS_TLS_TPREL32 tlsvar_ie +1000005c R_MIPS_TLS_TPREL32 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 ................ + 10000060 00000000 00000000 00000000 ............