X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Felfxx-mips.c;h=89acbc57a34a8da521ecaec66b81e322df3cdb38;hb=a64ae7e0640900786fcb0d20c2c98372dd12a885;hp=2c98354a3410dc324882a5249765a100b31faa2d;hpb=dfeffb9fe1d18c568b06be976da294b928753821;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c index 2c98354a34..89acbc57a3 100644 --- a/bfd/elfxx-mips.c +++ b/bfd/elfxx-mips.c @@ -1,6 +1,6 @@ /* MIPS-specific support for 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, . @@ -23,7 +23,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ /* This file handles functionality common to the different MIPS ABI's. */ @@ -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_arg 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 @@ -210,8 +242,24 @@ struct mips_elf_link_hash_entry being called returns a floating point value. */ asection *call_fp_stub; - /* Are we forced local? .*/ + /* Are we forced local? This will only be set if we have converted + the initial global GOT entry to a local GOT entry. */ 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 +285,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 @@ -369,132 +432,21 @@ typedef struct runtime_pdr { #define cbRPDR sizeof (RPDR) #define rpdNil ((pRPDR) 0) -static struct bfd_hash_entry *mips_elf_link_hash_newfunc - (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); -static void ecoff_swap_rpdr_out - (bfd *, const RPDR *, struct rpdr_ext *); -static bfd_boolean mips_elf_create_procedure_table - (void *, bfd *, struct bfd_link_info *, asection *, - struct ecoff_debug_info *); -static bfd_boolean mips_elf_check_mips16_stubs - (struct mips_elf_link_hash_entry *, void *); -static void bfd_mips_elf32_swap_gptab_in - (bfd *, const Elf32_External_gptab *, Elf32_gptab *); -static void bfd_mips_elf32_swap_gptab_out - (bfd *, const Elf32_gptab *, Elf32_External_gptab *); -static void bfd_elf32_swap_compact_rel_out - (bfd *, const Elf32_compact_rel *, Elf32_External_compact_rel *); -static void bfd_elf32_swap_crinfo_out - (bfd *, const Elf32_crinfo *, Elf32_External_crinfo *); -static int sort_dynamic_relocs - (const void *, const void *); -static int sort_dynamic_relocs_64 - (const void *, const void *); -static bfd_boolean mips_elf_output_extsym - (struct mips_elf_link_hash_entry *, void *); -static int gptab_compare - (const void *, const void *); -static asection *mips_elf_rel_dyn_section - (bfd *, bfd_boolean); -static asection *mips_elf_got_section - (bfd *, bfd_boolean); -static struct mips_got_info *mips_elf_got_info - (bfd *, asection **); -static bfd_vma mips_elf_local_got_index - (bfd *, bfd *, struct bfd_link_info *, bfd_vma); -static bfd_vma mips_elf_global_got_index - (bfd *, bfd *, struct elf_link_hash_entry *); -static bfd_vma mips_elf_got_page - (bfd *, bfd *, struct bfd_link_info *, bfd_vma, bfd_vma *); -static bfd_vma mips_elf_got16_entry - (bfd *, bfd *, struct bfd_link_info *, bfd_vma, bfd_boolean); -static bfd_vma mips_elf_got_offset_from_index - (bfd *, bfd *, bfd *, bfd_vma); static struct mips_got_entry *mips_elf_create_local_got_entry - (bfd *, bfd *, struct mips_got_info *, asection *, bfd_vma); -static bfd_boolean mips_elf_sort_hash_table - (struct bfd_link_info *, unsigned long); + (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_boolean mips_elf_record_local_got_symbol - (bfd *, long, bfd_vma, struct mips_got_info *); -static bfd_boolean mips_elf_record_global_got_symbol - (struct elf_link_hash_entry *, bfd *, struct bfd_link_info *, - struct mips_got_info *); -static const Elf_Internal_Rela *mips_elf_next_relocation - (bfd *, unsigned int, const Elf_Internal_Rela *, const Elf_Internal_Rela *); -static bfd_boolean mips_elf_local_relocation_p - (bfd *, const Elf_Internal_Rela *, asection **, bfd_boolean); -static bfd_boolean mips_elf_overflow_p - (bfd_vma, int); static bfd_vma mips_elf_high (bfd_vma); -static bfd_vma mips_elf_higher - (bfd_vma); -static bfd_vma mips_elf_highest - (bfd_vma); -static bfd_boolean mips_elf_create_compact_rel_section - (bfd *, struct bfd_link_info *); -static bfd_boolean mips_elf_create_got_section - (bfd *, struct bfd_link_info *, bfd_boolean); -static bfd_reloc_status_type mips_elf_calculate_relocation - (bfd *, bfd *, asection *, struct bfd_link_info *, - const Elf_Internal_Rela *, bfd_vma, reloc_howto_type *, - Elf_Internal_Sym *, asection **, bfd_vma *, const char **, - bfd_boolean *, bfd_boolean); -static bfd_vma mips_elf_obtain_contents - (reloc_howto_type *, const Elf_Internal_Rela *, bfd *, bfd_byte *); -static bfd_boolean mips_elf_perform_relocation - (struct bfd_link_info *, reloc_howto_type *, const Elf_Internal_Rela *, - bfd_vma, bfd *, asection *, bfd_byte *, bfd_boolean); static bfd_boolean mips_elf_stub_section_p (bfd *, asection *); -static void mips_elf_allocate_dynamic_relocations - (bfd *, unsigned int); static bfd_boolean mips_elf_create_dynamic_relocation (bfd *, struct bfd_link_info *, const Elf_Internal_Rela *, struct mips_elf_link_hash_entry *, asection *, bfd_vma, bfd_vma *, asection *); -static void mips_set_isa_flags - (bfd *); -static INLINE char *elf_mips_abi_name - (bfd *); -static void mips_elf_irix6_finish_dynamic_symbol - (bfd *, const char *, Elf_Internal_Sym *); -static bfd_boolean mips_mach_extends_p - (unsigned long, unsigned long); -static bfd_boolean mips_32bit_flags_p - (flagword); -static INLINE hashval_t mips_elf_hash_bfd_vma - (bfd_vma); static hashval_t mips_elf_got_entry_hash (const void *); -static int mips_elf_got_entry_eq - (const void *, const void *); - -static bfd_boolean mips_elf_multi_got - (bfd *, struct bfd_link_info *, struct mips_got_info *, - asection *, bfd_size_type); -static hashval_t mips_elf_multi_got_entry_hash - (const void *); -static int mips_elf_multi_got_entry_eq - (const void *, const void *); -static hashval_t mips_elf_bfd2got_entry_hash - (const void *); -static int mips_elf_bfd2got_entry_eq - (const void *, const void *); -static int mips_elf_make_got_per_bfd - (void **, void *); -static int mips_elf_merge_gots - (void **, void *); -static int mips_elf_set_global_got_offset - (void **, void *); -static int mips_elf_set_no_stub - (void **, void *); -static int mips_elf_resolve_final_got_entry - (void **, void *); -static void mips_elf_resolve_final_got_entries - (struct mips_got_info *); static bfd_vma mips_elf_adjust_gp (bfd *, struct mips_got_info *, bfd *); static struct mips_got_info *mips_elf_got_for_ibfd @@ -504,7 +456,6 @@ static struct mips_got_info *mips_elf_got_for_ibfd static bfd *reldyn_sorting_bfd; /* Nonzero if ABFD is using the N32 ABI. */ - #define ABI_N32_P(abfd) \ ((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI2) != 0) @@ -527,6 +478,11 @@ static bfd *reldyn_sorting_bfd; #define MIPS_ELF_OPTIONS_SECTION_NAME(abfd) \ (NEWABI_P (abfd) ? ".MIPS.options" : ".options") +/* True if NAME is the recognized name of any SHT_MIPS_OPTIONS section. + Some IRIX system files do not use MIPS_ELF_OPTIONS_SECTION_NAME. */ +#define MIPS_ELF_OPTIONS_SECTION_NAME_P(NAME) \ + (strcmp (NAME, ".MIPS.options") == 0 || strcmp (NAME, ".options") == 0) + /* The name of the stub section. */ #define MIPS_ELF_STUB_SECTION_NAME(abfd) ".MIPS.stubs" @@ -700,6 +656,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 * @@ -735,6 +715,7 @@ mips_elf_link_hash_newfunc (struct bfd_hash_entry *entry, ret->call_stub = NULL; ret->call_fp_stub = NULL; ret->forced_local = FALSE; + ret->tls_type = GOT_NORMAL; } return (struct bfd_hash_entry *) ret; @@ -857,9 +838,6 @@ ecoff_swap_rpdr_out (bfd *abfd, const RPDR *in, struct rpdr_ext *ex) H_PUT_16 (abfd, in->pcreg, ex->p_pcreg); H_PUT_32 (abfd, in->irpss, ex->p_irpss); -#if 0 /* FIXME */ - H_PUT_S32 (abfd, in->exception_info, ex->p_exception_info); -#endif } /* Create a runtime procedure table from the .mdebug section. */ @@ -930,7 +908,7 @@ mips_elf_create_procedure_table (void *handle, bfd *abfd, ss = bfd_malloc (count); if (ss == NULL) goto error_return; - if (! _bfd_ecoff_get_accumulated_ss (handle, ss)) + if (! _bfd_ecoff_get_accumulated_ss (handle, (bfd_byte *) ss)) goto error_return; count = hdr->ipdMax; @@ -983,7 +961,7 @@ mips_elf_create_procedure_table (void *handle, bfd *abfd, /* Skip this section later on (I don't think this currently matters, but someday it might). */ - s->link_order_head = NULL; + s->map_head.link_order = NULL; if (epdr != NULL) free (epdr); @@ -1061,6 +1039,152 @@ mips_elf_check_mips16_stubs (struct mips_elf_link_hash_entry *h, return TRUE; } +/* R_MIPS16_26 is used for the mips16 jal and jalx instructions. + Most mips16 instructions are 16 bits, but these instructions + are 32 bits. + + The format of these instructions is: + + +--------------+--------------------------------+ + | JALX | X| Imm 20:16 | Imm 25:21 | + +--------------+--------------------------------+ + | Immediate 15:0 | + +-----------------------------------------------+ + + JALX is the 5-bit value 00011. X is 0 for jal, 1 for jalx. + Note that the immediate value in the first word is swapped. + + When producing a relocatable object file, R_MIPS16_26 is + handled mostly like R_MIPS_26. In particular, the addend is + stored as a straight 26-bit value in a 32-bit instruction. + (gas makes life simpler for itself by never adjusting a + R_MIPS16_26 reloc to be against a section, so the addend is + always zero). However, the 32 bit instruction is stored as 2 + 16-bit values, rather than a single 32-bit value. In a + big-endian file, the result is the same; in a little-endian + file, the two 16-bit halves of the 32 bit value are swapped. + This is so that a disassembler can recognize the jal + instruction. + + When doing a final link, R_MIPS16_26 is treated as a 32 bit + instruction stored as two 16-bit values. The addend A is the + contents of the targ26 field. The calculation is the same as + R_MIPS_26. When storing the calculated value, reorder the + immediate value as shown above, and don't forget to store the + value as two 16-bit values. + + To put it in MIPS ABI terms, the relocation field is T-targ26-16, + defined as + + big-endian: + +--------+----------------------+ + | | | + | | targ26-16 | + |31 26|25 0| + +--------+----------------------+ + + little-endian: + +----------+------+-------------+ + | | | | + | sub1 | | sub2 | + |0 9|10 15|16 31| + +----------+--------------------+ + where targ26-16 is sub1 followed by sub2 (i.e., the addend field A is + ((sub1 << 16) | sub2)). + + When producing a relocatable object file, the calculation is + (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2) + When producing a fully linked file, the calculation is + let R = (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2) + ((R & 0x1f0000) << 5) | ((R & 0x3e00000) >> 5) | (R & 0xffff) + + R_MIPS16_GPREL is used for GP-relative addressing in mips16 + mode. A typical instruction will have a format like this: + + +--------------+--------------------------------+ + | EXTEND | Imm 10:5 | Imm 15:11 | + +--------------+--------------------------------+ + | Major | rx | ry | Imm 4:0 | + +--------------+--------------------------------+ + + EXTEND is the five bit value 11110. Major is the instruction + opcode. + + This is handled exactly like R_MIPS_GPREL16, except that the + addend is retrieved and stored as shown in this diagram; that + is, the Imm fields above replace the V-rel16 field. + + All we need to do here is shuffle the bits appropriately. As + above, the two 16-bit halves must be swapped on a + little-endian system. + + R_MIPS16_HI16 and R_MIPS16_LO16 are used in mips16 mode to + access data when neither GP-relative nor PC-relative addressing + can be used. They are handled like R_MIPS_HI16 and R_MIPS_LO16, + except that the addend is retrieved and stored as shown above + for R_MIPS16_GPREL. + */ +void +_bfd_mips16_elf_reloc_unshuffle (bfd *abfd, int r_type, + bfd_boolean jal_shuffle, bfd_byte *data) +{ + bfd_vma extend, insn, val; + + if (r_type != R_MIPS16_26 && r_type != R_MIPS16_GPREL + && r_type != R_MIPS16_HI16 && r_type != R_MIPS16_LO16) + return; + + /* Pick up the mips16 extend instruction and the real instruction. */ + extend = bfd_get_16 (abfd, data); + insn = bfd_get_16 (abfd, data + 2); + if (r_type == R_MIPS16_26) + { + if (jal_shuffle) + val = ((extend & 0xfc00) << 16) | ((extend & 0x3e0) << 11) + | ((extend & 0x1f) << 21) | insn; + else + val = extend << 16 | insn; + } + else + val = ((extend & 0xf800) << 16) | ((insn & 0xffe0) << 11) + | ((extend & 0x1f) << 11) | (extend & 0x7e0) | (insn & 0x1f); + bfd_put_32 (abfd, val, data); +} + +void +_bfd_mips16_elf_reloc_shuffle (bfd *abfd, int r_type, + bfd_boolean jal_shuffle, bfd_byte *data) +{ + bfd_vma extend, insn, val; + + if (r_type != R_MIPS16_26 && r_type != R_MIPS16_GPREL + && r_type != R_MIPS16_HI16 && r_type != R_MIPS16_LO16) + return; + + val = bfd_get_32 (abfd, data); + if (r_type == R_MIPS16_26) + { + if (jal_shuffle) + { + insn = val & 0xffff; + extend = ((val >> 16) & 0xfc00) | ((val >> 11) & 0x3e0) + | ((val >> 21) & 0x1f); + } + else + { + insn = val & 0xffff; + extend = val >> 16; + } + } + else + { + insn = ((val >> 11) & 0xffe0) | (val & 0x1f); + extend = ((val >> 16) & 0xf800) | ((val >> 11) & 0x1f) | (val & 0x7e0); + } + bfd_put_16 (abfd, insn, data + 2); + bfd_put_16 (abfd, extend, data); +} + bfd_reloc_status_type _bfd_mips_elf_gprel16_with_gp (bfd *abfd, asymbol *symbol, arelent *reloc_entry, asection *input_section, @@ -1194,11 +1318,17 @@ _bfd_mips_elf_lo16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, bfd *output_bfd, char **error_message) { bfd_vma vallo; + bfd_byte *location = (bfd_byte *) data + reloc_entry->address; if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) return bfd_reloc_outofrange; - vallo = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); + _bfd_mips16_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, FALSE, + location); + vallo = bfd_get_32 (abfd, location); + _bfd_mips16_elf_reloc_shuffle (abfd, reloc_entry->howto->type, FALSE, + location); + while (mips_hi16_list != NULL) { bfd_reloc_status_type ret; @@ -1284,13 +1414,19 @@ _bfd_mips_elf_generic_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry, reloc_entry->addend += val; else { + bfd_byte *location = (bfd_byte *) data + reloc_entry->address; + /* Add in the separate addend, if any. */ val += reloc_entry->addend; /* Add VAL to the relocation field. */ + _bfd_mips16_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, FALSE, + location); status = _bfd_relocate_contents (reloc_entry->howto, abfd, val, - (bfd_byte *) data - + reloc_entry->address); + location); + _bfd_mips16_elf_reloc_shuffle (abfd, reloc_entry->howto->type, FALSE, + location); + if (status != bfd_reloc_ok) return status; } @@ -1449,8 +1585,10 @@ sort_dynamic_relocs (const void *arg1, const void *arg2) /* Like sort_dynamic_relocs, but used for elf64 relocations. */ static int -sort_dynamic_relocs_64 (const void *arg1, const void *arg2) +sort_dynamic_relocs_64 (const void *arg1 ATTRIBUTE_UNUSED, + const void *arg2 ATTRIBUTE_UNUSED) { +#ifdef BFD64 Elf_Internal_Rela int_reloc1[3]; Elf_Internal_Rela int_reloc2[3]; @@ -1461,6 +1599,9 @@ sort_dynamic_relocs_64 (const void *arg1, const void *arg2) return (ELF64_R_SYM (int_reloc1[0].r_info) - ELF64_R_SYM (int_reloc2[0].r_info)); +#else + abort (); +#endif } @@ -1491,7 +1632,8 @@ mips_elf_output_extsym (struct mips_elf_link_hash_entry *h, void *data) if (h->root.indx == -2) strip = FALSE; else if ((h->root.def_dynamic - || h->root.ref_dynamic) + || h->root.ref_dynamic + || h->root.type == bfd_link_hash_new) && !h->root.def_regular && !h->root.ref_regular) strip = TRUE; @@ -1639,9 +1781,6 @@ mips_elf_output_extsym (struct mips_elf_link_hash_entry *h, void *data) else h->esym.asym.value = 0; } -#if 0 /* FIXME? */ - h->esym.ifd = 0; -#endif } } @@ -1692,6 +1831,7 @@ mips_elf_got_entry_hash (const void *entry_) 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) @@ -1704,6 +1844,10 @@ mips_elf_got_entry_eq (const void *entry1, const void *entry2) 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 @@ -1724,8 +1868,10 @@ mips_elf_multi_got_entry_hash (const void *entry_) + (! 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); } @@ -1735,6 +1881,14 @@ mips_elf_multi_got_entry_eq (const void *entry1, const void *entry2) 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 @@ -1753,15 +1907,14 @@ mips_elf_rel_dyn_section (bfd *dynobj, bfd_boolean create_p) sreloc = bfd_get_section_by_name (dynobj, dname); if (sreloc == NULL && create_p) { - sreloc = bfd_make_section (dynobj, dname); + sreloc = bfd_make_section_with_flags (dynobj, dname, + (SEC_ALLOC + | SEC_LOAD + | SEC_HAS_CONTENTS + | SEC_IN_MEMORY + | SEC_LINKER_CREATED + | SEC_READONLY)); if (sreloc == NULL - || ! bfd_set_section_flags (dynobj, sreloc, - (SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED - | SEC_READONLY)) || ! bfd_set_section_alignment (dynobj, sreloc, MIPS_ELF_LOG_FILE_ALIGN (dynobj))) return NULL; @@ -1803,13 +1956,299 @@ mips_elf_got_info (bfd *abfd, asection **sgotp) 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; @@ -1817,17 +2256,23 @@ mips_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, 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; @@ -1842,29 +2287,64 @@ mips_elf_global_got_index (bfd *abfd, bfd *ibfd, struct elf_link_hash_entry *h) 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; @@ -1889,7 +2369,8 @@ mips_elf_got_page (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, 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; @@ -1924,7 +2405,8 @@ mips_elf_got16_entry (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, 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 @@ -1950,12 +2432,16 @@ mips_elf_got_offset_from_index (bfd *dynobj, bfd *output_bfd, } /* 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; @@ -1963,6 +2449,7 @@ mips_elf_create_local_got_entry (bfd *abfd, bfd *ibfd, 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) @@ -1971,12 +2458,44 @@ mips_elf_create_local_got_entry (bfd *abfd, bfd *ibfd, 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->root.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); @@ -2072,6 +2591,8 @@ mips_elf_sort_hash_table_f (struct mips_elf_link_hash_entry *h, void *data) -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++; @@ -2080,6 +2601,8 @@ mips_elf_sort_hash_table_f (struct mips_elf_link_hash_entry *h, void *data) 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; } @@ -2094,7 +2617,8 @@ mips_elf_sort_hash_table_f (struct mips_elf_link_hash_entry *h, void *data) 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; @@ -2113,9 +2637,13 @@ mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h, return FALSE; } + /* Make sure we have a GOT to put this entry into. */ + BFD_ASSERT (g != NULL); + 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); @@ -2123,7 +2651,10 @@ mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h, /* 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); @@ -2131,6 +2662,8 @@ mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h, return FALSE; entry.gotidx = -1; + entry.tls_type = tls_flag; + memcpy (*loc, &entry, sizeof entry); if (h->got.offset != MINUS_ONE) @@ -2139,7 +2672,8 @@ mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h, /* 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; } @@ -2149,20 +2683,52 @@ mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h, 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); @@ -2198,7 +2764,7 @@ mips_elf_bfd2got_entry_eq (const void *entry1, const void *entry2) return e1->bfd == e2->bfd; } -/* In a multi-got link, determine the GOT to be used for IBDF. G must +/* In a multi-got link, determine the GOT to be used for IBFD. G must be the master GOT data. */ static struct mips_got_info * @@ -2262,6 +2828,9 @@ mips_elf_make_got_per_bfd (void **entryp, void *p) 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) @@ -2281,7 +2850,14 @@ mips_elf_make_got_per_bfd (void **entryp, void *p) *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; @@ -2304,11 +2880,26 @@ mips_elf_merge_gots (void **bfd2got_, void *p) 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; @@ -2316,12 +2907,13 @@ mips_elf_merge_gots (void **bfd2got_, void *p) /* 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; @@ -2338,17 +2930,19 @@ mips_elf_merge_gots (void **bfd2got_, void *p) 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; @@ -2362,9 +2956,10 @@ mips_elf_merge_gots (void **bfd2got_, void *p) 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 @@ -2374,12 +2969,64 @@ mips_elf_merge_gots (void **bfd2got_, void *p) 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) + { + entry->gotidx = entry->d.h->tls_got_offset; + 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. @@ -2401,8 +3048,14 @@ mips_elf_set_global_got_offset (void **entryp, void *p) = (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) { @@ -2517,7 +3170,8 @@ mips_elf_adjust_gp (bfd *abfd, struct mips_got_info *g, bfd *ibfd) 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 @@ -2544,7 +3198,6 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info, /* 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; @@ -2557,6 +3210,10 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info, 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 @@ -2565,7 +3222,7 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info, 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 *) @@ -2576,7 +3233,10 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info, 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); @@ -2676,6 +3336,7 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info, 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; @@ -2686,7 +3347,12 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info, 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. */ @@ -2703,7 +3369,8 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info, 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; } @@ -2849,9 +3516,8 @@ mips_elf_create_compact_rel_section flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED | SEC_READONLY); - s = bfd_make_section (abfd, ".compact_rel"); + s = bfd_make_section_with_flags (abfd, ".compact_rel", flags); if (s == NULL - || ! bfd_set_section_flags (abfd, s, flags) || ! bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd))) return FALSE; @@ -2892,9 +3558,8 @@ mips_elf_create_got_section (bfd *abfd, struct bfd_link_info *info, /* We have to use an alignment of 2**4 here because this is hardcoded in the function stub generation and in the linker script. */ - s = bfd_make_section (abfd, ".got"); + s = bfd_make_section_with_flags (abfd, ".got", flags); if (s == NULL - || ! bfd_set_section_flags (abfd, s, flags) || ! bfd_set_section_alignment (abfd, s, 4)) return FALSE; @@ -2922,10 +3587,12 @@ mips_elf_create_got_section (bfd *abfd, struct bfd_link_info *info, 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) @@ -2987,6 +3654,9 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, bfd_boolean local_p, was_local_p; /* TRUE if the symbol referred to by this relocation is "_gp_disp". */ bfd_boolean gp_disp_p = FALSE; + /* TRUE if the symbol referred to by this relocation is + "__gnu_local_gp". */ + bfd_boolean gnu_local_gp_p = FALSE; Elf_Internal_Shdr *symtab_hdr; size_t extsymoff; unsigned long r_symndx; @@ -3077,11 +3747,18 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, { /* Relocations against _gp_disp are permitted only with R_MIPS_HI16 and R_MIPS_LO16 relocations. */ - if (r_type != R_MIPS_HI16 && r_type != R_MIPS_LO16) + if (r_type != R_MIPS_HI16 && r_type != R_MIPS_LO16 + && r_type != R_MIPS16_HI16 && r_type != R_MIPS16_LO16) return bfd_reloc_notsupported; gp_disp_p = TRUE; } + /* See if this is the special _gp symbol. Note that such a + symbol must always be a global symbol. */ + else if (strcmp (*namep, "__gnu_local_gp") == 0) + gnu_local_gp_p = TRUE; + + /* If this symbol is defined, calculate its address. Note that _gp_disp is a magic symbol, always implicitly defined by the linker, so it's inappropriate to check to see whether or not @@ -3120,6 +3797,17 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, BFD_ASSERT (bfd_get_section_by_name (abfd, ".dynamic") == NULL); symbol = 0; } + else if (ELF_MIPS_IS_OPTIONAL (h->root.other)) + { + /* This is an optional symbol - an Irix specific extension to the + ELF spec. Ignore it for now. + XXX - FIXME - there is more to the spec for OPTIONAL symbols + than simply ignoring them, but we do not handle this for now. + For information see the "64-bit ELF Object File Specification" + which is available from here: + http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf */ + symbol = 0; + } else { if (! ((*info->callbacks->undefined_symbol) @@ -3221,8 +3909,18 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, 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 @@ -3231,11 +3929,13 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, 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.forced_local) + && h->root.def_regular))) { /* This is a static link or a -Bsymbolic link. The symbol is defined locally, or was forced to be local. @@ -3252,7 +3952,8 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, 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; } @@ -3264,10 +3965,12 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, case R_MIPS_HI16: case R_MIPS_LO16: - case R_MIPS16_GPREL: case R_MIPS_GPREL16: case R_MIPS_GPREL32: case R_MIPS_LITERAL: + case R_MIPS16_HI16: + case R_MIPS16_LO16: + case R_MIPS16_GPREL: gp0 = _bfd_get_gp_value (input_bfd); gp = _bfd_get_gp_value (abfd); if (elf_hash_table (info)->dynobj) @@ -3281,6 +3984,9 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, break; } + if (gnu_local_gp_p) + symbol = gp; + /* Figure out what kind of relocation is being performed. */ switch (r_type) { @@ -3334,12 +4040,6 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, value &= howto->dst_mask; break; - case R_MIPS_GNU_REL16_S2: - value = symbol + _bfd_mips_elf_sign_extend (addend, 18) - p; - overflowed_p = mips_elf_overflow_p (value, 18); - value = (value >> 2) & howto->dst_mask; - break; - case R_MIPS16_26: /* The calculation for R_MIPS16_26 is just the same as for an R_MIPS_26. It's only the storage of the relocated field into @@ -3350,11 +4050,34 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, if (local_p) value = ((addend | ((p + 4) & 0xf0000000)) + symbol) >> 2; else - value = (_bfd_mips_elf_sign_extend (addend, 28) + symbol) >> 2; + { + value = (_bfd_mips_elf_sign_extend (addend, 28) + symbol) >> 2; + if (h->root.root.type != bfd_link_hash_undefweak) + overflowed_p = (value >> 26) != ((p + 4) >> 28); + } 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) { value = mips_elf_high (addend + symbol); @@ -3362,17 +4085,35 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, } else { - value = mips_elf_high (addend + gp - p); + /* For MIPS16 ABI code we generate this sequence + 0: li $v0,%hi(_gp_disp) + 4: addiupc $v1,%lo(_gp_disp) + 8: sll $v0,16 + 12: addu $v0,$v1 + 14: move $gp,$v0 + So the offsets of hi and lo relocs are the same, but the + $pc is four higher than $t9 would be, so reduce + both reloc addends by 4. */ + if (r_type == R_MIPS16_HI16) + value = mips_elf_high (addend + gp - p - 4); + else + value = mips_elf_high (addend + gp - p); overflowed_p = mips_elf_overflow_p (value, 16); } break; case R_MIPS_LO16: + case R_MIPS16_LO16: if (!gp_disp_p) value = (symbol + addend) & howto->dst_mask; else { - value = addend + gp - p + 4; + /* See the comment for R_MIPS16_HI16 above for the reason + for this conditional. */ + if (r_type == R_MIPS16_LO16) + value = addend + gp - p; + else + value = addend + gp - p + 4; /* The MIPS ABI requires checking the R_MIPS_LO16 relocation for overflow. But, on, say, IRIX5, relocations against _gp_disp are normally generated from the .cpload @@ -3446,6 +4187,9 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, /* 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; @@ -3459,8 +4203,10 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, break; case R_MIPS_PC16: - value = _bfd_mips_elf_sign_extend (addend, 16) + symbol - p; - overflowed_p = mips_elf_overflow_p (value, 16); + case R_MIPS_GNU_REL16_S2: + value = symbol + _bfd_mips_elf_sign_extend (addend, 18) - p; + overflowed_p = mips_elf_overflow_p (value, 18); + value = (value >> 2) & howto->dst_mask; break; case R_MIPS_GOT_HI16: @@ -3520,12 +4266,16 @@ mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, value &= howto->dst_mask; break; - case R_MIPS_PJUMP: case R_MIPS_JALR: - /* Both of these may be ignored. R_MIPS_JALR is an optimization - hint; we could improve performance by honoring that hint. */ - return bfd_reloc_continue; + /* This relocation is only a hint. In some cases, we optimize + it into a bal instruction. But we don't try to optimize + branches to the PLT; that will wind up wasting time. */ + if (h != NULL && h->root.plt.offset != (bfd_vma) -1) + return bfd_reloc_continue; + value = symbol + addend; + break; + case R_MIPS_PJUMP: case R_MIPS_GNU_VTINHERIT: case R_MIPS_GNU_VTENTRY: /* We don't do anything with these at present. */ @@ -3554,13 +4304,6 @@ mips_elf_obtain_contents (reloc_howto_type *howto, /* Obtain the bytes. */ x = bfd_get ((8 * bfd_get_reloc_size (howto)), input_bfd, location); - if ((ELF_R_TYPE (input_bfd, relocation->r_info) == R_MIPS16_26 - || ELF_R_TYPE (input_bfd, relocation->r_info) == R_MIPS16_GPREL) - && bfd_little_endian (input_bfd)) - /* The two 16-bit words will be reversed on a little-endian system. - See mips_elf_perform_relocation for more details. */ - x = (((x & 0xffff) << 16) | ((x & 0xffff0000) >> 16)); - return x; } @@ -3588,107 +4331,14 @@ mips_elf_perform_relocation (struct bfd_link_info *info, /* Figure out where the relocation is occurring. */ location = contents + relocation->r_offset; + _bfd_mips16_elf_reloc_unshuffle (input_bfd, r_type, FALSE, location); + /* Obtain the current value. */ x = mips_elf_obtain_contents (howto, relocation, input_bfd, contents); /* Clear the field we are setting. */ x &= ~howto->dst_mask; - /* If this is the R_MIPS16_26 relocation, we must store the - value in a funny way. */ - if (r_type == R_MIPS16_26) - { - /* R_MIPS16_26 is used for the mips16 jal and jalx instructions. - Most mips16 instructions are 16 bits, but these instructions - are 32 bits. - - The format of these instructions is: - - +--------------+--------------------------------+ - ! JALX ! X! Imm 20:16 ! Imm 25:21 ! - +--------------+--------------------------------+ - ! Immediate 15:0 ! - +-----------------------------------------------+ - - JALX is the 5-bit value 00011. X is 0 for jal, 1 for jalx. - Note that the immediate value in the first word is swapped. - - When producing a relocatable object file, R_MIPS16_26 is - handled mostly like R_MIPS_26. In particular, the addend is - stored as a straight 26-bit value in a 32-bit instruction. - (gas makes life simpler for itself by never adjusting a - R_MIPS16_26 reloc to be against a section, so the addend is - always zero). However, the 32 bit instruction is stored as 2 - 16-bit values, rather than a single 32-bit value. In a - big-endian file, the result is the same; in a little-endian - file, the two 16-bit halves of the 32 bit value are swapped. - This is so that a disassembler can recognize the jal - instruction. - - When doing a final link, R_MIPS16_26 is treated as a 32 bit - instruction stored as two 16-bit values. The addend A is the - contents of the targ26 field. The calculation is the same as - R_MIPS_26. When storing the calculated value, reorder the - immediate value as shown above, and don't forget to store the - value as two 16-bit values. - - To put it in MIPS ABI terms, the relocation field is T-targ26-16, - defined as - - big-endian: - +--------+----------------------+ - | | | - | | targ26-16 | - |31 26|25 0| - +--------+----------------------+ - - little-endian: - +----------+------+-------------+ - | | | | - | sub1 | | sub2 | - |0 9|10 15|16 31| - +----------+--------------------+ - where targ26-16 is sub1 followed by sub2 (i.e., the addend field A is - ((sub1 << 16) | sub2)). - - When producing a relocatable object file, the calculation is - (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2) - When producing a fully linked file, the calculation is - let R = (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2) - ((R & 0x1f0000) << 5) | ((R & 0x3e00000) >> 5) | (R & 0xffff) */ - - if (!info->relocatable) - /* Shuffle the bits according to the formula above. */ - value = (((value & 0x1f0000) << 5) - | ((value & 0x3e00000) >> 5) - | (value & 0xffff)); - } - else if (r_type == R_MIPS16_GPREL) - { - /* R_MIPS16_GPREL is used for GP-relative addressing in mips16 - mode. A typical instruction will have a format like this: - - +--------------+--------------------------------+ - ! EXTEND ! Imm 10:5 ! Imm 15:11 ! - +--------------+--------------------------------+ - ! Major ! rx ! ry ! Imm 4:0 ! - +--------------+--------------------------------+ - - EXTEND is the five bit value 11110. Major is the instruction - opcode. - - This is handled exactly like R_MIPS_GPREL16, except that the - addend is retrieved and stored as shown in this diagram; that - is, the Imm fields above replace the V-rel16 field. - - All we need to do here is shuffle the bits appropriately. As - above, the two 16-bit halves must be swapped on a - little-endian system. */ - value = (((value & 0x7e0) << 16) - | ((value & 0xf800) << 5) - | (value & 0x1f)); - } - /* Set the field. */ x |= (value & howto->dst_mask); @@ -3727,14 +4377,39 @@ mips_elf_perform_relocation (struct bfd_link_info *info, x = (x & ~(0x3f << 26)) | (jalx_opcode << 26); } - /* Swap the high- and low-order 16 bits on little-endian systems - when doing a MIPS16 relocation. */ - if ((r_type == R_MIPS16_GPREL || r_type == R_MIPS16_26) - && bfd_little_endian (input_bfd)) - x = (((x & 0xffff) << 16) | ((x & 0xffff0000) >> 16)); + /* On the RM9000, bal is faster than jal, because bal uses branch + prediction hardware. If we are linking for the RM9000, and we + see jal, and bal fits, use it instead. Note that this + transformation should be safe for all architectures. */ + if (bfd_get_mach (input_bfd) == bfd_mach_mips9000 + && !info->relocatable + && !require_jalx + && ((r_type == R_MIPS_26 && (x >> 26) == 0x3) /* jal addr */ + || (r_type == R_MIPS_JALR && x == 0x0320f809))) /* jalr t9 */ + { + bfd_vma addr; + bfd_vma dest; + bfd_signed_vma off; + + addr = (input_section->output_section->vma + + input_section->output_offset + + relocation->r_offset + + 4); + if (r_type == R_MIPS_26) + dest = (value << 2) | ((addr >> 28) << 28); + else + dest = value; + off = dest - addr; + if (off <= 0x1ffff && off >= -0x20000) + x = 0x04110000 | (((bfd_vma) off >> 2) & 0xffff); /* bal addr */ + } /* Put the value into the output. */ bfd_put (8 * bfd_get_reloc_size (howto), input_bfd, x, location); + + _bfd_mips16_elf_reloc_shuffle(input_bfd, r_type, !info->relocatable, + location); + return TRUE; } @@ -3783,10 +4458,11 @@ mips_elf_create_dynamic_relocation (bfd *output_bfd, bfd_vma *addendp, asection *input_section) { Elf_Internal_Rela outrel[3]; - bfd_boolean skip; asection *sreloc; bfd *dynobj; int r_type; + long indx; + bfd_boolean defined_p; r_type = ELF_R_TYPE (output_bfd, rel->r_info); dynobj = elf_hash_table (info)->dynobj; @@ -3796,7 +4472,6 @@ mips_elf_create_dynamic_relocation (bfd *output_bfd, BFD_ASSERT (sreloc->reloc_count * MIPS_ELF_REL_SIZE (output_bfd) < sreloc->size); - skip = FALSE; outrel[0].r_offset = _bfd_elf_section_offset (output_bfd, info, input_section, rel[0].r_offset); outrel[1].r_offset = @@ -3804,144 +4479,108 @@ mips_elf_create_dynamic_relocation (bfd *output_bfd, outrel[2].r_offset = _bfd_elf_section_offset (output_bfd, info, input_section, rel[2].r_offset); -#if 0 - /* We begin by assuming that the offset for the dynamic relocation - is the same as for the original relocation. We'll adjust this - later to reflect the correct output offsets. */ - if (input_section->sec_info_type != ELF_INFO_TYPE_STABS) - { - outrel[1].r_offset = rel[1].r_offset; - outrel[2].r_offset = rel[2].r_offset; - } - else - { - /* Except that in a stab section things are more complex. - Because we compress stab information, the offset given in the - relocation may not be the one we want; we must let the stabs - machinery tell us the offset. */ - outrel[1].r_offset = outrel[0].r_offset; - outrel[2].r_offset = outrel[0].r_offset; - /* If we didn't need the relocation at all, this value will be - -1. */ - if (outrel[0].r_offset == MINUS_ONE) - skip = TRUE; - } -#endif - if (outrel[0].r_offset == MINUS_ONE) /* The relocation field has been deleted. */ - skip = TRUE; - else if (outrel[0].r_offset == MINUS_TWO) + return TRUE; + + if (outrel[0].r_offset == MINUS_TWO) { /* The relocation field has been converted into a relative value of some sort. Functions like _bfd_elf_write_section_eh_frame expect the field to be fully relocated, so add in the symbol's value. */ - skip = TRUE; *addendp += symbol; + return TRUE; } - /* If we've decided to skip this relocation, just output an empty - record. Note that R_MIPS_NONE == 0, so that this call to memset - is a way of setting R_TYPE to R_MIPS_NONE. */ - if (skip) - memset (outrel, 0, sizeof (Elf_Internal_Rela) * 3); + /* We must now calculate the dynamic symbol table index to use + in the relocation. */ + if (h != NULL + && (!h->root.def_regular + || (info->shared && !info->symbolic && !h->root.forced_local))) + { + indx = h->root.dynindx; + if (SGI_COMPAT (output_bfd)) + defined_p = h->root.def_regular; + else + /* ??? glibc's ld.so just adds the final GOT entry to the + relocation field. It therefore treats relocs against + defined symbols in the same way as relocs against + undefined symbols. */ + defined_p = FALSE; + } else { - long indx; - bfd_boolean defined_p; - - /* We must now calculate the dynamic symbol table index to use - in the relocation. */ - if (h != NULL - && (! info->symbolic || !h->root.def_regular) - /* h->root.dynindx may be -1 if this symbol was marked to - become local. */ - && h->root.dynindx != -1) - { - indx = h->root.dynindx; - if (SGI_COMPAT (output_bfd)) - defined_p = h->root.def_regular; - else - /* ??? glibc's ld.so just adds the final GOT entry to the - relocation field. It therefore treats relocs against - defined symbols in the same way as relocs against - undefined symbols. */ - defined_p = FALSE; + if (sec != NULL && bfd_is_abs_section (sec)) + indx = 0; + else if (sec == NULL || sec->owner == NULL) + { + bfd_set_error (bfd_error_bad_value); + return FALSE; } else { - if (sec != NULL && bfd_is_abs_section (sec)) - indx = 0; - else if (sec == NULL || sec->owner == NULL) - { - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - else - { - indx = elf_section_data (sec->output_section)->dynindx; - if (indx == 0) - abort (); - } + indx = elf_section_data (sec->output_section)->dynindx; + if (indx == 0) + abort (); + } - /* Instead of generating a relocation using the section - symbol, we may as well make it a fully relative - relocation. We want to avoid generating relocations to - local symbols because we used to generate them - incorrectly, without adding the original symbol value, - which is mandated by the ABI for section symbols. In - order to give dynamic loaders and applications time to - phase out the incorrect use, we refrain from emitting - section-relative relocations. It's not like they're - useful, after all. This should be a bit more efficient - as well. */ - /* ??? Although this behavior is compatible with glibc's ld.so, - the ABI says that relocations against STN_UNDEF should have - a symbol value of 0. Irix rld honors this, so relocations - against STN_UNDEF have no effect. */ - if (!SGI_COMPAT (output_bfd)) - indx = 0; - defined_p = TRUE; - } - - /* If the relocation was previously an absolute relocation and - this symbol will not be referred to by the relocation, we must - adjust it by the value we give it in the dynamic symbol table. - Otherwise leave the job up to the dynamic linker. */ - if (defined_p && r_type != R_MIPS_REL32) - *addendp += symbol; - - /* The relocation is always an REL32 relocation because we don't - know where the shared library will wind up at load-time. */ - outrel[0].r_info = ELF_R_INFO (output_bfd, (unsigned long) indx, - R_MIPS_REL32); - /* For strict adherence to the ABI specification, we should - generate a R_MIPS_64 relocation record by itself before the - _REL32/_64 record as well, such that the addend is read in as - a 64-bit value (REL32 is a 32-bit relocation, after all). - However, since none of the existing ELF64 MIPS dynamic - loaders seems to care, we don't waste space with these - artificial relocations. If this turns out to not be true, - mips_elf_allocate_dynamic_relocation() should be tweaked so - as to make room for a pair of dynamic relocations per - invocation if ABI_64_P, and here we should generate an - additional relocation record with R_MIPS_64 by itself for a - NULL symbol before this relocation record. */ - outrel[1].r_info = ELF_R_INFO (output_bfd, 0, - ABI_64_P (output_bfd) - ? R_MIPS_64 - : R_MIPS_NONE); - outrel[2].r_info = ELF_R_INFO (output_bfd, 0, R_MIPS_NONE); - - /* Adjust the output offset of the relocation to reference the - correct location in the output file. */ - outrel[0].r_offset += (input_section->output_section->vma - + input_section->output_offset); - outrel[1].r_offset += (input_section->output_section->vma - + input_section->output_offset); - outrel[2].r_offset += (input_section->output_section->vma - + input_section->output_offset); - } + /* Instead of generating a relocation using the section + symbol, we may as well make it a fully relative + relocation. We want to avoid generating relocations to + local symbols because we used to generate them + incorrectly, without adding the original symbol value, + which is mandated by the ABI for section symbols. In + order to give dynamic loaders and applications time to + phase out the incorrect use, we refrain from emitting + section-relative relocations. It's not like they're + useful, after all. This should be a bit more efficient + as well. */ + /* ??? Although this behavior is compatible with glibc's ld.so, + the ABI says that relocations against STN_UNDEF should have + a symbol value of 0. Irix rld honors this, so relocations + against STN_UNDEF have no effect. */ + if (!SGI_COMPAT (output_bfd)) + indx = 0; + defined_p = TRUE; + } + + /* If the relocation was previously an absolute relocation and + this symbol will not be referred to by the relocation, we must + adjust it by the value we give it in the dynamic symbol table. + Otherwise leave the job up to the dynamic linker. */ + if (defined_p && r_type != R_MIPS_REL32) + *addendp += symbol; + + /* The relocation is always an REL32 relocation because we don't + know where the shared library will wind up at load-time. */ + outrel[0].r_info = ELF_R_INFO (output_bfd, (unsigned long) indx, + R_MIPS_REL32); + /* For strict adherence to the ABI specification, we should + generate a R_MIPS_64 relocation record by itself before the + _REL32/_64 record as well, such that the addend is read in as + a 64-bit value (REL32 is a 32-bit relocation, after all). + However, since none of the existing ELF64 MIPS dynamic + loaders seems to care, we don't waste space with these + artificial relocations. If this turns out to not be true, + mips_elf_allocate_dynamic_relocation() should be tweaked so + as to make room for a pair of dynamic relocations per + invocation if ABI_64_P, and here we should generate an + additional relocation record with R_MIPS_64 by itself for a + NULL symbol before this relocation record. */ + outrel[1].r_info = ELF_R_INFO (output_bfd, 0, + ABI_64_P (output_bfd) + ? R_MIPS_64 + : R_MIPS_NONE); + outrel[2].r_info = ELF_R_INFO (output_bfd, 0, R_MIPS_NONE); + + /* Adjust the output offset of the relocation to reference the + correct location in the output file. */ + outrel[0].r_offset += (input_section->output_section->vma + + input_section->output_offset); + outrel[1].r_offset += (input_section->output_section->vma + + input_section->output_offset); + outrel[2].r_offset += (input_section->output_section->vma + + input_section->output_offset); /* Put the relocation back out. We have to use the special relocation outputter in the 64-bit case since the 64-bit @@ -3967,7 +4606,7 @@ mips_elf_create_dynamic_relocation (bfd *output_bfd, |= SHF_WRITE; /* On IRIX5, make an entry of compact relocation info. */ - if (! skip && IRIX_COMPAT (output_bfd) == ict_irix5) + if (IRIX_COMPAT (output_bfd) == ict_irix5) { asection *scpt = bfd_get_section_by_name (dynobj, ".compact_rel"); bfd_byte *cr; @@ -3989,6 +4628,7 @@ mips_elf_create_dynamic_relocation (bfd *output_bfd, cr = (scpt->contents + sizeof (Elf32_External_compact_rel)); + mips_elf_set_cr_relvaddr (cptrel, 0); bfd_elf32_swap_crinfo_out (output_bfd, &cptrel, ((Elf32_External_crinfo *) cr + scpt->reloc_count)); @@ -4030,6 +4670,9 @@ _bfd_elf_mips_mach (flagword flags) case E_MIPS_MACH_5500: return bfd_mach_mips5500; + case E_MIPS_MACH_9000: + return bfd_mach_mips9000; + case E_MIPS_MACH_SB1: return bfd_mach_mips_sb1; @@ -4220,6 +4863,72 @@ _bfd_mips_elf_symbol_processing (bfd *abfd, asymbol *asym) } } +/* Implement elf_backend_eh_frame_address_size. This differs from + the default in the way it handles EABI64. + + EABI64 was originally specified as an LP64 ABI, and that is what + -mabi=eabi normally gives on a 64-bit target. However, gcc has + historically accepted the combination of -mabi=eabi and -mlong32, + and this ILP32 variation has become semi-official over time. + Both forms use elf32 and have pointer-sized FDE addresses. + + If an EABI object was generated by GCC 4.0 or above, it will have + an empty .gcc_compiled_longXX section, where XX is the size of longs + in bits. Unfortunately, ILP32 objects generated by earlier compilers + have no special marking to distinguish them from LP64 objects. + + We don't want users of the official LP64 ABI to be punished for the + existence of the ILP32 variant, but at the same time, we don't want + to mistakenly interpret pre-4.0 ILP32 objects as being LP64 objects. + We therefore take the following approach: + + - If ABFD contains a .gcc_compiled_longXX section, use it to + determine the pointer size. + + - Otherwise check the type of the first relocation. Assume that + the LP64 ABI is being used if the relocation is of type R_MIPS_64. + + - Otherwise punt. + + The second check is enough to detect LP64 objects generated by pre-4.0 + compilers because, in the kind of output generated by those compilers, + the first relocation will be associated with either a CIE personality + routine or an FDE start address. Furthermore, the compilers never + used a special (non-pointer) encoding for this ABI. + + Checking the relocation type should also be safe because there is no + reason to use R_MIPS_64 in an ILP32 object. Pre-4.0 compilers never + did so. */ + +unsigned int +_bfd_mips_elf_eh_frame_address_size (bfd *abfd, asection *sec) +{ + if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64) + return 8; + if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI) == E_MIPS_ABI_EABI64) + { + bfd_boolean long32_p, long64_p; + + long32_p = bfd_get_section_by_name (abfd, ".gcc_compiled_long32") != 0; + long64_p = bfd_get_section_by_name (abfd, ".gcc_compiled_long64") != 0; + if (long32_p && long64_p) + return 0; + if (long32_p) + return 4; + if (long64_p) + return 8; + + if (sec->reloc_count > 0 + && elf_section_data (sec)->relocs != NULL + && (ELF32_R_TYPE (elf_section_data (sec)->relocs[0].r_info) + == R_MIPS_64)) + return 8; + + return 0; + } + return 4; +} + /* There appears to be a bug in the MIPSpro linker that causes GOT_DISP relocations against two unnamed section symbols to resolve to the same address. For example, if we have code like: @@ -4288,6 +4997,13 @@ _bfd_mips_elf_section_processing (bfd *abfd, Elf_Internal_Shdr *hdr) bfd_mips_elf_swap_options_in (abfd, (Elf_External_Options *) l, &intopt); + if (intopt.size < sizeof (Elf_External_Options)) + { + (*_bfd_error_handler) + (_("%B: Warning: bad `%s' option size %u smaller than its header"), + abfd, MIPS_ELF_OPTIONS_SECTION_NAME (abfd), intopt.size); + break; + } if (ABI_64_P (abfd) && intopt.kind == ODK_REGINFO) { bfd_byte buf[8]; @@ -4372,8 +5088,10 @@ _bfd_mips_elf_section_processing (bfd *abfd, Elf_Internal_Shdr *hdr) how to. */ bfd_boolean -_bfd_mips_elf_section_from_shdr (bfd *abfd, Elf_Internal_Shdr *hdr, - const char *name) +_bfd_mips_elf_section_from_shdr (bfd *abfd, + Elf_Internal_Shdr *hdr, + const char *name, + int shindex) { flagword flags = 0; @@ -4424,7 +5142,7 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd, Elf_Internal_Shdr *hdr, return FALSE; break; case SHT_MIPS_OPTIONS: - if (strcmp (name, MIPS_ELF_OPTIONS_SECTION_NAME (abfd)) != 0) + if (!MIPS_ELF_OPTIONS_SECTION_NAME_P (name)) return FALSE; break; case SHT_MIPS_DWARF: @@ -4442,10 +5160,10 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd, Elf_Internal_Shdr *hdr, return FALSE; break; default: - return FALSE; + break; } - if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name)) + if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) return FALSE; if (flags) @@ -4500,6 +5218,13 @@ _bfd_mips_elf_section_from_shdr (bfd *abfd, Elf_Internal_Shdr *hdr, bfd_mips_elf_swap_options_in (abfd, (Elf_External_Options *) l, &intopt); + if (intopt.size < sizeof (Elf_External_Options)) + { + (*_bfd_error_handler) + (_("%B: Warning: bad `%s' option size %u smaller than its header"), + abfd, MIPS_ELF_OPTIONS_SECTION_NAME (abfd), intopt.size); + break; + } if (ABI_64_P (abfd) && intopt.kind == ODK_REGINFO) { Elf64_Internal_RegInfo intreg; @@ -4538,8 +5263,10 @@ bfd_boolean _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec) { register const char *name; + unsigned int sh_type; name = bfd_get_section_name (abfd, sec); + sh_type = hdr->sh_type; if (strcmp (name, ".liblist") == 0) { @@ -4612,7 +5339,7 @@ _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec) hdr->sh_flags |= SHF_MIPS_NOSTRIP; /* The sh_info field is set in final_write_processing. */ } - else if (strcmp (name, MIPS_ELF_OPTIONS_SECTION_NAME (abfd)) == 0) + else if (MIPS_ELF_OPTIONS_SECTION_NAME_P (name)) { hdr->sh_type = SHT_MIPS_OPTIONS; hdr->sh_entsize = 1; @@ -4641,6 +5368,12 @@ _bfd_mips_elf_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec) hdr->sh_entsize = 8; } + /* In the unlikely event a special section is empty it has to lose its + special meaning. This may happen e.g. when using `strip' with the + "--only-keep-debug" option. */ + if (sec->size > 0 && !(sec->flags & SEC_HAS_CONTENTS)) + hdr->sh_type = sh_type; + /* The generic elf_fake_sections will set up REL_HDR using the default kind of relocations. We used to set up a second header for the non-default kind of relocations here, but only NewABI would use @@ -4691,6 +5424,20 @@ _bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info, return TRUE; } + /* Shared objects may have a dynamic symbol '_gp_disp' defined as + a SECTION *ABS*. This causes ld to think it can resolve _gp_disp + by setting a DT_NEEDED for the shared object. Since _gp_disp is + a magic symbol resolved by the linker, we ignore this bogus definition + of _gp_disp. New ABI objects do not suffer from this problem so this + is not done for them. */ + if (!NEWABI_P(abfd) + && (sym->st_shndx == SHN_ABS) + && (strcmp (*namep, "_gp_disp") == 0)) + { + *namep = NULL; + return TRUE; + } + switch (sym->st_shndx) { case SHN_COMMON: @@ -4884,9 +5631,10 @@ _bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) if (bfd_get_section_by_name (abfd, MIPS_ELF_STUB_SECTION_NAME (abfd)) == NULL) { - s = bfd_make_section (abfd, MIPS_ELF_STUB_SECTION_NAME (abfd)); + s = bfd_make_section_with_flags (abfd, + MIPS_ELF_STUB_SECTION_NAME (abfd), + flags | SEC_CODE); if (s == NULL - || ! bfd_set_section_flags (abfd, s, flags | SEC_CODE) || ! bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd))) return FALSE; @@ -4896,9 +5644,9 @@ _bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) && !info->shared && bfd_get_section_by_name (abfd, ".rld_map") == NULL) { - s = bfd_make_section (abfd, ".rld_map"); + s = bfd_make_section_with_flags (abfd, ".rld_map", + flags &~ (flagword) SEC_READONLY); if (s == NULL - || ! bfd_set_section_flags (abfd, s, flags &~ (flagword) SEC_READONLY) || ! bfd_set_section_alignment (abfd, s, MIPS_ELF_LOG_FILE_ALIGN (abfd))) return FALSE; @@ -5126,6 +5874,10 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, h = ((struct mips_elf_link_hash_entry *) sym_hashes[r_symndx - extsymoff]); + while (h->root.root.type == bfd_link_hash_indirect + || h->root.root.type == bfd_link_hash_warning) + h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link; + /* H is the symbol this stub is for. */ h->fn_stub = sec; @@ -5251,6 +6003,9 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_MIPS_GOT_PAGE: case R_MIPS_GOT_OFST: case R_MIPS_GOT_DISP: + case R_MIPS_TLS_GOTTPREL: + 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)) @@ -5284,7 +6039,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, 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; } @@ -5306,7 +6061,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, 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 @@ -5343,11 +6098,52 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, 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: @@ -5400,7 +6196,7 @@ _bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, 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; } } @@ -5766,6 +6562,7 @@ _bfd_mips_elf_always_size_sections (bfd *output_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"); @@ -5834,9 +6631,30 @@ _bfd_mips_elf_always_size_sections (bfd *output_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; } @@ -5875,7 +6693,6 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd, for (s = dynobj->sections; s != NULL; s = s->next) { const char *name; - bfd_boolean strip; /* It's OK to base decisions on the section name, because none of the dynobj section names depend upon the input files. */ @@ -5884,24 +6701,9 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd, if ((s->flags & SEC_LINKER_CREATED) == 0) continue; - strip = FALSE; - if (strncmp (name, ".rel", 4) == 0) { - if (s->size == 0) - { - /* We only strip the section if the output section name - has the same name. Otherwise, there might be several - input sections for this output section. FIXME: This - code is probably not needed these days anyhow, since - the linker now does not create empty output sections. */ - if (s->output_section != NULL - && strcmp (name, - bfd_get_section_name (s->output_section->owner, - s->output_section)) == 0) - strip = TRUE; - } - else + if (s->size != 0) { const char *outname; asection *target; @@ -5951,6 +6753,9 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_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) { @@ -5976,13 +6781,28 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_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) { @@ -6007,15 +6827,18 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd, continue; } - if (strip) + if (s->size == 0) { - _bfd_strip_section_from_output (info, s); + s->flags |= SEC_EXCLUDE; continue; } + if ((s->flags & SEC_HAS_CONTENTS) == 0) + continue; + /* Allocate memory for the section contents. */ s->contents = bfd_zalloc (dynobj, s->size); - if (s->contents == NULL && s->size != 0) + if (s->contents == NULL) { bfd_set_error (bfd_error_no_memory); return FALSE; @@ -6081,22 +6904,6 @@ _bfd_mips_elf_size_dynamic_sections (bfd *output_bfd, if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_FLAGS, 0)) return FALSE; -#if 0 - /* Time stamps in executable files are a bad idea. */ - if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_TIME_STAMP, 0)) - return FALSE; -#endif - -#if 0 /* FIXME */ - if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_ICHECKSUM, 0)) - return FALSE; -#endif - -#if 0 /* FIXME */ - if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_IVERSION, 0)) - return FALSE; -#endif - if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_BASE_ADDRESS, 0)) return FALSE; @@ -6146,7 +6953,7 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, for (rel = relocs; rel < relend; ++rel) { const char *name; - bfd_vma value; + bfd_vma value = 0; reloc_howto_type *howto; bfd_boolean require_jalx; /* TRUE if the relocation is a RELA relocation, rather than a @@ -6195,18 +7002,25 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, rel_hdr = elf_section_data (input_section)->rel_hdr2; if (rel_hdr->sh_entsize == MIPS_ELF_REL_SIZE (input_bfd)) { + bfd_byte *location = contents + rel->r_offset; + /* Note that this is a REL relocation. */ rela_relocation_p = FALSE; /* Get the addend, which is stored in the input file. */ + _bfd_mips16_elf_reloc_unshuffle (input_bfd, r_type, FALSE, + location); addend = mips_elf_obtain_contents (howto, rel, input_bfd, contents); + _bfd_mips16_elf_reloc_shuffle(input_bfd, r_type, FALSE, + location); + addend &= howto->src_mask; /* For some kinds of relocations, the ADDEND is a combination of the addend stored in two different relocations. */ - if (r_type == R_MIPS_HI16 + if (r_type == R_MIPS_HI16 || r_type == R_MIPS16_HI16 || (r_type == R_MIPS_GOT16 && mips_elf_local_relocation_p (input_bfd, rel, local_sections, FALSE))) @@ -6214,6 +7028,13 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, bfd_vma l; const Elf_Internal_Rela *lo16_relocation; reloc_howto_type *lo16_howto; + bfd_byte *lo16_location; + int lo16_type; + + if (r_type == R_MIPS16_HI16) + lo16_type = R_MIPS16_LO16; + else + lo16_type = R_MIPS_LO16; /* The combined value is the sum of the HI16 addend, left-shifted by sixteen bits, and the LO16 @@ -6232,16 +7053,22 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, as one of these. We permit a similar extension in general, as that is useful for GCC. */ lo16_relocation = mips_elf_next_relocation (input_bfd, - R_MIPS_LO16, + lo16_type, rel, relend); if (lo16_relocation == NULL) return FALSE; + lo16_location = contents + lo16_relocation->r_offset; + /* Obtain the addend kept there. */ lo16_howto = MIPS_ELF_RTYPE_TO_HOWTO (input_bfd, - R_MIPS_LO16, FALSE); + lo16_type, FALSE); + _bfd_mips16_elf_reloc_unshuffle (input_bfd, lo16_type, FALSE, + lo16_location); l = mips_elf_obtain_contents (lo16_howto, lo16_relocation, input_bfd, contents); + _bfd_mips16_elf_reloc_shuffle (input_bfd, lo16_type, FALSE, + lo16_location); l &= lo16_howto->src_mask; l <<= lo16_howto->rightshift; l = _bfd_mips_elf_sign_extend (l, 16); @@ -6251,15 +7078,6 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, /* Compute the combined addend. */ addend += l; } - else if (r_type == R_MIPS16_GPREL) - { - /* The addend is scrambled in the object file. See - mips_elf_perform_relocation for details on the - format. */ - addend = (((addend & 0x1f0000) >> 5) - | ((addend & 0x7e00000) >> 16) - | (addend & 0x1f)); - } else addend <<= howto->rightshift; } @@ -6572,7 +7390,7 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd, MIPS_ELF_STUB_SECTION_NAME (dynobj)); BFD_ASSERT (s != NULL); - /* FIXME: Can h->dynindex be more than 64K? */ + /* FIXME: Can h->dynindx be more than 64K? */ if (h->dynindx & 0xffff0000) return FALSE; @@ -6614,11 +7432,11 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_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; @@ -6629,6 +7447,7 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_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) { @@ -6673,7 +7492,7 @@ _bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd, /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ name = h->root.root.string; if (strcmp (name, "_DYNAMIC") == 0 - || strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0) + || h == elf_hash_table (info)->hgot) sym->st_shndx = SHN_ABS; else if (strcmp (name, "_DYNAMIC_LINK") == 0 || strcmp (name, "_DYNAMIC_LINKING") == 0) @@ -6830,7 +7649,11 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd, break; case DT_MIPS_TIME_STAMP: - time ((time_t *) &dyn.d_un.d_val); + { + time_t t; + time (&t); + dyn.d_un.d_val = t; + } break; case DT_MIPS_ICHECKSUM: @@ -6893,18 +7716,6 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd, dyn.d_un.d_ptr = s->vma; break; - case DT_RELSZ: - /* Reduce DT_RELSZ to account for any relocations we - decided not to make. This is for the n64 irix rld, - which doesn't seem to apply any relocations if there - are trailing null entries. */ - s = mips_elf_rel_dyn_section (dynobj, FALSE); - dyn.d_un.d_val = (s->reloc_count - * (ABI_64_P (output_bfd) - ? sizeof (Elf64_Mips_External_Rel) - : sizeof (Elf32_External_Rel))); - break; - default: swap_out_p = FALSE; break; @@ -6941,7 +7752,8 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd, 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)); @@ -6965,6 +7777,55 @@ _bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd, } } + /* The generation of dynamic relocations for the non-primary gots + adds more dynamic relocations. We cannot count them until + here. */ + + if (elf_hash_table (info)->dynamic_sections_created) + { + bfd_byte *b; + bfd_boolean swap_out_p; + + BFD_ASSERT (sdyn != NULL); + + for (b = sdyn->contents; + b < sdyn->contents + sdyn->size; + b += MIPS_ELF_DYN_SIZE (dynobj)) + { + Elf_Internal_Dyn dyn; + asection *s; + + /* Read in the current dynamic entry. */ + (*get_elf_backend_data (dynobj)->s->swap_dyn_in) (dynobj, b, &dyn); + + /* Assume that we're going to modify it and write it out. */ + swap_out_p = TRUE; + + switch (dyn.d_tag) + { + case DT_RELSZ: + /* Reduce DT_RELSZ to account for any relocations we + decided not to make. This is for the n64 irix rld, + which doesn't seem to apply any relocations if there + are trailing null entries. */ + s = mips_elf_rel_dyn_section (dynobj, FALSE); + dyn.d_un.d_val = (s->reloc_count + * (ABI_64_P (output_bfd) + ? sizeof (Elf64_Mips_External_Rel) + : sizeof (Elf32_External_Rel))); + break; + + default: + swap_out_p = FALSE; + break; + } + + if (swap_out_p) + (*get_elf_backend_data (dynobj)->s->swap_dyn_out) + (dynobj, &dyn, b); + } + } + { asection *s; Elf32_compact_rel cpt; @@ -7080,6 +7941,10 @@ mips_set_isa_flags (bfd *abfd) val = E_MIPS_ARCH_4 | E_MIPS_MACH_5500; break; + case bfd_mach_mips9000: + val = E_MIPS_ARCH_4 | E_MIPS_MACH_9000; + break; + case bfd_mach_mips5000: case bfd_mach_mips7000: case bfd_mach_mips8000: @@ -7533,13 +8398,13 @@ _bfd_mips_elf_gc_sweep_hook (bfd *abfd ATTRIBUTE_UNUSED, _bfd_elf_link_hash_copy_indirect copy the flags for us. */ void -_bfd_mips_elf_copy_indirect_symbol (const struct elf_backend_data *bed, +_bfd_mips_elf_copy_indirect_symbol (struct bfd_link_info *info, struct elf_link_hash_entry *dir, struct elf_link_hash_entry *ind) { struct mips_elf_link_hash_entry *dirmips, *indmips; - _bfd_elf_link_hash_copy_indirect (bed, dir, ind); + _bfd_elf_link_hash_copy_indirect (info, dir, ind); if (ind->root.type != bfd_link_hash_indirect) return; @@ -7551,6 +8416,9 @@ _bfd_mips_elf_copy_indirect_symbol (const struct elf_backend_data *bed, 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; } void @@ -7569,11 +8437,10 @@ _bfd_mips_elf_hide_symbol (struct bfd_link_info *info, 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)) != NULL + && (g = mips_elf_section_data (got)->u.got_info) != NULL) { - got = mips_elf_got_section (dynobj, FALSE); - g = mips_elf_section_data (got)->u.got_info; - if (g->next) { struct mips_got_entry e; @@ -7587,6 +8454,7 @@ _bfd_mips_elf_hide_symbol (struct bfd_link_info *info, 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)) @@ -7833,6 +8701,20 @@ _bfd_mips_elf_find_nearest_line (bfd *abfd, asection *section, filename_ptr, functionname_ptr, line_ptr); } + +bfd_boolean +_bfd_mips_elf_find_inliner_info (bfd *abfd, + const char **filename_ptr, + const char **functionname_ptr, + unsigned int *line_ptr) +{ + bfd_boolean found; + found = _bfd_dwarf2_find_inliner_info (abfd, filename_ptr, + functionname_ptr, line_ptr, + & elf_tdata (abfd)->dwarf2_find_line_info); + return found; +} + /* When are writing out the .options or .MIPS.options section, remember the bytes we are writing out, so that we can install the @@ -7843,7 +8725,7 @@ _bfd_mips_elf_set_section_contents (bfd *abfd, sec_ptr section, const void *location, file_ptr offset, bfd_size_type count) { - if (strcmp (section->name, MIPS_ELF_OPTIONS_SECTION_NAME (abfd)) == 0) + if (MIPS_ELF_OPTIONS_SECTION_NAME_P (section->name)) { bfd_byte *c; @@ -7966,30 +8848,21 @@ _bfd_elf_mips_get_relocated_section_contents /* Specific to MIPS: Deal with relocation types that require knowing the gp of the output bfd. */ asymbol *sym = *(*parent)->sym_ptr_ptr; - if (bfd_is_abs_section (sym->section) && abfd) - { - /* The special_function wouldn't get called anyway. */ - } - else if (!gp_found) - { - /* The gp isn't there; let the special function code - fall over on its own. */ - } - else if ((*parent)->howto->special_function - == _bfd_mips_elf32_gprel16_reloc) - { - /* bypass special_function call */ - r = _bfd_mips_elf_gprel16_with_gp (input_bfd, sym, *parent, - input_section, relocatable, - data, gp); - goto skip_bfd_perform_relocation; - } - /* end mips specific stuff */ - r = bfd_perform_relocation (input_bfd, *parent, data, input_section, - relocatable ? abfd : NULL, - &error_message); - skip_bfd_perform_relocation: + /* If we've managed to find the gp and have a special + function for the relocation then go ahead, else default + to the generic handling. */ + if (gp_found + && (*parent)->howto->special_function + == _bfd_mips_elf32_gprel16_reloc) + r = _bfd_mips_elf_gprel16_with_gp (input_bfd, sym, *parent, + input_section, relocatable, + data, gp); + else + r = bfd_perform_relocation (input_bfd, *parent, data, + input_section, + relocatable ? abfd : NULL, + &error_message); if (relocatable) { @@ -8007,8 +8880,7 @@ _bfd_elf_mips_get_relocated_section_contents case bfd_reloc_undefined: if (!((*link_info->callbacks->undefined_symbol) (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr), - input_bfd, input_section, (*parent)->address, - TRUE))) + input_bfd, input_section, (*parent)->address, TRUE))) goto error_return; break; case bfd_reloc_dangerous: @@ -8085,7 +8957,6 @@ _bfd_mips_elf_link_hash_table_create (bfd *abfd) bfd_boolean _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info) { - asection **secpp; asection *o; struct bfd_link_order *p; asection *reginfo_sec, *mdebug_sec, *gptab_data_sec, *gptab_bss_sec; @@ -8141,7 +9012,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info) && !(*bed->elf_backend_omit_section_dynsym) (abfd, info, p)) ++ dynsecsymcount; } - + if (! mips_elf_sort_hash_table (info, dynsecsymcount + 1)) return FALSE; @@ -8156,47 +9027,6 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info) <= g->global_gotno); } -#if 0 - /* We want to set the GP value for ld -r. */ - /* On IRIX5, we omit the .options section. On IRIX6, however, we - include it, even though we don't process it quite right. (Some - entries are supposed to be merged.) Empirically, we seem to be - better off including it then not. */ - if (IRIX_COMPAT (abfd) == ict_irix5 || IRIX_COMPAT (abfd) == ict_none) - for (secpp = &abfd->sections; *secpp != NULL; secpp = &(*secpp)->next) - { - if (strcmp ((*secpp)->name, MIPS_ELF_OPTIONS_SECTION_NAME (abfd)) == 0) - { - for (p = (*secpp)->link_order_head; p != NULL; p = p->next) - if (p->type == bfd_indirect_link_order) - p->u.indirect.section->flags &= ~SEC_HAS_CONTENTS; - (*secpp)->link_order_head = NULL; - bfd_section_list_remove (abfd, secpp); - --abfd->section_count; - - break; - } - } - - /* We include .MIPS.options, even though we don't process it quite right. - (Some entries are supposed to be merged.) At IRIX6 empirically we seem - to be better off including it than not. */ - for (secpp = &abfd->sections; *secpp != NULL; secpp = &(*secpp)->next) - { - if (strcmp ((*secpp)->name, ".MIPS.options") == 0) - { - for (p = (*secpp)->link_order_head; p != NULL; p = p->next) - if (p->type == bfd_indirect_link_order) - p->u.indirect.section->flags &=~ SEC_HAS_CONTENTS; - (*secpp)->link_order_head = NULL; - bfd_section_list_remove (abfd, secpp); - --abfd->section_count; - - break; - } - } -#endif - /* Get a value for the GP register. */ if (elf_gp (abfd) == 0) { @@ -8243,7 +9073,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info) /* We have found the .reginfo section in the output file. Look through all the link_orders comprising it and merge the information together. */ - for (p = o->link_order_head; p != NULL; p = p->next) + for (p = o->map_head.link_order; p != NULL; p = p->next) { asection *input_section; bfd *input_bfd; @@ -8286,7 +9116,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info) /* Skip this section later on (I don't think this currently matters, but someday it might). */ - o->link_order_head = NULL; + o->map_head.link_order = NULL; reginfo_sec = o; } @@ -8359,7 +9189,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info) return FALSE; } - for (p = o->link_order_head; p != NULL; p = p->next) + for (p = o->map_head.link_order; p != NULL; p = p->next) { asection *input_section; bfd *input_bfd; @@ -8470,9 +9300,10 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info) flagword flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED | SEC_READONLY); - rtproc_sec = bfd_make_section (abfd, ".rtproc"); + rtproc_sec = bfd_make_section_with_flags (abfd, + ".rtproc", + flags); if (rtproc_sec == NULL - || ! bfd_set_section_flags (abfd, rtproc_sec, flags) || ! bfd_set_section_alignment (abfd, rtproc_sec, 4)) return FALSE; } @@ -8499,7 +9330,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info) /* Skip this section later on (I don't think this currently matters, but someday it might). */ - o->link_order_head = NULL; + o->map_head.link_order = NULL; mdebug_sec = o; } @@ -8518,7 +9349,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info) not used in executables files. */ if (! info->relocatable) { - for (p = o->link_order_head; p != NULL; p = p->next) + for (p = o->map_head.link_order; p != NULL; p = p->next) { asection *input_section; @@ -8538,14 +9369,10 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info) /* Skip this section later on (I don't think this currently matters, but someday it might). */ - o->link_order_head = NULL; + o->map_head.link_order = NULL; /* Really remove the section. */ - for (secpp = &abfd->sections; - *secpp != o; - secpp = &(*secpp)->next) - ; - bfd_section_list_remove (abfd, secpp); + bfd_section_list_remove (abfd, o); --abfd->section_count; continue; @@ -8592,7 +9419,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info) tab[0].gt_header.gt_unused = 0; /* Combine the input sections. */ - for (p = o->link_order_head; p != NULL; p = p->next) + for (p = o->map_head.link_order; p != NULL; p = p->next) { asection *input_section; bfd *input_bfd; @@ -8715,7 +9542,7 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info) /* Skip this section later on (I don't think this currently matters, but someday it might). */ - o->link_order_head = NULL; + o->map_head.link_order = NULL; } } @@ -8810,6 +9637,7 @@ static const struct mips_mach_extension mips_mach_extensions[] = { { bfd_mach_mips10000, bfd_mach_mips8000 }, { bfd_mach_mips5000, bfd_mach_mips8000 }, { bfd_mach_mips7000, bfd_mach_mips8000 }, + { bfd_mach_mips9000, bfd_mach_mips8000 }, /* VR4100 extensions. */ { bfd_mach_mips4120, bfd_mach_mips4100 }, @@ -8844,11 +9672,26 @@ mips_mach_extends_p (unsigned long base, unsigned long extension) { size_t i; - for (i = 0; extension != base && i < ARRAY_SIZE (mips_mach_extensions); i++) + if (extension == base) + return TRUE; + + if (base == bfd_mach_mipsisa32 + && mips_mach_extends_p (bfd_mach_mipsisa64, extension)) + return TRUE; + + if (base == bfd_mach_mipsisa32r2 + && mips_mach_extends_p (bfd_mach_mipsisa64r2, extension)) + return TRUE; + + for (i = 0; i < ARRAY_SIZE (mips_mach_extensions); i++) if (extension == mips_mach_extensions[i].extension) - extension = mips_mach_extensions[i].base; + { + extension = mips_mach_extensions[i].base; + if (extension == base) + return TRUE; + } - return extension == base; + return FALSE; } @@ -9153,13 +9996,34 @@ _bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr) return TRUE; } -struct bfd_elf_special_section const _bfd_mips_elf_special_sections[]= +const struct bfd_elf_special_section _bfd_mips_elf_special_sections[] = { - { ".sdata", 6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL }, - { ".sbss", 5, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL }, { ".lit4", 5, 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL }, { ".lit8", 5, 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL }, - { ".ucode", 6, 0, SHT_MIPS_UCODE, 0 }, { ".mdebug", 7, 0, SHT_MIPS_DEBUG, 0 }, + { ".sbss", 5, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL }, + { ".sdata", 6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL }, + { ".ucode", 6, 0, SHT_MIPS_UCODE, 0 }, { NULL, 0, 0, 0, 0 } }; + +/* Ensure that the STO_OPTIONAL flag is copied into h->other, + even if this is not a defintion of the symbol. */ +void +_bfd_mips_elf_merge_symbol_attribute (struct elf_link_hash_entry *h, + const Elf_Internal_Sym *isym, + bfd_boolean definition, + bfd_boolean dynamic ATTRIBUTE_UNUSED) +{ + if (! definition + && ELF_MIPS_IS_OPTIONAL (isym->st_other)) + h->other |= STO_OPTIONAL; +} + +/* Decide whether an undefined symbol is special and can be ignored. + This is the case for OPTIONAL symbols on IRIX. */ +bfd_boolean +_bfd_mips_elf_ignore_undef_symbol (struct elf_link_hash_entry *h) +{ + return ELF_MIPS_IS_OPTIONAL (h->other) ? TRUE : FALSE; +}