From: Maciej W. Rozycki Date: Fri, 6 Dec 2013 23:20:14 +0000 (+0000) Subject: MIPS: MIPS16 and microMIPS PLT entry support for binutils 2.24 X-Git-Tag: gdb_7_6_2-2013-12-08-release~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7af8396e63463638dfba5ab732b2380cffd0774c;p=thirdparty%2Fbinutils-gdb.git MIPS: MIPS16 and microMIPS PLT entry support for binutils 2.24 This is a backport from trunk to handle MIPS16 and microMIPS code in PLT entries as produced by LD from binutils version 2.24 onwards. This feature requires explicit support in GDB for correct operation when debugging through function calls made via the PLT. bfd/ * elfxx-mips.h (_bfd_mips_elf_get_synthetic_symtab): New prototype. * elf32-mips.c (elf_backend_plt_sym_val): Remove macro. (bfd_elf32_get_synthetic_symtab): New macro. * elfxx-mips.c (micromips_o32_exec_plt0_entry): New variable. (micromips_insn32_o32_exec_plt0_entry): Likewise. (mips16_o32_exec_plt_entry): Likewise. (micromips_o32_exec_plt_entry): Likewise. (micromips_insn32_o32_exec_plt_entry): Likewise. (_bfd_mips_elf_get_synthetic_symtab): New function. gdb/ * mips-tdep.c (mips_elf_make_msymbol_special): Handle MIPS16 and microMIPS synthetic symbols. opcodes/ * mips-dis.c (is_mips16_plt_tail): New function. (print_insn_mips16): Handle MIPS16 PLT entry's GOT slot address word. (is_compressed_mode_p): Handle MIPS16/microMIPS PLT entries. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 42d6c27dfa7..8798b865723 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,18 @@ +2013-12-06 Maciej W. Rozycki + Paul Brook + + * elfxx-mips.h (_bfd_mips_elf_get_synthetic_symtab): New + prototype. + * elf32-mips.c (elf_backend_plt_sym_val): Remove macro. + (bfd_elf32_get_synthetic_symtab): New macro. + * elfxx-mips.c (micromips_o32_exec_plt0_entry): New variable. + (micromips_insn32_o32_exec_plt0_entry): Likewise. + (mips16_o32_exec_plt_entry): Likewise. + (micromips_o32_exec_plt_entry): Likewise. + (micromips_insn32_o32_exec_plt_entry): Likewise. + (_bfd_mips_elf_get_synthetic_symtab): New + function. + 2013-03-08 Venkataramanan Kumar * elf64-aarch64.c (elf_backend_can_gc_sections): Enable gc-section diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c index cb7692bf08f..a65de248950 100644 --- a/bfd/elf32-mips.c +++ b/bfd/elf32-mips.c @@ -2344,7 +2344,6 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = { #define elf_backend_default_use_rela_p 0 #define elf_backend_sign_extend_vma TRUE #define elf_backend_plt_readonly 1 -#define elf_backend_plt_sym_val _bfd_mips_elf_plt_sym_val #define elf_backend_discard_info _bfd_mips_elf_discard_info #define elf_backend_ignore_discarded_relocs \ @@ -2356,6 +2355,7 @@ static const struct ecoff_debug_swap mips_elf32_ecoff_debug_swap = { mips_elf_is_local_label_name #define bfd_elf32_bfd_is_target_special_symbol \ _bfd_mips_elf_is_target_special_symbol +#define bfd_elf32_get_synthetic_symtab _bfd_mips_elf_get_synthetic_symtab #define bfd_elf32_find_nearest_line _bfd_mips_elf_find_nearest_line #define bfd_elf32_find_inliner_info _bfd_mips_elf_find_inliner_info #define bfd_elf32_new_section_hook _bfd_mips_elf_new_section_hook @@ -2483,7 +2483,6 @@ mips_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker) #define elf_backend_default_use_rela_p 1 #undef elf_backend_got_header_size #define elf_backend_got_header_size (4 * 3) -#undef elf_backend_plt_sym_val #undef elf_backend_finish_dynamic_symbol #define elf_backend_finish_dynamic_symbol \ @@ -2509,4 +2508,6 @@ mips_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker) #undef elf_backend_symbol_processing /* NOTE: elf_backend_rela_normal is not defined for MIPS. */ +#undef bfd_elf32_get_synthetic_symtab + #include "elf32-target.h" diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c index a5ad454a79b..3388cfe9212 100644 --- a/bfd/elfxx-mips.c +++ b/bfd/elfxx-mips.c @@ -969,7 +969,40 @@ static const bfd_vma mips_n64_exec_plt0_entry[] = 0x2718fffe /* subu $24, $24, 2 */ }; -/* The format of subsequent PLT entries. */ +/* The format of the microMIPS first PLT entry in an O32 executable. + We rely on v0 ($2) rather than t8 ($24) to contain the address + of the GOTPLT entry handled, so this stub may only be used when + all the subsequent PLT entries are microMIPS code too. + + The trailing NOP is for alignment and correct disassembly only. */ +static const bfd_vma micromips_o32_exec_plt0_entry[] = +{ + 0x7980, 0x0000, /* addiupc $3, (&GOTPLT[0]) - . */ + 0xff23, 0x0000, /* lw $25, 0($3) */ + 0x0535, /* subu $2, $2, $3 */ + 0x2525, /* srl $2, $2, 2 */ + 0x3302, 0xfffe, /* subu $24, $2, 2 */ + 0x0dff, /* move $15, $31 */ + 0x45f9, /* jalrs $25 */ + 0x0f83, /* move $28, $3 */ + 0x0c00 /* nop */ +}; + +/* The format of the microMIPS first PLT entry in an O32 executable + in the insn32 mode. */ +static const bfd_vma micromips_insn32_o32_exec_plt0_entry[] = +{ + 0x41bc, 0x0000, /* lui $28, %hi(&GOTPLT[0]) */ + 0xff3c, 0x0000, /* lw $25, %lo(&GOTPLT[0])($28) */ + 0x339c, 0x0000, /* addiu $28, $28, %lo(&GOTPLT[0]) */ + 0x0398, 0xc1d0, /* subu $24, $24, $28 */ + 0x001f, 0x7950, /* move $15, $31 */ + 0x0318, 0x1040, /* srl $24, $24, 2 */ + 0x03f9, 0x0f3c, /* jalr $25 */ + 0x3318, 0xfffe /* subu $24, $24, 2 */ +}; + +/* The format of subsequent standard PLT entries. */ static const bfd_vma mips_exec_plt_entry[] = { 0x3c0f0000, /* lui $15, %hi(.got.plt entry) */ @@ -978,6 +1011,39 @@ static const bfd_vma mips_exec_plt_entry[] = 0x03200008 /* jr $25 */ }; +/* The format of subsequent MIPS16 o32 PLT entries. We use v0 ($2) + and v1 ($3) as temporaries because t8 ($24) and t9 ($25) are not + directly addressable. */ +static const bfd_vma mips16_o32_exec_plt_entry[] = +{ + 0xb203, /* lw $2, 12($pc) */ + 0x9a60, /* lw $3, 0($2) */ + 0x651a, /* move $24, $2 */ + 0xeb00, /* jr $3 */ + 0x653b, /* move $25, $3 */ + 0x6500, /* nop */ + 0x0000, 0x0000 /* .word (.got.plt entry) */ +}; + +/* The format of subsequent microMIPS o32 PLT entries. We use v0 ($2) + as a temporary because t8 ($24) is not addressable with ADDIUPC. */ +static const bfd_vma micromips_o32_exec_plt_entry[] = +{ + 0x7900, 0x0000, /* addiupc $2, (.got.plt entry) - . */ + 0xff22, 0x0000, /* lw $25, 0($2) */ + 0x4599, /* jr $25 */ + 0x0f02 /* move $24, $2 */ +}; + +/* The format of subsequent microMIPS o32 PLT entries in the insn32 mode. */ +static const bfd_vma micromips_insn32_o32_exec_plt_entry[] = +{ + 0x41af, 0x0000, /* lui $15, %hi(.got.plt entry) */ + 0xff2f, 0x0000, /* lw $25, %lo(.got.plt entry)($15) */ + 0x0019, 0x0f3c, /* jr $25 */ + 0x330f, 0x0000 /* addiu $24, $15, %lo(.got.plt entry) */ +}; + /* The format of the first PLT entry in a VxWorks executable. */ static const bfd_vma mips_vxworks_exec_plt0_entry[] = { @@ -14347,6 +14413,246 @@ _bfd_mips_elf_plt_sym_val (bfd_vma i, const asection *plt, + i * 4 * ARRAY_SIZE (mips_exec_plt_entry)); } +/* Build a table of synthetic symbols to represent the PLT. As with MIPS16 + and microMIPS PLT slots we may have a many-to-one mapping between .plt + and .got.plt and also the slots may be of a different size each we walk + the PLT manually fetching instructions and matching them against known + patterns. To make things easier standard MIPS slots, if any, always come + first. As we don't create proper ELF symbols we use the UDATA.I member + of ASYMBOL to carry ISA annotation. The encoding used is the same as + with the ST_OTHER member of the ELF symbol. */ + +long +_bfd_mips_elf_get_synthetic_symtab (bfd *abfd, + long symcount ATTRIBUTE_UNUSED, + asymbol **syms ATTRIBUTE_UNUSED, + long dynsymcount, asymbol **dynsyms, + asymbol **ret) +{ + static const char pltname[] = "_PROCEDURE_LINKAGE_TABLE_"; + static const char microsuffix[] = "@micromipsplt"; + static const char m16suffix[] = "@mips16plt"; + static const char mipssuffix[] = "@plt"; + + bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + bfd_boolean micromips_p = MICROMIPS_P (abfd); + Elf_Internal_Shdr *hdr; + bfd_byte *plt_data; + bfd_vma plt_offset; + unsigned int other; + bfd_vma entry_size; + bfd_vma plt0_size; + asection *relplt; + bfd_vma opcode; + asection *plt; + asymbol *send; + size_t size; + char *names; + long counti; + arelent *p; + asymbol *s; + char *nend; + long count; + long pi; + long i; + long n; + + *ret = NULL; + + if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0 || dynsymcount <= 0) + return 0; + + relplt = bfd_get_section_by_name (abfd, ".rel.plt"); + if (relplt == NULL) + return 0; + + hdr = &elf_section_data (relplt)->this_hdr; + if (hdr->sh_link != elf_dynsymtab (abfd) || hdr->sh_type != SHT_REL) + return 0; + + plt = bfd_get_section_by_name (abfd, ".plt"); + if (plt == NULL) + return 0; + + slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; + if (!(*slurp_relocs) (abfd, relplt, dynsyms, TRUE)) + return -1; + p = relplt->relocation; + + /* Calculating the exact amount of space required for symbols would + require two passes over the PLT, so just pessimise assuming two + PLT slots per relocation. */ + count = relplt->size / hdr->sh_entsize; + counti = count * bed->s->int_rels_per_ext_rel; + size = 2 * count * sizeof (asymbol); + size += count * (sizeof (mipssuffix) + + (micromips_p ? sizeof (microsuffix) : sizeof (m16suffix))); + for (pi = 0; pi < counti; pi += bed->s->int_rels_per_ext_rel) + size += 2 * strlen ((*p[pi].sym_ptr_ptr)->name); + + /* Add the size of "_PROCEDURE_LINKAGE_TABLE_" too. */ + size += sizeof (asymbol) + sizeof (pltname); + + if (!bfd_malloc_and_get_section (abfd, plt, &plt_data)) + return -1; + + if (plt->size < 16) + return -1; + + s = *ret = bfd_malloc (size); + if (s == NULL) + return -1; + send = s + 2 * count + 1; + + names = (char *) send; + nend = (char *) s + size; + n = 0; + + opcode = bfd_get_micromips_32 (abfd, plt_data + 12); + if (opcode == 0x3302fffe) + { + if (!micromips_p) + return -1; + plt0_size = 2 * ARRAY_SIZE (micromips_o32_exec_plt0_entry); + other = STO_MICROMIPS; + } + else if (opcode == 0x0398c1d0) + { + if (!micromips_p) + return -1; + plt0_size = 2 * ARRAY_SIZE (micromips_insn32_o32_exec_plt0_entry); + other = STO_MICROMIPS; + } + else + { + plt0_size = 4 * ARRAY_SIZE (mips_o32_exec_plt0_entry); + other = 0; + } + + s->the_bfd = abfd; + s->flags = BSF_SYNTHETIC | BSF_FUNCTION | BSF_LOCAL; + s->section = plt; + s->value = 0; + s->name = names; + s->udata.i = other; + memcpy (names, pltname, sizeof (pltname)); + names += sizeof (pltname); + ++s, ++n; + + pi = 0; + for (plt_offset = plt0_size; + plt_offset + 8 <= plt->size && s < send; + plt_offset += entry_size) + { + bfd_vma gotplt_addr; + const char *suffix; + bfd_vma gotplt_hi; + bfd_vma gotplt_lo; + size_t suffixlen; + + opcode = bfd_get_micromips_32 (abfd, plt_data + plt_offset + 4); + + /* Check if the second word matches the expected MIPS16 instruction. */ + if (opcode == 0x651aeb00) + { + if (micromips_p) + return -1; + /* Truncated table??? */ + if (plt_offset + 16 > plt->size) + break; + gotplt_addr = bfd_get_32 (abfd, plt_data + plt_offset + 12); + entry_size = 2 * ARRAY_SIZE (mips16_o32_exec_plt_entry); + suffixlen = sizeof (m16suffix); + suffix = m16suffix; + other = STO_MIPS16; + } + /* Likewise the expected microMIPS instruction (no insn32 mode). */ + else if (opcode == 0xff220000) + { + if (!micromips_p) + return -1; + gotplt_hi = bfd_get_16 (abfd, plt_data + plt_offset) & 0x7f; + gotplt_lo = bfd_get_16 (abfd, plt_data + plt_offset + 2) & 0xffff; + gotplt_hi = ((gotplt_hi ^ 0x40) - 0x40) << 18; + gotplt_lo <<= 2; + gotplt_addr = gotplt_hi + gotplt_lo; + gotplt_addr += ((plt->vma + plt_offset) | 3) ^ 3; + entry_size = 2 * ARRAY_SIZE (micromips_o32_exec_plt_entry); + suffixlen = sizeof (microsuffix); + suffix = microsuffix; + other = STO_MICROMIPS; + } + /* Likewise the expected microMIPS instruction (insn32 mode). */ + else if ((opcode & 0xffff0000) == 0xff2f0000) + { + gotplt_hi = bfd_get_16 (abfd, plt_data + plt_offset + 2) & 0xffff; + gotplt_lo = bfd_get_16 (abfd, plt_data + plt_offset + 6) & 0xffff; + gotplt_hi = ((gotplt_hi ^ 0x8000) - 0x8000) << 16; + gotplt_lo = (gotplt_lo ^ 0x8000) - 0x8000; + gotplt_addr = gotplt_hi + gotplt_lo; + entry_size = 2 * ARRAY_SIZE (micromips_insn32_o32_exec_plt_entry); + suffixlen = sizeof (microsuffix); + suffix = microsuffix; + other = STO_MICROMIPS; + } + /* Otherwise assume standard MIPS code. */ + else + { + gotplt_hi = bfd_get_32 (abfd, plt_data + plt_offset) & 0xffff; + gotplt_lo = bfd_get_32 (abfd, plt_data + plt_offset + 4) & 0xffff; + gotplt_hi = ((gotplt_hi ^ 0x8000) - 0x8000) << 16; + gotplt_lo = (gotplt_lo ^ 0x8000) - 0x8000; + gotplt_addr = gotplt_hi + gotplt_lo; + entry_size = 4 * ARRAY_SIZE (mips_exec_plt_entry); + suffixlen = sizeof (mipssuffix); + suffix = mipssuffix; + other = 0; + } + /* Truncated table??? */ + if (plt_offset + entry_size > plt->size) + break; + + for (i = 0; + i < count && p[pi].address != gotplt_addr; + i++, pi = (pi + bed->s->int_rels_per_ext_rel) % counti); + + if (i < count) + { + size_t namelen; + size_t len; + + *s = **p[pi].sym_ptr_ptr; + /* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set. Since + we are defining a symbol, ensure one of them is set. */ + if ((s->flags & BSF_LOCAL) == 0) + s->flags |= BSF_GLOBAL; + s->flags |= BSF_SYNTHETIC; + s->section = plt; + s->value = plt_offset; + s->name = names; + s->udata.i = other; + + len = strlen ((*p[pi].sym_ptr_ptr)->name); + namelen = len + suffixlen; + if (names + namelen > nend) + break; + + memcpy (names, (*p[pi].sym_ptr_ptr)->name, len); + names += len; + memcpy (names, suffix, suffixlen); + names += suffixlen; + + ++s, ++n; + pi = (pi + bed->s->int_rels_per_ext_rel) % counti; + } + } + + free (plt_data); + + return n; +} + void _bfd_mips_post_process_headers (bfd *abfd, struct bfd_link_info *link_info) { diff --git a/bfd/elfxx-mips.h b/bfd/elfxx-mips.h index 589f1ce8b67..45ccabb2090 100644 --- a/bfd/elfxx-mips.h +++ b/bfd/elfxx-mips.h @@ -152,6 +152,8 @@ extern bfd_boolean _bfd_mips_elf_init_stubs asection *(*) (const char *, asection *, asection *)); extern bfd_vma _bfd_mips_elf_plt_sym_val (bfd_vma, const asection *, const arelent *rel); +extern long _bfd_mips_elf_get_synthetic_symtab + (bfd *, long, asymbol **, long, asymbol **, asymbol **); extern void _bfd_mips_post_process_headers (bfd *abfd, struct bfd_link_info *link_info); diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 4944882f0b4..16b3a4fb030 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,8 @@ +2013-12-06 Maciej W. Rozycki + + * mips-tdep.c (mips_elf_make_msymbol_special): Handle MIPS16 and + microMIPS synthetic symbols. + 2013-09-12 Andrew Pinski * aarch64-linux-nat.c (aarch64_linux_set_debug_regs): Zero out regs. diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index f83bc99295e..80e6a78da7c 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -343,8 +343,9 @@ make_compact_addr (CORE_ADDR addr) "special", i.e. refers to a MIPS16 or microMIPS function, and sets one of the "special" bits in a minimal symbol to mark it accordingly. The test checks an ELF-private flag that is valid for true function - symbols only; in particular synthetic symbols such as for PLT stubs - have no ELF-private part at all. + symbols only; for synthetic symbols such as for PLT stubs that have + no ELF-private part at all the MIPS BFD backend arranges for this + information to be carried in the asymbol's udata field instead. msymbol_is_mips16 and msymbol_is_micromips test the "special" bit in a minimal symbol. */ @@ -353,13 +354,18 @@ static void mips_elf_make_msymbol_special (asymbol * sym, struct minimal_symbol *msym) { elf_symbol_type *elfsym = (elf_symbol_type *) sym; + unsigned char st_other; - if ((sym->flags & BSF_SYNTHETIC) != 0) + if ((sym->flags & BSF_SYNTHETIC) == 0) + st_other = elfsym->internal_elf_sym.st_other; + else if ((sym->flags & BSF_FUNCTION) != 0) + st_other = sym->udata.i; + else return; - if (ELF_ST_IS_MICROMIPS (elfsym->internal_elf_sym.st_other)) + if (ELF_ST_IS_MICROMIPS (st_other)) MSYMBOL_TARGET_FLAG_2 (msym) = 1; - else if (ELF_ST_IS_MIPS16 (elfsym->internal_elf_sym.st_other)) + else if (ELF_ST_IS_MIPS16 (st_other)) MSYMBOL_TARGET_FLAG_1 (msym) = 1; } diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index 66556f1c913..c86f8cccd47 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,10 @@ +2013-12-06 Maciej W. Rozycki + + * mips-dis.c (is_mips16_plt_tail): New function. + (print_insn_mips16): Handle MIPS16 PLT entry's GOT slot address + word. + (is_compressed_mode_p): Handle MIPS16/microMIPS PLT entries. + 2013-03-12 Michael Eager * opcodes/mips-dis.c (print_insn_args): Modify def of reg. diff --git a/opcodes/mips-dis.c b/opcodes/mips-dis.c index 018ac94f302..9a1ffdec856 100644 --- a/opcodes/mips-dis.c +++ b/opcodes/mips-dis.c @@ -2033,6 +2033,23 @@ print_mips16_insn_arg (char type, } } + +/* Check if the given address is the last word of a MIPS16 PLT entry. + This word is data and depending on the value it may interfere with + disassembly of further PLT entries. We make use of the fact PLT + symbols are marked BSF_SYNTHETIC. */ +static bfd_boolean +is_mips16_plt_tail (struct disassemble_info *info, bfd_vma addr) +{ + if (info->symbols + && info->symbols[0] + && (info->symbols[0]->flags & BSF_SYNTHETIC) + && addr == bfd_asymbol_value (info->symbols[0]) + 12) + return TRUE; + + return FALSE; +} + /* Disassemble mips16 instructions. */ static int @@ -2040,7 +2057,7 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info) { const fprintf_ftype infprintf = info->fprintf_func; int status; - bfd_byte buffer[2]; + bfd_byte buffer[4]; int length; int insn; bfd_boolean use_extend; @@ -2053,11 +2070,32 @@ print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info) info->insn_info_valid = 1; info->branch_delay_insns = 0; info->data_size = 0; - info->insn_type = dis_nonbranch; info->target = 0; info->target2 = 0; - status = (*info->read_memory_func) (memaddr, buffer, 2, info); + /* Decode PLT entry's GOT slot address word. */ + if (is_mips16_plt_tail (info, memaddr)) + { + info->insn_type = dis_noninsn; + status = (*info->read_memory_func) (memaddr, buffer, 4, info); + if (status == 0) + { + unsigned int gotslot; + + if (info->endian == BFD_ENDIAN_BIG) + gotslot = bfd_getb32 (buffer); + else + gotslot = bfd_getl32 (buffer); + infprintf (is, ".word\t0x%x", gotslot); + + return 4; + } + } + else + { + info->insn_type = dis_nonbranch; + status = (*info->read_memory_func) (memaddr, buffer, 2, info); + } if (status != 0) { (*info->memory_error_func) (status, memaddr, info); @@ -2931,27 +2969,26 @@ print_insn_micromips (bfd_vma memaddr, struct disassemble_info *info) static bfd_boolean is_compressed_mode_p (struct disassemble_info *info) { - elf_symbol_type *symbol; - int pos; int i; - - for (i = 0; i < info->num_symbols; i++) - { - pos = info->symtab_pos + i; - - if (bfd_asymbol_flavour (info->symtab[pos]) != bfd_target_elf_flavour) - continue; - - if (info->symtab[pos]->section != info->section) - continue; - - symbol = (elf_symbol_type *) info->symtab[pos]; - if ((!micromips_ase - && ELF_ST_IS_MIPS16 (symbol->internal_elf_sym.st_other)) - || (micromips_ase - && ELF_ST_IS_MICROMIPS (symbol->internal_elf_sym.st_other))) - return 1; - } + int l; + + for (i = info->symtab_pos, l = i + info->num_symbols; i < l; i++) + if (((info->symtab[i])->flags & BSF_SYNTHETIC) != 0 + && ((!micromips_ase + && ELF_ST_IS_MIPS16 ((*info->symbols)->udata.i)) + || (micromips_ase + && ELF_ST_IS_MICROMIPS ((*info->symbols)->udata.i)))) + return 1; + else if (bfd_asymbol_flavour (info->symtab[i]) == bfd_target_elf_flavour + && info->symtab[i]->section == info->section) + { + elf_symbol_type *symbol = (elf_symbol_type *) info->symtab[i]; + if ((!micromips_ase + && ELF_ST_IS_MIPS16 (symbol->internal_elf_sym.st_other)) + || (micromips_ase + && ELF_ST_IS_MICROMIPS (symbol->internal_elf_sym.st_other))) + return 1; + } return 0; }