X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf32-mips.c;h=efbcbfab293e3b2ea4f9835a0f1c72e9eed37c9c;hb=5a0a214415f6190b75ffe8b807008009e5d70ad6;hp=b9b99c76b2ef0dbcc4e0fce538c2323ee1438d68;hpb=be3ccd9c2b879034525ceceed75d60fb86648551;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c index b9b99c76b2..efbcbfab29 100644 --- a/bfd/elf32-mips.c +++ b/bfd/elf32-mips.c @@ -1,5 +1,5 @@ /* MIPS-specific support for 32-bit ELF - Copyright 1993, 94, 95, 96, 97, 98, 99, 2000 + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. Most of the information added by Ian Lance Taylor, Cygnus Support, @@ -49,7 +49,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This structure is used to hold .got information when linking. It is stored in the tdata field of the bfd_elf_section_data structure. */ -struct mips_got_info { +struct mips_got_info +{ /* The global symbol in the GOT with the lowest index in the dynamic symbol table. */ struct elf_link_hash_entry *global_gotsym; @@ -64,7 +65,8 @@ struct mips_got_info { /* The MIPS ELF linker needs additional information for each symbol in the global hash table. */ -struct mips_elf_link_hash_entry { +struct mips_elf_link_hash_entry +{ struct elf_link_hash_entry root; /* External symbol information. */ @@ -78,6 +80,12 @@ struct mips_elf_link_hash_entry { 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", + p. 4-20. */ + boolean no_fn_stub; + /* If there is a stub that 32 bit functions should use to call this 16 bit function, this points to the section containing the stub. */ asection *fn_stub; @@ -191,7 +199,7 @@ static bfd_vma mips_elf_got16_entry static 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 *, boolean local_p)); + bfd_vma, bfd_vma *, asection *)); static void mips_elf_allocate_dynamic_relocations PARAMS ((bfd *, unsigned int)); static boolean mips_elf_stub_section_p @@ -200,6 +208,11 @@ static int sort_dynamic_relocs PARAMS ((const void *, const void *)); extern const bfd_target bfd_elf32_tradbigmips_vec; +extern const bfd_target bfd_elf32_tradlittlemips_vec; +#ifdef BFD64 +extern const bfd_target bfd_elf64_tradbigmips_vec; +extern const bfd_target bfd_elf64_tradlittlemips_vec; +#endif /* The level of IRIX compatibility we're striving for. */ @@ -217,18 +230,25 @@ static bfd *reldyn_sorting_bfd; #define ABI_N32_P(abfd) \ ((elf_elfheader (abfd)->e_flags & EF_MIPS_ABI2) != 0) -/* Nonzero if ABFD is using the 64-bit ABI. FIXME: This is never - true, yet. */ +/* Nonzero if ABFD is using the 64-bit ABI. */ #define ABI_64_P(abfd) \ ((elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64) != 0) /* Depending on the target vector we generate some version of Irix executables or "normal" MIPS ELF ABI executables. */ - +#ifdef BFD64 #define IRIX_COMPAT(abfd) \ - (abfd->xvec == &bfd_elf32_tradbigmips_vec ? ict_none : \ + (((abfd->xvec == &bfd_elf64_tradbigmips_vec) || \ + (abfd->xvec == &bfd_elf64_tradlittlemips_vec) || \ + (abfd->xvec == &bfd_elf32_tradbigmips_vec) || \ + (abfd->xvec == &bfd_elf32_tradlittlemips_vec)) ? ict_none : \ ((ABI_N32_P (abfd) || ABI_64_P (abfd)) ? ict_irix6 : ict_irix5)) - +#else +#define IRIX_COMPAT(abfd) \ + (((abfd->xvec == &bfd_elf32_tradbigmips_vec) || \ + (abfd->xvec == &bfd_elf32_tradlittlemips_vec)) ? ict_none : \ + ((ABI_N32_P (abfd) || ABI_64_P (abfd)) ? ict_irix6 : ict_irix5)) +#endif /* Whether we are trying to be compatible with IRIX at all. */ #define SGI_COMPAT(abfd) \ @@ -321,7 +341,8 @@ static bfd *reldyn_sorting_bfd; /* Names of sections which appear in the .dynsym section in an Irix 5 executable. */ -static const char * const mips_elf_dynsym_sec_names[] = { +static const char * const mips_elf_dynsym_sec_names[] = +{ ".text", ".init", ".fini", @@ -345,7 +366,8 @@ static const char * const mips_elf_dynsym_sec_names[] = { /* The names of the runtime procedure table symbols used on Irix 5. */ -static const char * const mips_elf_dynsym_rtproc_names[] = { +static const char * const mips_elf_dynsym_rtproc_names[] = +{ "_procedure_table", "_procedure_string_table", "_procedure_table_size", @@ -355,7 +377,8 @@ static const char * const mips_elf_dynsym_rtproc_names[] = { /* These structures are used to generate the .compact_rel section on Irix 5. */ -typedef struct { +typedef struct +{ unsigned long id1; /* Always one? */ unsigned long num; /* Number of compact relocation entries. */ unsigned long id2; /* Always two? */ @@ -364,7 +387,8 @@ typedef struct { unsigned long reserved1; /* Zero? */ } Elf32_compact_rel; -typedef struct { +typedef struct +{ bfd_byte id1[4]; bfd_byte num[4]; bfd_byte id2[4]; @@ -373,7 +397,8 @@ typedef struct { bfd_byte reserved1[4]; } Elf32_External_compact_rel; -typedef struct { +typedef struct +{ unsigned int ctype : 1; /* 1: long 0: short format. See below. */ unsigned int rtype : 4; /* Relocation types. See below. */ unsigned int dist2to : 8; @@ -382,7 +407,8 @@ typedef struct { unsigned long vaddr; /* VADDR to be relocated. */ } Elf32_crinfo; -typedef struct { +typedef struct +{ unsigned int ctype : 1; /* 1: long 0: short format. See below. */ unsigned int rtype : 4; /* Relocation types. See below. */ unsigned int dist2to : 8; @@ -390,13 +416,15 @@ typedef struct { unsigned long konst; /* KONST field. See below. */ } Elf32_crinfo2; -typedef struct { +typedef struct +{ bfd_byte info[4]; bfd_byte konst[4]; bfd_byte vaddr[4]; } Elf32_External_crinfo; -typedef struct { +typedef struct +{ bfd_byte info[4]; bfd_byte konst[4]; } Elf32_External_crinfo2; @@ -449,7 +477,8 @@ static void bfd_elf32_swap_crinfo_out from smaller values. Start with zero, widen, *then* decrement. */ #define MINUS_ONE (((bfd_vma)0) - 1) -static reloc_howto_type elf_mips_howto_table[] = { +static reloc_howto_type elf_mips_howto_table[] = +{ /* No relocation. */ HOWTO (R_MIPS_NONE, /* type */ 0, /* rightshift */ @@ -520,7 +549,7 @@ static reloc_howto_type elf_mips_howto_table[] = { complain_overflow_dont, /* complain_on_overflow */ /* This needs complex overflow detection, because the upper four - bits must match the PC. */ + bits must match the PC + 4. */ bfd_elf_generic_reloc, /* special_function */ "R_MIPS_26", /* name */ true, /* partial_inplace */ @@ -1067,7 +1096,8 @@ static reloc_howto_type elf_mips_gnu_vtentry_howto = reloc. This extension permits gcc to output the HI and LO relocs itself. */ -struct mips_hi16 { +struct mips_hi16 +{ struct mips_hi16 *next; bfd_byte *addr; bfd_vma addend; @@ -1810,6 +1840,12 @@ elf_mips_isa (flags) return 3; case E_MIPS_ARCH_4: return 4; + case E_MIPS_ARCH_5: + return 5; + case E_MIPS_ARCH_32: + return 32; + case E_MIPS_ARCH_64: + return 64; } return 4; } @@ -1837,8 +1873,11 @@ elf_mips_mach (flags) case E_MIPS_MACH_4650: return bfd_mach_mips4650; - case E_MIPS_MACH_MIPS32: - return bfd_mach_mips4K; + case E_MIPS_MACH_MIPS32_4K: + return bfd_mach_mips32_4k; + + case E_MIPS_MACH_SB1: + return bfd_mach_mips_sb1; default: switch (flags & EF_MIPS_ARCH) @@ -1859,6 +1898,18 @@ elf_mips_mach (flags) case E_MIPS_ARCH_4: return bfd_mach_mips8000; break; + + case E_MIPS_ARCH_5: + return bfd_mach_mips5; + break; + + case E_MIPS_ARCH_32: + return bfd_mach_mips32; + break; + + case E_MIPS_ARCH_64: + return bfd_mach_mips64; + break; } } @@ -1903,7 +1954,8 @@ struct elf_reloc_map { enum elf_mips_reloc_type elf_reloc_val; }; -static CONST struct elf_reloc_map mips_reloc_map[] = { +static CONST struct elf_reloc_map mips_reloc_map[] = +{ { BFD_RELOC_NONE, R_MIPS_NONE, }, { BFD_RELOC_16, R_MIPS_16 }, { BFD_RELOC_32, R_MIPS_32 }, @@ -2261,7 +2313,12 @@ mips_elf_sym_is_global (abfd, sym) bfd *abfd ATTRIBUTE_UNUSED; asymbol *sym; { - return (sym->flags & BSF_SECTION_SYM) == 0 ? true : false; + if (SGI_COMPAT(abfd)) + return (sym->flags & BSF_SECTION_SYM) == 0 ? true : false; + else + return ((sym->flags & (BSF_GLOBAL | BSF_WEAK)) != 0 + || bfd_is_und_section (bfd_get_section (sym)) + || bfd_is_com_section (bfd_get_section (sym))); } /* Set the right machine number for a MIPS ELF file. This is used for @@ -2336,8 +2393,24 @@ _bfd_mips_elf_final_write_processing (abfd, linker) val = E_MIPS_ARCH_4; break; - case bfd_mach_mips4K: - val = E_MIPS_ARCH_2 | E_MIPS_MACH_MIPS32; + case bfd_mach_mips32: + val = E_MIPS_ARCH_32; + break; + + case bfd_mach_mips32_4k: + val = E_MIPS_ARCH_32 | E_MIPS_MACH_MIPS32_4K; + break; + + case bfd_mach_mips5: + val = E_MIPS_ARCH_5; + break; + + case bfd_mach_mips64: + val = E_MIPS_ARCH_64; + break; + + case bfd_mach_mips_sb1: + val = E_MIPS_ARCH_64 | E_MIPS_MACH_SB1; break; } @@ -2460,6 +2533,8 @@ _bfd_mips_elf_merge_private_bfd_data (ibfd, obfd) flagword old_flags; flagword new_flags; boolean ok; + boolean null_input_bfd = true; + asection *sec; /* Check if we have the same endianess */ if (_bfd_generic_verify_endian_match (ibfd, obfd) == false) @@ -2499,6 +2574,27 @@ _bfd_mips_elf_merge_private_bfd_data (ibfd, obfd) if (new_flags == old_flags) return true; + /* Check to see if the input BFD actually contains any sections. + If not, its flags may not have been initialised either, but it cannot + actually cause any incompatibility. */ + for (sec = ibfd->sections; sec != NULL; sec = sec->next) + { + /* Ignore synthetic sections and empty .text, .data and .bss sections + 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)) + { + null_input_bfd = false; + break; + } + } + if (null_input_bfd) + return true; + ok = true; if ((new_flags & EF_MIPS_PIC) != (old_flags & EF_MIPS_PIC)) @@ -2537,13 +2633,12 @@ _bfd_mips_elf_merge_private_bfd_data (ibfd, obfd) || new_mach == old_mach ) { - /* Don't warn about mixing -mips1 and -mips2 code, or mixing -mips3 - and -mips4 code. They will normally use the same data sizes and - calling conventions. */ + /* Don't warn about mixing code using 32-bit ISAs, or mixing code + using 64-bit ISAs. They will normally use the same data sizes + and calling conventions. */ - if ((new_isa == 1 || new_isa == 2) - ? (old_isa != 1 && old_isa != 2) - : (old_isa == 1 || old_isa == 2)) + if (( (new_isa == 1 || new_isa == 2 || new_isa == 32) + ^ (old_isa == 1 || old_isa == 2 || old_isa == 32)) != 0) { (*_bfd_error_handler) (_("%s: ISA mismatch (-mips%d) with previous modules (-mips%d)"), @@ -2647,6 +2742,12 @@ _bfd_mips_elf_print_private_bfd_data (abfd, ptr) fprintf (file, _(" [mips3]")); else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_4) fprintf (file, _(" [mips4]")); + else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_5) + fprintf (file, _ (" [mips5]")); + else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_32) + fprintf (file, _ (" [mips32]")); + else if ((elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_64) + fprintf (file, _ (" [mips64]")); else fprintf (file, _(" [unknown ISA]")); @@ -3426,7 +3527,8 @@ _bfd_mips_elf_modify_segment_map (abfd) if (m != NULL && m->count == 1 && strcmp (m->sections[0]->name, ".dynamic") == 0) { - static const char *sec_names[] = { + static const char *sec_names[] = + { ".dynamic", ".dynstr", ".dynsym", ".hash" }; bfd_vma low, high; @@ -3645,7 +3747,8 @@ mips_elf_is_local_label_name (abfd, name) /* MIPS ELF uses a special find_nearest_line routine in order the handle the ECOFF debugging information. */ -struct mips_elf_find_line { +struct mips_elf_find_line +{ struct ecoff_debug_info d; struct ecoff_find_line i; }; @@ -3671,7 +3774,8 @@ _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, - ABI_64_P (abfd) ? 8 : 0)) + ABI_64_P (abfd) ? 8 : 0, + &elf_tdata (abfd)->dwarf2_find_line_info)) return true; msec = bfd_get_section_by_name (abfd, ".mdebug"); @@ -3797,7 +3901,8 @@ _bfd_mips_elf_find_nearest_line (abfd, section, symbols, offset, filename_ptr, /* MIPS ELF linker hash table. */ -struct mips_elf_link_hash_table { +struct mips_elf_link_hash_table +{ struct elf_link_hash_table root; #if 0 /* We no longer use this. */ @@ -3873,6 +3978,7 @@ mips_elf_link_hash_newfunc (entry, table, string) ret->esym.ifd = -2; ret->possibly_dynamic_relocs = 0; ret->min_dyn_reloc_index = 0; + ret->no_fn_stub = false; ret->fn_stub = NULL; ret->need_fn_stub = false; ret->call_stub = NULL; @@ -4091,7 +4197,8 @@ _bfd_mips_elf_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp) /* Structure used to pass information to mips_elf_output_extsym. */ -struct extsym_info { +struct extsym_info +{ bfd *abfd; struct bfd_link_info *info; struct ecoff_debug_info *debug; @@ -4247,24 +4354,36 @@ mips_elf_output_extsym (h, data) } else if ((h->root.elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0) { - /* Set type and value for a symbol with a function stub. */ - h->esym.asym.st = stProc; - sec = h->root.root.u.def.section; - if (sec == NULL) - h->esym.asym.value = 0; - else + struct mips_elf_link_hash_entry *hd = h; + boolean no_fn_stub = h->no_fn_stub; + + while (hd->root.root.type == bfd_link_hash_indirect) { - output_section = sec->output_section; - if (output_section != NULL) - h->esym.asym.value = (h->root.plt.offset - + sec->output_offset - + output_section->vma); - else - h->esym.asym.value = 0; + hd = (struct mips_elf_link_hash_entry *)h->root.root.u.i.link; + no_fn_stub = no_fn_stub || hd->no_fn_stub; } + + if (!no_fn_stub) + { + /* Set type and value for a symbol with a function stub. */ + h->esym.asym.st = stProc; + sec = hd->root.root.u.def.section; + if (sec == NULL) + h->esym.asym.value = 0; + else + { + output_section = sec->output_section; + if (output_section != NULL) + h->esym.asym.value = (hd->root.plt.offset + + sec->output_offset + + output_section->vma); + else + h->esym.asym.value = 0; + } #if 0 /* FIXME? */ - h->esym.ifd = 0; + h->esym.ifd = 0; #endif + } } if (! bfd_ecoff_debug_one_external (einfo->abfd, einfo->debug, einfo->swap, @@ -4466,11 +4585,13 @@ _bfd_mips_elf_final_link (abfd, info) EXTR esym; bfd_vma last; unsigned int i; - static const char * const name[] = { + static const char * const name[] = + { ".text", ".init", ".fini", ".data", ".rodata", ".sdata", ".sbss", ".bss" }; - static const int sc[] = { + static const int sc[] = + { scText, scInit, scFini, scData, scRData, scSData, scSBss, scBss }; @@ -5389,7 +5510,8 @@ mips_elf_record_global_got_symbol (h, info, g) /* This structure is passed to mips_elf_sort_hash_table_f when sorting the dynamic symbols. */ -struct mips_elf_hash_sort_data { +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; @@ -5662,7 +5784,7 @@ mips_elf_next_relocation (r_type, relocation, relend) static boolean mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec, - symbol, addendp, input_section, local_p) + symbol, addendp, input_section) bfd *output_bfd; struct bfd_link_info *info; const Elf_Internal_Rela *rel; @@ -5671,7 +5793,6 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec, bfd_vma symbol; bfd_vma *addendp; asection *input_section; - boolean local_p; { Elf_Internal_Rel outrel; boolean skip; @@ -5756,15 +5877,16 @@ mips_elf_create_dynamic_relocation (output_bfd, info, rel, h, sec, /* The relocation we're building is section-relative. Therefore, the original addend must be adjusted by the section offset. */ - *addendp += symbol - sec->output_section->vma; + *addendp += section_offset; /* Now, the relocation is just against the section. */ symbol = sec->output_section->vma; } - /* If the relocation is against a local symbol was previously an - absolute relocation, we must adjust it by the value we give - it in the dynamic symbol table. */ - if (local_p && r_type != R_MIPS_REL32) + /* 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 (!indx && r_type != R_MIPS_REL32) *addendp += symbol; /* The relocation is always an REL32 relocation because we don't @@ -6139,7 +6261,7 @@ mips_elf_calculate_relocation (abfd, symbol + addend, sgot->contents + g); } } - else if (r_type == R_MIPS_GOT16) + else if (r_type == R_MIPS_GOT16 || r_type == R_MIPS_CALL16) /* There's no need to create a local GOT entry here; the calculation for a local GOT16 entry does not involve G. */ break; @@ -6202,7 +6324,7 @@ mips_elf_calculate_relocation (abfd, sec, symbol, &value, - input_section, local_p)) + input_section)) return false; } else @@ -6234,14 +6356,14 @@ mips_elf_calculate_relocation (abfd, break; case R_MIPS16_26: - /* The calculation for R_MIPS_26 is just the same as for an + /* 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 the output file that's different. That's handled in mips_elf_perform_relocation. So, we just fall through to the R_MIPS_26 case here. */ case R_MIPS_26: if (local_p) - value = (((addend << 2) | (p & 0xf0000000)) + symbol) >> 2; + value = (((addend << 2) | ((p + 4) & 0xf0000000)) + symbol) >> 2; else value = (mips_elf_sign_extend (addend << 2, 28) + symbol) >> 2; value &= howto->dst_mask; @@ -6307,6 +6429,7 @@ mips_elf_calculate_relocation (abfd, break; case R_MIPS_GOT16: + case R_MIPS_CALL16: if (local_p) { boolean forced; @@ -6329,7 +6452,6 @@ mips_elf_calculate_relocation (abfd, /* Fall through. */ - case R_MIPS_CALL16: case R_MIPS_GOT_DISP: value = g; overflowed_p = mips_elf_overflow_p (value, 16); @@ -6534,9 +6656,9 @@ mips_elf_perform_relocation (info, howto, relocation, value, ((sub1 << 16) | sub2)). When producing a relocateable object file, the calculation is - (((A < 2) | (P & 0xf0000000) + S) >> 2) + (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2) When producing a fully linked file, the calculation is - let R = (((A < 2) | (P & 0xf0000000) + S) >> 2) + let R = (((A < 2) | ((P + 4) & 0xf0000000) + S) >> 2) ((R & 0x1f0000) << 5) | ((R & 0x3e00000) >> 5) | (R & 0xffff) */ if (!info->relocateable) @@ -6544,7 +6666,6 @@ mips_elf_perform_relocation (info, howto, relocation, value, value = (((value & 0x1f0000) << 5) | ((value & 0x3e00000) >> 5) | (value & 0xffff)); - } else if (r_type == R_MIPS16_GPREL) { @@ -6667,6 +6788,7 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, REL relocation. */ boolean rela_relocation_p = true; int r_type = ELF32_R_TYPE (rel->r_info); + const char * msg = (const char *) NULL; /* Find the relocation howto for this relocation. */ if (r_type == R_MIPS_64 && !ABI_64_P (output_bfd)) @@ -6921,8 +7043,10 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, continue; case bfd_reloc_notsupported: - abort (); - break; + msg = _("internal error: unsupported relocation error"); + info->callbacks->warning + (info, msg, name, input_bfd, input_section, rel->r_offset); + return false; case bfd_reloc_overflow: if (use_saved_addend_p) @@ -7643,10 +7767,10 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs) /* We may need a local GOT entry for this relocation. We don't count R_MIPS_GOT_PAGE because we can estimate the maximum number of pages needed by looking at the size of - the segment. Similar comments apply to R_MIPS_GOT16. We - don't count R_MIPS_GOT_HI16, or R_MIPS_CALL_HI16 because - these are always followed by an R_MIPS_GOT_LO16 or - R_MIPS_CALL_LO16. + the segment. Similar comments apply to R_MIPS_GOT16 and + R_MIPS_CALL16. We don't count R_MIPS_GOT_HI16, or + R_MIPS_CALL_HI16 because these are always followed by an + R_MIPS_GOT_LO16 or R_MIPS_CALL_LO16. This estimation is very conservative since we can merge duplicate entries in the GOT. In order to be less @@ -7778,6 +7902,25 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs) break; } + /* We must not create a stub for a symbol that has relocations + related to taking the function's address. */ + switch (r_type) + { + default: + if (h != NULL) + { + struct mips_elf_link_hash_entry *mh; + + mh = (struct mips_elf_link_hash_entry *) h; + mh->no_fn_stub = true; + } + break; + case R_MIPS_CALL16: + case R_MIPS_CALL_HI16: + case R_MIPS_CALL_LO16: + break; + } + /* If this reloc is not a 16 bit call, and it has a global symbol, then we will need the fn_stub if there is one. References from a stub section do not count. */ @@ -7913,6 +8056,8 @@ _bfd_mips_elf_copy_indirect_symbol (dir, ind) || (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; } /* Adjust a symbol defined by a dynamic object and referenced by a @@ -7953,8 +8098,9 @@ _bfd_mips_elf_adjust_dynamic_symbol (info, h) mips_elf_allocate_dynamic_relocations (dynobj, hmips->possibly_dynamic_relocs); - /* For a function, create a stub, if needed. */ - if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0) + /* For a function, create a stub, if allowed. */ + if (! hmips->no_fn_stub + && (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0) { if (! elf_hash_table (info)->dynamic_sections_created) return true;