diff options
Diffstat (limited to 'bfd/elfxx-mips.c')
-rw-r--r-- | bfd/elfxx-mips.c | 57 |
1 files changed, 55 insertions, 2 deletions
diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c index 3510938..6dd0592 100644 --- a/bfd/elfxx-mips.c +++ b/bfd/elfxx-mips.c @@ -9324,6 +9324,55 @@ mips_elf_adjust_addend (bfd *output_bfd, struct bfd_link_info *info, } } +/* Handle relocations against symbols from removed linkonce sections, + or sections discarded by a linker script. We use this wrapper around + RELOC_AGAINST_DISCARDED_SECTION to handle triplets of compound relocs + on 64-bit ELF targets. In this case for any relocation handled, which + always be the first in a triplet, the remaining two have to be processed + together with the first, even if they are R_MIPS_NONE. It is the symbol + index referred by the first reloc that applies to all the three and the + remaining two never refer to an object symbol. And it is the final + relocation (the last non-null one) that determines the output field of + the whole relocation so retrieve the corresponding howto structure for + the relocatable field to be cleared by RELOC_AGAINST_DISCARDED_SECTION. + + Note that RELOC_AGAINST_DISCARDED_SECTION is a macro that uses "continue" + and therefore requires to be pasted in a loop. It also defines a block + and does not protect any of its arguments, hence the extra brackets. */ + +static void +mips_reloc_against_discarded_section (bfd *output_bfd, + struct bfd_link_info *info, + bfd *input_bfd, asection *input_section, + Elf_Internal_Rela **rel, + const Elf_Internal_Rela **relend, + bfd_boolean rel_reloc, + reloc_howto_type *howto, + bfd_byte *contents) +{ + const struct elf_backend_data *bed = get_elf_backend_data (output_bfd); + int count = bed->s->int_rels_per_ext_rel; + unsigned int r_type; + int i; + + for (i = count - 1; i > 0; i--) + { + r_type = ELF_R_TYPE (output_bfd, (*rel)[i].r_info); + if (r_type != R_MIPS_NONE) + { + howto = MIPS_ELF_RTYPE_TO_HOWTO (input_bfd, r_type, !rel_reloc); + break; + } + } + do + { + RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, + (*rel), count, (*relend), + howto, i, contents); + } + while (0); +} + /* Relocate a MIPS ELF section. */ bfd_boolean @@ -9390,8 +9439,12 @@ _bfd_mips_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info, } if (sec != NULL && discarded_section (sec)) - RELOC_AGAINST_DISCARDED_SECTION (info, input_bfd, input_section, - rel, relend, howto, contents); + { + mips_reloc_against_discarded_section (output_bfd, info, input_bfd, + input_section, &rel, &relend, + rel_reloc, howto, contents); + continue; + } if (r_type == R_MIPS_64 && ! NEWABI_P (input_bfd)) { |