X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felfxx-mips.c;h=9bae5d58378349261c9beef049416c1119d18270;hb=0bf60745767d2465c81ee57ae7705a62d6d8fafe;hp=bef1c79b5e0b9834bd895dedf1bac4e44e29e697;hpb=fdd07405582d22ef5ceb04fe805e5c32dc9ca12e;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c index bef1c79b5e..9bae5d5837 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 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 @@ -188,10 +220,6 @@ struct mips_elf_link_hash_entry a readonly section. */ bfd_boolean readonly_reloc; - /* The index of the first dynamic relocation (in the .rel.dyn - section) against this symbol. */ - unsigned int min_dyn_reloc_index; - /* We must not create a stub for a symbol that has relocations related to taking the function's address, i.e. any but R_MIPS_CALL*16 ones -- see "MIPS ABI Supplement, 3rd Edition", @@ -214,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. */ @@ -241,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 @@ -373,123 +432,25 @@ typedef struct runtime_pdr { #define cbRPDR sizeof (RPDR) #define rpdNil ((pRPDR) 0) -static struct bfd_hash_entry *mips_elf_link_hash_newfunc - PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); -static void ecoff_swap_rpdr_out - PARAMS ((bfd *, const RPDR *, struct rpdr_ext *)); -static bfd_boolean mips_elf_create_procedure_table - PARAMS ((PTR, bfd *, struct bfd_link_info *, asection *, - struct ecoff_debug_info *)); -static bfd_boolean mips_elf_check_mips16_stubs - PARAMS ((struct mips_elf_link_hash_entry *, PTR)); -static void bfd_mips_elf32_swap_gptab_in - PARAMS ((bfd *, const Elf32_External_gptab *, Elf32_gptab *)); -static void bfd_mips_elf32_swap_gptab_out - PARAMS ((bfd *, const Elf32_gptab *, Elf32_External_gptab *)); -static void bfd_elf32_swap_compact_rel_out - PARAMS ((bfd *, const Elf32_compact_rel *, Elf32_External_compact_rel *)); -static void bfd_elf32_swap_crinfo_out - PARAMS ((bfd *, const Elf32_crinfo *, Elf32_External_crinfo *)); -#if 0 -static void bfd_mips_elf_swap_msym_in - PARAMS ((bfd *, const Elf32_External_Msym *, Elf32_Internal_Msym *)); -#endif -static void bfd_mips_elf_swap_msym_out - PARAMS ((bfd *, const Elf32_Internal_Msym *, Elf32_External_Msym *)); -static int sort_dynamic_relocs - PARAMS ((const void *, const void *)); -static int sort_dynamic_relocs_64 - PARAMS ((const void *, const void *)); -static bfd_boolean mips_elf_output_extsym - PARAMS ((struct mips_elf_link_hash_entry *, PTR)); -static int gptab_compare PARAMS ((const void *, const void *)); -static asection * mips_elf_rel_dyn_section PARAMS ((bfd *, bfd_boolean)); -static asection * mips_elf_got_section PARAMS ((bfd *, bfd_boolean)); -static struct mips_got_info *mips_elf_got_info - PARAMS ((bfd *, asection **)); -static long mips_elf_get_global_gotsym_index PARAMS ((bfd *abfd)); -static bfd_vma mips_elf_local_got_index - PARAMS ((bfd *, bfd *, struct bfd_link_info *, bfd_vma)); -static bfd_vma mips_elf_global_got_index - PARAMS ((bfd *, bfd *, struct elf_link_hash_entry *)); -static bfd_vma mips_elf_got_page - PARAMS ((bfd *, bfd *, struct bfd_link_info *, bfd_vma, bfd_vma *)); -static bfd_vma mips_elf_got16_entry - PARAMS ((bfd *, bfd *, struct bfd_link_info *, bfd_vma, bfd_boolean)); -static bfd_vma mips_elf_got_offset_from_index - PARAMS ((bfd *, bfd *, bfd *, bfd_vma)); static struct mips_got_entry *mips_elf_create_local_got_entry - PARAMS ((bfd *, bfd *, struct mips_got_info *, asection *, bfd_vma)); -static bfd_boolean mips_elf_sort_hash_table - PARAMS ((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 - PARAMS ((struct mips_elf_link_hash_entry *, PTR)); -static bfd_boolean mips_elf_record_local_got_symbol - PARAMS ((bfd *, long, bfd_vma, struct mips_got_info *)); -static bfd_boolean mips_elf_record_global_got_symbol - PARAMS ((struct elf_link_hash_entry *, bfd *, struct bfd_link_info *, - struct mips_got_info *)); -static const Elf_Internal_Rela *mips_elf_next_relocation - PARAMS ((bfd *, unsigned int, const Elf_Internal_Rela *, - const Elf_Internal_Rela *)); -static bfd_boolean mips_elf_local_relocation_p - PARAMS ((bfd *, const Elf_Internal_Rela *, asection **, bfd_boolean)); -static bfd_boolean mips_elf_overflow_p PARAMS ((bfd_vma, int)); -static bfd_vma mips_elf_high PARAMS ((bfd_vma)); -static bfd_vma mips_elf_higher PARAMS ((bfd_vma)); -static bfd_vma mips_elf_highest PARAMS ((bfd_vma)); -static bfd_boolean mips_elf_create_compact_rel_section - PARAMS ((bfd *, struct bfd_link_info *)); -static bfd_boolean mips_elf_create_got_section - PARAMS ((bfd *, struct bfd_link_info *, bfd_boolean)); -static asection *mips_elf_create_msym_section - PARAMS ((bfd *)); -static bfd_reloc_status_type mips_elf_calculate_relocation - PARAMS ((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 - PARAMS ((reloc_howto_type *, const Elf_Internal_Rela *, bfd *, bfd_byte *)); -static bfd_boolean mips_elf_perform_relocation - PARAMS ((struct bfd_link_info *, reloc_howto_type *, - const Elf_Internal_Rela *, bfd_vma, bfd *, asection *, bfd_byte *, - bfd_boolean)); + (struct mips_elf_link_hash_entry *, void *); +static bfd_vma mips_elf_high + (bfd_vma); static bfd_boolean mips_elf_stub_section_p - PARAMS ((bfd *, asection *)); -static void mips_elf_allocate_dynamic_relocations - PARAMS ((bfd *, unsigned int)); + (bfd *, asection *); static bfd_boolean mips_elf_create_dynamic_relocation - PARAMS ((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 PARAMS ((bfd *)); -static INLINE char* elf_mips_abi_name PARAMS ((bfd *)); -static void mips_elf_irix6_finish_dynamic_symbol - PARAMS ((bfd *, const char *, Elf_Internal_Sym *)); -static bfd_boolean mips_mach_extends_p PARAMS ((unsigned long, unsigned long)); -static bfd_boolean mips_32bit_flags_p PARAMS ((flagword)); -static INLINE hashval_t mips_elf_hash_bfd_vma PARAMS ((bfd_vma)); -static hashval_t mips_elf_got_entry_hash PARAMS ((const PTR)); -static int mips_elf_got_entry_eq PARAMS ((const PTR, const PTR)); - -static bfd_boolean mips_elf_multi_got - PARAMS ((bfd *, struct bfd_link_info *, struct mips_got_info *, - asection *, bfd_size_type)); -static hashval_t mips_elf_multi_got_entry_hash PARAMS ((const PTR)); -static int mips_elf_multi_got_entry_eq PARAMS ((const PTR, const PTR)); -static hashval_t mips_elf_bfd2got_entry_hash PARAMS ((const PTR)); -static int mips_elf_bfd2got_entry_eq PARAMS ((const PTR, const PTR)); -static int mips_elf_make_got_per_bfd PARAMS ((void **, void *)); -static int mips_elf_merge_gots PARAMS ((void **, void *)); -static int mips_elf_set_global_got_offset PARAMS ((void**, void *)); -static int mips_elf_resolve_final_got_entry PARAMS ((void**, void *)); -static void mips_elf_resolve_final_got_entries - PARAMS ((struct mips_got_info *)); + (bfd *, struct bfd_link_info *, const Elf_Internal_Rela *, + struct mips_elf_link_hash_entry *, asection *, bfd_vma, + bfd_vma *, asection *); +static hashval_t mips_elf_got_entry_hash + (const void *); static bfd_vma mips_elf_adjust_gp - PARAMS ((bfd *, struct mips_got_info *, bfd *)); + (bfd *, struct mips_got_info *, bfd *); static struct mips_got_info *mips_elf_got_for_ibfd - PARAMS ((struct mips_got_info *, bfd *)); + (struct mips_got_info *, bfd *); /* This will be used when we sort the dynamic relocation records. */ static bfd *reldyn_sorting_bfd; @@ -518,9 +479,13 @@ 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) \ - (NEWABI_P (abfd) ? ".MIPS.stubs" : ".stub") +#define MIPS_ELF_STUB_SECTION_NAME(abfd) ".MIPS.stubs" /* The size of an external REL relocation. */ #define MIPS_ELF_REL_SIZE(abfd) \ @@ -553,17 +518,8 @@ static bfd *reldyn_sorting_bfd; : bfd_put_32 (abfd, val, ptr)) /* Add a dynamic symbol table-entry. */ -#ifdef BFD64 -#define MIPS_ELF_ADD_DYNAMIC_ENTRY(info, tag, val) \ - (ABI_64_P (elf_hash_table (info)->dynobj) \ - ? bfd_elf64_add_dynamic_entry (info, (bfd_vma) tag, (bfd_vma) val) \ - : bfd_elf32_add_dynamic_entry (info, (bfd_vma) tag, (bfd_vma) val)) -#else -#define MIPS_ELF_ADD_DYNAMIC_ENTRY(info, tag, val) \ - (ABI_64_P (elf_hash_table (info)->dynobj) \ - ? (abort (), FALSE) \ - : bfd_elf32_add_dynamic_entry (info, (bfd_vma) tag, (bfd_vma) val)) -#endif +#define MIPS_ELF_ADD_DYNAMIC_ENTRY(info, tag, val) \ + _bfd_elf_add_dynamic_entry (info, tag, val) #define MIPS_ELF_RTYPE_TO_HOWTO(abfd, rtype, rela) \ (get_elf_backend_data (abfd)->elf_backend_mips_rtype_to_howto (rtype, rela)) @@ -588,6 +544,7 @@ static bfd *reldyn_sorting_bfd; /* In case we're on a 32-bit machine, construct a 64-bit "-1" value from smaller values. Start with zero, widen, *then* decrement. */ #define MINUS_ONE (((bfd_vma)0) - 1) +#define MINUS_TWO (((bfd_vma)0) - 2) /* The number of local .got entries we reserve. */ #define MIPS_RESERVED_GOTNO (2) @@ -599,17 +556,20 @@ static bfd *reldyn_sorting_bfd; offsets from $gp. */ #define MIPS_ELF_GOT_MAX_SIZE(abfd) (ELF_MIPS_GP_OFFSET(abfd) + 0x7fff) -/* Instructions which appear in a stub. For some reason the stub is - slightly different on an SGI system. */ +/* Instructions which appear in a stub. */ #define STUB_LW(abfd) \ ((ABI_64_P (abfd) \ ? 0xdf998010 /* ld t9,0x8010(gp) */ \ : 0x8f998010)) /* lw t9,0x8010(gp) */ #define STUB_MOVE(abfd) \ - (SGI_COMPAT (abfd) ? 0x03e07825 : 0x03e07821) /* move t7,ra */ -#define STUB_JALR 0x0320f809 /* jal t9 */ + ((ABI_64_P (abfd) \ + ? 0x03e0782d /* daddu t7,ra */ \ + : 0x03e07821)) /* addu t7,ra */ +#define STUB_JALR 0x0320f809 /* jalr t9,ra */ #define STUB_LI16(abfd) \ - (SGI_COMPAT (abfd) ? 0x34180000 : 0x24180000) /* ori t8,zero,0 */ + ((ABI_64_P (abfd) \ + ? 0x64180000 /* daddiu t8,zero,0 */ \ + : 0x24180000)) /* addiu t8,zero,0 */ #define MIPS_FUNCTION_STUB_SIZE (16) /* The name of the dynamic interpreter. This is put in the .interp @@ -689,7 +649,7 @@ static bfd *reldyn_sorting_bfd; #define mips_elf_link_hash_traverse(table, func, info) \ (elf_link_hash_traverse \ (&(table)->root, \ - (bfd_boolean (*) PARAMS ((struct elf_link_hash_entry *, PTR))) (func), \ + (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func), \ (info))) /* Get the MIPS ELF linker hash table from a link_info structure. */ @@ -697,31 +657,51 @@ 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 * -mips_elf_link_hash_newfunc (entry, table, string) - struct bfd_hash_entry *entry; - struct bfd_hash_table *table; - const char *string; +mips_elf_link_hash_newfunc (struct bfd_hash_entry *entry, + struct bfd_hash_table *table, const char *string) { struct mips_elf_link_hash_entry *ret = (struct mips_elf_link_hash_entry *) entry; /* Allocate the structure if it has not already been allocated by a subclass. */ - if (ret == (struct mips_elf_link_hash_entry *) NULL) - ret = ((struct mips_elf_link_hash_entry *) - bfd_hash_allocate (table, - sizeof (struct mips_elf_link_hash_entry))); - if (ret == (struct mips_elf_link_hash_entry *) NULL) + if (ret == NULL) + ret = bfd_hash_allocate (table, sizeof (struct mips_elf_link_hash_entry)); + if (ret == NULL) return (struct bfd_hash_entry *) ret; /* Call the allocation method of the superclass. */ ret = ((struct mips_elf_link_hash_entry *) _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, table, string)); - if (ret != (struct mips_elf_link_hash_entry *) NULL) + if (ret != NULL) { /* Set local fields. */ memset (&ret->esym, 0, sizeof (EXTR)); @@ -730,30 +710,28 @@ mips_elf_link_hash_newfunc (entry, table, string) ret->esym.ifd = -2; ret->possibly_dynamic_relocs = 0; ret->readonly_reloc = FALSE; - ret->min_dyn_reloc_index = 0; ret->no_fn_stub = FALSE; ret->fn_stub = NULL; ret->need_fn_stub = FALSE; ret->call_stub = NULL; ret->call_fp_stub = NULL; ret->forced_local = FALSE; + ret->tls_type = GOT_NORMAL; } return (struct bfd_hash_entry *) ret; } bfd_boolean -_bfd_mips_elf_new_section_hook (abfd, sec) - bfd *abfd; - asection *sec; +_bfd_mips_elf_new_section_hook (bfd *abfd, asection *sec) { struct _mips_elf_section_data *sdata; bfd_size_type amt = sizeof (*sdata); - sdata = (struct _mips_elf_section_data *) bfd_zalloc (abfd, amt); + sdata = bfd_zalloc (abfd, amt); if (sdata == NULL) return FALSE; - sec->used_by_bfd = (PTR) sdata; + sec->used_by_bfd = sdata; return _bfd_elf_new_section_hook (abfd, sec); } @@ -762,23 +740,21 @@ _bfd_mips_elf_new_section_hook (abfd, sec) ecoff_debug_info structure. */ bfd_boolean -_bfd_mips_elf_read_ecoff_info (abfd, section, debug) - bfd *abfd; - asection *section; - struct ecoff_debug_info *debug; +_bfd_mips_elf_read_ecoff_info (bfd *abfd, asection *section, + struct ecoff_debug_info *debug) { HDRR *symhdr; const struct ecoff_debug_swap *swap; - char *ext_hdr = NULL; + char *ext_hdr; swap = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap; memset (debug, 0, sizeof (*debug)); - ext_hdr = (char *) bfd_malloc (swap->external_hdr_size); + ext_hdr = bfd_malloc (swap->external_hdr_size); if (ext_hdr == NULL && swap->external_hdr_size != 0) goto error_return; - if (! bfd_get_section_contents (abfd, section, ext_hdr, (file_ptr) 0, + if (! bfd_get_section_contents (abfd, section, ext_hdr, 0, swap->external_hdr_size)) goto error_return; @@ -793,30 +769,29 @@ _bfd_mips_elf_read_ecoff_info (abfd, section, debug) else \ { \ bfd_size_type amt = (bfd_size_type) size * symhdr->count; \ - debug->ptr = (type) bfd_malloc (amt); \ + debug->ptr = bfd_malloc (amt); \ if (debug->ptr == NULL) \ goto error_return; \ - if (bfd_seek (abfd, (file_ptr) symhdr->offset, SEEK_SET) != 0 \ + if (bfd_seek (abfd, symhdr->offset, SEEK_SET) != 0 \ || bfd_bread (debug->ptr, amt, abfd) != amt) \ goto error_return; \ } READ (line, cbLineOffset, cbLine, sizeof (unsigned char), unsigned char *); - READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size, PTR); - READ (external_pdr, cbPdOffset, ipdMax, swap->external_pdr_size, PTR); - READ (external_sym, cbSymOffset, isymMax, swap->external_sym_size, PTR); - READ (external_opt, cbOptOffset, ioptMax, swap->external_opt_size, PTR); + READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size, void *); + READ (external_pdr, cbPdOffset, ipdMax, swap->external_pdr_size, void *); + READ (external_sym, cbSymOffset, isymMax, swap->external_sym_size, void *); + READ (external_opt, cbOptOffset, ioptMax, swap->external_opt_size, void *); READ (external_aux, cbAuxOffset, iauxMax, sizeof (union aux_ext), union aux_ext *); READ (ss, cbSsOffset, issMax, sizeof (char), char *); READ (ssext, cbSsExtOffset, issExtMax, sizeof (char), char *); - READ (external_fdr, cbFdOffset, ifdMax, swap->external_fdr_size, PTR); - READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size, PTR); - READ (external_ext, cbExtOffset, iextMax, swap->external_ext_size, PTR); + READ (external_fdr, cbFdOffset, ifdMax, swap->external_fdr_size, void *); + READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size, void *); + READ (external_ext, cbExtOffset, iextMax, swap->external_ext_size, void *); #undef READ debug->fdr = NULL; - debug->adjust = NULL; return TRUE; @@ -851,10 +826,7 @@ _bfd_mips_elf_read_ecoff_info (abfd, section, debug) /* Swap RPDR (runtime procedure table entry) for output. */ static void -ecoff_swap_rpdr_out (abfd, in, ex) - bfd *abfd; - const RPDR *in; - struct rpdr_ext *ex; +ecoff_swap_rpdr_out (bfd *abfd, const RPDR *in, struct rpdr_ext *ex) { H_PUT_S32 (abfd, in->adr, ex->p_adr); H_PUT_32 (abfd, in->regmask, ex->p_regmask); @@ -867,26 +839,20 @@ ecoff_swap_rpdr_out (abfd, in, 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. */ static bfd_boolean -mips_elf_create_procedure_table (handle, abfd, info, s, debug) - PTR handle; - bfd *abfd; - struct bfd_link_info *info; - asection *s; - struct ecoff_debug_info *debug; +mips_elf_create_procedure_table (void *handle, bfd *abfd, + struct bfd_link_info *info, asection *s, + struct ecoff_debug_info *debug) { const struct ecoff_debug_swap *swap; HDRR *hdr = &debug->symbolic_header; RPDR *rpdr, *rp; struct rpdr_ext *erp; - PTR rtproc; + void *rtproc; struct pdr_ext *epdr; struct sym_ext *esym; char *ss, **sv; @@ -913,44 +879,44 @@ mips_elf_create_procedure_table (handle, abfd, info, s, debug) { size = swap->external_pdr_size; - epdr = (struct pdr_ext *) bfd_malloc (size * count); + epdr = bfd_malloc (size * count); if (epdr == NULL) goto error_return; - if (! _bfd_ecoff_get_accumulated_pdr (handle, (PTR) epdr)) + if (! _bfd_ecoff_get_accumulated_pdr (handle, (bfd_byte *) epdr)) goto error_return; size = sizeof (RPDR); - rp = rpdr = (RPDR *) bfd_malloc (size * count); + rp = rpdr = bfd_malloc (size * count); if (rpdr == NULL) goto error_return; size = sizeof (char *); - sv = (char **) bfd_malloc (size * count); + sv = bfd_malloc (size * count); if (sv == NULL) goto error_return; count = hdr->isymMax; size = swap->external_sym_size; - esym = (struct sym_ext *) bfd_malloc (size * count); + esym = bfd_malloc (size * count); if (esym == NULL) goto error_return; - if (! _bfd_ecoff_get_accumulated_sym (handle, (PTR) esym)) + if (! _bfd_ecoff_get_accumulated_sym (handle, (bfd_byte *) esym)) goto error_return; count = hdr->issMax; - ss = (char *) bfd_malloc (count); + ss = bfd_malloc (count); if (ss == NULL) goto error_return; - if (! _bfd_ecoff_get_accumulated_ss (handle, (PTR) ss)) + if (! _bfd_ecoff_get_accumulated_ss (handle, (bfd_byte *) ss)) goto error_return; count = hdr->ipdMax; for (i = 0; i < (unsigned long) count; i++, rp++) { - (*swap->swap_pdr_in) (abfd, (PTR) (epdr + i), &pdr); - (*swap->swap_sym_in) (abfd, (PTR) &esym[pdr.isym], &sym); + (*swap->swap_pdr_in) (abfd, epdr + i, &pdr); + (*swap->swap_sym_in) (abfd, &esym[pdr.isym], &sym); rp->adr = sym.value; rp->regmask = pdr.regmask; rp->regoffset = pdr.regoffset; @@ -967,7 +933,7 @@ mips_elf_create_procedure_table (handle, abfd, info, s, debug) size = sizeof (struct rpdr_ext) * (count + 2) + sindex; size = BFD_ALIGN (size, 16); - rtproc = (PTR) bfd_alloc (abfd, size); + rtproc = bfd_alloc (abfd, size); if (rtproc == NULL) { mips_elf_hash_table (info)->procedure_count = 0; @@ -976,7 +942,7 @@ mips_elf_create_procedure_table (handle, abfd, info, s, debug) mips_elf_hash_table (info)->procedure_count = count + 2; - erp = (struct rpdr_ext *) rtproc; + erp = rtproc; memset (erp, 0, sizeof (struct rpdr_ext)); erp++; str = (char *) rtproc + sizeof (struct rpdr_ext) * (count + 2); @@ -991,12 +957,12 @@ mips_elf_create_procedure_table (handle, abfd, info, s, debug) H_PUT_S32 (abfd, -1, (erp + count)->p_adr); /* Set the size and contents of .rtproc section. */ - s->_raw_size = size; - s->contents = (bfd_byte *) rtproc; + s->size = size; + s->contents = rtproc; /* Skip this section later on (I don't think this currently matters, but someday it might). */ - s->link_order_head = (struct bfd_link_order *) NULL; + s->map_head.link_order = NULL; if (epdr != NULL) free (epdr); @@ -1029,9 +995,8 @@ mips_elf_create_procedure_table (handle, abfd, info, s, debug) discard them. */ static bfd_boolean -mips_elf_check_mips16_stubs (h, data) - struct mips_elf_link_hash_entry *h; - PTR data ATTRIBUTE_UNUSED; +mips_elf_check_mips16_stubs (struct mips_elf_link_hash_entry *h, + void *data ATTRIBUTE_UNUSED) { if (h->root.root.type == bfd_link_hash_warning) h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link; @@ -1042,8 +1007,7 @@ mips_elf_check_mips16_stubs (h, data) /* We don't need the fn_stub; the only references to this symbol are 16 bit calls. Clobber the size to 0 to prevent it from being included in the link. */ - h->fn_stub->_raw_size = 0; - h->fn_stub->_cooked_size = 0; + h->fn_stub->size = 0; h->fn_stub->flags &= ~SEC_RELOC; h->fn_stub->reloc_count = 0; h->fn_stub->flags |= SEC_EXCLUDE; @@ -1055,8 +1019,7 @@ mips_elf_check_mips16_stubs (h, data) /* We don't need the call_stub; this is a 16 bit function, so calls from other 16 bit functions are OK. Clobber the size to 0 to prevent it from being included in the link. */ - h->call_stub->_raw_size = 0; - h->call_stub->_cooked_size = 0; + h->call_stub->size = 0; h->call_stub->flags &= ~SEC_RELOC; h->call_stub->reloc_count = 0; h->call_stub->flags |= SEC_EXCLUDE; @@ -1068,8 +1031,7 @@ mips_elf_check_mips16_stubs (h, data) /* We don't need the call_stub; this is a 16 bit function, so calls from other 16 bit functions are OK. Clobber the size to 0 to prevent it from being included in the link. */ - h->call_fp_stub->_raw_size = 0; - h->call_fp_stub->_cooked_size = 0; + h->call_fp_stub->size = 0; h->call_fp_stub->flags &= ~SEC_RELOC; h->call_fp_stub->reloc_count = 0; h->call_fp_stub->flags |= SEC_EXCLUDE; @@ -1078,20 +1040,160 @@ mips_elf_check_mips16_stubs (h, data) 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 (abfd, symbol, reloc_entry, input_section, - relocatable, data, gp) - bfd *abfd; - asymbol *symbol; - arelent *reloc_entry; - asection *input_section; - bfd_boolean relocatable; - PTR data; - bfd_vma gp; +_bfd_mips_elf_gprel16_with_gp (bfd *abfd, asymbol *symbol, + arelent *reloc_entry, asection *input_section, + bfd_boolean relocatable, void *data, bfd_vma gp) { bfd_vma relocation; - unsigned long insn = 0; bfd_signed_vma val; + bfd_reloc_status_type status; if (bfd_is_com_section (symbol->section)) relocation = 0; @@ -1101,19 +1203,13 @@ _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry, input_section, relocation += symbol->section->output_section->vma; relocation += symbol->section->output_offset; - if (reloc_entry->address > input_section->_cooked_size) + if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) return bfd_reloc_outofrange; /* Set val to the offset into the section or symbol. */ val = reloc_entry->addend; - if (reloc_entry->howto->partial_inplace) - { - insn = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); - val += insn & 0xffff; - } - - _bfd_mips_elf_sign_extend(val, 16); + _bfd_mips_elf_sign_extend (val, 16); /* Adjust val for the final section location and GP value. If we are producing relocatable output, we don't want to do this for @@ -1124,17 +1220,220 @@ _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry, input_section, if (reloc_entry->howto->partial_inplace) { - insn = (insn & ~0xffff) | (val & 0xffff); - bfd_put_32 (abfd, (bfd_vma) insn, - (bfd_byte *) data + reloc_entry->address); + status = _bfd_relocate_contents (reloc_entry->howto, abfd, val, + (bfd_byte *) data + + reloc_entry->address); + if (status != bfd_reloc_ok) + return status; } else reloc_entry->addend = val; if (relocatable) reloc_entry->address += input_section->output_offset; - else if (((val & ~0xffff) != ~0xffff) && ((val & ~0xffff) != 0)) - return bfd_reloc_overflow; + + return bfd_reloc_ok; +} + +/* Used to store a REL high-part relocation such as R_MIPS_HI16 or + R_MIPS_GOT16. REL is the relocation, INPUT_SECTION is the section + that contains the relocation field and DATA points to the start of + INPUT_SECTION. */ + +struct mips_hi16 +{ + struct mips_hi16 *next; + bfd_byte *data; + asection *input_section; + arelent rel; +}; + +/* FIXME: This should not be a static variable. */ + +static struct mips_hi16 *mips_hi16_list; + +/* A howto special_function for REL *HI16 relocations. We can only + calculate the correct value once we've seen the partnering + *LO16 relocation, so just save the information for later. + + The ABI requires that the *LO16 immediately follow the *HI16. + However, as a GNU extension, we permit an arbitrary number of + *HI16s to be associated with a single *LO16. This significantly + simplies the relocation handling in gcc. */ + +bfd_reloc_status_type +_bfd_mips_elf_hi16_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry, + asymbol *symbol ATTRIBUTE_UNUSED, void *data, + asection *input_section, bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ + struct mips_hi16 *n; + + if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) + return bfd_reloc_outofrange; + + n = bfd_malloc (sizeof *n); + if (n == NULL) + return bfd_reloc_outofrange; + + n->next = mips_hi16_list; + n->data = data; + n->input_section = input_section; + n->rel = *reloc_entry; + mips_hi16_list = n; + + if (output_bfd != NULL) + reloc_entry->address += input_section->output_offset; + + return bfd_reloc_ok; +} + +/* A howto special_function for REL R_MIPS_GOT16 relocations. This is just + like any other 16-bit relocation when applied to global symbols, but is + treated in the same as R_MIPS_HI16 when applied to local symbols. */ + +bfd_reloc_status_type +_bfd_mips_elf_got16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + void *data, asection *input_section, + bfd *output_bfd, char **error_message) +{ + if ((symbol->flags & (BSF_GLOBAL | BSF_WEAK)) != 0 + || bfd_is_und_section (bfd_get_section (symbol)) + || bfd_is_com_section (bfd_get_section (symbol))) + /* The relocation is against a global symbol. */ + return _bfd_mips_elf_generic_reloc (abfd, reloc_entry, symbol, data, + input_section, output_bfd, + error_message); + + return _bfd_mips_elf_hi16_reloc (abfd, reloc_entry, symbol, data, + input_section, output_bfd, error_message); +} + +/* A howto special_function for REL *LO16 relocations. The *LO16 itself + is a straightforward 16 bit inplace relocation, but we must deal with + any partnering high-part relocations as well. */ + +bfd_reloc_status_type +_bfd_mips_elf_lo16_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, + void *data, asection *input_section, + 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; + + _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; + struct mips_hi16 *hi; + + hi = mips_hi16_list; + + /* R_MIPS_GOT16 relocations are something of a special case. We + want to install the addend in the same way as for a R_MIPS_HI16 + relocation (with a rightshift of 16). However, since GOT16 + relocations can also be used with global symbols, their howto + has a rightshift of 0. */ + if (hi->rel.howto->type == R_MIPS_GOT16) + hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MIPS_HI16, FALSE); + + /* VALLO is a signed 16-bit number. Bias it by 0x8000 so that any + carry or borrow will induce a change of +1 or -1 in the high part. */ + hi->rel.addend += (vallo + 0x8000) & 0xffff; + + ret = _bfd_mips_elf_generic_reloc (abfd, &hi->rel, symbol, hi->data, + hi->input_section, output_bfd, + error_message); + if (ret != bfd_reloc_ok) + return ret; + + mips_hi16_list = hi->next; + free (hi); + } + + return _bfd_mips_elf_generic_reloc (abfd, reloc_entry, symbol, data, + input_section, output_bfd, + error_message); +} + +/* A generic howto special_function. This calculates and installs the + relocation itself, thus avoiding the oft-discussed problems in + bfd_perform_relocation and bfd_install_relocation. */ + +bfd_reloc_status_type +_bfd_mips_elf_generic_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry, + asymbol *symbol, void *data ATTRIBUTE_UNUSED, + asection *input_section, bfd *output_bfd, + char **error_message ATTRIBUTE_UNUSED) +{ + bfd_signed_vma val; + bfd_reloc_status_type status; + bfd_boolean relocatable; + + relocatable = (output_bfd != NULL); + + if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) + return bfd_reloc_outofrange; + + /* Build up the field adjustment in VAL. */ + val = 0; + if (!relocatable || (symbol->flags & BSF_SECTION_SYM) != 0) + { + /* Either we're calculating the final field value or we have a + relocation against a section symbol. Add in the section's + offset or address. */ + val += symbol->section->output_section->vma; + val += symbol->section->output_offset; + } + + if (!relocatable) + { + /* We're calculating the final field value. Add in the symbol's value + and, if pc-relative, subtract the address of the field itself. */ + val += symbol->value; + if (reloc_entry->howto->pc_relative) + { + val -= input_section->output_section->vma; + val -= input_section->output_offset; + val -= reloc_entry->address; + } + } + + /* VAL is now the final adjustment. If we're keeping this relocation + in the output file, and if the relocation uses a separate addend, + we just need to add VAL to that addend. Otherwise we need to add + VAL to the relocation field itself. */ + if (relocatable && !reloc_entry->howto->partial_inplace) + 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, + location); + _bfd_mips16_elf_reloc_shuffle (abfd, reloc_entry->howto->type, FALSE, + location); + + if (status != bfd_reloc_ok) + return status; + } + + if (relocatable) + reloc_entry->address += input_section->output_offset; return bfd_reloc_ok; } @@ -1143,30 +1442,24 @@ _bfd_mips_elf_gprel16_with_gp (abfd, symbol, reloc_entry, input_section, on the equivalence of the two elements of the union. */ static void -bfd_mips_elf32_swap_gptab_in (abfd, ex, in) - bfd *abfd; - const Elf32_External_gptab *ex; - Elf32_gptab *in; +bfd_mips_elf32_swap_gptab_in (bfd *abfd, const Elf32_External_gptab *ex, + Elf32_gptab *in) { in->gt_entry.gt_g_value = H_GET_32 (abfd, ex->gt_entry.gt_g_value); in->gt_entry.gt_bytes = H_GET_32 (abfd, ex->gt_entry.gt_bytes); } static void -bfd_mips_elf32_swap_gptab_out (abfd, in, ex) - bfd *abfd; - const Elf32_gptab *in; - Elf32_External_gptab *ex; +bfd_mips_elf32_swap_gptab_out (bfd *abfd, const Elf32_gptab *in, + Elf32_External_gptab *ex) { H_PUT_32 (abfd, in->gt_entry.gt_g_value, ex->gt_entry.gt_g_value); H_PUT_32 (abfd, in->gt_entry.gt_bytes, ex->gt_entry.gt_bytes); } static void -bfd_elf32_swap_compact_rel_out (abfd, in, ex) - bfd *abfd; - const Elf32_compact_rel *in; - Elf32_External_compact_rel *ex; +bfd_elf32_swap_compact_rel_out (bfd *abfd, const Elf32_compact_rel *in, + Elf32_External_compact_rel *ex) { H_PUT_32 (abfd, in->id1, ex->id1); H_PUT_32 (abfd, in->num, ex->num); @@ -1177,10 +1470,8 @@ bfd_elf32_swap_compact_rel_out (abfd, in, ex) } static void -bfd_elf32_swap_crinfo_out (abfd, in, ex) - bfd *abfd; - const Elf32_crinfo *in; - Elf32_External_crinfo *ex; +bfd_elf32_swap_crinfo_out (bfd *abfd, const Elf32_crinfo *in, + Elf32_External_crinfo *ex) { unsigned long l; @@ -1192,41 +1483,14 @@ bfd_elf32_swap_crinfo_out (abfd, in, ex) H_PUT_32 (abfd, in->konst, ex->konst); H_PUT_32 (abfd, in->vaddr, ex->vaddr); } - -#if 0 -/* Swap in an MSYM entry. */ - -static void -bfd_mips_elf_swap_msym_in (abfd, ex, in) - bfd *abfd; - const Elf32_External_Msym *ex; - Elf32_Internal_Msym *in; -{ - in->ms_hash_value = H_GET_32 (abfd, ex->ms_hash_value); - in->ms_info = H_GET_32 (abfd, ex->ms_info); -} -#endif -/* Swap out an MSYM entry. */ - -static void -bfd_mips_elf_swap_msym_out (abfd, in, ex) - bfd *abfd; - const Elf32_Internal_Msym *in; - Elf32_External_Msym *ex; -{ - H_PUT_32 (abfd, in->ms_hash_value, ex->ms_hash_value); - H_PUT_32 (abfd, in->ms_info, ex->ms_info); -} /* A .reginfo section holds a single Elf32_RegInfo structure. These routines swap this structure in and out. They are used outside of BFD, so they are globally visible. */ void -bfd_mips_elf32_swap_reginfo_in (abfd, ex, in) - bfd *abfd; - const Elf32_External_RegInfo *ex; - Elf32_RegInfo *in; +bfd_mips_elf32_swap_reginfo_in (bfd *abfd, const Elf32_External_RegInfo *ex, + Elf32_RegInfo *in) { in->ri_gprmask = H_GET_32 (abfd, ex->ri_gprmask); in->ri_cprmask[0] = H_GET_32 (abfd, ex->ri_cprmask[0]); @@ -1237,10 +1501,8 @@ bfd_mips_elf32_swap_reginfo_in (abfd, ex, in) } void -bfd_mips_elf32_swap_reginfo_out (abfd, in, ex) - bfd *abfd; - const Elf32_RegInfo *in; - Elf32_External_RegInfo *ex; +bfd_mips_elf32_swap_reginfo_out (bfd *abfd, const Elf32_RegInfo *in, + Elf32_External_RegInfo *ex) { H_PUT_32 (abfd, in->ri_gprmask, ex->ri_gprmask); H_PUT_32 (abfd, in->ri_cprmask[0], ex->ri_cprmask[0]); @@ -1257,10 +1519,8 @@ bfd_mips_elf32_swap_reginfo_out (abfd, in, ex) without worrying about whether the 64 bit ABI has been included. */ void -bfd_mips_elf64_swap_reginfo_in (abfd, ex, in) - bfd *abfd; - const Elf64_External_RegInfo *ex; - Elf64_Internal_RegInfo *in; +bfd_mips_elf64_swap_reginfo_in (bfd *abfd, const Elf64_External_RegInfo *ex, + Elf64_Internal_RegInfo *in) { in->ri_gprmask = H_GET_32 (abfd, ex->ri_gprmask); in->ri_pad = H_GET_32 (abfd, ex->ri_pad); @@ -1272,10 +1532,8 @@ bfd_mips_elf64_swap_reginfo_in (abfd, ex, in) } void -bfd_mips_elf64_swap_reginfo_out (abfd, in, ex) - bfd *abfd; - const Elf64_Internal_RegInfo *in; - Elf64_External_RegInfo *ex; +bfd_mips_elf64_swap_reginfo_out (bfd *abfd, const Elf64_Internal_RegInfo *in, + Elf64_External_RegInfo *ex) { H_PUT_32 (abfd, in->ri_gprmask, ex->ri_gprmask); H_PUT_32 (abfd, in->ri_pad, ex->ri_pad); @@ -1289,10 +1547,8 @@ bfd_mips_elf64_swap_reginfo_out (abfd, in, ex) /* Swap in an options header. */ void -bfd_mips_elf_swap_options_in (abfd, ex, in) - bfd *abfd; - const Elf_External_Options *ex; - Elf_Internal_Options *in; +bfd_mips_elf_swap_options_in (bfd *abfd, const Elf_External_Options *ex, + Elf_Internal_Options *in) { in->kind = H_GET_8 (abfd, ex->kind); in->size = H_GET_8 (abfd, ex->size); @@ -1303,10 +1559,8 @@ bfd_mips_elf_swap_options_in (abfd, ex, in) /* Swap out an options header. */ void -bfd_mips_elf_swap_options_out (abfd, in, ex) - bfd *abfd; - const Elf_Internal_Options *in; - Elf_External_Options *ex; +bfd_mips_elf_swap_options_out (bfd *abfd, const Elf_Internal_Options *in, + Elf_External_Options *ex) { H_PUT_8 (abfd, in->kind, ex->kind); H_PUT_8 (abfd, in->size, ex->size); @@ -1318,9 +1572,7 @@ bfd_mips_elf_swap_options_out (abfd, in, ex) entries by increasing r_symndx value. */ static int -sort_dynamic_relocs (arg1, arg2) - const PTR arg1; - const PTR arg2; +sort_dynamic_relocs (const void *arg1, const void *arg2) { Elf_Internal_Rela int_reloc1; Elf_Internal_Rela int_reloc2; @@ -1334,10 +1586,10 @@ sort_dynamic_relocs (arg1, arg2) /* Like sort_dynamic_relocs, but used for elf64 relocations. */ static int -sort_dynamic_relocs_64 (arg1, arg2) - const PTR arg1; - const PTR 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]; @@ -1348,6 +1600,9 @@ sort_dynamic_relocs_64 (arg1, arg2) return (ELF64_R_SYM (int_reloc1[0].r_info) - ELF64_R_SYM (int_reloc2[0].r_info)); +#else + abort (); +#endif } @@ -1366,11 +1621,9 @@ sort_dynamic_relocs_64 (arg1, arg2) when generating a final executable. */ static bfd_boolean -mips_elf_output_extsym (h, data) - struct mips_elf_link_hash_entry *h; - PTR data; +mips_elf_output_extsym (struct mips_elf_link_hash_entry *h, void *data) { - struct extsym_info *einfo = (struct extsym_info *) data; + struct extsym_info *einfo = data; bfd_boolean strip; asection *sec, *output_section; @@ -1379,10 +1632,11 @@ mips_elf_output_extsym (h, data) if (h->root.indx == -2) strip = FALSE; - else if (((h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 - || (h->root.elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0) - && (h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0 - && (h->root.elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) == 0) + else if ((h->root.def_dynamic + || h->root.ref_dynamic + || h->root.type == bfd_link_hash_new) + && !h->root.def_regular + && !h->root.ref_regular) strip = TRUE; else if (einfo->info->strip == strip_all || (einfo->info->strip == strip_some @@ -1500,7 +1754,7 @@ mips_elf_output_extsym (h, data) else h->esym.asym.value = 0; } - else if ((h->root.elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0) + else if (h->root.needs_plt) { struct mips_elf_link_hash_entry *hd = h; bfd_boolean no_fn_stub = h->no_fn_stub; @@ -1528,9 +1782,6 @@ mips_elf_output_extsym (h, data) else h->esym.asym.value = 0; } -#if 0 /* FIXME? */ - h->esym.ifd = 0; -#endif } } @@ -1548,12 +1799,10 @@ mips_elf_output_extsym (h, data) /* A comparison routine used to sort .gptab entries. */ static int -gptab_compare (p1, p2) - const PTR p1; - const PTR p2; +gptab_compare (const void *p1, const void *p2) { - const Elf32_gptab *a1 = (const Elf32_gptab *) p1; - const Elf32_gptab *a2 = (const Elf32_gptab *) p2; + const Elf32_gptab *a1 = p1; + const Elf32_gptab *a2 = p2; return a1->gt_entry.gt_g_value - a2->gt_entry.gt_g_value; } @@ -1564,8 +1813,7 @@ gptab_compare (p1, p2) hash number. */ static INLINE hashval_t -mips_elf_hash_bfd_vma (addr) - bfd_vma addr; +mips_elf_hash_bfd_vma (bfd_vma addr) { #ifdef BFD64 return addr + (addr >> 32); @@ -1579,12 +1827,12 @@ mips_elf_hash_bfd_vma (addr) union members. */ static hashval_t -mips_elf_got_entry_hash (entry_) - const PTR entry_; +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) @@ -1592,13 +1840,15 @@ mips_elf_got_entry_hash (entry_) } static int -mips_elf_got_entry_eq (entry1, entry2) - const PTR entry1; - const PTR entry2; +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 @@ -1611,8 +1861,7 @@ mips_elf_got_entry_eq (entry1, entry2) accordingly. */ static hashval_t -mips_elf_multi_got_entry_hash (entry_) - const PTR entry_; +mips_elf_multi_got_entry_hash (const void *entry_) { const struct mips_got_entry *entry = (struct mips_got_entry *)entry_; @@ -1620,19 +1869,27 @@ mips_elf_multi_got_entry_hash (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); } static int -mips_elf_multi_got_entry_eq (entry1, entry2) - const PTR entry1; - const PTR entry2; +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 @@ -1643,9 +1900,7 @@ mips_elf_multi_got_entry_eq (entry1, entry2) /* Returns the dynamic relocation section for DYNOBJ. */ static asection * -mips_elf_rel_dyn_section (dynobj, create_p) - bfd *dynobj; - bfd_boolean create_p; +mips_elf_rel_dyn_section (bfd *dynobj, bfd_boolean create_p) { static const char dname[] = ".rel.dyn"; asection *sreloc; @@ -1653,15 +1908,14 @@ mips_elf_rel_dyn_section (dynobj, 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; @@ -1672,9 +1926,7 @@ mips_elf_rel_dyn_section (dynobj, create_p) /* Returns the GOT section for ABFD. */ static asection * -mips_elf_got_section (abfd, maybe_excluded) - bfd *abfd; - bfd_boolean maybe_excluded; +mips_elf_got_section (bfd *abfd, bfd_boolean maybe_excluded) { asection *sgot = bfd_get_section_by_name (abfd, ".got"); if (sgot == NULL @@ -1688,9 +1940,7 @@ mips_elf_got_section (abfd, maybe_excluded) section. */ static struct mips_got_info * -mips_elf_got_info (abfd, sgotp) - bfd *abfd; - asection **sgotp; +mips_elf_got_info (bfd *abfd, asection **sgotp) { asection *sgot; struct mips_got_info *g; @@ -1707,38 +1957,299 @@ mips_elf_got_info (abfd, sgotp) return g; } -/* Obtain the lowest dynamic index of a symbol that was assigned a - global GOT entry. */ -static long -mips_elf_get_global_gotsym_index (abfd) - bfd *abfd; +/* 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) { - asection *sgot; - struct mips_got_info *g; + int indx = 0; + int ret = 0; + bfd_boolean need_relocs = FALSE; + bfd_boolean dyn = elf_hash_table (info)->dynamic_sections_created; - if (abfd == NULL) - return 0; + if (h && WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) + && (!info->shared || !SYMBOL_REFERENCES_LOCAL (info, h))) + indx = h->dynindx; - sgot = mips_elf_got_section (abfd, TRUE); - if (sgot == NULL || mips_elf_section_data (sgot) == NULL) - return 0; + if ((info->shared || indx != 0) + && (h == NULL + || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak)) + need_relocs = TRUE; - g = mips_elf_section_data (sgot)->u.got_info; - if (g == NULL || g->global_gotsym == NULL) - return 0; + 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); - return g->global_gotsym->dynindx; + 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 (abfd, ibfd, info, value) - bfd *abfd, *ibfd; - struct bfd_link_info *info; - bfd_vma value; +mips_elf_local_got_index (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, + bfd_vma value, unsigned long r_symndx, + struct mips_elf_link_hash_entry *h, int r_type) { asection *sgot; struct mips_got_info *g; @@ -1746,19 +2257,23 @@ mips_elf_local_got_index (abfd, ibfd, info, value) 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 (abfd, ibfd, h) - bfd *abfd, *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; @@ -1773,30 +2288,65 @@ mips_elf_global_got_index (abfd, ibfd, 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 = (struct mips_got_entry *) htab_find (g->got_entries, &e); + 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)); - BFD_ASSERT (index < sgot->_raw_size); + 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; } @@ -1808,11 +2358,8 @@ mips_elf_global_got_index (abfd, ibfd, h) OFFSETP, if it is non-NULL. */ static bfd_vma -mips_elf_got_page (abfd, ibfd, info, value, offsetp) - bfd *abfd, *ibfd; - struct bfd_link_info *info; - bfd_vma value; - bfd_vma *offsetp; +mips_elf_got_page (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, + bfd_vma value, bfd_vma *offsetp) { asection *sgot; struct mips_got_info *g; @@ -1823,7 +2370,8 @@ mips_elf_got_page (abfd, ibfd, info, value, offsetp) 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; @@ -1840,11 +2388,8 @@ mips_elf_got_page (abfd, ibfd, info, value, offsetp) for value. Return the index into the GOT for this entry. */ static bfd_vma -mips_elf_got16_entry (abfd, ibfd, info, value, external) - bfd *abfd, *ibfd; - struct bfd_link_info *info; - bfd_vma value; - bfd_boolean external; +mips_elf_got16_entry (bfd *abfd, bfd *ibfd, struct bfd_link_info *info, + bfd_vma value, bfd_boolean external) { asection *sgot; struct mips_got_info *g; @@ -1861,7 +2406,8 @@ mips_elf_got16_entry (abfd, ibfd, info, value, external) 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 @@ -1872,11 +2418,8 @@ mips_elf_got16_entry (abfd, ibfd, info, value, external) in the GOT. */ static bfd_vma -mips_elf_got_offset_from_index (dynobj, output_bfd, input_bfd, index) - bfd *dynobj; - bfd *output_bfd; - bfd *input_bfd; - bfd_vma index; +mips_elf_got_offset_from_index (bfd *dynobj, bfd *output_bfd, + bfd *input_bfd, bfd_vma index) { asection *sgot; bfd_vma gp; @@ -1890,14 +2433,16 @@ mips_elf_got_offset_from_index (dynobj, output_bfd, input_bfd, index) } /* 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 (abfd, ibfd, gg, sgot, value) - bfd *abfd, *ibfd; - struct mips_got_info *gg; - asection *sgot; - bfd_vma value; +mips_elf_create_local_got_entry (bfd *abfd, bfd *ibfd, + struct mips_got_info *gg, + 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; @@ -1905,6 +2450,7 @@ mips_elf_create_local_got_entry (abfd, ibfd, gg, sgot, value) 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) @@ -1913,12 +2459,44 @@ mips_elf_create_local_got_entry (abfd, ibfd, gg, sgot, value) 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); @@ -1951,9 +2529,7 @@ mips_elf_create_local_got_entry (abfd, ibfd, gg, sgot, value) section symbols are added and the count is higher. */ static bfd_boolean -mips_elf_sort_hash_table (info, max_local) - struct bfd_link_info *info; - unsigned long max_local; +mips_elf_sort_hash_table (struct bfd_link_info *info, unsigned long max_local) { struct mips_elf_hash_sort_data hsd; struct mips_got_info *g; @@ -1998,12 +2574,9 @@ mips_elf_sort_hash_table (info, max_local) index. */ static bfd_boolean -mips_elf_sort_hash_table_f (h, data) - struct mips_elf_link_hash_entry *h; - PTR data; +mips_elf_sort_hash_table_f (struct mips_elf_link_hash_entry *h, void *data) { - struct mips_elf_hash_sort_data *hsd - = (struct mips_elf_hash_sort_data *) data; + struct mips_elf_hash_sort_data *hsd = data; if (h->root.root.type == bfd_link_hash_warning) h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link; @@ -2019,6 +2592,8 @@ mips_elf_sort_hash_table_f (h, 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++; @@ -2027,6 +2602,8 @@ mips_elf_sort_hash_table_f (h, 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; } @@ -2039,11 +2616,10 @@ mips_elf_sort_hash_table_f (h, data) posterity. */ static bfd_boolean -mips_elf_record_global_got_symbol (h, abfd, info, g) - struct elf_link_hash_entry *h; - bfd *abfd; - struct bfd_link_info *info; - struct mips_got_info *g; +mips_elf_record_global_got_symbol (struct elf_link_hash_entry *h, + bfd *abfd, struct bfd_link_info *info, + struct mips_got_info *g, + unsigned char tls_flag) { struct mips_got_entry entry, **loc; @@ -2058,13 +2634,14 @@ mips_elf_record_global_got_symbol (h, abfd, info, g) _bfd_mips_elf_hide_symbol (info, h, TRUE); break; } - if (!bfd_elf32_link_record_dynamic_symbol (info, h)) + if (!bfd_elf_link_record_dynamic_symbol (info, h)) return FALSE; } 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); @@ -2072,7 +2649,10 @@ mips_elf_record_global_got_symbol (h, abfd, info, g) /* 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); @@ -2080,6 +2660,8 @@ mips_elf_record_global_got_symbol (h, abfd, info, g) return FALSE; entry.gotidx = -1; + entry.tls_type = tls_flag; + memcpy (*loc, &entry, sizeof entry); if (h->got.offset != MINUS_ONE) @@ -2088,7 +2670,8 @@ mips_elf_record_global_got_symbol (h, abfd, info, g) /* 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; } @@ -2097,24 +2680,53 @@ mips_elf_record_global_got_symbol (h, abfd, info, g) SYMNDX in input bfd ABDF, plus ADDEND. */ static bfd_boolean -mips_elf_record_local_got_symbol (abfd, symndx, addend, g) - bfd *abfd; - long symndx; - bfd_vma addend; - struct mips_got_info *g; +mips_elf_record_local_got_symbol (bfd *abfd, long symndx, bfd_vma addend, + 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); @@ -2129,8 +2741,7 @@ mips_elf_record_local_got_symbol (abfd, symndx, addend, g) /* Compute the hash value of the bfd in a bfd2got hash entry. */ static hashval_t -mips_elf_bfd2got_entry_hash (entry_) - const PTR entry_; +mips_elf_bfd2got_entry_hash (const void *entry_) { const struct mips_elf_bfd2got_hash *entry = (struct mips_elf_bfd2got_hash *)entry_; @@ -2141,9 +2752,7 @@ mips_elf_bfd2got_entry_hash (entry_) /* Check whether two hash entries have the same bfd. */ static int -mips_elf_bfd2got_entry_eq (entry1, entry2) - const PTR entry1; - const PTR entry2; +mips_elf_bfd2got_entry_eq (const void *entry1, const void *entry2) { const struct mips_elf_bfd2got_hash *e1 = (const struct mips_elf_bfd2got_hash *)entry1; @@ -2157,9 +2766,7 @@ mips_elf_bfd2got_entry_eq (entry1, entry2) be the master GOT data. */ static struct mips_got_info * -mips_elf_got_for_ibfd (g, ibfd) - struct mips_got_info *g; - bfd *ibfd; +mips_elf_got_for_ibfd (struct mips_got_info *g, bfd *ibfd) { struct mips_elf_bfd2got_hash e, *p; @@ -2167,7 +2774,7 @@ mips_elf_got_for_ibfd (g, ibfd) return g; e.bfd = ibfd; - p = (struct mips_elf_bfd2got_hash *) htab_find (g->bfd2got, &e); + p = htab_find (g->bfd2got, &e); return p ? p->g : NULL; } @@ -2176,9 +2783,7 @@ mips_elf_got_for_ibfd (g, ibfd) bfd requires. */ static int -mips_elf_make_got_per_bfd (entryp, p) - void **entryp; - void *p; +mips_elf_make_got_per_bfd (void **entryp, void *p) { struct mips_got_entry *entry = (struct mips_got_entry *)*entryp; struct mips_elf_got_per_bfd_arg *arg = (struct mips_elf_got_per_bfd_arg *)p; @@ -2221,9 +2826,11 @@ mips_elf_make_got_per_bfd (entryp, 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, - (htab_del) NULL); + mips_elf_multi_got_entry_eq, NULL); if (g->got_entries == NULL) { arg->obfd = 0; @@ -2241,7 +2848,14 @@ mips_elf_make_got_per_bfd (entryp, 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; @@ -2257,20 +2871,33 @@ mips_elf_make_got_per_bfd (entryp, p) and then make make the new got current. */ static int -mips_elf_merge_gots (bfd2got_, p) - void **bfd2got_; - void *p; +mips_elf_merge_gots (void **bfd2got_, void *p) { struct mips_elf_bfd2got_hash *bfd2got = (struct mips_elf_bfd2got_hash *)*bfd2got_; 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; @@ -2278,12 +2905,13 @@ mips_elf_merge_gots (bfd2got_, 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; @@ -2298,19 +2926,21 @@ mips_elf_merge_gots (bfd2got_, p) got entries, since they're all in the master got_entries hash table anyway. */ - BFD_ASSERT (old_lcount + lcount == arg->primary->local_gotno); + 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; @@ -2322,11 +2952,12 @@ mips_elf_merge_gots (bfd2got_, p) htab_delete (g->got_entries); - BFD_ASSERT (old_lcount + lcount == arg->current->local_gotno); + 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 @@ -2336,12 +2967,61 @@ mips_elf_merge_gots (bfd2got_, 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) + 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. @@ -2353,36 +3033,34 @@ mips_elf_merge_gots (bfd2got_, p) first available global GOT entry in G. VALUE must contain the size of a GOT entry in bytes. For each global GOT entry that requires a dynamic relocation, NEEDED_RELOCS is incremented, and the symbol is - marked as not elligible for lazy resolution through a function + marked as not eligible for lazy resolution through a function stub. */ static int -mips_elf_set_global_got_offset (entryp, p) - void **entryp; - void *p; +mips_elf_set_global_got_offset (void **entryp, void *p) { struct mips_got_entry *entry = (struct mips_got_entry *)*entryp; struct mips_elf_set_global_got_offset_arg *arg = (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) { BFD_ASSERT (g->global_gotsym == NULL); entry->gotidx = arg->value * (long) g->assigned_gotno++; - /* We can't do lazy update of GOT entries for - non-primary GOTs since the PLT entries don't use the - right offsets, so punt at it for now. */ - entry->d.h->no_fn_stub = TRUE; if (arg->info->shared || (elf_hash_table (arg->info)->dynamic_sections_created - && ((entry->d.h->root.elf_link_hash_flags - & ELF_LINK_HASH_DEF_DYNAMIC) != 0) - && ((entry->d.h->root.elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR) == 0))) + && entry->d.h->root.def_dynamic + && !entry->d.h->root.def_regular)) ++arg->needed_relocs; } else @@ -2392,6 +3070,21 @@ mips_elf_set_global_got_offset (entryp, p) return 1; } +/* Mark any global symbols referenced in the GOT we are iterating over + as inelligible for lazy resolution stubs. */ +static int +mips_elf_set_no_stub (void **entryp, void *p ATTRIBUTE_UNUSED) +{ + struct mips_got_entry *entry = (struct mips_got_entry *)*entryp; + + if (entry->abfd != NULL + && entry->symndx == -1 + && entry->d.h->root.dynindx != -1) + entry->d.h->no_fn_stub = TRUE; + + return 1; +} + /* Follow indirect and warning hash entries so that each got entry points to the final symbol definition. P must point to a pointer to the hash table we're traversing. Since this traversal may @@ -2399,9 +3092,7 @@ mips_elf_set_global_got_offset (entryp, p) we've made a potentially-destructive change to the hash table, so the traversal must be restarted. */ static int -mips_elf_resolve_final_got_entry (entryp, p) - void **entryp; - void *p; +mips_elf_resolve_final_got_entry (void **entryp, void *p) { struct mips_got_entry *entry = (struct mips_got_entry *)*entryp; htab_t got_entries = *(htab_t *)p; @@ -2443,8 +3134,7 @@ mips_elf_resolve_final_got_entry (entryp, p) /* Turn indirect got entries in a got_entries table into their final locations. */ static void -mips_elf_resolve_final_got_entries (g) - struct mips_got_info *g; +mips_elf_resolve_final_got_entries (struct mips_got_info *g) { htab_t got_entries; @@ -2462,10 +3152,7 @@ mips_elf_resolve_final_got_entries (g) /* Return the offset of an input bfd IBFD's GOT from the beginning of the primary GOT. */ static bfd_vma -mips_elf_adjust_gp (abfd, g, ibfd) - bfd *abfd; - struct mips_got_info *g; - bfd *ibfd; +mips_elf_adjust_gp (bfd *abfd, struct mips_got_info *g, bfd *ibfd) { if (g->bfd2got == NULL) return 0; @@ -2478,19 +3165,17 @@ mips_elf_adjust_gp (abfd, g, 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 a sequence of GOTs, each one 16-bit addressable. */ static bfd_boolean -mips_elf_multi_got (abfd, info, g, got, pages) - bfd *abfd; - struct bfd_link_info *info; - struct mips_got_info *g; - asection *got; - bfd_size_type pages; +mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info, + struct mips_got_info *g, asection *got, + bfd_size_type pages) { struct mips_elf_got_per_bfd_arg got_per_bfd_arg; struct mips_elf_set_global_got_offset_arg set_got_offset_arg; @@ -2498,8 +3183,7 @@ mips_elf_multi_got (abfd, info, g, got, pages) unsigned int assign; g->bfd2got = htab_try_create (1, mips_elf_bfd2got_entry_hash, - mips_elf_bfd2got_entry_eq, - (htab_del) NULL); + mips_elf_bfd2got_entry_eq, NULL); if (g->bfd2got == NULL) return FALSE; @@ -2509,7 +3193,6 @@ mips_elf_multi_got (abfd, info, g, got, pages) /* 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; @@ -2522,6 +3205,10 @@ mips_elf_multi_got (abfd, info, g, got, pages) 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 @@ -2530,7 +3217,7 @@ mips_elf_multi_got (abfd, info, g, got, pages) 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 *) @@ -2541,10 +3228,13 @@ mips_elf_multi_got (abfd, info, g, got, pages) 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, - (htab_del) NULL); + NULL); if (g->next->got_entries == NULL) return FALSE; g->next->bfd2got = NULL; @@ -2641,6 +3331,7 @@ mips_elf_multi_got (abfd, info, g, got, pages) 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; @@ -2651,7 +3342,12 @@ mips_elf_multi_got (abfd, info, g, got, pages) 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. */ @@ -2659,11 +3355,17 @@ mips_elf_multi_got (abfd, info, g, got, pages) g->next = gg->next; gg->next = g; g = gn; + + /* Mark global symbols in every non-primary GOT as ineligible for + stubs. */ + if (g) + htab_traverse (g->got_entries, mips_elf_set_no_stub, NULL); } while (g); - got->_raw_size = (gg->next->local_gotno - + gg->next->global_gotno) * MIPS_ELF_GOT_SIZE (abfd); + got->size = (gg->next->local_gotno + + gg->next->global_gotno + + gg->next->tls_gotno) * MIPS_ELF_GOT_SIZE (abfd); return TRUE; } @@ -2673,18 +3375,10 @@ mips_elf_multi_got (abfd, info, g, got, pages) RELOCATION. RELEND is one-past-the-end of the relocation table. */ static const Elf_Internal_Rela * -mips_elf_next_relocation (abfd, r_type, relocation, relend) - bfd *abfd ATTRIBUTE_UNUSED; - unsigned int r_type; - const Elf_Internal_Rela *relocation; - const Elf_Internal_Rela *relend; -{ - /* According to the MIPS ELF ABI, the R_MIPS_LO16 relocation must be - immediately following. However, for the IRIX6 ABI, the next - relocation may be a composed relocation consisting of several - relocations for the same address. In that case, the R_MIPS_LO16 - relocation may occur as one of these. We permit a similar - extension in general, as that is useful for GCC. */ +mips_elf_next_relocation (bfd *abfd ATTRIBUTE_UNUSED, unsigned int r_type, + const Elf_Internal_Rela *relocation, + const Elf_Internal_Rela *relend) +{ while (relocation < relend) { if (ELF_R_TYPE (abfd, relocation->r_info) == r_type) @@ -2701,12 +3395,10 @@ mips_elf_next_relocation (abfd, r_type, relocation, relend) /* Return whether a relocation is against a local symbol. */ static bfd_boolean -mips_elf_local_relocation_p (input_bfd, relocation, local_sections, - check_forced) - bfd *input_bfd; - const Elf_Internal_Rela *relocation; - asection **local_sections; - bfd_boolean check_forced; +mips_elf_local_relocation_p (bfd *input_bfd, + const Elf_Internal_Rela *relocation, + asection **local_sections, + bfd_boolean check_forced) { unsigned long r_symndx; Elf_Internal_Shdr *symtab_hdr; @@ -2732,7 +3424,7 @@ mips_elf_local_relocation_p (input_bfd, relocation, local_sections, 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; - if ((h->root.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0) + if (h->root.forced_local) return TRUE; } @@ -2742,9 +3434,7 @@ mips_elf_local_relocation_p (input_bfd, relocation, local_sections, /* Sign-extend VALUE, which has the indicated number of BITS. */ bfd_vma -_bfd_mips_elf_sign_extend (value, bits) - bfd_vma value; - int bits; +_bfd_mips_elf_sign_extend (bfd_vma value, int bits) { if (value & ((bfd_vma) 1 << (bits - 1))) /* VALUE is negative. */ @@ -2754,13 +3444,11 @@ _bfd_mips_elf_sign_extend (value, bits) } /* Return non-zero if the indicated VALUE has overflowed the maximum - range expressable by a signed number with the indicated number of + range expressible by a signed number with the indicated number of BITS. */ static bfd_boolean -mips_elf_overflow_p (value, bits) - bfd_vma value; - int bits; +mips_elf_overflow_p (bfd_vma value, int bits) { bfd_signed_vma svalue = (bfd_signed_vma) value; @@ -2778,8 +3466,7 @@ mips_elf_overflow_p (value, bits) /* Calculate the %high function. */ static bfd_vma -mips_elf_high (value) - bfd_vma value; +mips_elf_high (bfd_vma value) { return ((value + (bfd_vma) 0x8000) >> 16) & 0xffff; } @@ -2787,37 +3474,34 @@ mips_elf_high (value) /* Calculate the %higher function. */ static bfd_vma -mips_elf_higher (value) - bfd_vma value ATTRIBUTE_UNUSED; +mips_elf_higher (bfd_vma value ATTRIBUTE_UNUSED) { #ifdef BFD64 return ((value + (bfd_vma) 0x80008000) >> 32) & 0xffff; #else abort (); - return (bfd_vma) -1; + return MINUS_ONE; #endif } /* Calculate the %highest function. */ static bfd_vma -mips_elf_highest (value) - bfd_vma value ATTRIBUTE_UNUSED; +mips_elf_highest (bfd_vma value ATTRIBUTE_UNUSED) { #ifdef BFD64 return ((value + (((bfd_vma) 0x8000 << 32) | 0x80008000)) >> 48) & 0xffff; #else abort (); - return (bfd_vma) -1; + return MINUS_ONE; #endif } /* Create the .compact_rel section. */ static bfd_boolean -mips_elf_create_compact_rel_section (abfd, info) - bfd *abfd; - struct bfd_link_info *info ATTRIBUTE_UNUSED; +mips_elf_create_compact_rel_section + (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) { flagword flags; register asection *s; @@ -2827,14 +3511,13 @@ mips_elf_create_compact_rel_section (abfd, info) 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; - s->_raw_size = sizeof (Elf32_External_compact_rel); + s->size = sizeof (Elf32_External_compact_rel); } return TRUE; @@ -2843,10 +3526,8 @@ mips_elf_create_compact_rel_section (abfd, info) /* Create the .got section to hold the global offset table. */ static bfd_boolean -mips_elf_create_got_section (abfd, info, maybe_exclude) - bfd *abfd; - struct bfd_link_info *info; - bfd_boolean maybe_exclude; +mips_elf_create_got_section (bfd *abfd, struct bfd_link_info *info, + bfd_boolean maybe_exclude) { flagword flags; register asection *s; @@ -2872,9 +3553,8 @@ mips_elf_create_got_section (abfd, info, maybe_exclude) /* 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; @@ -2884,31 +3564,32 @@ mips_elf_create_got_section (abfd, info, maybe_exclude) bh = NULL; if (! (_bfd_generic_link_add_one_symbol (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s, - (bfd_vma) 0, (const char *) NULL, FALSE, - get_elf_backend_data (abfd)->collect, &bh))) + 0, NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh))) return FALSE; h = (struct elf_link_hash_entry *) bh; - h->elf_link_hash_flags &= ~ELF_LINK_NON_ELF; - h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->non_elf = 0; + h->def_regular = 1; h->type = STT_OBJECT; if (info->shared - && ! bfd_elf32_link_record_dynamic_symbol (info, h)) + && ! bfd_elf_link_record_dynamic_symbol (info, h)) return FALSE; amt = sizeof (struct mips_got_info); - g = (struct mips_got_info *) bfd_alloc (abfd, amt); + g = bfd_alloc (abfd, amt); if (g == NULL) 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, - (htab_del) NULL); + mips_elf_got_entry_eq, NULL); if (g->got_entries == NULL) return FALSE; mips_elf_section_data (s)->u.got_info = g; @@ -2917,34 +3598,6 @@ mips_elf_create_got_section (abfd, info, maybe_exclude) return TRUE; } - -/* Returns the .msym section for ABFD, creating it if it does not - already exist. Returns NULL to indicate error. */ - -static asection * -mips_elf_create_msym_section (abfd) - bfd *abfd; -{ - asection *s; - - s = bfd_get_section_by_name (abfd, ".msym"); - if (!s) - { - s = bfd_make_section (abfd, ".msym"); - if (!s - || !bfd_set_section_flags (abfd, s, - SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_LINKER_CREATED - | SEC_READONLY) - || !bfd_set_section_alignment (abfd, s, - MIPS_ELF_LOG_FILE_ALIGN (abfd))) - return NULL; - } - - return s; -} /* Calculate the value produced by the RELOCATION (which comes from the INPUT_BFD). The ADDEND is the addend to use for this @@ -2960,23 +3613,15 @@ mips_elf_create_msym_section (abfd) overflow occurs, and bfd_reloc_ok to indicate success. */ static bfd_reloc_status_type -mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, - relocation, addend, howto, local_syms, - local_sections, valuep, namep, - require_jalxp, save_addend) - bfd *abfd; - bfd *input_bfd; - asection *input_section; - struct bfd_link_info *info; - const Elf_Internal_Rela *relocation; - bfd_vma addend; - reloc_howto_type *howto; - Elf_Internal_Sym *local_syms; - asection **local_sections; - bfd_vma *valuep; - const char **namep; - bfd_boolean *require_jalxp; - bfd_boolean save_addend; +mips_elf_calculate_relocation (bfd *abfd, bfd *input_bfd, + asection *input_section, + struct bfd_link_info *info, + const Elf_Internal_Rela *relocation, + bfd_vma addend, reloc_howto_type *howto, + Elf_Internal_Sym *local_syms, + asection **local_sections, bfd_vma *valuep, + const char **namep, bfd_boolean *require_jalxp, + bfd_boolean save_addend) { /* The eventual value we will return. */ bfd_vma value; @@ -3004,6 +3649,9 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, 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; @@ -3074,6 +3722,8 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, } else { + /* ??? Could we use RELOC_FOR_GLOBAL_SYMBOL here ? */ + /* For global symbols we look up the symbol in the hash-table. */ h = ((struct mips_elf_link_hash_entry *) elf_sym_hashes (input_bfd) [r_symndx - extsymoff]); @@ -3087,16 +3737,23 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, /* See if this is the special _gp_disp symbol. Note that such a symbol must always be a global symbol. */ - if (strcmp (h->root.root.root.string, "_gp_disp") == 0 + if (strcmp (*namep, "_gp_disp") == 0 && ! NEWABI_P (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 @@ -3119,12 +3776,11 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, and check to see if they exist by looking at their addresses. */ symbol = 0; - else if (info->shared - && !info->no_undefined + else if (info->unresolved_syms_in_objects == RM_IGNORE && ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT) symbol = 0; - else if (strcmp (h->root.root.root.string, "_DYNAMIC_LINK") == 0 || - strcmp (h->root.root.root.string, "_DYNAMIC_LINKING") == 0) + else if (strcmp (*namep, SGI_COMPAT (input_bfd) + ? "_DYNAMIC_LINK" : "_DYNAMIC_LINKING") == 0) { /* If this is a dynamic link, we should have created a _DYNAMIC_LINK symbol or _DYNAMIC_LINKING(for normal mips) symbol @@ -3141,8 +3797,8 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, if (! ((*info->callbacks->undefined_symbol) (info, h->root.root.root.string, input_bfd, input_section, relocation->r_offset, - (!info->shared || info->no_undefined - || ELF_ST_VISIBILITY (h->root.other))))) + (info->unresolved_syms_in_objects == RM_GENERATE_ERROR) + || ELF_ST_VISIBILITY (h->root.other)))) return bfd_reloc_undefined; symbol = 0; } @@ -3204,7 +3860,7 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, else sec = h->call_fp_stub; - BFD_ASSERT (sec->_raw_size > 0); + BFD_ASSERT (sec->size > 0); symbol = sec->output_section->vma + sec->output_offset; } @@ -3223,12 +3879,9 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, { case R_MIPS_GOT_PAGE: case R_MIPS_GOT_OFST: - /* If this symbol got a global GOT entry, we have to decay - GOT_PAGE/GOT_OFST to GOT_DISP/addend. */ - local_p = local_p || ! h - || (h->root.dynindx - < mips_elf_get_global_gotsym_index (elf_hash_table (info) - ->dynobj)); + /* We need to decay to GOT_DISP/addend if the symbol doesn't + bind locally. */ + local_p = local_p || _bfd_elf_symbol_refs_local_p (&h->root, info, 1); if (local_p || r_type == R_MIPS_GOT_OFST) break; /* Fall through. */ @@ -3240,8 +3893,18 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, 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 @@ -3250,11 +3913,13 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, 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.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))) + (struct elf_link_hash_entry *) h, + r_type, info); + if (h->tls_type == GOT_NORMAL + && (! elf_hash_table(info)->dynamic_sections_created + || (info->shared + && (info->symbolic || h->root.dynindx == -1) + && h->root.def_regular))) { /* This is a static link or a -Bsymbolic link. The symbol is defined locally, or was forced to be local. @@ -3271,7 +3936,8 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, 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; } @@ -3283,10 +3949,12 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, 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) @@ -3300,6 +3968,9 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, break; } + if (gnu_local_gp_p) + symbol = gp; + /* Figure out what kind of relocation is being performed. */ switch (r_type) { @@ -3317,10 +3988,8 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, if ((info->shared || (elf_hash_table (info)->dynamic_sections_created && h != NULL - && ((h->root.elf_link_hash_flags - & ELF_LINK_HASH_DEF_DYNAMIC) != 0) - && ((h->root.elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR) == 0))) + && h->root.def_dynamic + && !h->root.def_regular)) && r_symndx != 0 && (input_section->flags & SEC_ALLOC) != 0) { @@ -3351,28 +4020,16 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, break; case R_MIPS_PC32: - case R_MIPS_PC64: - case R_MIPS_GNU_REL_LO16: value = symbol + addend - p; value &= howto->dst_mask; break; case R_MIPS_GNU_REL16_S2: - value = symbol + _bfd_mips_elf_sign_extend (addend << 2, 18) - p; + 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_GNU_REL_HI16: - /* Instead of subtracting 'p' here, we should be subtracting the - equivalent value for the LO part of the reloc, since the value - here is relative to that address. Because that's not easy to do, - we adjust 'addend' in _bfd_mips_elf_relocate_section(). See also - the comment there for more information. */ - value = mips_elf_high (addend + symbol - p); - value &= 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 @@ -3381,13 +4038,36 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, R_MIPS_26 case here. */ case R_MIPS_26: if (local_p) - value = (((addend << 2) | ((p + 4) & 0xf0000000)) + symbol) >> 2; + value = ((addend | ((p + 4) & 0xf0000000)) + symbol) >> 2; else - value = (_bfd_mips_elf_sign_extend (addend << 2, 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); @@ -3395,17 +4075,35 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, } 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 @@ -3479,6 +4177,9 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, /* 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; @@ -3553,12 +4254,16 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, 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. */ @@ -3577,11 +4282,9 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, /* Obtain the field relocated by RELOCATION. */ static bfd_vma -mips_elf_obtain_contents (howto, relocation, input_bfd, contents) - reloc_howto_type *howto; - const Elf_Internal_Rela *relocation; - bfd *input_bfd; - bfd_byte *contents; +mips_elf_obtain_contents (reloc_howto_type *howto, + const Elf_Internal_Rela *relocation, + bfd *input_bfd, bfd_byte *contents) { bfd_vma x; bfd_byte *location = contents + relocation->r_offset; @@ -3589,13 +4292,6 @@ mips_elf_obtain_contents (howto, relocation, input_bfd, contents) /* 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; } @@ -3609,16 +4305,12 @@ mips_elf_obtain_contents (howto, relocation, input_bfd, contents) Returns FALSE if anything goes wrong. */ static bfd_boolean -mips_elf_perform_relocation (info, howto, relocation, value, input_bfd, - input_section, contents, require_jalx) - struct bfd_link_info *info; - reloc_howto_type *howto; - const Elf_Internal_Rela *relocation; - bfd_vma value; - bfd *input_bfd; - asection *input_section; - bfd_byte *contents; - bfd_boolean require_jalx; +mips_elf_perform_relocation (struct bfd_link_info *info, + reloc_howto_type *howto, + const Elf_Internal_Rela *relocation, + bfd_vma value, bfd *input_bfd, + asection *input_section, bfd_byte *contents, + bfd_boolean require_jalx) { bfd_vma x; bfd_byte *location; @@ -3627,107 +4319,14 @@ mips_elf_perform_relocation (info, howto, relocation, value, input_bfd, /* 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); @@ -3754,9 +4353,9 @@ mips_elf_perform_relocation (info, howto, relocation, value, input_bfd, if (!ok) { (*_bfd_error_handler) - (_("%s: %s+0x%lx: jump to stub routine which is not jal"), - bfd_archive_filename (input_bfd), - input_section->name, + (_("%B: %A+0x%lx: jump to stub routine which is not jal"), + input_bfd, + input_section, (unsigned long) relocation->r_offset); bfd_set_error (bfd_error_bad_value); return FALSE; @@ -3766,23 +4365,46 @@ mips_elf_perform_relocation (info, howto, relocation, value, input_bfd, 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; } /* Returns TRUE if SECTION is a MIPS16 stub section. */ static bfd_boolean -mips_elf_stub_section_p (abfd, section) - bfd *abfd ATTRIBUTE_UNUSED; - asection *section; +mips_elf_stub_section_p (bfd *abfd ATTRIBUTE_UNUSED, asection *section) { const char *name = bfd_get_section_name (abfd, section); @@ -3794,22 +4416,20 @@ mips_elf_stub_section_p (abfd, section) /* Add room for N relocations to the .rel.dyn section in ABFD. */ static void -mips_elf_allocate_dynamic_relocations (abfd, n) - bfd *abfd; - unsigned int n; +mips_elf_allocate_dynamic_relocations (bfd *abfd, unsigned int n) { asection *s; s = mips_elf_rel_dyn_section (abfd, FALSE); BFD_ASSERT (s != NULL); - if (s->_raw_size == 0) + if (s->size == 0) { /* Make room for a null element. */ - s->_raw_size += MIPS_ELF_REL_SIZE (abfd); + s->size += MIPS_ELF_REL_SIZE (abfd); ++s->reloc_count; } - s->_raw_size += n * MIPS_ELF_REL_SIZE (abfd); + s->size += n * MIPS_ELF_REL_SIZE (abfd); } /* Create a rel.dyn relocation for the dynamic linker to resolve. REL @@ -3818,22 +4438,19 @@ mips_elf_allocate_dynamic_relocations (abfd, n) caller should store the result in place of the original addend. */ static bfd_boolean -mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec, - symbol, addendp, input_section) - bfd *output_bfd; - struct bfd_link_info *info; - const Elf_Internal_Rela *rel; - struct mips_elf_link_hash_entry *h; - asection *sec; - bfd_vma symbol; - bfd_vma *addendp; - asection *input_section; +mips_elf_create_dynamic_relocation (bfd *output_bfd, + struct bfd_link_info *info, + const Elf_Internal_Rela *rel, + struct mips_elf_link_hash_entry *h, + asection *sec, bfd_vma symbol, + 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; @@ -3841,9 +4458,8 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec, BFD_ASSERT (sreloc != NULL); BFD_ASSERT (sreloc->contents != NULL); BFD_ASSERT (sreloc->reloc_count * MIPS_ELF_REL_SIZE (output_bfd) - < sreloc->_raw_size); + < 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 = @@ -3851,139 +4467,110 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec, 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) + if (outrel[0].r_offset == MINUS_ONE) + /* The relocation field has been deleted. */ + return TRUE; + + if (outrel[0].r_offset == MINUS_TWO) { - outrel[1].r_offset = rel[1].r_offset; - outrel[2].r_offset = rel[2].r_offset; + /* 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. */ + *addendp += symbol; + return TRUE; } - else + + /* 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) { - /* 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 == (bfd_vma) -1) - skip = TRUE; + 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; } -#endif - - if (outrel[0].r_offset == (bfd_vma) -1 - || outrel[0].r_offset == (bfd_vma) -2) - skip = 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); 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.elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR) == 0) - /* 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.elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR) != 0); - 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, (unsigned long) 0, - ABI_64_P (output_bfd) - ? R_MIPS_64 - : R_MIPS_NONE); - outrel[2].r_info = ELF_R_INFO (output_bfd, (unsigned long) 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 @@ -4000,13 +4587,6 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec, (output_bfd, &outrel[0], (sreloc->contents + sreloc->reloc_count * sizeof (Elf32_External_Rel))); - /* Record the index of the first relocation referencing H. This - information is later emitted in the .msym section. */ - if (h != NULL - && (h->min_dyn_reloc_index == 0 - || sreloc->reloc_count < h->min_dyn_reloc_index)) - h->min_dyn_reloc_index = sreloc->reloc_count; - /* We've now added another relocation. */ ++sreloc->reloc_count; @@ -4016,7 +4596,7 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec, |= 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; @@ -4038,6 +4618,7 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec, 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)); @@ -4051,8 +4632,7 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec, /* Return the MACH for a MIPS e_flags value. */ unsigned long -_bfd_elf_mips_mach (flags) - flagword flags; +_bfd_elf_mips_mach (flagword flags) { switch (flags & EF_MIPS_MACH) { @@ -4080,6 +4660,9 @@ _bfd_elf_mips_mach (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; @@ -4118,6 +4701,10 @@ _bfd_elf_mips_mach (flags) case E_MIPS_ARCH_32R2: return bfd_mach_mipsisa32r2; break; + + case E_MIPS_ARCH_64R2: + return bfd_mach_mipsisa64r2; + break; } } @@ -4127,8 +4714,7 @@ _bfd_elf_mips_mach (flags) /* Return printable name for ABI. */ static INLINE char * -elf_mips_abi_name (abfd) - bfd *abfd; +elf_mips_abi_name (bfd *abfd) { flagword flags; @@ -4175,9 +4761,7 @@ static asymbol *mips_elf_acom_symbol_ptr; This is used for both the 32-bit and the 64-bit ABI. */ void -_bfd_mips_elf_symbol_processing (abfd, asym) - bfd *abfd; - asymbol *asym; +_bfd_mips_elf_symbol_processing (bfd *abfd, asymbol *asym) { elf_symbol_type *elfsym; @@ -4235,16 +4819,124 @@ _bfd_mips_elf_symbol_processing (abfd, asym) asym->section = bfd_und_section_ptr; break; -#if 0 /* for SGI_COMPAT */ - case SHN_MIPS_TEXT: - asym->section = mips_elf_text_section_ptr; - break; + case SHN_MIPS_TEXT: + { + asection *section = bfd_get_section_by_name (abfd, ".text"); + + BFD_ASSERT (SGI_COMPAT (abfd)); + if (section != NULL) + { + asym->section = section; + /* MIPS_TEXT is a bit special, the address is not an offset + to the base of the .text section. So substract the section + base address to make it an offset. */ + asym->value -= section->vma; + } + } + break; + + case SHN_MIPS_DATA: + { + asection *section = bfd_get_section_by_name (abfd, ".data"); + + BFD_ASSERT (SGI_COMPAT (abfd)); + if (section != NULL) + { + asym->section = section; + /* MIPS_DATA is a bit special, the address is not an offset + to the base of the .data section. So substract the section + base address to make it an offset. */ + asym->value -= section->vma; + } + } + break; + } +} + +/* 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; - case SHN_MIPS_DATA: - asym->section = mips_elf_data_section_ptr; - break; -#endif + 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: + + lw $4,%got_disp(.data)($gp) + lw $25,%got_disp(.text)($gp) + jalr $25 + + then the linker will resolve both relocations to .data and the program + will jump there rather than to .text. + + We can work around this problem by giving names to local section symbols. + This is also what the MIPSpro tools do. */ + +bfd_boolean +_bfd_mips_elf_name_local_section_symbols (bfd *abfd) +{ + return SGI_COMPAT (abfd); } /* Work over a section just before writing it out. This routine is @@ -4253,9 +4945,7 @@ _bfd_mips_elf_symbol_processing (abfd, asym) a better way. */ bfd_boolean -_bfd_mips_elf_section_processing (abfd, hdr) - bfd *abfd; - Elf_Internal_Shdr *hdr; +_bfd_mips_elf_section_processing (bfd *abfd, Elf_Internal_Shdr *hdr) { if (hdr->sh_type == SHT_MIPS_REGINFO && hdr->sh_size > 0) @@ -4270,7 +4960,7 @@ _bfd_mips_elf_section_processing (abfd, hdr) SEEK_SET) != 0) return FALSE; H_PUT_32 (abfd, elf_gp (abfd), buf); - if (bfd_bwrite (buf, (bfd_size_type) 4, abfd) != 4) + if (bfd_bwrite (buf, 4, abfd) != 4) return FALSE; } @@ -4297,6 +4987,13 @@ _bfd_mips_elf_section_processing (abfd, 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]; @@ -4309,7 +5006,7 @@ _bfd_mips_elf_section_processing (abfd, hdr) SEEK_SET) != 0) return FALSE; H_PUT_64 (abfd, elf_gp (abfd), buf); - if (bfd_bwrite (buf, (bfd_size_type) 8, abfd) != 8) + if (bfd_bwrite (buf, 8, abfd) != 8) return FALSE; } else if (intopt.kind == ODK_REGINFO) @@ -4324,7 +5021,7 @@ _bfd_mips_elf_section_processing (abfd, hdr) SEEK_SET) != 0) return FALSE; H_PUT_32 (abfd, elf_gp (abfd), buf); - if (bfd_bwrite (buf, (bfd_size_type) 4, abfd) != 4) + if (bfd_bwrite (buf, 4, abfd) != 4) return FALSE; } l += intopt.size; @@ -4381,10 +5078,10 @@ _bfd_mips_elf_section_processing (abfd, hdr) how to. */ bfd_boolean -_bfd_mips_elf_section_from_shdr (abfd, hdr, name) - 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; @@ -4435,7 +5132,7 @@ _bfd_mips_elf_section_from_shdr (abfd, hdr, name) 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: @@ -4453,10 +5150,10 @@ _bfd_mips_elf_section_from_shdr (abfd, hdr, name) 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) @@ -4479,9 +5176,8 @@ _bfd_mips_elf_section_from_shdr (abfd, hdr, name) Elf32_External_RegInfo ext; Elf32_RegInfo s; - if (! bfd_get_section_contents (abfd, hdr->bfd_section, (PTR) &ext, - (file_ptr) 0, - (bfd_size_type) sizeof ext)) + if (! bfd_get_section_contents (abfd, hdr->bfd_section, + &ext, 0, sizeof ext)) return FALSE; bfd_mips_elf32_swap_reginfo_in (abfd, &ext, &s); elf_gp (abfd) = s.ri_gp_value; @@ -4495,11 +5191,11 @@ _bfd_mips_elf_section_from_shdr (abfd, hdr, name) { bfd_byte *contents, *l, *lend; - contents = (bfd_byte *) bfd_malloc (hdr->sh_size); + contents = bfd_malloc (hdr->sh_size); if (contents == NULL) return FALSE; if (! bfd_get_section_contents (abfd, hdr->bfd_section, contents, - (file_ptr) 0, hdr->sh_size)) + 0, hdr->sh_size)) { free (contents); return FALSE; @@ -4512,6 +5208,13 @@ _bfd_mips_elf_section_from_shdr (abfd, hdr, name) 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; @@ -4547,19 +5250,18 @@ _bfd_mips_elf_section_from_shdr (abfd, hdr, name) used by both the 32-bit and the 64-bit ABI. */ bfd_boolean -_bfd_mips_elf_fake_sections (abfd, hdr, sec) - bfd *abfd; - Elf_Internal_Shdr *hdr; - asection *sec; +_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) { hdr->sh_type = SHT_MIPS_LIBLIST; - hdr->sh_info = sec->_raw_size / sizeof (Elf32_Lib); + hdr->sh_info = sec->size / sizeof (Elf32_Lib); /* The sh_link field is set in final_write_processing. */ } else if (strcmp (name, ".conflict") == 0) @@ -4627,7 +5329,7 @@ _bfd_mips_elf_fake_sections (abfd, hdr, 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; @@ -4656,6 +5358,12 @@ _bfd_mips_elf_fake_sections (abfd, hdr, 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 @@ -4672,10 +5380,8 @@ _bfd_mips_elf_fake_sections (abfd, hdr, sec) the .scommon section. */ bfd_boolean -_bfd_mips_elf_section_from_bfd_section (abfd, sec, retval) - bfd *abfd ATTRIBUTE_UNUSED; - asection *sec; - int *retval; +_bfd_mips_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED, + asection *sec, int *retval) { if (strcmp (bfd_get_section_name (abfd, sec), ".scommon") == 0) { @@ -4694,14 +5400,10 @@ _bfd_mips_elf_section_from_bfd_section (abfd, sec, retval) file. We must handle the special MIPS section numbers here. */ bfd_boolean -_bfd_mips_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp) - bfd *abfd; - struct bfd_link_info *info; - const Elf_Internal_Sym *sym; - const char **namep; - flagword *flagsp ATTRIBUTE_UNUSED; - asection **secp; - bfd_vma *valp; +_bfd_mips_elf_add_symbol_hook (bfd *abfd, struct bfd_link_info *info, + Elf_Internal_Sym *sym, const char **namep, + flagword *flagsp ATTRIBUTE_UNUSED, + asection **secp, bfd_vma *valp) { if (SGI_COMPAT (abfd) && (abfd->flags & DYNAMIC) != 0 @@ -4823,17 +5525,16 @@ _bfd_mips_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp) /* Mark __rld_obj_head as dynamic. */ bh = NULL; if (! (_bfd_generic_link_add_one_symbol - (info, abfd, *namep, BSF_GLOBAL, *secp, - (bfd_vma) *valp, (const char *) NULL, FALSE, + (info, abfd, *namep, BSF_GLOBAL, *secp, *valp, NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh))) return FALSE; h = (struct elf_link_hash_entry *) bh; - h->elf_link_hash_flags &= ~ELF_LINK_NON_ELF; - h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->non_elf = 0; + h->def_regular = 1; h->type = STT_OBJECT; - if (! bfd_elf32_link_record_dynamic_symbol (info, h)) + if (! bfd_elf_link_record_dynamic_symbol (info, h)) return FALSE; mips_elf_hash_table (info)->use_rld_obj_head = TRUE; @@ -4853,12 +5554,10 @@ _bfd_mips_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp) also where we undo the increment of the value for a mips16 symbol. */ bfd_boolean -_bfd_mips_elf_link_output_symbol_hook (abfd, info, name, sym, input_sec) - bfd *abfd ATTRIBUTE_UNUSED; - struct bfd_link_info *info ATTRIBUTE_UNUSED; - const char *name ATTRIBUTE_UNUSED; - Elf_Internal_Sym *sym; - asection *input_sec; +_bfd_mips_elf_link_output_symbol_hook + (struct bfd_link_info *info ATTRIBUTE_UNUSED, + const char *name ATTRIBUTE_UNUSED, Elf_Internal_Sym *sym, + asection *input_sec, struct elf_link_hash_entry *h ATTRIBUTE_UNUSED) { /* If we see a common symbol, which implies a relocatable link, then if a symbol was small common in an input file, mark it as small @@ -4867,9 +5566,8 @@ _bfd_mips_elf_link_output_symbol_hook (abfd, info, name, sym, input_sec) && strcmp (input_sec->name, ".scommon") == 0) sym->st_shndx = SHN_MIPS_SCOMMON; - if (sym->st_other == STO_MIPS16 - && (sym->st_value & 1) != 0) - --sym->st_value; + if (sym->st_other == STO_MIPS16) + sym->st_value &= ~1; return TRUE; } @@ -4879,9 +5577,7 @@ _bfd_mips_elf_link_output_symbol_hook (abfd, info, name, sym, input_sec) /* Create dynamic sections when linking against a dynamic object. */ bfd_boolean -_bfd_mips_elf_create_dynamic_sections (abfd, info) - bfd *abfd; - struct bfd_link_info *info; +_bfd_mips_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) { struct elf_link_hash_entry *h; struct bfd_link_hash_entry *bh; @@ -4907,20 +5603,14 @@ _bfd_mips_elf_create_dynamic_sections (abfd, info) if (! mips_elf_rel_dyn_section (elf_hash_table (info)->dynobj, TRUE)) return FALSE; - /* Create the .msym section on IRIX6. It is used by the dynamic - linker to speed up dynamic relocations, and to avoid computing - the ELF hash for symbols. */ - if (IRIX_COMPAT (abfd) == ict_irix6 - && !mips_elf_create_msym_section (abfd)) - return FALSE; - /* Create .stub section. */ 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; @@ -4930,9 +5620,9 @@ _bfd_mips_elf_create_dynamic_sections (abfd, 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; @@ -4948,17 +5638,16 @@ _bfd_mips_elf_create_dynamic_sections (abfd, info) { bh = NULL; if (! (_bfd_generic_link_add_one_symbol - (info, abfd, *namep, BSF_GLOBAL, bfd_und_section_ptr, - (bfd_vma) 0, (const char *) NULL, FALSE, - get_elf_backend_data (abfd)->collect, &bh))) + (info, abfd, *namep, BSF_GLOBAL, bfd_und_section_ptr, 0, + NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh))) return FALSE; h = (struct elf_link_hash_entry *) bh; - h->elf_link_hash_flags &= ~ELF_LINK_NON_ELF; - h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->non_elf = 0; + h->def_regular = 1; h->type = STT_SECTION; - if (! bfd_elf32_link_record_dynamic_symbol (info, h)) + if (! bfd_elf_link_record_dynamic_symbol (info, h)) return FALSE; } @@ -4994,17 +5683,16 @@ _bfd_mips_elf_create_dynamic_sections (abfd, info) name = SGI_COMPAT (abfd) ? "_DYNAMIC_LINK" : "_DYNAMIC_LINKING"; bh = NULL; if (!(_bfd_generic_link_add_one_symbol - (info, abfd, name, BSF_GLOBAL, bfd_abs_section_ptr, - (bfd_vma) 0, (const char *) NULL, FALSE, - get_elf_backend_data (abfd)->collect, &bh))) + (info, abfd, name, BSF_GLOBAL, bfd_abs_section_ptr, 0, + NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh))) return FALSE; h = (struct elf_link_hash_entry *) bh; - h->elf_link_hash_flags &= ~ELF_LINK_NON_ELF; - h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->non_elf = 0; + h->def_regular = 1; h->type = STT_SECTION; - if (! bfd_elf32_link_record_dynamic_symbol (info, h)) + if (! bfd_elf_link_record_dynamic_symbol (info, h)) return FALSE; if (! mips_elf_hash_table (info)->use_rld_obj_head) @@ -5019,17 +5707,16 @@ _bfd_mips_elf_create_dynamic_sections (abfd, info) name = SGI_COMPAT (abfd) ? "__rld_map" : "__RLD_MAP"; bh = NULL; if (!(_bfd_generic_link_add_one_symbol - (info, abfd, name, BSF_GLOBAL, s, - (bfd_vma) 0, (const char *) NULL, FALSE, + (info, abfd, name, BSF_GLOBAL, s, 0, NULL, FALSE, get_elf_backend_data (abfd)->collect, &bh))) return FALSE; h = (struct elf_link_hash_entry *) bh; - h->elf_link_hash_flags &= ~ELF_LINK_NON_ELF; - h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; + h->non_elf = 0; + h->def_regular = 1; h->type = STT_OBJECT; - if (! bfd_elf32_link_record_dynamic_symbol (info, h)) + if (! bfd_elf_link_record_dynamic_symbol (info, h)) return FALSE; } } @@ -5041,11 +5728,8 @@ _bfd_mips_elf_create_dynamic_sections (abfd, info) allocate space in the global offset table. */ bfd_boolean -_bfd_mips_elf_check_relocs (abfd, info, sec, relocs) - bfd *abfd; - struct bfd_link_info *info; - asection *sec; - const Elf_Internal_Rela *relocs; +_bfd_mips_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, + asection *sec, const Elf_Internal_Rela *relocs) { const char *name; bfd *dynobj; @@ -5057,7 +5741,7 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs) const Elf_Internal_Rela *rel_end; asection *sgot; asection *sreloc; - struct elf_backend_data *bed; + const struct elf_backend_data *bed; if (info->relocatable) return TRUE; @@ -5104,8 +5788,7 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs) continue; sec_relocs - = _bfd_elf_link_read_relocs (abfd, o, (PTR) NULL, - (Elf_Internal_Rela *) NULL, + = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL, info->keep_memory); if (sec_relocs == NULL) return FALSE; @@ -5147,7 +5830,7 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs) else symcount = symtab_hdr->sh_info; amt = symcount * sizeof (asection *); - n = (asection **) bfd_zalloc (abfd, amt); + n = bfd_zalloc (abfd, amt); if (n == NULL) return FALSE; elf_tdata (abfd)->local_stubs = n; @@ -5261,8 +5944,8 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs) else if (r_symndx >= extsymoff + NUM_SHDR_ENTRIES (symtab_hdr)) { (*_bfd_error_handler) - (_("%s: Malformed reloc detected for section %s"), - bfd_archive_filename (abfd), name); + (_("%B: Malformed reloc detected for section %s"), + abfd, name); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -5292,6 +5975,8 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs) case R_MIPS_GOT_PAGE: case R_MIPS_GOT_OFST: case R_MIPS_GOT_DISP: + case R_MIPS_TLS_GD: + case R_MIPS_TLS_LDM: if (dynobj == NULL) elf_hash_table (info)->dynobj = dynobj = abfd; if (! mips_elf_create_got_section (dynobj, info, FALSE)) @@ -5325,7 +6010,7 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs) 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; } @@ -5335,8 +6020,8 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs) if (h == NULL) { (*_bfd_error_handler) - (_("%s: CALL16 reloc at 0x%lx not against global symbol"), - bfd_archive_filename (abfd), (unsigned long) rel->r_offset); + (_("%B: CALL16 reloc at 0x%lx not against global symbol"), + abfd, (unsigned long) rel->r_offset); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -5347,13 +6032,13 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs) 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 function. But we record it as if it needs plt. See - elf_adjust_dynamic_symbol in elflink.h. */ - h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; + _bfd_elf_adjust_dynamic_symbol. */ + h->needs_plt = 1; h->type = STT_FUNC; } break; @@ -5373,25 +6058,9 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs) hmips = (struct mips_elf_link_hash_entry *) hmips->root.root.u.i.link; - if ((hmips->root.root.type == bfd_link_hash_defined - || hmips->root.root.type == bfd_link_hash_defweak) - && hmips->root.root.u.def.section + if (hmips->root.def_regular && ! (info->shared && ! info->symbolic - && ! (hmips->root.elf_link_hash_flags - & ELF_LINK_FORCED_LOCAL)) - /* If we've encountered any other relocation - referencing the symbol, we'll have marked it as - dynamic, and, even though we might be able to get - rid of the GOT entry should we know for sure all - previous relocations were GOT_PAGE ones, at this - point we can't tell, so just keep using the - symbol as dynamic. This is very important in the - multi-got case, since we don't decide whether to - decay GOT_PAGE to GOT_DISP on a per-GOT basis: if - the symbol is dynamic, we'll need a GOT entry for - every GOT in which the symbol is referenced with - a GOT_PAGE relocation. */ - && hmips->root.dynindx == -1) + && ! hmips->root.forced_local)) break; } /* Fall through. */ @@ -5400,11 +6069,52 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs) 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: @@ -5457,7 +6167,7 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs) 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; } } @@ -5479,14 +6189,14 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs) /* This relocation describes the C++ object vtable hierarchy. Reconstruct it for later use during GC. */ case R_MIPS_GNU_VTINHERIT: - if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) + if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) return FALSE; break; /* This relocation describes which C++ vtable entries are actually used. Record for later use during GC. */ case R_MIPS_GNU_VTENTRY: - if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_offset)) + if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset)) return FALSE; break; @@ -5537,17 +6247,14 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs) } bfd_boolean -_bfd_mips_relax_section (abfd, sec, link_info, again) - bfd *abfd; - asection *sec; - struct bfd_link_info *link_info; - bfd_boolean *again; +_bfd_mips_relax_section (bfd *abfd, asection *sec, + struct bfd_link_info *link_info, + bfd_boolean *again) { Elf_Internal_Rela *internal_relocs; Elf_Internal_Rela *irel, *irelend; Elf_Internal_Shdr *symtab_hdr; bfd_byte *contents = NULL; - bfd_byte *free_contents = NULL; size_t extsymoff; bfd_boolean changed_contents = FALSE; bfd_vma sec_start = sec->output_section->vma + sec->output_offset; @@ -5559,8 +6266,7 @@ _bfd_mips_relax_section (abfd, sec, link_info, again) if (link_info->relocatable) return TRUE; - internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, (PTR) NULL, - (Elf_Internal_Rela *) NULL, + internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, link_info->keep_memory); if (internal_relocs == NULL) return TRUE; @@ -5604,7 +6310,7 @@ _bfd_mips_relax_section (abfd, sec, link_info, again) || h->root.root.type == bfd_link_hash_defweak) && h->root.root.u.def.section) || (link_info->shared && ! link_info->symbolic - && ! (h->root.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL))) + && !h->root.forced_local)) continue; sym_sec = h->root.root.u.def.section; @@ -5669,13 +6375,7 @@ _bfd_mips_relax_section (abfd, sec, link_info, again) contents = elf_section_data (sec)->this_hdr.contents; else { - contents = (bfd_byte *) bfd_malloc (sec->_raw_size); - if (contents == NULL) - goto relax_return; - - free_contents = contents; - if (! bfd_get_section_contents (abfd, sec, contents, - (file_ptr) 0, sec->_raw_size)) + if (!bfd_malloc_and_get_section (abfd, sec, &contents)) goto relax_return; } } @@ -5710,8 +6410,9 @@ _bfd_mips_relax_section (abfd, sec, link_info, again) return TRUE; relax_return: - if (free_contents != NULL) - free (free_contents); + if (contents != NULL + && elf_section_data (sec)->this_hdr.contents != contents) + free (contents); return FALSE; } @@ -5722,9 +6423,8 @@ _bfd_mips_relax_section (abfd, sec, link_info, again) understand. */ bfd_boolean -_bfd_mips_elf_adjust_dynamic_symbol (info, h) - struct bfd_link_info *info; - struct elf_link_hash_entry *h; +_bfd_mips_elf_adjust_dynamic_symbol (struct bfd_link_info *info, + struct elf_link_hash_entry *h) { bfd *dynobj; struct mips_elf_link_hash_entry *hmips; @@ -5734,14 +6434,11 @@ _bfd_mips_elf_adjust_dynamic_symbol (info, h) /* Make sure we know what is going on here. */ BFD_ASSERT (dynobj != NULL - && ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) - || h->weakdef != NULL - || ((h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_DYNAMIC) != 0 - && (h->elf_link_hash_flags - & ELF_LINK_HASH_REF_REGULAR) != 0 - && (h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR) == 0))); + && (h->needs_plt + || h->u.weakdef != NULL + || (h->def_dynamic + && h->ref_regular + && !h->def_regular))); /* If this symbol is defined in a dynamic object, we need to copy any R_MIPS_32 or R_MIPS_REL32 relocs against it into the output @@ -5750,8 +6447,7 @@ _bfd_mips_elf_adjust_dynamic_symbol (info, h) if (! info->relocatable && hmips->possibly_dynamic_relocs != 0 && (h->root.type == bfd_link_hash_defweak - || (h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR) == 0)) + || !h->def_regular)) { mips_elf_allocate_dynamic_relocations (dynobj, hmips->possibly_dynamic_relocs); @@ -5763,7 +6459,7 @@ _bfd_mips_elf_adjust_dynamic_symbol (info, h) /* For a function, create a stub, if allowed. */ if (! hmips->no_fn_stub - && (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0) + && h->needs_plt) { if (! elf_hash_table (info)->dynamic_sections_created) return TRUE; @@ -5772,7 +6468,7 @@ _bfd_mips_elf_adjust_dynamic_symbol (info, h) the symbol to the stub location. This is required to make function pointers compare as equal between the normal executable and the shared library. */ - if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + if (!h->def_regular) { /* We need .stub section. */ s = bfd_get_section_by_name (dynobj, @@ -5780,13 +6476,13 @@ _bfd_mips_elf_adjust_dynamic_symbol (info, h) BFD_ASSERT (s != NULL); h->root.u.def.section = s; - h->root.u.def.value = s->_raw_size; + h->root.u.def.value = s->size; /* XXX Write this stub address somewhere. */ - h->plt.offset = s->_raw_size; + h->plt.offset = s->size; /* Make room for this stub code. */ - s->_raw_size += MIPS_FUNCTION_STUB_SIZE; + s->size += MIPS_FUNCTION_STUB_SIZE; /* The last half word of the stub will be filled with the index of this symbol in .dynsym section. */ @@ -5794,7 +6490,7 @@ _bfd_mips_elf_adjust_dynamic_symbol (info, h) } } else if ((h->type == STT_FUNC) - && (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) == 0) + && !h->needs_plt) { /* This will set the entry for this symbol in the GOT to 0, and the dynamic linker will take care of this. */ @@ -5805,12 +6501,12 @@ _bfd_mips_elf_adjust_dynamic_symbol (info, h) /* If this is a weak symbol, and there is a real definition, the processor independent code will have arranged for us to see the real definition first, and we can just use the same value. */ - if (h->weakdef != NULL) + if (h->u.weakdef != NULL) { - BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined - || h->weakdef->root.type == bfd_link_hash_defweak); - h->root.u.def.section = h->weakdef->root.u.def.section; - h->root.u.def.value = h->weakdef->root.u.def.value; + BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined + || h->u.weakdef->root.type == bfd_link_hash_defweak); + h->root.u.def.section = h->u.weakdef->root.u.def.section; + h->root.u.def.value = h->u.weakdef->root.u.def.value; return TRUE; } @@ -5825,9 +6521,8 @@ _bfd_mips_elf_adjust_dynamic_symbol (info, h) check for any mips16 stub sections that we can discard. */ bfd_boolean -_bfd_mips_elf_always_size_sections (output_bfd, info) - bfd *output_bfd; - struct bfd_link_info *info; +_bfd_mips_elf_always_size_sections (bfd *output_bfd, + struct bfd_link_info *info) { asection *ri; @@ -5838,18 +6533,17 @@ _bfd_mips_elf_always_size_sections (output_bfd, info) 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"); if (ri != NULL) - bfd_set_section_size (output_bfd, ri, - (bfd_size_type) sizeof (Elf32_External_RegInfo)); + bfd_set_section_size (output_bfd, ri, sizeof (Elf32_External_RegInfo)); if (! (info->relocatable || ! mips_elf_hash_table (info)->mips16_stubs_seen)) mips_elf_link_hash_traverse (mips_elf_hash_table (info), - mips_elf_check_mips16_stubs, - (PTR) NULL); + mips_elf_check_mips16_stubs, NULL); dynobj = elf_hash_table (info)->dynobj; if (dynobj == NULL) @@ -5873,7 +6567,7 @@ _bfd_mips_elf_always_size_sections (output_bfd, info) { if ((subsection->flags & SEC_ALLOC) == 0) continue; - loadable_size += ((subsection->_raw_size + 0xf) + loadable_size += ((subsection->size + 0xf) &~ (bfd_size_type) 0xf); } } @@ -5903,14 +6597,35 @@ _bfd_mips_elf_always_size_sections (output_bfd, info) local_gotno = (loadable_size >> 16) + 5; g->local_gotno += local_gotno; - s->_raw_size += g->local_gotno * MIPS_ELF_GOT_SIZE (output_bfd); + s->size += g->local_gotno * MIPS_ELF_GOT_SIZE (output_bfd); g->global_gotno = i; - s->_raw_size += i * MIPS_ELF_GOT_SIZE (output_bfd); + s->size += i * MIPS_ELF_GOT_SIZE (output_bfd); + + /* 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); - if (s->_raw_size > MIPS_ELF_GOT_MAX_SIZE (output_bfd) - && ! mips_elf_multi_got (output_bfd, info, g, s, local_gotno)) - return FALSE; + 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; } @@ -5918,9 +6633,8 @@ _bfd_mips_elf_always_size_sections (output_bfd, info) /* Set the sizes of the dynamic sections. */ bfd_boolean -_bfd_mips_elf_size_dynamic_sections (output_bfd, info) - bfd *output_bfd; - struct bfd_link_info *info; +_bfd_mips_elf_size_dynamic_sections (bfd *output_bfd, + struct bfd_link_info *info) { bfd *dynobj; asection *s; @@ -5932,11 +6646,11 @@ _bfd_mips_elf_size_dynamic_sections (output_bfd, info) if (elf_hash_table (info)->dynamic_sections_created) { /* Set the contents of the .interp section to the interpreter. */ - if (! info->shared) + if (info->executable) { s = bfd_get_section_by_name (dynobj, ".interp"); BFD_ASSERT (s != NULL); - s->_raw_size + s->size = strlen (ELF_DYNAMIC_INTERPRETER (output_bfd)) + 1; s->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER (output_bfd); @@ -5963,7 +6677,7 @@ _bfd_mips_elf_size_dynamic_sections (output_bfd, info) if (strncmp (name, ".rel", 4) == 0) { - if (s->_raw_size == 0) + if (s->size == 0) { /* We only strip the section if the output section name has the same name. Otherwise, there might be several @@ -6026,6 +6740,9 @@ _bfd_mips_elf_size_dynamic_sections (output_bfd, info) 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) { @@ -6051,19 +6768,34 @@ _bfd_mips_elf_size_dynamic_sections (output_bfd, info) 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) { /* IRIX rld assumes that the function stub isn't at the end of .text section. So put a dummy. XXX */ - s->_raw_size += MIPS_FUNCTION_STUB_SIZE; + s->size += MIPS_FUNCTION_STUB_SIZE; } else if (! info->shared && ! mips_elf_hash_table (info)->use_rld_obj_head @@ -6071,15 +6803,11 @@ _bfd_mips_elf_size_dynamic_sections (output_bfd, info) { /* We add a room for __rld_map. It will be filled in by the rtld to contain a pointer to the _r_debug structure. */ - s->_raw_size += 4; + s->size += 4; } else if (SGI_COMPAT (output_bfd) && strncmp (name, ".compact_rel", 12) == 0) - s->_raw_size += mips_elf_hash_table (info)->compact_rel_size; - else if (strcmp (name, ".msym") == 0) - s->_raw_size = (sizeof (Elf32_External_Msym) - * (elf_hash_table (info)->dynsymcount - + bfd_count_sections (output_bfd))); + s->size += mips_elf_hash_table (info)->compact_rel_size; else if (strncmp (name, ".init", 5) != 0) { /* It's not one of our sections, so don't allocate space. */ @@ -6088,13 +6816,13 @@ _bfd_mips_elf_size_dynamic_sections (output_bfd, info) if (strip) { - _bfd_strip_section_from_output (info, s); + s->flags |= SEC_EXCLUDE; continue; } /* Allocate memory for the section contents. */ - s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->_raw_size); - if (s->contents == NULL && s->_raw_size != 0) + s->contents = bfd_zalloc (dynobj, s->size); + if (s->contents == NULL && s->size != 0) { bfd_set_error (bfd_error_no_memory); return FALSE; @@ -6154,52 +6882,12 @@ _bfd_mips_elf_size_dynamic_sections (output_bfd, info) return FALSE; } - if (SGI_COMPAT (output_bfd)) - { - if (!MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_CONFLICTNO, 0)) - return FALSE; - } - - if (SGI_COMPAT (output_bfd)) - { - if (!MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_LIBLISTNO, 0)) - return FALSE; - } - - if (bfd_get_section_by_name (dynobj, ".conflict") != NULL) - { - if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_CONFLICT, 0)) - return FALSE; - - s = bfd_get_section_by_name (dynobj, ".liblist"); - BFD_ASSERT (s != NULL); - - if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_LIBLIST, 0)) - return FALSE; - } - if (! MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_RLD_VERSION, 0)) return FALSE; 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; @@ -6224,10 +6912,6 @@ _bfd_mips_elf_size_dynamic_sections (output_bfd, info) (dynobj, MIPS_ELF_OPTIONS_SECTION_NAME (dynobj))) && !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_OPTIONS, 0)) return FALSE; - - if (bfd_get_section_by_name (dynobj, ".msym") - && !MIPS_ELF_ADD_DYNAMIC_ENTRY (info, DT_MIPS_MSYM, 0)) - return FALSE; } return TRUE; @@ -6236,22 +6920,17 @@ _bfd_mips_elf_size_dynamic_sections (output_bfd, info) /* Relocate a MIPS ELF section. */ bfd_boolean -_bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, - contents, relocs, local_syms, local_sections) - bfd *output_bfd; - struct bfd_link_info *info; - bfd *input_bfd; - asection *input_section; - bfd_byte *contents; - Elf_Internal_Rela *relocs; - Elf_Internal_Sym *local_syms; - asection **local_sections; +_bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, + bfd *input_bfd, asection *input_section, + bfd_byte *contents, Elf_Internal_Rela *relocs, + Elf_Internal_Sym *local_syms, + asection **local_sections) { Elf_Internal_Rela *rel; const Elf_Internal_Rela *relend; bfd_vma addend = 0; bfd_boolean use_saved_addend_p = FALSE; - struct elf_backend_data *bed; + const struct elf_backend_data *bed; bed = get_elf_backend_data (output_bfd); relend = relocs + input_section->reloc_count * bed->s->int_rels_per_ext_rel; @@ -6265,7 +6944,7 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, REL relocation. */ bfd_boolean rela_relocation_p = TRUE; unsigned int r_type = ELF_R_TYPE (output_bfd, rel->r_info); - const char * msg = (const char *) NULL; + const char *msg; /* Find the relocation howto for this relocation. */ if (r_type == R_MIPS_64 && ! NEWABI_P (input_bfd)) @@ -6307,20 +6986,25 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, 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; - addend <<= howto->rightshift; /* For some kinds of relocations, the ADDEND is a combination of the addend stored in two different relocations. */ - if (r_type == R_MIPS_HI16 - || r_type == R_MIPS_GNU_REL_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))) @@ -6328,7 +7012,13 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, bfd_vma l; const Elf_Internal_Rela *lo16_relocation; reloc_howto_type *lo16_howto; - unsigned int lo; + 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 @@ -6336,20 +7026,33 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, a `lui' of the HI16 value, and then an `addiu' of the LO16 value.) - Scan ahead to find a matching LO16 relocation. */ - if (r_type == R_MIPS_GNU_REL_HI16) - lo = R_MIPS_GNU_REL_LO16; - else - lo = R_MIPS_LO16; - lo16_relocation = mips_elf_next_relocation (input_bfd, lo, + Scan ahead to find a matching LO16 relocation. + + According to the MIPS ELF ABI, the R_MIPS_LO16 + relocation must be immediately following. + However, for the IRIX6 ABI, the next relocation + may be a composed relocation consisting of + several relocations for the same address. In + that case, the R_MIPS_LO16 relocation may occur + 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, + 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, lo, FALSE); + lo16_howto = MIPS_ELF_RTYPE_TO_HOWTO (input_bfd, + 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); @@ -6358,26 +7061,9 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, /* Compute the combined addend. */ addend += l; - - /* If PC-relative, subtract the difference between the - address of the LO part of the reloc and the address of - the HI part. The relocation is relative to the LO - part, but mips_elf_calculate_relocation() doesn't - know its address or the difference from the HI part, so - we subtract that difference here. See also the - comment in mips_elf_calculate_relocation(). */ - if (r_type == R_MIPS_GNU_REL_HI16) - addend -= (lo16_relocation->r_offset - rel->r_offset); - } - 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; } else addend = rel->r_addend; @@ -6417,33 +7103,24 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, /* Adjust the addend appropriately. */ addend += local_sections[r_symndx]->output_offset; - if (howto->partial_inplace) + if (rela_relocation_p) + /* If this is a RELA relocation, just update the addend. */ + rel->r_addend = addend; + else { - /* If the relocation is for a R_MIPS_HI16 or R_MIPS_GOT16, - then we only want to write out the high-order 16 bits. - The subsequent R_MIPS_LO16 will handle the low-order bits. - */ - if (r_type == R_MIPS_HI16 || r_type == R_MIPS_GOT16 - || r_type == R_MIPS_GNU_REL_HI16) + if (r_type == R_MIPS_HI16 + || r_type == R_MIPS_GOT16) addend = mips_elf_high (addend); else if (r_type == R_MIPS_HIGHER) addend = mips_elf_higher (addend); else if (r_type == R_MIPS_HIGHEST) addend = mips_elf_highest (addend); - } + else + addend >>= howto->rightshift; - if (rela_relocation_p) - /* If this is a RELA relocation, just update the addend. - We have to cast away constness for REL. */ - rel->r_addend = addend; - else - { - /* Otherwise, we have to write the value back out. Note - that we use the source mask, rather than the - destination mask because the place to which we are - writing will be source of the addend in the final - link. */ - addend >>= howto->rightshift; + /* We use the source mask, rather than the destination + mask because the place to which we are writing will be + source of the addend in the final link. */ addend &= howto->src_mask; if (r_type == R_MIPS_64 && ! NEWABI_P (output_bfd)) @@ -6507,8 +7184,6 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, else use_saved_addend_p = FALSE; - addend >>= howto->rightshift; - /* Figure out what value we are supposed to relocate. */ switch (mips_elf_calculate_relocation (output_bfd, input_bfd, input_section, info, rel, @@ -6543,7 +7218,7 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, { BFD_ASSERT (name != NULL); if (! ((*info->callbacks->reloc_overflow) - (info, name, howto->name, (bfd_vma) 0, + (info, NULL, name, howto->name, (bfd_vma) 0, input_bfd, input_section, rel->r_offset))) return FALSE; } @@ -6624,10 +7299,8 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, adjust it appropriately now. */ static void -mips_elf_irix6_finish_dynamic_symbol (abfd, name, sym) - bfd *abfd ATTRIBUTE_UNUSED; - const char *name; - Elf_Internal_Sym *sym; +mips_elf_irix6_finish_dynamic_symbol (bfd *abfd ATTRIBUTE_UNUSED, + const char *name, Elf_Internal_Sym *sym) { /* The linker script takes care of providing names and values for these, but we must place them into the right sections. */ @@ -6660,6 +7333,7 @@ mips_elf_irix6_finish_dynamic_symbol (abfd, name, sym) /* All of these symbols are given type STT_SECTION by the IRIX6 linker. */ sym->st_info = ELF_ST_INFO (STB_GLOBAL, STT_SECTION); + sym->st_other = STO_PROTECTED; /* The IRIX linker puts these symbols in special sections. */ if (i == 0) @@ -6675,25 +7349,19 @@ mips_elf_irix6_finish_dynamic_symbol (abfd, name, sym) dynamic sections here. */ bfd_boolean -_bfd_mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym) - bfd *output_bfd; - struct bfd_link_info *info; - struct elf_link_hash_entry *h; - Elf_Internal_Sym *sym; +_bfd_mips_elf_finish_dynamic_symbol (bfd *output_bfd, + struct bfd_link_info *info, + struct elf_link_hash_entry *h, + Elf_Internal_Sym *sym) { bfd *dynobj; - bfd_vma gval; asection *sgot; - asection *smsym; struct mips_got_info *g, *gg; const char *name; - struct mips_elf_link_hash_entry *mh; dynobj = elf_hash_table (info)->dynobj; - gval = sym->st_value; - mh = (struct mips_elf_link_hash_entry *) h; - if (h->plt.offset != (bfd_vma) -1) + if (h->plt.offset != MINUS_ONE) { asection *s; bfd_byte stub[MIPS_FUNCTION_STUB_SIZE]; @@ -6716,7 +7384,7 @@ _bfd_mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym) bfd_put_32 (output_bfd, STUB_JALR, stub + 8); bfd_put_32 (output_bfd, STUB_LI16 (output_bfd) + h->dynindx, stub + 12); - BFD_ASSERT (h->plt.offset <= s->_raw_size); + BFD_ASSERT (h->plt.offset <= s->size); memcpy (s->contents + h->plt.offset, stub, MIPS_FUNCTION_STUB_SIZE); /* Mark the symbol as undefined. plt.offset != -1 occurs @@ -6726,12 +7394,12 @@ _bfd_mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym) /* The run-time linker uses the st_value field of the symbol to reset the global offset table entry for this external to its stub address when unlinking a shared object. */ - gval = s->output_section->vma + s->output_offset + h->plt.offset; - sym->st_value = gval; + sym->st_value = (s->output_section->vma + s->output_offset + + h->plt.offset); } BFD_ASSERT (h->dynindx != -1 - || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0); + || h->forced_local); sgot = mips_elf_got_section (dynobj, FALSE); BFD_ASSERT (sgot != NULL); @@ -6748,35 +7416,22 @@ _bfd_mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym) 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; bfd_vma offset; - bfd_vma value; - Elf_Internal_Rela rel[3]; - bfd_vma addend = 0; gg = g; e.abfd = output_bfd; e.symndx = -1; e.d.h = (struct mips_elf_link_hash_entry *)h; - - if (info->shared - || h->root.type == bfd_link_hash_undefined - || h->root.type == bfd_link_hash_undefweak) - value = 0; - else if (sym->st_value) - value = sym->st_value; - else - value = h->root.u.def.value; - - memset (rel, 0, sizeof (rel)); - rel[0].r_info = ELF_R_INFO (output_bfd, 0, R_MIPS_REL32); + e.tls_type = 0; for (g = g->next; g->next != gg; g = g->next) { @@ -6785,41 +7440,39 @@ _bfd_mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym) &e))) { offset = p->gotidx; - rel[0].r_offset = rel[1].r_offset = rel[2].r_offset = offset; - - MIPS_ELF_PUT_WORD (output_bfd, value, sgot->contents + offset); - - if ((info->shared - || (elf_hash_table (info)->dynamic_sections_created - && p->d.h != NULL - && ((p->d.h->root.elf_link_hash_flags - & ELF_LINK_HASH_DEF_DYNAMIC) != 0) - && ((p->d.h->root.elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR) == 0))) - && ! (mips_elf_create_dynamic_relocation - (output_bfd, info, rel, - e.d.h, NULL, value, &addend, sgot))) - return FALSE; - BFD_ASSERT (addend == 0); + if (info->shared + || (elf_hash_table (info)->dynamic_sections_created + && p->d.h != NULL + && p->d.h->root.def_dynamic + && !p->d.h->root.def_regular)) + { + /* Create an R_MIPS_REL32 relocation for this entry. Due to + the various compatibility problems, it's easier to mock + up an R_MIPS_32 or R_MIPS_64 relocation and leave + mips_elf_create_dynamic_relocation to calculate the + appropriate addend. */ + Elf_Internal_Rela rel[3]; + + memset (rel, 0, sizeof (rel)); + if (ABI_64_P (output_bfd)) + rel[0].r_info = ELF_R_INFO (output_bfd, 0, R_MIPS_64); + else + rel[0].r_info = ELF_R_INFO (output_bfd, 0, R_MIPS_32); + rel[0].r_offset = rel[1].r_offset = rel[2].r_offset = offset; + + entry = 0; + if (! (mips_elf_create_dynamic_relocation + (output_bfd, info, rel, + e.d.h, NULL, sym->st_value, &entry, sgot))) + return FALSE; + } + else + entry = sym->st_value; + MIPS_ELF_PUT_WORD (output_bfd, entry, sgot->contents + offset); } } } - /* Create a .msym entry, if appropriate. */ - smsym = bfd_get_section_by_name (dynobj, ".msym"); - if (smsym) - { - Elf32_Internal_Msym msym; - - msym.ms_hash_value = bfd_elf_hash (h->root.root.string); - /* It is undocumented what the `1' indicates, but IRIX6 uses - this value. */ - msym.ms_info = ELF32_MS_INFO (mh->min_dyn_reloc_index, 1); - bfd_mips_elf_swap_msym_out - (dynobj, &msym, - ((Elf32_External_Msym *) smsym->contents) + h->dynindx); - } - /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ name = h->root.root.string; if (strcmp (name, "_DYNAMIC") == 0 @@ -6877,7 +7530,7 @@ _bfd_mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym) asection *s = bfd_get_section_by_name (dynobj, ".rld_map"); BFD_ASSERT (s != NULL); sym->st_value = s->output_section->vma + s->output_offset; - bfd_put_32 (output_bfd, (bfd_vma) 0, s->contents); + bfd_put_32 (output_bfd, 0, s->contents); if (mips_elf_hash_table (info)->rld_value == 0) mips_elf_hash_table (info)->rld_value = sym->st_value; } @@ -6894,9 +7547,8 @@ _bfd_mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym) } /* If this is a mips16 symbol, force the value to be even. */ - if (sym->st_other == STO_MIPS16 - && (sym->st_value & 1) != 0) - --sym->st_value; + if (sym->st_other == STO_MIPS16) + sym->st_value &= ~1; return TRUE; } @@ -6904,9 +7556,8 @@ _bfd_mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym) /* Finish up the dynamic sections. */ bfd_boolean -_bfd_mips_elf_finish_dynamic_sections (output_bfd, info) - bfd *output_bfd; - struct bfd_link_info *info; +_bfd_mips_elf_finish_dynamic_sections (bfd *output_bfd, + struct bfd_link_info *info) { bfd *dynobj; asection *sdyn; @@ -6937,7 +7588,7 @@ _bfd_mips_elf_finish_dynamic_sections (output_bfd, info) BFD_ASSERT (g != NULL); for (b = sdyn->contents; - b < sdyn->contents + sdyn->_raw_size; + b < sdyn->contents + sdyn->size; b += MIPS_ELF_DYN_SIZE (dynobj)) { Elf_Internal_Dyn dyn; @@ -6968,13 +7619,6 @@ _bfd_mips_elf_finish_dynamic_sections (output_bfd, info) case DT_PLTGOT: name = ".got"; - goto get_vma; - case DT_MIPS_CONFLICT: - name = ".conflict"; - goto get_vma; - case DT_MIPS_LIBLIST: - name = ".liblist"; - get_vma: s = bfd_get_section_by_name (output_bfd, name); BFD_ASSERT (s != NULL); dyn.d_un.d_ptr = s->vma; @@ -6988,27 +7632,6 @@ _bfd_mips_elf_finish_dynamic_sections (output_bfd, info) dyn.d_un.d_val = RHF_NOTPOT; /* XXX */ break; - case DT_MIPS_CONFLICTNO: - name = ".conflict"; - elemsize = sizeof (Elf32_Conflict); - goto set_elemno; - - case DT_MIPS_LIBLISTNO: - name = ".liblist"; - elemsize = sizeof (Elf32_Lib); - set_elemno: - s = bfd_get_section_by_name (output_bfd, name); - if (s != NULL) - { - if (s->_cooked_size != 0) - dyn.d_un.d_val = s->_cooked_size / elemsize; - else - dyn.d_un.d_val = s->_raw_size / elemsize; - } - else - dyn.d_un.d_val = 0; - break; - case DT_MIPS_TIME_STAMP: time ((time_t *) &dyn.d_un.d_val); break; @@ -7056,10 +7679,7 @@ _bfd_mips_elf_finish_dynamic_sections (output_bfd, info) s = bfd_get_section_by_name (output_bfd, name); BFD_ASSERT (s != NULL); - if (s->_cooked_size != 0) - dyn.d_un.d_val = s->_cooked_size / elemsize; - else - dyn.d_un.d_val = s->_raw_size / elemsize; + dyn.d_un.d_val = s->size / elemsize; break; case DT_MIPS_HIPAGENO: @@ -7076,11 +7696,6 @@ _bfd_mips_elf_finish_dynamic_sections (output_bfd, info) dyn.d_un.d_ptr = s->vma; break; - case DT_MIPS_MSYM: - s = (bfd_get_section_by_name (output_bfd, ".msym")); - dyn.d_un.d_ptr = s->vma; - break; - default: swap_out_p = FALSE; break; @@ -7095,10 +7710,10 @@ _bfd_mips_elf_finish_dynamic_sections (output_bfd, info) /* The first entry of the global offset table will be filled at runtime. The second entry will be used by some runtime loaders. This isn't the case of IRIX rld. */ - if (sgot != NULL && sgot->_raw_size > 0) + if (sgot != NULL && sgot->size > 0) { - MIPS_ELF_PUT_WORD (output_bfd, (bfd_vma) 0, sgot->contents); - MIPS_ELF_PUT_WORD (output_bfd, (bfd_vma) 0x80000000, + MIPS_ELF_PUT_WORD (output_bfd, 0, sgot->contents); + MIPS_ELF_PUT_WORD (output_bfd, 0x80000000, sgot->contents + MIPS_ELF_GOT_SIZE (output_bfd)); } @@ -7117,11 +7732,12 @@ _bfd_mips_elf_finish_dynamic_sections (output_bfd, info) 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, (bfd_vma) 0, sgot->contents + MIPS_ELF_PUT_WORD (output_bfd, 0, sgot->contents + index++ * MIPS_ELF_GOT_SIZE (output_bfd)); - MIPS_ELF_PUT_WORD (output_bfd, (bfd_vma) 0x80000000, sgot->contents + MIPS_ELF_PUT_WORD (output_bfd, 0x80000000, sgot->contents + index++ * MIPS_ELF_GOT_SIZE (output_bfd)); if (! info->shared) @@ -7141,33 +7757,58 @@ _bfd_mips_elf_finish_dynamic_sections (output_bfd, info) } } - { - asection *smsym; - asection *s; - Elf32_compact_rel cpt; + /* The generation of dynamic relocations for the non-primary gots + adds more dynamic relocations. We cannot count them until + here. */ - /* ??? The section symbols for the output sections were set up in - _bfd_elf_final_link. SGI sets the STT_NOTYPE attribute for these - symbols. Should we do so? */ + if (elf_hash_table (info)->dynamic_sections_created) + { + bfd_byte *b; + bfd_boolean swap_out_p; - smsym = bfd_get_section_by_name (dynobj, ".msym"); - if (smsym != NULL) - { - Elf32_Internal_Msym msym; + 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; - msym.ms_hash_value = 0; - msym.ms_info = ELF32_MS_INFO (0, 1); + /* Read in the current dynamic entry. */ + (*get_elf_backend_data (dynobj)->s->swap_dyn_in) (dynobj, b, &dyn); - for (s = output_bfd->sections; s != NULL; s = s->next) - { - long dynindx = elf_section_data (s)->dynindx; + /* Assume that we're going to modify it and write it out. */ + swap_out_p = TRUE; - bfd_mips_elf_swap_msym_out - (output_bfd, &msym, - (((Elf32_External_Msym *) smsym->contents) - + dynindx)); - } - } + 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; if (SGI_COMPAT (output_bfd)) { @@ -7193,8 +7834,8 @@ _bfd_mips_elf_finish_dynamic_sections (output_bfd, info) { file_ptr dummy_offset; - BFD_ASSERT (s->_raw_size >= MIPS_FUNCTION_STUB_SIZE); - dummy_offset = s->_raw_size - MIPS_FUNCTION_STUB_SIZE; + BFD_ASSERT (s->size >= MIPS_FUNCTION_STUB_SIZE); + dummy_offset = s->size - MIPS_FUNCTION_STUB_SIZE; memset (s->contents + dummy_offset, 0, MIPS_FUNCTION_STUB_SIZE); } @@ -7206,17 +7847,15 @@ _bfd_mips_elf_finish_dynamic_sections (output_bfd, info) s = mips_elf_rel_dyn_section (dynobj, FALSE); if (s != NULL - && s->_raw_size > (bfd_vma)2 * MIPS_ELF_REL_SIZE (output_bfd)) + && s->size > (bfd_vma)2 * MIPS_ELF_REL_SIZE (output_bfd)) { reldyn_sorting_bfd = output_bfd; if (ABI_64_P (output_bfd)) - qsort ((Elf64_External_Rel *) s->contents + 1, - (size_t) s->reloc_count - 1, + qsort ((Elf64_External_Rel *) s->contents + 1, s->reloc_count - 1, sizeof (Elf64_Mips_External_Rel), sort_dynamic_relocs_64); else - qsort ((Elf32_External_Rel *) s->contents + 1, - (size_t) s->reloc_count - 1, + qsort ((Elf32_External_Rel *) s->contents + 1, s->reloc_count - 1, sizeof (Elf32_External_Rel), sort_dynamic_relocs); } } @@ -7228,8 +7867,7 @@ _bfd_mips_elf_finish_dynamic_sections (output_bfd, info) /* Set ABFD's EF_MIPS_ARCH and EF_MIPS_MACH flags. */ static void -mips_set_isa_flags (abfd) - bfd *abfd; +mips_set_isa_flags (bfd *abfd) { flagword val; @@ -7283,7 +7921,12 @@ mips_set_isa_flags (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: case bfd_mach_mips10000: case bfd_mach_mips12000: @@ -7309,6 +7952,10 @@ mips_set_isa_flags (abfd) case bfd_mach_mipsisa32r2: val = E_MIPS_ARCH_32R2; break; + + case bfd_mach_mipsisa64r2: + val = E_MIPS_ARCH_64R2; + break; } elf_elfheader (abfd)->e_flags &= ~(EF_MIPS_ARCH | EF_MIPS_MACH); elf_elfheader (abfd)->e_flags |= val; @@ -7321,9 +7968,8 @@ mips_set_isa_flags (abfd) number. This is used by both the 32-bit and the 64-bit ABI. */ void -_bfd_mips_elf_final_write_processing (abfd, linker) - bfd *abfd; - bfd_boolean linker ATTRIBUTE_UNUSED; +_bfd_mips_elf_final_write_processing (bfd *abfd, + bfd_boolean linker ATTRIBUTE_UNUSED) { unsigned int i; Elf_Internal_Shdr **hdrpp; @@ -7409,8 +8055,7 @@ _bfd_mips_elf_final_write_processing (abfd, linker) segments. */ int -_bfd_mips_elf_additional_program_headers (abfd) - bfd *abfd; +_bfd_mips_elf_additional_program_headers (bfd *abfd) { asection *s; int ret = 0; @@ -7438,8 +8083,8 @@ _bfd_mips_elf_additional_program_headers (abfd) /* Modify the segment map for an IRIX5 executable. */ bfd_boolean -_bfd_mips_elf_modify_segment_map (abfd) - bfd *abfd; +_bfd_mips_elf_modify_segment_map (bfd *abfd, + struct bfd_link_info *info ATTRIBUTE_UNUSED) { asection *s; struct elf_segment_map *m, **pm; @@ -7456,7 +8101,7 @@ _bfd_mips_elf_modify_segment_map (abfd) if (m == NULL) { amt = sizeof *m; - m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); + m = bfd_zalloc (abfd, amt); if (m == NULL) return FALSE; @@ -7478,7 +8123,7 @@ _bfd_mips_elf_modify_segment_map (abfd) /* For IRIX 6, we don't have .mdebug sections, nor does anything but .dynamic end up in PT_DYNAMIC. However, we do have to insert a - PT_OPTIONS segment immediately following the program header + PT_MIPS_OPTIONS segment immediately following the program header table. */ if (NEWABI_P (abfd) /* On non-IRIX6 new abi, we'll have already created a segment @@ -7495,15 +8140,11 @@ _bfd_mips_elf_modify_segment_map (abfd) { struct elf_segment_map *options_segment; - /* Usually, there's a program header table. But, sometimes - there's not (like when running the `ld' testsuite). So, - if there's no program header table, we just put the - options segment at the end. */ - for (pm = &elf_tdata (abfd)->segment_map; - *pm != NULL; - pm = &(*pm)->next) - if ((*pm)->p_type == PT_PHDR) - break; + pm = &elf_tdata (abfd)->segment_map; + while (*pm != NULL + && ((*pm)->p_type == PT_PHDR + || (*pm)->p_type == PT_INTERP)) + pm = &(*pm)->next; amt = sizeof (struct elf_segment_map); options_segment = bfd_zalloc (abfd, amt); @@ -7532,7 +8173,7 @@ _bfd_mips_elf_modify_segment_map (abfd) if (m == NULL) { amt = sizeof *m; - m = (struct elf_segment_map *) bfd_zalloc (abfd, amt); + m = bfd_zalloc (abfd, amt); if (m == NULL) return FALSE; @@ -7594,7 +8235,7 @@ _bfd_mips_elf_modify_segment_map (abfd) unsigned int i, c; struct elf_segment_map *n; - low = 0xffffffff; + low = ~(bfd_vma) 0; high = 0; for (i = 0; i < sizeof sec_names / sizeof sec_names[0]; i++) { @@ -7605,9 +8246,7 @@ _bfd_mips_elf_modify_segment_map (abfd) if (low > s->vma) low = s->vma; - sz = s->_cooked_size; - if (sz == 0) - sz = s->_raw_size; + sz = s->size; if (high < s->vma + sz) high = s->vma + sz; } @@ -7617,13 +8256,11 @@ _bfd_mips_elf_modify_segment_map (abfd) for (s = abfd->sections; s != NULL; s = s->next) if ((s->flags & SEC_LOAD) != 0 && s->vma >= low - && ((s->vma - + (s->_cooked_size != - 0 ? s->_cooked_size : s->_raw_size)) <= high)) + && s->vma + s->size <= high) ++c; amt = sizeof *n + (bfd_size_type) (c - 1) * sizeof (asection *); - n = (struct elf_segment_map *) bfd_zalloc (abfd, amt); + n = bfd_zalloc (abfd, amt); if (n == NULL) return FALSE; *n = *m; @@ -7634,9 +8271,7 @@ _bfd_mips_elf_modify_segment_map (abfd) { if ((s->flags & SEC_LOAD) != 0 && s->vma >= low - && ((s->vma - + (s->_cooked_size != 0 ? - s->_cooked_size : s->_raw_size)) <= high)) + && s->vma + s->size <= high) { n->sections[i] = s; ++i; @@ -7654,12 +8289,11 @@ _bfd_mips_elf_modify_segment_map (abfd) relocation. */ asection * -_bfd_mips_elf_gc_mark_hook (sec, info, rel, h, sym) - asection *sec; - struct bfd_link_info *info ATTRIBUTE_UNUSED; - Elf_Internal_Rela *rel; - struct elf_link_hash_entry *h; - Elf_Internal_Sym *sym; +_bfd_mips_elf_gc_mark_hook (asection *sec, + struct bfd_link_info *info ATTRIBUTE_UNUSED, + Elf_Internal_Rela *rel, + struct elf_link_hash_entry *h, + Elf_Internal_Sym *sym) { /* ??? Do mips16 stub sections need to be handled special? */ @@ -7695,11 +8329,10 @@ _bfd_mips_elf_gc_mark_hook (sec, info, rel, h, sym) /* Update the got entry reference counts for the section being removed. */ bfd_boolean -_bfd_mips_elf_gc_sweep_hook (abfd, info, sec, relocs) - bfd *abfd ATTRIBUTE_UNUSED; - struct bfd_link_info *info ATTRIBUTE_UNUSED; - asection *sec ATTRIBUTE_UNUSED; - const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED; +_bfd_mips_elf_gc_sweep_hook (bfd *abfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info ATTRIBUTE_UNUSED, + asection *sec ATTRIBUTE_UNUSED, + const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED) { #if 0 Elf_Internal_Shdr *symtab_hdr; @@ -7745,9 +8378,9 @@ _bfd_mips_elf_gc_sweep_hook (abfd, info, sec, relocs) _bfd_elf_link_hash_copy_indirect copy the flags for us. */ void -_bfd_mips_elf_copy_indirect_symbol (bed, dir, ind) - struct elf_backend_data *bed; - struct elf_link_hash_entry *dir, *ind; +_bfd_mips_elf_copy_indirect_symbol (const struct elf_backend_data *bed, + struct elf_link_hash_entry *dir, + struct elf_link_hash_entry *ind) { struct mips_elf_link_hash_entry *dirmips, *indmips; @@ -7761,19 +8394,19 @@ _bfd_mips_elf_copy_indirect_symbol (bed, dir, ind) dirmips->possibly_dynamic_relocs += indmips->possibly_dynamic_relocs; if (indmips->readonly_reloc) dirmips->readonly_reloc = TRUE; - if (dirmips->min_dyn_reloc_index == 0 - || (indmips->min_dyn_reloc_index != 0 - && indmips->min_dyn_reloc_index < dirmips->min_dyn_reloc_index)) - dirmips->min_dyn_reloc_index = indmips->min_dyn_reloc_index; if (indmips->no_fn_stub) dirmips->no_fn_stub = TRUE; + + if (dirmips->tls_type == 0) + dirmips->tls_type = indmips->tls_type; + else + BFD_ASSERT (indmips->tls_type == 0); } void -_bfd_mips_elf_hide_symbol (info, entry, force_local) - struct bfd_link_info *info; - struct elf_link_hash_entry *entry; - bfd_boolean force_local; +_bfd_mips_elf_hide_symbol (struct bfd_link_info *info, + struct elf_link_hash_entry *entry, + bfd_boolean force_local) { bfd *dynobj; asection *got; @@ -7786,7 +8419,7 @@ _bfd_mips_elf_hide_symbol (info, entry, force_local) h->forced_local = force_local; dynobj = elf_hash_table (info)->dynobj; - if (dynobj != NULL && force_local) + if (dynobj != NULL && force_local && h->root.type != STT_TLS) { got = mips_elf_got_section (dynobj, FALSE); g = mips_elf_section_data (got)->u.got_info; @@ -7804,6 +8437,7 @@ _bfd_mips_elf_hide_symbol (info, entry, force_local) 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)) @@ -7845,10 +8479,8 @@ _bfd_mips_elf_hide_symbol (info, entry, force_local) #define PDR_SIZE 32 bfd_boolean -_bfd_mips_elf_discard_info (abfd, cookie, info) - bfd *abfd; - struct elf_reloc_cookie *cookie; - struct bfd_link_info *info; +_bfd_mips_elf_discard_info (bfd *abfd, struct elf_reloc_cookie *cookie, + struct bfd_link_info *info) { asection *o; bfd_boolean ret = FALSE; @@ -7858,20 +8490,19 @@ _bfd_mips_elf_discard_info (abfd, cookie, info) o = bfd_get_section_by_name (abfd, ".pdr"); if (! o) return FALSE; - if (o->_raw_size == 0) + if (o->size == 0) return FALSE; - if (o->_raw_size % PDR_SIZE != 0) + if (o->size % PDR_SIZE != 0) return FALSE; if (o->output_section != NULL && bfd_is_abs_section (o->output_section)) return FALSE; - tdata = bfd_zmalloc (o->_raw_size / PDR_SIZE); + tdata = bfd_zmalloc (o->size / PDR_SIZE); if (! tdata) return FALSE; - cookie->rels = _bfd_elf_link_read_relocs (abfd, o, (PTR) NULL, - (Elf_Internal_Rela *) NULL, + cookie->rels = _bfd_elf_link_read_relocs (abfd, o, NULL, NULL, info->keep_memory); if (!cookie->rels) { @@ -7882,9 +8513,9 @@ _bfd_mips_elf_discard_info (abfd, cookie, info) cookie->rel = cookie->rels; cookie->relend = cookie->rels + o->reloc_count; - for (i = 0, skip = 0; i < o->_raw_size / PDR_SIZE; i ++) + for (i = 0, skip = 0; i < o->size / PDR_SIZE; i ++) { - if (MNAME(abfd,_bfd_elf,reloc_symbol_deleted_p) (i * PDR_SIZE, cookie)) + if (bfd_elf_reloc_symbol_deleted_p (i * PDR_SIZE, cookie)) { tdata[i] = 1; skip ++; @@ -7894,7 +8525,7 @@ _bfd_mips_elf_discard_info (abfd, cookie, info) if (skip != 0) { mips_elf_section_data (o)->u.tdata = tdata; - o->_cooked_size = o->_raw_size - skip * PDR_SIZE; + o->size -= skip * PDR_SIZE; ret = TRUE; } else @@ -7907,8 +8538,7 @@ _bfd_mips_elf_discard_info (abfd, cookie, info) } bfd_boolean -_bfd_mips_elf_ignore_discarded_relocs (sec) - asection *sec; +_bfd_mips_elf_ignore_discarded_relocs (asection *sec) { if (strcmp (sec->name, ".pdr") == 0) return TRUE; @@ -7916,10 +8546,8 @@ _bfd_mips_elf_ignore_discarded_relocs (sec) } bfd_boolean -_bfd_mips_elf_write_section (output_bfd, sec, contents) - bfd *output_bfd; - asection *sec; - bfd_byte *contents; +_bfd_mips_elf_write_section (bfd *output_bfd, asection *sec, + bfd_byte *contents) { bfd_byte *to, *from, *end; int i; @@ -7931,7 +8559,7 @@ _bfd_mips_elf_write_section (output_bfd, sec, contents) return FALSE; to = contents; - end = contents + sec->_raw_size; + end = contents + sec->size; for (from = contents, i = 0; from < end; from += PDR_SIZE, i++) @@ -7943,8 +8571,7 @@ _bfd_mips_elf_write_section (output_bfd, sec, contents) to += PDR_SIZE; } bfd_set_section_contents (output_bfd, sec->output_section, contents, - (file_ptr) sec->output_offset, - sec->_cooked_size); + sec->output_offset, sec->size); return TRUE; } @@ -7958,15 +8585,11 @@ struct mips_elf_find_line }; bfd_boolean -_bfd_mips_elf_find_nearest_line (abfd, section, symbols, offset, filename_ptr, - functionname_ptr, line_ptr) - bfd *abfd; - asection *section; - asymbol **symbols; - bfd_vma offset; - const char **filename_ptr; - const char **functionname_ptr; - unsigned int *line_ptr; +_bfd_mips_elf_find_nearest_line (bfd *abfd, asection *section, + asymbol **symbols, bfd_vma offset, + const char **filename_ptr, + const char **functionname_ptr, + unsigned int *line_ptr) { asection *msec; @@ -7977,8 +8600,7 @@ _bfd_mips_elf_find_nearest_line (abfd, section, symbols, offset, filename_ptr, if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset, filename_ptr, functionname_ptr, - line_ptr, - (unsigned) (ABI_64_P (abfd) ? 8 : 0), + line_ptr, ABI_64_P (abfd) ? 8 : 0, &elf_tdata (abfd)->dwarf2_find_line_info)) return TRUE; @@ -8006,7 +8628,7 @@ _bfd_mips_elf_find_nearest_line (abfd, section, symbols, offset, filename_ptr, struct fdr *fdr_ptr; bfd_size_type amt = sizeof (struct mips_elf_find_line); - fi = (struct mips_elf_find_line *) bfd_zalloc (abfd, amt); + fi = bfd_zalloc (abfd, amt); if (fi == NULL) { msec->flags = origflags; @@ -8021,7 +8643,7 @@ _bfd_mips_elf_find_nearest_line (abfd, section, symbols, offset, filename_ptr, /* Swap in the FDR information. */ amt = fi->d.symbolic_header.ifdMax * sizeof (struct fdr); - fi->d.fdr = (struct fdr *) bfd_alloc (abfd, amt); + fi->d.fdr = bfd_alloc (abfd, amt); if (fi->d.fdr == NULL) { msec->flags = origflags; @@ -8033,7 +8655,7 @@ _bfd_mips_elf_find_nearest_line (abfd, section, symbols, offset, filename_ptr, fraw_end = (fraw_src + fi->d.symbolic_header.ifdMax * external_fdr_size); for (; fraw_src < fraw_end; fraw_src += external_fdr_size, fdr_ptr++) - (*swap->swap_fdr_in) (abfd, (PTR) fraw_src, fdr_ptr); + (*swap->swap_fdr_in) (abfd, fraw_src, fdr_ptr); elf_tdata (abfd)->find_line_info = fi; @@ -8062,46 +8684,51 @@ _bfd_mips_elf_find_nearest_line (abfd, section, symbols, offset, filename_ptr, 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 GP value in the section_processing routine. */ bfd_boolean -_bfd_mips_elf_set_section_contents (abfd, section, location, offset, count) - bfd *abfd; - sec_ptr section; - PTR location; - file_ptr offset; - bfd_size_type count; +_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; if (elf_section_data (section) == NULL) { bfd_size_type amt = sizeof (struct bfd_elf_section_data); - section->used_by_bfd = (PTR) bfd_zalloc (abfd, amt); + section->used_by_bfd = bfd_zalloc (abfd, amt); if (elf_section_data (section) == NULL) return FALSE; } c = mips_elf_section_data (section)->u.tdata; if (c == NULL) { - bfd_size_type size; - - if (section->_cooked_size != 0) - size = section->_cooked_size; - else - size = section->_raw_size; - c = (bfd_byte *) bfd_zalloc (abfd, size); + c = bfd_zalloc (abfd, section->size); if (c == NULL) return FALSE; mips_elf_section_data (section)->u.tdata = c; } - memcpy (c + offset, location, (size_t) count); + memcpy (c + offset, location, count); } return _bfd_elf_set_section_contents (abfd, section, location, offset, @@ -8112,18 +8739,18 @@ _bfd_mips_elf_set_section_contents (abfd, section, location, offset, count) MIPS relocations need to be handled specially. Sigh. */ bfd_byte * -_bfd_elf_mips_get_relocated_section_contents (abfd, link_info, link_order, - data, relocatable, symbols) - bfd *abfd; - struct bfd_link_info *link_info; - struct bfd_link_order *link_order; - bfd_byte *data; - bfd_boolean relocatable; - asymbol **symbols; +_bfd_elf_mips_get_relocated_section_contents + (bfd *abfd, + struct bfd_link_info *link_info, + struct bfd_link_order *link_order, + bfd_byte *data, + bfd_boolean relocatable, + asymbol **symbols) { /* Get enough memory to hold the stuff */ bfd *input_bfd = link_order->u.indirect.section->owner; asection *input_section = link_order->u.indirect.section; + bfd_size_type sz; long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section); arelent **reloc_vector = NULL; @@ -8132,22 +8759,15 @@ _bfd_elf_mips_get_relocated_section_contents (abfd, link_info, link_order, if (reloc_size < 0) goto error_return; - reloc_vector = (arelent **) bfd_malloc ((bfd_size_type) reloc_size); + reloc_vector = bfd_malloc (reloc_size); if (reloc_vector == NULL && reloc_size != 0) goto error_return; /* read in the section */ - if (!bfd_get_section_contents (input_bfd, - input_section, - (PTR) data, - (file_ptr) 0, - input_section->_raw_size)) + sz = input_section->rawsize ? input_section->rawsize : input_section->size; + if (!bfd_get_section_contents (input_bfd, input_section, data, 0, sz)) goto error_return; - /* We're not relaxing the section, so just copy the size info */ - input_section->_cooked_size = input_section->_raw_size; - input_section->reloc_done = TRUE; - reloc_count = bfd_canonicalize_reloc (input_bfd, input_section, reloc_vector, @@ -8203,42 +8823,29 @@ _bfd_elf_mips_get_relocated_section_contents (abfd, link_info, link_order, gp_found = 0; } /* end mips */ - for (parent = reloc_vector; *parent != (arelent *) NULL; - parent++) + for (parent = reloc_vector; *parent != NULL; parent++) { - char *error_message = (char *) NULL; + char *error_message = NULL; bfd_reloc_status_type r; /* 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, - (PTR) data, gp); - goto skip_bfd_perform_relocation; - } - /* end mips specific stuff */ - r = bfd_perform_relocation (input_bfd, - *parent, - (PTR) data, - input_section, - relocatable ? abfd : (bfd *) 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) { @@ -8261,7 +8868,7 @@ _bfd_elf_mips_get_relocated_section_contents (abfd, link_info, link_order, goto error_return; break; case bfd_reloc_dangerous: - BFD_ASSERT (error_message != (char *) NULL); + BFD_ASSERT (error_message != NULL); if (!((*link_info->callbacks->reloc_dangerous) (link_info, error_message, input_bfd, input_section, (*parent)->address))) @@ -8269,7 +8876,8 @@ _bfd_elf_mips_get_relocated_section_contents (abfd, link_info, link_order, break; case bfd_reloc_overflow: if (!((*link_info->callbacks->reloc_overflow) - (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr), + (link_info, NULL, + bfd_asymbol_name (*(*parent)->sym_ptr_ptr), (*parent)->howto->name, (*parent)->addend, input_bfd, input_section, (*parent)->address))) goto error_return; @@ -8296,14 +8904,13 @@ error_return: /* Create a MIPS ELF linker hash table. */ struct bfd_link_hash_table * -_bfd_mips_elf_link_hash_table_create (abfd) - bfd *abfd; +_bfd_mips_elf_link_hash_table_create (bfd *abfd) { struct mips_elf_link_hash_table *ret; bfd_size_type amt = sizeof (struct mips_elf_link_hash_table); - ret = (struct mips_elf_link_hash_table *) bfd_malloc (amt); - if (ret == (struct mips_elf_link_hash_table *) NULL) + ret = bfd_malloc (amt); + if (ret == NULL) return NULL; if (! _bfd_elf_link_hash_table_init (&ret->root, abfd, @@ -8332,21 +8939,18 @@ _bfd_mips_elf_link_hash_table_create (abfd) sections together, not write them all out sequentially. */ bfd_boolean -_bfd_mips_elf_final_link (abfd, info) - bfd *abfd; - struct bfd_link_info *info; +_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; asection *rtproc_sec; Elf32_RegInfo reginfo; struct ecoff_debug_info debug; - const struct ecoff_debug_swap *swap - = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + const struct ecoff_debug_swap *swap = bed->elf_backend_ecoff_debug_swap; HDRR *symhdr = &debug.symbolic_header; - PTR mdebug_handle = NULL; + void *mdebug_handle = NULL; asection *s; EXTR esym; unsigned int i; @@ -8372,6 +8976,7 @@ _bfd_mips_elf_final_link (abfd, info) bfd *dynobj; asection *got; struct mips_got_info *g; + bfd_size_type dynsecsymcount; /* When we resort, we must tell mips_elf_sort_hash_table what the lowest index it may use is. That's the number of section @@ -8379,9 +8984,20 @@ _bfd_mips_elf_final_link (abfd, info) adds these symbols when building a shared object. Note that we count the sections after (possibly) removing the .options section above. */ - if (! mips_elf_sort_hash_table (info, (info->shared - ? bfd_count_sections (abfd) + 1 - : 1))) + + dynsecsymcount = 0; + if (info->shared) + { + asection * p; + + for (p = abfd->sections; p ; p = p->next) + if ((p->flags & SEC_EXCLUDE) == 0 + && (p->flags & SEC_ALLOC) != 0 + && !(*bed->elf_backend_omit_section_dynsym) (abfd, info, p)) + ++ dynsecsymcount; + } + + if (! mips_elf_sort_hash_table (info, dynsecsymcount + 1)) return FALSE; /* Make sure we didn't grow the global .got region. */ @@ -8395,55 +9011,13 @@ _bfd_mips_elf_final_link (abfd, 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) { struct bfd_link_hash_entry *h; h = bfd_link_hash_lookup (info->hash, "_gp", FALSE, FALSE, TRUE); - if (h != (struct bfd_link_hash_entry *) NULL - && h->type == bfd_link_hash_defined) + if (h != NULL && h->type == bfd_link_hash_defined) elf_gp (abfd) = (h->u.def.value + h->u.def.section->output_section->vma + h->u.def.section->output_offset); @@ -8452,7 +9026,7 @@ _bfd_mips_elf_final_link (abfd, info) bfd_vma lo = MINUS_ONE; /* Find the GP-relative section with the lowest offset. */ - for (o = abfd->sections; o != (asection *) NULL; o = o->next) + for (o = abfd->sections; o != NULL; o = o->next) if (o->vma < lo && (elf_section_data (o)->this_hdr.sh_flags & SHF_MIPS_GPREL)) lo = o->vma; @@ -8474,7 +9048,7 @@ _bfd_mips_elf_final_link (abfd, info) mdebug_sec = NULL; gptab_data_sec = NULL; gptab_bss_sec = NULL; - for (o = abfd->sections; o != (asection *) NULL; o = o->next) + for (o = abfd->sections; o != NULL; o = o->next) { if (strcmp (o->name, ".reginfo") == 0) { @@ -8483,9 +9057,7 @@ _bfd_mips_elf_final_link (abfd, 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 != (struct bfd_link_order *) NULL; - p = p->next) + for (p = o->map_head.link_order; p != NULL; p = p->next) { asection *input_section; bfd *input_bfd; @@ -8502,15 +9074,8 @@ _bfd_mips_elf_final_link (abfd, info) input_section = p->u.indirect.section; input_bfd = input_section->owner; - /* The linker emulation code has probably clobbered the - size to be zero bytes. */ - if (input_section->_raw_size == 0) - input_section->_raw_size = sizeof (Elf32_External_RegInfo); - if (! bfd_get_section_contents (input_bfd, input_section, - (PTR) &ext, - (file_ptr) 0, - (bfd_size_type) sizeof ext)) + &ext, 0, sizeof ext)) return FALSE; bfd_mips_elf32_swap_reginfo_in (input_bfd, &ext, &sub); @@ -8531,11 +9096,11 @@ _bfd_mips_elf_final_link (abfd, info) } /* Size has been set in _bfd_mips_elf_always_size_sections. */ - BFD_ASSERT(o->_raw_size == sizeof (Elf32_External_RegInfo)); + BFD_ASSERT(o->size == sizeof (Elf32_External_RegInfo)); /* Skip this section later on (I don't think this currently matters, but someday it might). */ - o->link_order_head = (struct bfd_link_order *) NULL; + o->map_head.link_order = NULL; reginfo_sec = o; } @@ -8579,7 +9144,7 @@ _bfd_mips_elf_final_link (abfd, info) debug.external_ext = debug.external_ext_end = NULL; mdebug_handle = bfd_ecoff_debug_init (abfd, &debug, swap, info); - if (mdebug_handle == (PTR) NULL) + if (mdebug_handle == NULL) return FALSE; esym.jmptbl = 0; @@ -8599,7 +9164,7 @@ _bfd_mips_elf_final_link (abfd, info) if (s != NULL) { esym.asym.value = s->vma; - last = s->vma + s->_raw_size; + last = s->vma + s->size; } else esym.asym.value = last; @@ -8608,9 +9173,7 @@ _bfd_mips_elf_final_link (abfd, info) return FALSE; } - for (p = o->link_order_head; - p != (struct bfd_link_order *) NULL; - p = p->next) + for (p = o->map_head.link_order; p != NULL; p = p->next) { asection *input_section; bfd *input_bfd; @@ -8642,7 +9205,7 @@ _bfd_mips_elf_final_link (abfd, info) input_swap = (get_elf_backend_data (input_bfd) ->elf_backend_ecoff_debug_swap); - BFD_ASSERT (p->size == input_section->_raw_size); + BFD_ASSERT (p->size == input_section->size); /* The ECOFF linking code expects that we have already read in the debugging information and set up an @@ -8672,7 +9235,7 @@ _bfd_mips_elf_final_link (abfd, info) const char *name; struct mips_elf_link_hash_entry *h; - (*input_swap->swap_ext_in) (input_bfd, (PTR) eraw_src, &ext); + (*input_swap->swap_ext_in) (input_bfd, eraw_src, &ext); if (ext.asym.sc == scNil || ext.asym.sc == scUndefined || ext.asym.sc == scSUndefined) @@ -8721,9 +9284,10 @@ _bfd_mips_elf_final_link (abfd, 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; } @@ -8741,17 +9305,16 @@ _bfd_mips_elf_final_link (abfd, info) einfo.swap = swap; einfo.failed = FALSE; mips_elf_link_hash_traverse (mips_elf_hash_table (info), - mips_elf_output_extsym, - (PTR) &einfo); + mips_elf_output_extsym, &einfo); if (einfo.failed) return FALSE; /* Set the size of the .mdebug section. */ - o->_raw_size = bfd_ecoff_debug_size (abfd, &debug, swap); + o->size = bfd_ecoff_debug_size (abfd, &debug, swap); /* Skip this section later on (I don't think this currently matters, but someday it might). */ - o->link_order_head = (struct bfd_link_order *) NULL; + o->map_head.link_order = NULL; mdebug_sec = o; } @@ -8770,9 +9333,7 @@ _bfd_mips_elf_final_link (abfd, info) not used in executables files. */ if (! info->relocatable) { - for (p = o->link_order_head; - p != (struct bfd_link_order *) NULL; - p = p->next) + for (p = o->map_head.link_order; p != NULL; p = p->next) { asection *input_section; @@ -8792,14 +9353,10 @@ _bfd_mips_elf_final_link (abfd, info) /* Skip this section later on (I don't think this currently matters, but someday it might). */ - o->link_order_head = (struct bfd_link_order *) 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; @@ -8839,16 +9396,14 @@ _bfd_mips_elf_final_link (abfd, info) /* Set up the first entry. */ c = 1; amt = c * sizeof (Elf32_gptab); - tab = (Elf32_gptab *) bfd_malloc (amt); + tab = bfd_malloc (amt); if (tab == NULL) return FALSE; tab[0].gt_header.gt_current_g_value = elf_gp_size (abfd); tab[0].gt_header.gt_unused = 0; /* Combine the input sections. */ - for (p = o->link_order_head; - p != (struct bfd_link_order *) NULL; - p = p->next) + for (p = o->map_head.link_order; p != NULL; p = p->next) { asection *input_section; bfd *input_bfd; @@ -8869,7 +9424,7 @@ _bfd_mips_elf_final_link (abfd, info) /* Combine the gptab entries for this input section one by one. We know that the input gptab entries are sorted by ascending -G value. */ - size = bfd_section_size (input_bfd, input_section); + size = input_section->size; last = 0; for (gpentry = sizeof (Elf32_External_gptab); gpentry < size; @@ -8883,9 +9438,8 @@ _bfd_mips_elf_final_link (abfd, info) unsigned int look; if (! (bfd_get_section_contents - (input_bfd, input_section, (PTR) &ext_gptab, - (file_ptr) gpentry, - (bfd_size_type) sizeof (Elf32_External_gptab)))) + (input_bfd, input_section, &ext_gptab, gpentry, + sizeof (Elf32_External_gptab)))) { free (tab); return FALSE; @@ -8913,7 +9467,7 @@ _bfd_mips_elf_final_link (abfd, info) /* We need a new table entry. */ amt = (bfd_size_type) (c + 1) * sizeof (Elf32_gptab); - new_tab = (Elf32_gptab *) bfd_realloc ((PTR) tab, amt); + new_tab = bfd_realloc (tab, amt); if (new_tab == NULL) { free (tab); @@ -8956,7 +9510,7 @@ _bfd_mips_elf_final_link (abfd, info) /* Swap out the table. */ amt = (bfd_size_type) c * sizeof (Elf32_External_gptab); - ext_tab = (Elf32_External_gptab *) bfd_alloc (abfd, amt); + ext_tab = bfd_alloc (abfd, amt); if (ext_tab == NULL) { free (tab); @@ -8967,33 +9521,31 @@ _bfd_mips_elf_final_link (abfd, info) bfd_mips_elf32_swap_gptab_out (abfd, tab + j, ext_tab + j); free (tab); - o->_raw_size = c * sizeof (Elf32_External_gptab); + o->size = c * sizeof (Elf32_External_gptab); o->contents = (bfd_byte *) ext_tab; /* Skip this section later on (I don't think this currently matters, but someday it might). */ - o->link_order_head = (struct bfd_link_order *) NULL; + o->map_head.link_order = NULL; } } /* Invoke the regular ELF backend linker to do all the work. */ - if (!MNAME(abfd,bfd_elf,bfd_final_link) (abfd, info)) + if (!bfd_elf_final_link (abfd, info)) return FALSE; /* Now write out the computed sections. */ - if (reginfo_sec != (asection *) NULL) + if (reginfo_sec != NULL) { Elf32_External_RegInfo ext; bfd_mips_elf32_swap_reginfo_out (abfd, ®info, &ext); - if (! bfd_set_section_contents (abfd, reginfo_sec, (PTR) &ext, - (file_ptr) 0, - (bfd_size_type) sizeof ext)) + if (! bfd_set_section_contents (abfd, reginfo_sec, &ext, 0, sizeof ext)) return FALSE; } - if (mdebug_sec != (asection *) NULL) + if (mdebug_sec != NULL) { BFD_ASSERT (abfd->output_has_begun); if (! bfd_ecoff_write_accumulated_debug (mdebug_handle, abfd, &debug, @@ -9004,21 +9556,19 @@ _bfd_mips_elf_final_link (abfd, info) bfd_ecoff_debug_free (mdebug_handle, abfd, &debug, swap, info); } - if (gptab_data_sec != (asection *) NULL) + if (gptab_data_sec != NULL) { if (! bfd_set_section_contents (abfd, gptab_data_sec, gptab_data_sec->contents, - (file_ptr) 0, - gptab_data_sec->_raw_size)) + 0, gptab_data_sec->size)) return FALSE; } - if (gptab_bss_sec != (asection *) NULL) + if (gptab_bss_sec != NULL) { if (! bfd_set_section_contents (abfd, gptab_bss_sec, gptab_bss_sec->contents, - (file_ptr) 0, - gptab_bss_sec->_raw_size)) + 0, gptab_bss_sec->size)) return FALSE; } @@ -9029,8 +9579,7 @@ _bfd_mips_elf_final_link (abfd, info) { if (! bfd_set_section_contents (abfd, rtproc_sec, rtproc_sec->contents, - (file_ptr) 0, - rtproc_sec->_raw_size)) + 0, rtproc_sec->size)) return FALSE; } } @@ -9050,6 +9599,7 @@ struct mips_mach_extension { static const struct mips_mach_extension mips_mach_extensions[] = { /* MIPS64 extensions. */ + { bfd_mach_mipsisa64r2, bfd_mach_mipsisa64 }, { bfd_mach_mips_sb1, bfd_mach_mipsisa64 }, /* MIPS V extensions. */ @@ -9070,6 +9620,8 @@ static const struct mips_mach_extension mips_mach_extensions[] = { { bfd_mach_mips5, bfd_mach_mips8000 }, { 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 }, @@ -9100,8 +9652,7 @@ static const struct mips_mach_extension mips_mach_extensions[] = { /* Return true if bfd machine EXTENSION is an extension of machine BASE. */ static bfd_boolean -mips_mach_extends_p (base, extension) - unsigned long base, extension; +mips_mach_extends_p (unsigned long base, unsigned long extension) { size_t i; @@ -9116,8 +9667,7 @@ mips_mach_extends_p (base, extension) /* Return true if the given ELF header flags describe a 32-bit binary. */ static bfd_boolean -mips_32bit_flags_p (flags) - flagword flags; +mips_32bit_flags_p (flagword flags) { return ((flags & EF_MIPS_32BITMODE) != 0 || (flags & EF_MIPS_ABI) == E_MIPS_ABI_O32 @@ -9133,9 +9683,7 @@ mips_32bit_flags_p (flags) object file when linking. */ bfd_boolean -_bfd_mips_elf_merge_private_bfd_data (ibfd, obfd) - bfd *ibfd; - bfd *obfd; +_bfd_mips_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) { flagword old_flags; flagword new_flags; @@ -9147,8 +9695,8 @@ _bfd_mips_elf_merge_private_bfd_data (ibfd, obfd) if (! _bfd_generic_verify_endian_match (ibfd, obfd)) { (*_bfd_error_handler) - (_("%s: endianness incompatible with that of the selected emulation"), - bfd_archive_filename (ibfd)); + (_("%B: endianness incompatible with that of the selected emulation"), + ibfd); return FALSE; } @@ -9159,8 +9707,8 @@ _bfd_mips_elf_merge_private_bfd_data (ibfd, obfd) if (strcmp (bfd_get_target (ibfd), bfd_get_target (obfd)) != 0) { (*_bfd_error_handler) - (_("%s: ABI is incompatible with that of the selected emulation"), - bfd_archive_filename (ibfd)); + (_("%B: ABI is incompatible with that of the selected emulation"), + ibfd); return FALSE; } @@ -9196,6 +9744,11 @@ _bfd_mips_elf_merge_private_bfd_data (ibfd, obfd) new_flags &= ~EF_MIPS_XGOT; old_flags &= ~EF_MIPS_XGOT; + /* MIPSpro generates ucode info in n64 objects. Again, we should + just be able to ignore this. */ + new_flags &= ~EF_MIPS_UCODE; + old_flags &= ~EF_MIPS_UCODE; + if (new_flags == old_flags) return TRUE; @@ -9208,10 +9761,10 @@ _bfd_mips_elf_merge_private_bfd_data (ibfd, obfd) which are automatically generated by gas. */ if (strcmp (sec->name, ".reginfo") && strcmp (sec->name, ".mdebug") - && ((!strcmp (sec->name, ".text") - || !strcmp (sec->name, ".data") - || !strcmp (sec->name, ".bss")) - && sec->_raw_size != 0)) + && (sec->size != 0 + || (strcmp (sec->name, ".text") + && strcmp (sec->name, ".data") + && strcmp (sec->name, ".bss")))) { null_input_bfd = FALSE; break; @@ -9226,8 +9779,8 @@ _bfd_mips_elf_merge_private_bfd_data (ibfd, obfd) != ((old_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0)) { (*_bfd_error_handler) - (_("%s: warning: linking PIC files with non-PIC files"), - bfd_archive_filename (ibfd)); + (_("%B: warning: linking PIC files with non-PIC files"), + ibfd); ok = TRUE; } @@ -9243,8 +9796,8 @@ _bfd_mips_elf_merge_private_bfd_data (ibfd, obfd) if (mips_32bit_flags_p (old_flags) != mips_32bit_flags_p (new_flags)) { (*_bfd_error_handler) - (_("%s: linking 32-bit code with 64-bit code"), - bfd_archive_filename (ibfd)); + (_("%B: linking 32-bit code with 64-bit code"), + ibfd); ok = FALSE; } else if (!mips_mach_extends_p (bfd_get_mach (ibfd), bfd_get_mach (obfd))) @@ -9271,8 +9824,8 @@ _bfd_mips_elf_merge_private_bfd_data (ibfd, obfd) { /* The ISAs aren't compatible. */ (*_bfd_error_handler) - (_("%s: linking %s module with previous %s modules"), - bfd_archive_filename (ibfd), + (_("%B: linking %s module with previous %s modules"), + ibfd, bfd_printable_name (ibfd), bfd_printable_name (obfd)); ok = FALSE; @@ -9294,8 +9847,8 @@ _bfd_mips_elf_merge_private_bfd_data (ibfd, obfd) != elf_elfheader (obfd)->e_ident[EI_CLASS])) { (*_bfd_error_handler) - (_("%s: ABI mismatch: linking %s module with previous %s modules"), - bfd_archive_filename (ibfd), + (_("%B: ABI mismatch: linking %s module with previous %s modules"), + ibfd, elf_mips_abi_name (ibfd), elf_mips_abi_name (obfd)); ok = FALSE; @@ -9317,8 +9870,8 @@ _bfd_mips_elf_merge_private_bfd_data (ibfd, obfd) if (new_flags != old_flags) { (*_bfd_error_handler) - (_("%s: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"), - bfd_archive_filename (ibfd), (unsigned long) new_flags, + (_("%B: uses different e_flags (0x%lx) fields than previous modules (0x%lx)"), + ibfd, (unsigned long) new_flags, (unsigned long) old_flags); ok = FALSE; } @@ -9335,9 +9888,7 @@ _bfd_mips_elf_merge_private_bfd_data (ibfd, obfd) /* Function to keep MIPS specific file flags like as EF_MIPS_PIC. */ bfd_boolean -_bfd_mips_elf_set_private_flags (abfd, flags) - bfd *abfd; - flagword flags; +_bfd_mips_elf_set_private_flags (bfd *abfd, flagword flags) { BFD_ASSERT (!elf_flags_init (abfd) || elf_elfheader (abfd)->e_flags == flags); @@ -9348,11 +9899,9 @@ _bfd_mips_elf_set_private_flags (abfd, flags) } bfd_boolean -_bfd_mips_elf_print_private_bfd_data (abfd, ptr) - bfd *abfd; - PTR ptr; +_bfd_mips_elf_print_private_bfd_data (bfd *abfd, void *ptr) { - FILE *file = (FILE *) ptr; + FILE *file = ptr; BFD_ASSERT (abfd != NULL && ptr != NULL); @@ -9395,6 +9944,8 @@ _bfd_mips_elf_print_private_bfd_data (abfd, ptr) fprintf (file, _(" [mips64]")); else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32R2) fprintf (file, _(" [mips32r2]")); + else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_64R2) + fprintf (file, _(" [mips64r2]")); else fprintf (file, _(" [unknown ISA]")); @@ -9413,3 +9964,64 @@ _bfd_mips_elf_print_private_bfd_data (abfd, ptr) return TRUE; } + +static struct bfd_elf_special_section const + mips_special_sections_l[]= +{ + { ".lit4", 5, 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL }, + { ".lit8", 5, 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL }, + { NULL, 0, 0, 0, 0 } +}; + +static struct bfd_elf_special_section const + mips_special_sections_m[]= +{ + { ".mdebug", 7, 0, SHT_MIPS_DEBUG, 0 }, + { NULL, 0, 0, 0, 0 } +}; + +static struct bfd_elf_special_section const + mips_special_sections_s[]= +{ + { ".sdata", 6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL }, + { ".sbss", 5, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_MIPS_GPREL }, +}; + +static struct bfd_elf_special_section const + mips_special_sections_u[]= +{ + { ".ucode", 6, 0, SHT_MIPS_UCODE, 0 }, + { NULL, 0, 0, 0, 0 } +}; + +struct bfd_elf_special_section const * + _bfd_mips_elf_special_sections[27] = +{ + NULL, /* 'a' */ + NULL, /* 'b' */ + NULL, /* 'c' */ + NULL, /* 'd' */ + NULL, /* 'e' */ + NULL, /* 'f' */ + NULL, /* 'g' */ + NULL, /* 'h' */ + NULL, /* 'i' */ + NULL, /* 'j' */ + NULL, /* 'k' */ + mips_special_sections_l, /* 'l' */ + mips_special_sections_m, /* 'm' */ + NULL, /* 'n' */ + NULL, /* 'o' */ + NULL, /* 'p' */ + NULL, /* 'q' */ + NULL, /* 'r' */ + mips_special_sections_s, /* 'm' */ + NULL, /* 't' */ + mips_special_sections_u, /* 'u' */ + NULL, /* 'v' */ + NULL, /* 'w' */ + NULL, /* 'x' */ + NULL, /* 'y' */ + NULL, /* 'z' */ + NULL /* other */ +};