+
+ if (calculate_only)
+ {
+ *calculated_value = x >> 2;
+ return This::STATUS_OKAY;
+ }
+ else
+ elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
+ if (psymval->value(object, addend) & 3)
+ return This::STATUS_PCREL_UNALIGNED;
+
+ return check_overflow<18>(x);
+ }
+
+ // R_MIPS_PC21_S2
+ static inline typename This::Status
+ relpc21(unsigned char* view, const Mips_relobj<size, big_endian>* object,
+ const Symbol_value<size>* psymval, Mips_address address,
+ Mips_address addend_a, bool extract_addend, bool calculate_only,
+ Valtype* calculated_value)
+ {
+ Valtype32* wv = reinterpret_cast<Valtype32*>(view);
+ Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv);
+
+ Valtype addend = (extract_addend
+ ? Bits<23>::sign_extend32((val & 0x1fffff) << 2)
+ : addend_a);
+
+ Valtype x = psymval->value(object, addend) - address;
+ val = Bits<21>::bit_select32(val, x >> 2, 0x1fffff);
+
+ if (calculate_only)
+ {
+ *calculated_value = x >> 2;
+ return This::STATUS_OKAY;
+ }
+ else
+ elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
+ if (psymval->value(object, addend) & 3)
+ return This::STATUS_PCREL_UNALIGNED;
+
+ return check_overflow<23>(x);
+ }
+
+ // R_MIPS_PC26_S2
+ static inline typename This::Status
+ relpc26(unsigned char* view, const Mips_relobj<size, big_endian>* object,
+ const Symbol_value<size>* psymval, Mips_address address,
+ Mips_address addend_a, bool extract_addend, bool calculate_only,
+ Valtype* calculated_value)
+ {
+ Valtype32* wv = reinterpret_cast<Valtype32*>(view);
+ Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv);
+
+ Valtype addend = (extract_addend
+ ? Bits<28>::sign_extend32((val & 0x3ffffff) << 2)
+ : addend_a);
+
+ Valtype x = psymval->value(object, addend) - address;
+ val = Bits<26>::bit_select32(val, x >> 2, 0x3ffffff);
+
+ if (calculate_only)
+ {
+ *calculated_value = x >> 2;
+ return This::STATUS_OKAY;
+ }
+ else
+ elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
+ if (psymval->value(object, addend) & 3)
+ return This::STATUS_PCREL_UNALIGNED;
+
+ return check_overflow<28>(x);
+ }
+
+ // R_MIPS_PC18_S3
+ static inline typename This::Status
+ relpc18(unsigned char* view, const Mips_relobj<size, big_endian>* object,
+ const Symbol_value<size>* psymval, Mips_address address,
+ Mips_address addend_a, bool extract_addend, bool calculate_only,
+ Valtype* calculated_value)
+ {
+ Valtype32* wv = reinterpret_cast<Valtype32*>(view);
+ Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv);
+
+ Valtype addend = (extract_addend
+ ? Bits<21>::sign_extend32((val & 0x3ffff) << 3)
+ : addend_a);
+
+ Valtype x = psymval->value(object, addend) - ((address | 7) ^ 7);
+ val = Bits<18>::bit_select32(val, x >> 3, 0x3ffff);
+
+ if (calculate_only)
+ {
+ *calculated_value = x >> 3;
+ return This::STATUS_OKAY;
+ }
+ else
+ elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
+ if (psymval->value(object, addend) & 7)
+ return This::STATUS_PCREL_UNALIGNED;
+
+ return check_overflow<21>(x);
+ }
+
+ // R_MIPS_PC19_S2
+ static inline typename This::Status
+ relpc19(unsigned char* view, const Mips_relobj<size, big_endian>* object,
+ const Symbol_value<size>* psymval, Mips_address address,
+ Mips_address addend_a, bool extract_addend, bool calculate_only,
+ Valtype* calculated_value)
+ {
+ Valtype32* wv = reinterpret_cast<Valtype32*>(view);
+ Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv);
+
+ Valtype addend = (extract_addend
+ ? Bits<21>::sign_extend32((val & 0x7ffff) << 2)
+ : addend_a);
+
+ Valtype x = psymval->value(object, addend) - address;
+ val = Bits<19>::bit_select32(val, x >> 2, 0x7ffff);
+
+ if (calculate_only)
+ {
+ *calculated_value = x >> 2;
+ return This::STATUS_OKAY;
+ }
+ else
+ elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
+ if (psymval->value(object, addend) & 3)
+ return This::STATUS_PCREL_UNALIGNED;
+
+ return check_overflow<21>(x);
+ }
+
+ // R_MIPS_PCHI16
+ static inline typename This::Status
+ relpchi16(unsigned char* view, const Mips_relobj<size, big_endian>* object,
+ const Symbol_value<size>* psymval, Mips_address addend,
+ Mips_address address, unsigned int r_sym, bool extract_addend)
+ {
+ // Record the relocation. It will be resolved when we find pclo16 part.
+ pchi16_relocs.push_back(reloc_high<size, big_endian>(view, object, psymval,
+ addend, 0, r_sym, extract_addend, address));
+ return This::STATUS_OKAY;
+ }
+
+ // R_MIPS_PCHI16
+ static inline typename This::Status
+ do_relpchi16(unsigned char* view, const Mips_relobj<size, big_endian>* object,
+ const Symbol_value<size>* psymval, Mips_address addend_hi,
+ Mips_address address, bool extract_addend, Valtype32 addend_lo,
+ bool calculate_only, Valtype* calculated_value)
+ {
+ Valtype32* wv = reinterpret_cast<Valtype32*>(view);
+ Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv);
+
+ Valtype addend = (extract_addend ? ((val & 0xffff) << 16) + addend_lo
+ : addend_hi);
+
+ Valtype value = psymval->value(object, addend) - address;
+ Valtype x = ((value + 0x8000) >> 16) & 0xffff;
+ val = Bits<32>::bit_select32(val, x, 0xffff);
+
+ if (calculate_only)
+ *calculated_value = x;
+ else
+ elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
+ return This::STATUS_OKAY;
+ }
+
+ // R_MIPS_PCLO16
+ static inline typename This::Status
+ relpclo16(unsigned char* view, const Mips_relobj<size, big_endian>* object,
+ const Symbol_value<size>* psymval, Mips_address addend_a,
+ bool extract_addend, Mips_address address, unsigned int r_sym,
+ unsigned int rel_type, bool calculate_only,
+ Valtype* calculated_value)
+ {
+ Valtype32* wv = reinterpret_cast<Valtype32*>(view);
+ Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv);
+
+ Valtype addend = (extract_addend ? Bits<16>::sign_extend32(val & 0xffff)
+ : addend_a);
+
+ if (rel_type == elfcpp::SHT_REL)
+ {
+ // Resolve pending R_MIPS_PCHI16 relocations.
+ typename std::list<reloc_high<size, big_endian> >::iterator it =
+ pchi16_relocs.begin();
+ while (it != pchi16_relocs.end())
+ {
+ reloc_high<size, big_endian> pchi16 = *it;
+ if (pchi16.r_sym == r_sym)
+ {
+ do_relpchi16(pchi16.view, pchi16.object, pchi16.psymval,
+ pchi16.addend, pchi16.address,
+ pchi16.extract_addend, addend, calculate_only,
+ calculated_value);
+ it = pchi16_relocs.erase(it);
+ }
+ else
+ ++it;
+ }
+ }
+
+ // Resolve R_MIPS_PCLO16 relocation.
+ Valtype x = psymval->value(object, addend) - address;
+ val = Bits<32>::bit_select32(val, x, 0xffff);
+
+ if (calculate_only)
+ *calculated_value = x;
+ else
+ elfcpp::Swap<32, big_endian>::writeval(wv, val);
+
+ return This::STATUS_OKAY;