Index: elfxx-mips.c =================================================================== RCS file: /cvs/src/src/bfd/elfxx-mips.c,v retrieving revision 1.297 diff -u -p -r1.297 elfxx-mips.c --- elfxx-mips.c 8 Dec 2011 20:47:24 -0000 1.297 +++ elfxx-mips.c 10 Dec 2011 09:23:38 -0000 @@ -1573,7 +1573,9 @@ _bfd_mips_elf_init_stubs (struct bfd_lin /* Return true if H is a locally-defined PIC function, in the sense that it might need $25 to be valid on entry. Note that MIPS16 functions never need $25 to be valid on entry; they set up $gp - using PC-relative instructions instead. */ + using PC-relative instructions instead. We do process the case + where a MIPS16 function has a 32-bit stub, where the $25 load + is added for the 32-bit stub itself, not the 16-bit function. */ static bfd_boolean mips_elf_local_pic_function_p (struct mips_elf_link_hash_entry *h) @@ -1582,7 +1584,8 @@ mips_elf_local_pic_function_p (struct mi || h->root.root.type == bfd_link_hash_defweak) && h->root.def_regular && !bfd_is_abs_section (h->root.root.u.def.section) - && !ELF_ST_IS_MIPS16 (h->root.other) + && (!ELF_ST_IS_MIPS16 (h->root.other) + || (h->fn_stub && h->need_fn_stub)) && (PIC_OBJECT_P (h->root.root.u.def.section->owner) || ELF_ST_IS_MIPS_PIC (h->root.other))); } @@ -1610,8 +1613,10 @@ mips_elf_add_la25_intro (struct mips_elf return FALSE; sprintf (name, ".text.stub.%d", (int) htab_elements (htab->la25_stubs)); - /* Create the section. */ - input_section = stub->h->root.root.u.def.section; + /* Create the section. If H is a MIPS16 function with a stub, use the + stub function section. */ + input_section = (stub->h->fn_stub + ? stub->h->fn_stub : stub->h->root.root.u.def.section); s = htab->add_stub_section (name, input_section, input_section->output_section); if (s == NULL) @@ -1686,10 +1691,12 @@ mips_elf_add_la25_stub (struct bfd_link_ void **slot; /* Prefer to use LUI/ADDIU stubs if the function is at the beginning - of the section and if we would need no more than 2 nops. */ + of the section and if we would need no more than 2 nops. Also + when processing a 32-bit stub for a MIPS16 function, we can always + preprend before the stub section. */ s = h->root.root.u.def.section; value = h->root.root.u.def.value; - use_trampoline_p = (value != 0 || s->alignment_power > 4); + use_trampoline_p = (value != 0 || s->alignment_power > 4) && !h->fn_stub; /* Describe the stub we want. */ search.stub_section = NULL; @@ -5196,7 +5203,15 @@ mips_elf_calculate_relocation (bfd *abfd sec = h->fn_stub; } - symbol = sec->output_section->vma + sec->output_offset; + /* If a LA25 header for the stub itself exists, point to the prepended + LUI/ADDIU sequence. */ + if (h != NULL && h->la25_stub) + symbol = (h->la25_stub->stub_section->output_section->vma + + h->la25_stub->stub_section->output_offset + + h->la25_stub->offset); + else + symbol = sec->output_section->vma + sec->output_offset; + /* The target is 16-bit, but the stub isn't. */ target_is_16_bit_code_p = FALSE; } @@ -5246,7 +5261,8 @@ mips_elf_calculate_relocation (bfd *abfd /* If this is a direct call to a PIC function, redirect to the non-PIC stub. */ else if (h != NULL && h->la25_stub - && mips_elf_relocation_needs_la25_stub (input_bfd, r_type)) + && mips_elf_relocation_needs_la25_stub (input_bfd, r_type) + && !(r_type == R_MIPS16_26 && target_is_16_bit_code_p)) symbol = (h->la25_stub->stub_section->output_section->vma + h->la25_stub->stub_section->output_offset + h->la25_stub->offset); @@ -9615,10 +9631,16 @@ mips_elf_create_la25_stub (void **slot, /* Work out where in the section this stub should go. */ offset = stub->offset; - /* Work out the target address. */ - target = (stub->h->root.root.u.def.section->output_section->vma - + stub->h->root.root.u.def.section->output_offset - + stub->h->root.root.u.def.value); + /* Work out the target address. If a MIPS16 32-bit stub exists, + use it as the target instead. */ + if (stub->h->fn_stub) + target = (stub->h->fn_stub->output_section->vma + + stub->h->fn_stub->output_offset); + else + target = (stub->h->root.root.u.def.section->output_section->vma + + stub->h->root.root.u.def.section->output_offset + + stub->h->root.root.u.def.value); + target_high = ((target + 0x8000) >> 16) & 0xffff; target_low = (target & 0xffff);