Re: [PATCH 1/2] MIPS: Compressed PLT/stubs support

Maciej W. Rozycki
2013-06-07T21:09:51Z

On Sat, 9 Mar 2013, Richard Sandiford wrote:

> > Index: binutils-fsf-trunk-quilt/bfd/elfxx-mips.c
> > ===================================================================
> > --- binutils-fsf-trunk-quilt.orig/bfd/elfxx-mips.c 2013-03-08 11:09:04.000000000 +0000
> > +++ binutils-fsf-trunk-quilt/bfd/elfxx-mips.c 2013-03-09 02:43:31.765430204 +0000
> > @@ -319,6 +319,32 @@ struct mips_elf_hash_sort_data
> > long max_non_got_dynindx;
> > };
> >
> > +/* We make up to two PLT entries if needed, one for standard MIPS code
> > + and one for compressed code, either of MIPS16 or microMIPS one. We
> > + keep the record of a stub if one is used instead separately, for
> > + easier processing. */
>
> s/either of MIPS16 or microMIPS one/either a MIPS16 or microMIPS one/.
> Suggest "We keep a separate record of traditional lazy-binding stubs,
> for easier processing."

Done. I wasn't sure if that would sound better as "either MIPS16 or
microMIPS one," -- referring to "code" (uncountable) rather than "a PLT
entry" -- but eventually I decided it sounded better with the article. ;)

