X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felf32-mips.c;h=d91bab9726841e2e304b21e4d74a8381a2e40639;hb=eb6bd4d38ea6ee7306c538b657c008f77f38cd62;hp=05c83ac56ae48329b3d038fd12b3620ef30dd607;hpb=86033394008aa009b3382199efa24b0cfa749862;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c index 05c83ac56a..d91bab9726 100644 --- a/bfd/elf32-mips.c +++ b/bfd/elf32-mips.c @@ -159,8 +159,9 @@ static boolean mips_elf_record_global_got_symbol struct mips_got_info *)); static bfd_vma mips_elf_got_page PARAMS ((bfd *, struct bfd_link_info *, bfd_vma, bfd_vma *)); -static const Elf_Internal_Rela *mips_elf_next_lo16_relocation - PARAMS ((const Elf_Internal_Rela *, const Elf_Internal_Rela *)); +static const Elf_Internal_Rela *mips_elf_next_relocation + PARAMS ((unsigned int, const Elf_Internal_Rela *, + const Elf_Internal_Rela *)); static bfd_reloc_status_type mips_elf_calculate_relocation PARAMS ((bfd *, bfd *, asection *, struct bfd_link_info *, const Elf_Internal_Rela *, bfd_vma, reloc_howto_type *, @@ -614,7 +615,7 @@ static reloc_howto_type elf_mips_howto_table[] = true, /* partial_inplace */ 0xffff, /* src_mask */ 0xffff, /* dst_mask */ - false), /* pcrel_offset */ + true), /* pcrel_offset */ /* 16 bit call through global offset table. */ HOWTO (R_MIPS_CALL16, /* type */ @@ -944,6 +945,87 @@ static reloc_howto_type elf_mips16_gprel_howto = false); /* pcrel_offset */ +/* GNU extensions for embedded-pic. */ +/* High 16 bits of symbol value, pc-relative. */ +static reloc_howto_type elf_mips_gnu_rel_hi16 = + HOWTO (R_MIPS_GNU_REL_HI16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + _bfd_mips_elf_hi16_reloc, /* special_function */ + "R_MIPS_GNU_REL_HI16", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + true); /* pcrel_offset */ + +/* Low 16 bits of symbol value, pc-relative. */ +static reloc_howto_type elf_mips_gnu_rel_lo16 = + HOWTO (R_MIPS_GNU_REL_LO16, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + _bfd_mips_elf_lo16_reloc, /* special_function */ + "R_MIPS_GNU_REL_LO16", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + true); /* pcrel_offset */ + +/* 16 bit offset for pc-relative branches. */ +static reloc_howto_type elf_mips_gnu_rel16_s2 = + HOWTO (R_MIPS_GNU_REL16_S2, /* type */ + 2, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MIPS_GNU_REL16_S2", /* name */ + true, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + true); /* pcrel_offset */ + +/* 64 bit pc-relative. */ +static reloc_howto_type elf_mips_gnu_pcrel64 = + HOWTO (R_MIPS_PC64, /* type */ + 0, /* rightshift */ + 4, /* size (0 = byte, 1 = short, 2 = long) */ + 64, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MIPS_PC64", /* name */ + true, /* partial_inplace */ + MINUS_ONE, /* src_mask */ + MINUS_ONE, /* dst_mask */ + true); /* pcrel_offset */ + +/* 32 bit pc-relative. */ +static reloc_howto_type elf_mips_gnu_pcrel32 = + HOWTO (R_MIPS_PC32, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 32, /* bitsize */ + true, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_signed, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MIPS_PC32", /* name */ + true, /* partial_inplace */ + 0xffffffff, /* src_mask */ + 0xffffffff, /* dst_mask */ + true); /* pcrel_offset */ + /* GNU extension to record C++ vtable hierarchy */ static reloc_howto_type elf_mips_gnu_vtinherit_howto = HOWTO (R_MIPS_GNU_VTINHERIT, /* type */ @@ -1882,6 +1964,16 @@ bfd_elf32_bfd_reloc_type_lookup (abfd, code) return &elf_mips_gnu_vtinherit_howto; case BFD_RELOC_VTABLE_ENTRY: return &elf_mips_gnu_vtentry_howto; + case BFD_RELOC_PCREL_HI16_S: + return &elf_mips_gnu_rel_hi16; + case BFD_RELOC_PCREL_LO16: + return &elf_mips_gnu_rel_lo16; + case BFD_RELOC_16_PCREL_S2: + return &elf_mips_gnu_rel16_s2; + case BFD_RELOC_64_PCREL: + return &elf_mips_gnu_pcrel64; + case BFD_RELOC_32_PCREL: + return &elf_mips_gnu_pcrel32; } } @@ -1905,6 +1997,21 @@ mips_rtype_to_howto (r_type) case R_MIPS_GNU_VTENTRY: return &elf_mips_gnu_vtentry_howto; break; + case R_MIPS_GNU_REL_HI16: + return &elf_mips_gnu_rel_hi16; + break; + case R_MIPS_GNU_REL_LO16: + return &elf_mips_gnu_rel_lo16; + break; + case R_MIPS_GNU_REL16_S2: + return &elf_mips_gnu_rel16_s2; + break; + case R_MIPS_PC64: + return &elf_mips_gnu_pcrel64; + break; + case R_MIPS_PC32: + return &elf_mips_gnu_pcrel32; + break; default: BFD_ASSERT (r_type < (unsigned int) R_MIPS_max); @@ -5444,11 +5551,12 @@ mips_elf_got16_entry (abfd, info, value) return index; } -/* Returns the first R_MIPS_LO16 relocation found, beginning with +/* Returns the first relocation of type r_type found, beginning with RELOCATION. RELEND is one-past-the-end of the relocation table. */ static const Elf_Internal_Rela * -mips_elf_next_lo16_relocation (relocation, relend) +mips_elf_next_relocation (r_type, relocation, relend) + unsigned int r_type; const Elf_Internal_Rela *relocation; const Elf_Internal_Rela *relend; { @@ -5460,7 +5568,7 @@ mips_elf_next_lo16_relocation (relocation, relend) extension in general, as that is useful for GCC. */ while (relocation < relend) { - if (ELF32_R_TYPE (relocation->r_info) == R_MIPS_LO16) + if (ELF32_R_TYPE (relocation->r_info) == r_type) return relocation; ++relocation; @@ -6006,6 +6114,24 @@ mips_elf_calculate_relocation (abfd, value &= howto->dst_mask; break; + case R_MIPS_PC32: + case R_MIPS_PC64: + case R_MIPS_GNU_REL_LO16: + value = symbol + addend - p; + value &= howto->dst_mask; + break; + + case R_MIPS_GNU_REL16_S2: + value = symbol + mips_elf_sign_extend (addend << 2, 18) - p; + overflowed_p = mips_elf_overflow_p (value, 18); + value = (value >> 2) & howto->dst_mask; + break; + + case R_MIPS_GNU_REL_HI16: + value = mips_elf_high (addend + symbol - p); + value &= howto->dst_mask; + break; + case R_MIPS16_26: /* The calculation for R_MIPS_26 is just the same as for an R_MIPS_26. It's only the storage of the relocated field into @@ -6484,6 +6610,7 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, combination of the addend stored in two different relocations. */ if (r_type == R_MIPS_HI16 + || r_type == R_MIPS_GNU_REL_HI16 || (r_type == R_MIPS_GOT16 && mips_elf_local_relocation_p (input_bfd, rel, local_sections))) @@ -6491,6 +6618,7 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, bfd_vma l; const Elf_Internal_Rela *lo16_relocation; reloc_howto_type *lo16_howto; + int lo; /* The combined value is the sum of the HI16 addend, left-shifted by sixteen bits, and the LO16 @@ -6498,15 +6626,18 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, a `lui' of the HI16 value, and then an `addiu' of the LO16 value.) - Scan ahead to find a matching R_MIPS_LO16 - relocation. */ + Scan ahead to find a matching LO16 relocation. */ + if (r_type == R_MIPS_GNU_REL_HI16) + lo = R_MIPS_GNU_REL_LO16; + else + lo = R_MIPS_LO16; lo16_relocation - = mips_elf_next_lo16_relocation (rel, relend); + = mips_elf_next_relocation (lo, rel, relend); if (lo16_relocation == NULL) return false; /* Obtain the addend kept there. */ - lo16_howto = mips_rtype_to_howto (R_MIPS_LO16); + lo16_howto = mips_rtype_to_howto (lo); l = mips_elf_obtain_contents (lo16_howto, lo16_relocation, input_bfd, contents); @@ -6537,6 +6668,10 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, Elf_Internal_Sym *sym; unsigned long r_symndx; + if (r_type == R_MIPS_64 && !ABI_64_P (output_bfd) + && bfd_big_endian (input_bfd)) + rel->r_offset -= 4; + /* Since we're just relocating, all we need to do is copy the relocations back out to the object file, unless they're against a section symbol, in which case we need @@ -6554,7 +6689,8 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, || r_type == R_MIPS_LITERAL) addend -= (_bfd_get_gp_value (output_bfd) - _bfd_get_gp_value (input_bfd)); - else if (r_type == R_MIPS_26 || r_type == R_MIPS16_26) + else if (r_type == R_MIPS_26 || r_type == R_MIPS16_26 + || r_type == R_MIPS_GNU_REL16_S2) /* The addend is stored without its two least significant bits (which are always zero.) In a non-relocateable link, calculate_relocation will do @@ -6570,17 +6706,19 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, /* If the relocation is for a R_MIPS_HI16 or R_MIPS_GOT16, then we only want to write out the high-order 16 bits. The subsequent R_MIPS_LO16 will handle the low-order bits. */ - if (r_type == R_MIPS_HI16 || r_type == R_MIPS_GOT16) + if (r_type == R_MIPS_HI16 || r_type == R_MIPS_GOT16 + || r_type == R_MIPS_GNU_REL_HI16) addend = mips_elf_high (addend); /* If the relocation is for an R_MIPS_26 relocation, then the two low-order bits are not stored in the object file; they are implicitly zero. */ - else if (r_type == R_MIPS_26 || r_type == R_MIPS16_26) + else if (r_type == R_MIPS_26 || r_type == R_MIPS16_26 + || r_type == R_MIPS_GNU_REL16_S2) addend >>= 2; if (rela_relocation_p) /* If this is a RELA relocation, just update the addend. - We have to cast away constness for REL. */ + We have to cast away constness for REL. */ rel->r_addend = addend; else { @@ -6590,6 +6728,43 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, writing will be source of the addend in the final link. */ addend &= howto->src_mask; + + if (r_type == R_MIPS_64 && !ABI_64_P (output_bfd)) + /* See the comment above about using R_MIPS_64 in the 32-bit + ABI. Here, we need to update the addend. It would be + possible to get away with just using the R_MIPS_32 reloc + but for endianness. */ + { + bfd_vma sign_bits; + bfd_vma low_bits; + bfd_vma high_bits; + + if (addend & 0x80000000u) + sign_bits = 0xffffffffu; + else + sign_bits = 0; + + /* If we don't know that we have a 64-bit type, + do two separate stores. */ + if (bfd_big_endian (input_bfd)) + { + /* Store the sign-bits (which are most significant) + first. */ + low_bits = sign_bits; + high_bits = addend; + } + else + { + low_bits = addend; + high_bits = sign_bits; + } + bfd_put_32 (input_bfd, low_bits, + contents + rel->r_offset); + bfd_put_32 (input_bfd, high_bits, + contents + rel->r_offset + 4); + continue; + } + if (!mips_elf_perform_relocation (info, howto, rel, addend, input_bfd, input_section, contents, false)) @@ -6631,7 +6806,7 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, case bfd_reloc_undefined: /* mips_elf_calculate_relocation already called the - undefined_symbol callback. There's no real point in + undefined_symbol callback. There's no real point in trying to perform the relocation at this point, so we just skip ahead to the next relocation. */ continue; @@ -6684,13 +6859,13 @@ _bfd_mips_elf_relocate_section (output_bfd, info, input_bfd, input_section, bfd_vma low_bits; bfd_vma high_bits; - if (value & 0x80000000) - sign_bits = 0xffffffff; + if (value & 0x80000000u) + sign_bits = 0xffffffffu; else sign_bits = 0; - /* If only a 32-bit VMA is available do two separate - stores. */ + /* If we don't know that we have a 64-bit type, + do two separate stores. */ if (bfd_big_endian (input_bfd)) { /* Undo what we did above. */