> > @@ -5124,13 +5232,55 @@ mips_elf_calculate_relocation (bfd *abfd
> > || h->root.root.type == bfd_link_hash_defweak)
> > && h->root.root.u.def.section)
> > {
> > - sec = h->root.root.u.def.section;
> > - if (sec->output_section)
> > - symbol = (h->root.root.u.def.value
> > - + sec->output_section->vma
> > - + sec->output_offset);
> > + if (h->use_plt_entry)
> > + {
> > + bfd_boolean micromips_p = MICROMIPS_P (abfd);
> > + bfd_vma plt_offset;
> > + bfd_vma isa_bit;
> > + bfd_vma val;
> > +
> > + BFD_ASSERT (h->root.plt.plist != NULL);
> > + BFD_ASSERT (h->root.plt.plist->mips_offset != MINUS_ONE
> > + || h->root.plt.plist->comp_offset != MINUS_ONE);
> > +
> > + plt_offset = htab->plt_header_size;
> > + if (h->root.plt.plist->comp_offset == MINUS_ONE
> > + || (h->root.plt.plist->mips_offset != MINUS_ONE
> > + && r_type != R_MIPS16_26 && r_type != R_MICROMIPS_26_S1))
> > + {
> > + isa_bit = 0;
> > + target_is_16_bit_code_p = FALSE;
> > + target_is_micromips_code_p = FALSE;
> > + plt_offset += h->root.plt.plist->mips_offset;
> > + }
> > + else
> > + {
> > + isa_bit = 1;
> > + target_is_16_bit_code_p = !micromips_p;
> > + target_is_micromips_code_p = micromips_p;
> > + plt_offset += (htab->plt_mips_offset
> > + + h->root.plt.plist->comp_offset);
> > + }
> > + BFD_ASSERT (plt_offset <= htab->splt->size);
> > +
> > + sec = htab->splt;
> > + val = plt_offset + isa_bit;
> > + /* For VxWorks, point at the PLT load stub rather than the
> > + lazy resolution stub. */
> > + if (htab->is_vxworks)
> > + val += 8;
> > + symbol = sec->output_section->vma + sec->output_offset + val;
> > + }
> > else
> > - symbol = h->root.root.u.def.value;
> > + {
> > + sec = h->root.root.u.def.section;
> > + if (sec->output_section)
> > + symbol = (h->root.root.u.def.value
> > + + sec->output_section->vma
> > + + sec->output_offset);
> > + else
> > + symbol = h->root.root.u.def.value;
> > + }
> > }
> > else if (h->root.root.type == bfd_link_hash_undefweak)
> > /* We allow relocations against undefined weak symbols, giving
> > @@ -5177,12 +5327,6 @@ mips_elf_calculate_relocation (bfd *abfd
> > {
> > return bfd_reloc_notsupported;
> > }
> > -
> > - target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (h->root.other);
> > - /* If the output section is the PLT section,
> > - then the target is not microMIPS. */
> > - target_is_micromips_code_p = (htab->splt != sec
> > - && ELF_ST_IS_MICROMIPS (h->root.other));
> > }
> >
> > /* If this is a reference to a 16-bit function with a stub, we need
>
> The block of code that you're changing here is simply calculating the
> symbol value. Now that size_dynamic_sections has set that up for us,
> these two hunks should be dropped, and the test for whether to use a
> compressed PLT entry instead of the symbol value should be made
> afterwards, as it is for things like hard-float and LA25 stubs.

D'oh, it must have escaped me as the obvious consequence of the
introduction of mips_elf_set_plt_sym_value. I haven't merely reverted the
latter hunk though -- given that we're going to handle the PLT explicitly
later on now, we want to preset target_is_micromips_code_p according to
the symbol table here, just as we already do for target_is_16_bit_code_p.

> Maybe something like:
>
> /* If compressed PLT entries are available, make sure that we use them
> for MIPS16 and microMIPS calls. */
> else if ((r_type == R_MIPS16_26 || r_type == R_MICROMIPS_26_S1)
> && h != NULL
> && h->use_plt
> && h->root.plt.plist->comp_offset != MINUS_ONE)
> {
> sec = htab->splt;
> symbol = (sec->output_section->vma
> + sec->output_offset
> + htab->plt_header_size
> + htab->plt_mips_offset
> + h->root.plt.plist->comp_offset
> + 1);
> target_is_16_bit_code_p = !MICROMIPS_P (abfd);
> target_is_micromips_code_p = MICROMIPS_P (abfd);
> }
>
> at the end of the:
>
> /* If this is a reference to a 16-bit function with a stub, we need
> to redirect the relocation to the stub unless:
>
> chain of ifs.

More or less, though I've decided to push it ahead of the chain so that
it sees the state consistent regardless of whether any PLT entry processed
has been duplicated for dual-mode support. This probably does not really
matter right now (fn_stub/need_fn_stub cases will override any symbol
value to use for the relocation and likewise the mode setting anyway,
call_stub/call_fp_stub cases will only ever have a standard MIPS PLT entry
due to the arrangement in _bfd_mips_elf_adjust_dynamic_symbol and
la25_stub cases will never have a PLT entry as these must resolve
locally), but I feel a bit uneasy about this half-cooked state. Let me
know if you disagree (and why).

Also I've decided not to recalculate the symbol's value if what
mips_elf_set_plt_sym_value worked out is the right thing for compressed
direct calls too (i.e. there is no standard MIPS PLT entry alternative).

> > - /* Make room for the .got.plt entry and the R_MIPS_JUMP_SLOT
> > - relocation. */
> > - htab->sgotplt->size += MIPS_ELF_GOT_SIZE (dynobj);
> > + htab->splt->size = htab->plt_mips_offset + htab->plt_comp_offset;
> > + htab->sgotplt->size = htab->plt_got_index * MIPS_ELF_GOT_SIZE (dynobj);
>
> These last two lines should be done in size_dynamic_sections rather
> than once for each symbol. I.e.:
>
> > @@ -8985,18 +9318,60 @@ _bfd_mips_elf_size_dynamic_sections (bfd
> > = (bfd_byte *) ELF_DYNAMIC_INTERPRETER (output_bfd);
> > }
> >
> > - /* Create a symbol for the PLT, if we know that we are using it. */
> > - if (htab->splt && htab->splt->size > 0 && htab->root.hplt == NULL)
> > + /* Figure out the size of the PLT header if we know that we
> > + are using it. For the sake of cache alignment always use
> > + a standard header whenever any standard entries are present
> > + even if microMIPS entries are present as well. This also
> > + lets the microMIPS header rely on the value of $v0 only set
> > + by microMIPS entries, for a small size reduction.
> > +
> > + Set symbol table entry values for symbols that use the
> > + address of their PLT entry now that we can calculate it.
> > +
> > + Also create the _PROCEDURE_LINKAGE_TABLE_ symbol if we
> > + haven't already in _bfd_elf_create_dynamic_sections. */
> > + if (htab->splt && htab->splt->size > 0)
> > {
> > + bfd_boolean micromips_p = (MICROMIPS_P (output_bfd)
> > + && !htab->plt_mips_offset);
> > + unsigned int other = micromips_p ? STO_MICROMIPS : 0;
> > + bfd_vma isa_bit = micromips_p;
> > struct elf_link_hash_entry *h;
> > + bfd_vma size;
> >
> > BFD_ASSERT (htab->use_plts_and_copy_relocs);
> >
> > - h = _bfd_elf_define_linkage_sym (dynobj, info, htab->splt,
> > - "_PROCEDURE_LINKAGE_TABLE_");
> > - htab->root.hplt = h;
> > - if (h == NULL)
> > - return FALSE;
> > + if (htab->is_vxworks && info->shared)
> > + size = 4 * ARRAY_SIZE (mips_vxworks_shared_plt0_entry);
> > + else if (htab->is_vxworks)
> > + size = 4 * ARRAY_SIZE (mips_vxworks_exec_plt0_entry);
> > + else if (ABI_64_P (output_bfd))
> > + size = 4 * ARRAY_SIZE (mips_n64_exec_plt0_entry);
> > + else if (ABI_N32_P (output_bfd))
> > + size = 4 * ARRAY_SIZE (mips_n32_exec_plt0_entry);
> > + else if (!micromips_p)
> > + size = 4 * ARRAY_SIZE (mips_o32_exec_plt0_entry);
> > + else
> > + size = 2 * ARRAY_SIZE (micromips_o32_exec_plt0_entry);
> > +
> > + htab->plt_header_is_comp = micromips_p;
> > + htab->plt_header_size = size;
> > + htab->splt->size += size;
>
> htab->splt->size = (size
> + htab->plt_mips_offset
> + htab->plt_comp_offset;
> htab->sgotplt->size = (htab->plt_got_index
> * MIPS_ELF_GOT_SIZE (dynobj));

Sure, I had to adjust the condition around this block:

if (htab->splt && htab->splt->size > 0)

and one in _bfd_mips_elf_adjust_dynamic_symbol accordingly though.

> > + /* ADDIUPC has a span of +/-16MB, check we're in range. */
> > + if (gotpc_offset + 0x1000000 >= 0x2000000)
> > + {
> > + (*_bfd_error_handler)
> > + (_("%B: `%A' offset of %ld from `%A' "
> > + "beyond the range of ADDIUPC"),
> > + output_bfd,
> > + htab->sgotplt->output_section,
> > + htab->splt->output_section,
> > + (long) gotpc_offset);
>
> The last two arguments should be swapped.

Nope, %A and %B are handled specially (ahead of any other format
specifiers). See the comment at _bfd_default_error_handler in bfd/bfd.c.
I actually verified this range checking triggers correctly (hmm, it might
be worth making a dedicated test case for) and it would be outright silly
to make such a mistake, wouldn't it (hint, hint!)?

> > + /* ADDIUPC has a span of +/-16MB, check we're in range. */
> > + if (gotpc_offset + 0x1000000 >= 0x2000000)
> > + {
> > + (*_bfd_error_handler)
> > + (_("%B: `%A' offset of %ld from `%A' beyond the range of ADDIUPC"),
> > + output_bfd,
> > + htab->sgotplt->output_section,
> > + htab->splt->output_section,
> > + (long) gotpc_offset);
>
> Same here.

Ditto. ;)

> > + /* 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)));
> > + addlen = 2 * (sizeof ("+0x") - 1 + 8);
> > +#ifdef BFD64
> > + addlen += 2 * 8 * (bed->s->elfclass == ELFCLASS64);
> > +#endif
>
> Now that there are no addends (thanks), the last four lines should be dropped.

Missed that, thanks for catching; I guess a newer GCC version would
complain about this set-but-unused addlen variable. Dropped that now as
well as the variable itself.

> OK with those changes if they work, otherwise let me know.

Given that (as noted above) the change is more than just what you
suggested, here's a new version for you to review, in the form of an
incremental change on top of the previous one (let me know if you'd like
to see a combined version as well; I've included the intended set of
ChangeLog entries only). Please double-check you're all right with it.
No regressions across the usual set of MIPS targets (let me know if you
want me to remind you of the actual list). Thanks.

2013-06-07 Maciej W. Rozycki <macro@codesourcery.com>

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 (plt_entry): New structure.
(mips_elf_link_hash_entry): Add use_plt_entry member.
(mips_elf_link_hash_table): Rename plt_entry_size member to
plt_mips_entry_size. Add plt_comp_entry_size, plt_mips_offset,
plt_comp_offset, plt_got_index entries and plt_header_is_comp
members.
(STUB_LW_MICROMIPS, STUB_MOVE_MICROMIPS): New macros.
(STUB_LUI_MICROMIPS, STUB_JALR_MICROMIPS): Likewise.
(STUB_ORI_MICROMIPS, STUB_LI16U_MICROMIPS): Likewise.
(STUB_LI16S_MICROMIPS): Likewise.
(MICROMIPS_FUNCTION_STUB_NORMAL_SIZE): Likewise.
(MICROMIPS_FUNCTION_STUB_BIG_SIZE): Likewise.
(micromips_o32_exec_plt0_entry): New variable.
(mips16_o32_exec_plt_entry): Likewise.
(micromips_o32_exec_plt_entry): Likewise.
(mips_elf_link_hash_newfunc): Initialize use_plt_entry.
(mips_elf_output_extsym): Update to use gotplt_union's plist
member rather than offset.
(mips_elf_gotplt_index): Likewise. Remove the VxWorks
restriction. Use MIPS_ELF_GOT_SIZE to calculate GOT address.
(mips_elf_count_got_symbols): Update to use gotplt_union's plist
member rather than offset.
(mips_elf_calculate_relocation): Handle MIPS16/microMIPS PLT
entries.
(_bfd_mips_elf_create_dynamic_sections): Don't set PLT sizes
here.
(mips_elf_make_plt_record): New function.
(_bfd_mips_elf_check_relocs): Update comment. Record occurences
of JAL relocations that might need a PLT entry.
(_bfd_mips_elf_adjust_dynamic_symbol): Update to use
gotplt_union's plist member rather than offset. Set individual
PLT entry sizes here. Handle MIPS16/microMIPS PLT entries.
Don't set the symbol's value in the symbol table for PLT
references here. Don't set the PLT or PLT GOT section sizes
here.
(mips_elf_estimate_stub_size): Handle microMIPS stubs.
(mips_elf_allocate_lazy_stub): Likewise.
(mips_elf_lay_out_lazy_stubs): Likewise. Define a _MIPS_STUBS_
magic symbol.
(mips_elf_set_plt_sym_value): New function.
(_bfd_mips_elf_size_dynamic_sections): Set PLT header size and
PLT and PLT GOT section sizes here. Set the symbol values in
the symbol table for PLT references here. Handle microMIPS
annotation of the _PROCEDURE_LINKAGE_TABLE_ magic symbol.
(_bfd_mips_elf_finish_dynamic_symbol): Update to use
gotplt_union's plist member rather than offset. Handle
MIPS16/microMIPS PLT entries. Handle microMIPS stubs.
(_bfd_mips_vxworks_finish_dynamic_symbol): Update to use
gotplt_union's plist member rather than offset. Use
MIPS_ELF_GOT_SIZE to calculate GOT address.
(mips_finish_exec_plt): Handle microMIPS PLT. Return status.
(_bfd_mips_elf_finish_dynamic_sections): Handle result from
mips_finish_exec_plt.
(_bfd_mips_elf_link_hash_table_create): Update to use
gotplt_union's plist member rather than offset.
(_bfd_mips_elf_get_synthetic_symtab): New function.

include/elf/
* mips.h (ELF_ST_IS_MIPS_PLT): Respect STO_MIPS16 setting.
(ELF_ST_SET_MIPS_PLT): Likewise.

gdb/
* mips-tdep.c (mips_elf_make_msymbol_special): Handle MIPS16 and
microMIPS synthetic symbols.

ld/
* emulparams/elf32btsmip.sh: Arrange for .got.plt to be placed
as close to .plt as possible.
* scripttempl/elf.sc: Handle $INITIAL_READWRITE_SECTIONS and
$PLT_NEXT_DATA variables.

ld/testsuite/
* ld-mips-elf/jalx-2.dd: Update for microMIPS PLT support.
* ld-mips-elf/pic-and-nonpic-3a.dd: Update for the _MIPS_STUBS_
magic symbol.
* ld-mips-elf/pic-and-nonpic-3b.dd: Likewise.
* ld-mips-elf/pic-and-nonpic-6-n32.dd: Likewise.
* ld-mips-elf/pic-and-nonpic-6-n64.dd: Likewise.
* ld-mips-elf/pic-and-nonpic-6-o32.dd: Likewise.
* ld-mips-elf/stub-dynsym-1-10000.d: Likewise.
* ld-mips-elf/stub-dynsym-1-2fe80.d: Likewise.
* ld-mips-elf/stub-dynsym-1-7fff.d: Likewise.
* ld-mips-elf/stub-dynsym-1-8000.d: Likewise.
* ld-mips-elf/stub-dynsym-1-fff0.d: Likewise.
* ld-mips-elf/tlslib-o32.d: Likewise.

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.

Maciej

binutils-umips16-plt-stubs-update.diff
Index: binutils-fsf-trunk-quilt/bfd/elfxx-mips.c
===================================================================
--- binutils-fsf-trunk-quilt.orig/bfd/elfxx-mips.c 2013-06-07 19:07:47.000000000 +0100
+++ binutils-fsf-trunk-quilt/bfd/elfxx-mips.c 2013-06-07 21:02:39.942586414 +0100
@@ -318,9 +318,9 @@ struct mips_elf_hash_sort_data
};

/* We make up to two PLT entries if needed, one for standard MIPS code
- and one for compressed code, either of MIPS16 or microMIPS one. We
- keep the record of a stub if one is used instead separately, for
- easier processing. */
+ and one for compressed code, either a MIPS16 or microMIPS one. We
+ keep a separate record of traditional lazy-binding stubs, for easier
+ processing. */

struct plt_entry
{
@@ -5201,9 +5201,6 @@ mips_elf_calculate_relocation (bfd *abfd
/* Record the name of this symbol, for our caller. */
*namep = h->root.root.root.string;

- target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (h->root.other);
- target_is_micromips_code_p = ELF_ST_IS_MICROMIPS (h->root.other);
-
/* See if this is the special _gp_disp symbol. Note that such a
symbol must always be a global symbol. */
if (strcmp (*namep, "_gp_disp") == 0
@@ -5230,55 +5227,13 @@ mips_elf_calculate_relocation (bfd *abfd
|| h->root.root.type == bfd_link_hash_defweak)
&& h->root.root.u.def.section)
{
- if (h->use_plt_entry)
- {
- bfd_boolean micromips_p = MICROMIPS_P (abfd);
- bfd_vma plt_offset;
- bfd_vma isa_bit;
- bfd_vma val;
-
- BFD_ASSERT (h->root.plt.plist != NULL);
- BFD_ASSERT (h->root.plt.plist->mips_offset != MINUS_ONE
- || h->root.plt.plist->comp_offset != MINUS_ONE);
-
- plt_offset = htab->plt_header_size;
- if (h->root.plt.plist->comp_offset == MINUS_ONE
- || (h->root.plt.plist->mips_offset != MINUS_ONE
- && r_type != R_MIPS16_26 && r_type != R_MICROMIPS_26_S1))
- {
- isa_bit = 0;
- target_is_16_bit_code_p = FALSE;
- target_is_micromips_code_p = FALSE;
- plt_offset += h->root.plt.plist->mips_offset;
- }
- else
- {
- isa_bit = 1;
- target_is_16_bit_code_p = !micromips_p;
- target_is_micromips_code_p = micromips_p;
- plt_offset += (htab->plt_mips_offset
- + h->root.plt.plist->comp_offset);
- }
- BFD_ASSERT (plt_offset <= htab->splt->size);
-
- sec = htab->splt;
- val = plt_offset + isa_bit;
- /* For VxWorks, point at the PLT load stub rather than the
- lazy resolution stub. */
- if (htab->is_vxworks)
- val += 8;
- symbol = sec->output_section->vma + sec->output_offset + val;
- }
+ sec = h->root.root.u.def.section;
+ if (sec->output_section)
+ symbol = (h->root.root.u.def.value
+ + sec->output_section->vma
+ + sec->output_offset);
else
- {
- sec = h->root.root.u.def.section;
- if (sec->output_section)
- symbol = (h->root.root.u.def.value
- + sec->output_section->vma
- + sec->output_offset);
- else
- symbol = h->root.root.u.def.value;
- }
+ symbol = h->root.root.u.def.value;
}
else if (h->root.root.type == bfd_link_hash_undefweak)
/* We allow relocations against undefined weak symbols, giving
@@ -5325,6 +5280,35 @@ mips_elf_calculate_relocation (bfd *abfd
{
return bfd_reloc_notsupported;
}
+
+ target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (h->root.other);
+ target_is_micromips_code_p = ELF_ST_IS_MICROMIPS (h->root.other);
+ }
+
+ /* For direct MIPS16 and microMIPS calls make sure the compressed PLT
+ entry is used if a standard PLT entry has also been made. In this
+ case the symbol will have been set by mips_elf_set_plt_sym_value
+ to point to the standard PLT entry, so redirect to the compressed
+ one. Adjust the mode settings accordingly. */
+ if ((r_type == R_MIPS16_26 || r_type == R_MICROMIPS_26_S1)
+ && !info->relocatable
+ && h != NULL
+ && h->use_plt_entry
+ && h->root.plt.plist->comp_offset != MINUS_ONE
+ && h->root.plt.plist->mips_offset != MINUS_ONE)
+ {
+ bfd_boolean micromips_p = MICROMIPS_P (abfd);
+
+ sec = htab->splt;
+ symbol = (sec->output_section->vma
+ + sec->output_offset
+ + htab->plt_header_size
+ + htab->plt_mips_offset
+ + h->root.plt.plist->comp_offset
+ + 1);
+
+ target_is_16_bit_code_p = !micromips_p;
+ target_is_micromips_code_p = micromips_p;
}

/* If this is a reference to a 16-bit function with a stub, we need
@@ -8778,7 +8762,7 @@ _bfd_mips_elf_adjust_dynamic_symbol (str
/* If this is the first symbol to need a PLT entry, then make some
basic setup. Also work out PLT entry sizes. We'll need them
for PLT offset calculations. */
- if (htab->splt->size == 0)
+ if (htab->plt_mips_offset + htab->plt_comp_offset == 0)
{
BFD_ASSERT (htab->sgotplt->size == 0);
BFD_ASSERT (htab->plt_got_index == 0);
@@ -8890,9 +8874,6 @@ _bfd_mips_elf_adjust_dynamic_symbol (str
if (!info->shared && !h->def_regular)
hmips->use_plt_entry = TRUE;

- htab->splt->size = htab->plt_mips_offset + htab->plt_comp_offset;
- htab->sgotplt->size = htab->plt_got_index * MIPS_ELF_GOT_SIZE (dynobj);
-
/* Make room for the R_MIPS_JUMP_SLOT relocation. */
htab->srelplt->size += (htab->is_vxworks
? MIPS_ELF_RELA_SIZE (dynobj)
@@ -9338,7 +9319,7 @@ _bfd_mips_elf_size_dynamic_sections (bfd

Also create the _PROCEDURE_LINKAGE_TABLE_ symbol if we
haven't already in _bfd_elf_create_dynamic_sections. */
- if (htab->splt && htab->splt->size > 0)
+ if (htab->splt && htab->plt_mips_offset + htab->plt_comp_offset != 0)
{
bfd_boolean micromips_p = (MICROMIPS_P (output_bfd)
&& !htab->plt_mips_offset);
@@ -9348,6 +9329,8 @@ _bfd_mips_elf_size_dynamic_sections (bfd
bfd_vma size;

BFD_ASSERT (htab->use_plts_and_copy_relocs);
+ BFD_ASSERT (htab->sgotplt->size == 0);
+ BFD_ASSERT (htab->splt->size == 0);

if (htab->is_vxworks && info->shared)
size = 4 * ARRAY_SIZE (mips_vxworks_shared_plt0_entry);
@@ -9364,7 +9347,11 @@ _bfd_mips_elf_size_dynamic_sections (bfd

htab->plt_header_is_comp = micromips_p;
htab->plt_header_size = size;
- htab->splt->size += size;
+ htab->splt->size = (size
+ + htab->plt_mips_offset
+ + htab->plt_comp_offset);
+ htab->sgotplt->size = (htab->plt_got_index
+ * MIPS_ELF_GOT_SIZE (dynobj));

mips_elf_link_hash_traverse (htab, mips_elf_set_plt_sym_value, info);

@@ -14943,7 +14930,6 @@ _bfd_mips_elf_get_synthetic_symtab (bfd
bfd_vma opcode;
asection *plt;
asymbol *send;
- size_t addlen;
size_t size;
char *names;
long counti;
@@ -14985,10 +14971,6 @@ _bfd_mips_elf_get_synthetic_symtab (bfd
size = 2 * count * sizeof (asymbol);
size += count * (sizeof (mipssuffix) +
(micromips_p ? sizeof (microsuffix) : sizeof (m16suffix)));
- addlen = 2 * (sizeof ("+0x") - 1 + 8);
-#ifdef BFD64
- addlen += 2 * 8 * (bed->s->elfclass == ELFCLASS64);
-#endif
for (pi = 0; pi < counti; pi += bed->s->int_rels_per_ext_rel)
size += 2 * strlen ((*p[pi].sym_ptr_ptr)->name);

Index: binutils-fsf-trunk-quilt/include/elf/mips.h
===================================================================
--- binutils-fsf-trunk-quilt.orig/include/elf/mips.h 2013-06-07 19:06:39.000000000 +0100
+++ binutils-fsf-trunk-quilt/include/elf/mips.h 2013-06-07 19:07:49.052856391 +0100
@@ -803,8 +803,14 @@ extern void bfd_mips_elf32_swap_reginfo_
PLT entries and traditional MIPS lazy binding stubs. We mark the former
with STO_MIPS_PLT to distinguish them from the latter. */
#define STO_MIPS_PLT 0x8
-#define ELF_ST_IS_MIPS_PLT(other) (((other) & STO_MIPS_FLAGS) == STO_MIPS_PLT)
-#define ELF_ST_SET_MIPS_PLT(other) (((other) & ~STO_MIPS_FLAGS) | STO_MIPS_PLT)
+#define ELF_ST_IS_MIPS_PLT(other) \
+ ((ELF_ST_IS_MIPS16 (other) \
+ ? ((other) & (~STO_MIPS16 & STO_MIPS_FLAGS)) \
+ : ((other) & STO_MIPS_FLAGS)) == STO_MIPS_PLT)
+#define ELF_ST_SET_MIPS_PLT(other) \
+ ((ELF_ST_IS_MIPS16 (other) \
+ ? ((other) & (STO_MIPS16 | ~STO_MIPS_FLAGS)) \
+ : ((other) & ~STO_MIPS_FLAGS)) | STO_MIPS_PLT)

/* This value is used to mark PIC functions in an object that mixes
PIC and non-PIC. Note that this bit overlaps with STO_MIPS16,