X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Fmips.cc;h=ffaad453822a453e40bbf9e4ee4334a1a1f703b8;hb=945e0f82dad31db89a107b496532886fe215c011;hp=c57ef4f807f4a51ade8a46ed822ef1267acc80a1;hpb=4d625b70fc3fb7facc7159feb8d49b78ac6641f9;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/mips.cc b/gold/mips.cc index c57ef4f807..ffaad45382 100644 --- a/gold/mips.cc +++ b/gold/mips.cc @@ -132,6 +132,31 @@ enum Got_tls_type GOT_TLS_IE = 4 }; +// Values found in the r_ssym field of a relocation entry. +enum Special_relocation_symbol +{ + RSS_UNDEF = 0, // None - value is zero. + RSS_GP = 1, // Value of GP. + RSS_GP0 = 2, // Value of GP in object being relocated. + RSS_LOC = 3 // Address of location being relocated. +}; + +// Whether the section is readonly. +static inline bool +is_readonly_section(Output_section* output_section) +{ + elfcpp::Elf_Xword section_flags = output_section->flags(); + elfcpp::Elf_Word section_type = output_section->type(); + + if (section_type == elfcpp::SHT_NOBITS) + return false; + + if (section_flags & elfcpp::SHF_WRITE) + return false; + + return true; +} + // Return TRUE if a relocation of type R_TYPE from OBJECT might // require an la25 stub. See also local_pic_function, which determines // whether the destination function ever requires a stub. @@ -231,6 +256,12 @@ got_lo16_reloc(unsigned int r_type) || r_type == elfcpp::R_MICROMIPS_GOT_LO16); } +static inline bool +eh_reloc(unsigned int r_type) +{ + return (r_type == elfcpp::R_MIPS_EH); +} + static inline bool got_disp_reloc(unsigned int r_type) { @@ -401,13 +432,15 @@ class Mips_got_entry public: Mips_got_entry(Mips_relobj* object, unsigned int symndx, Mips_address addend, unsigned char tls_type, - unsigned int shndx) - : object_(object), symndx_(symndx), tls_type_(tls_type), shndx_(shndx) + unsigned int shndx, bool is_section_symbol) + : object_(object), symndx_(symndx), tls_type_(tls_type), + is_section_symbol_(is_section_symbol), shndx_(shndx) { this->d.addend = addend; } Mips_got_entry(Mips_relobj* object, Mips_symbol* sym, unsigned char tls_type) - : object_(object), symndx_(-1U), tls_type_(tls_type), shndx_(-1U) + : object_(object), symndx_(-1U), tls_type_(tls_type), + is_section_symbol_(false), shndx_(-1U) { this->d.sym = sym; } // Return whether this entry is for a local symbol. @@ -501,6 +534,11 @@ class Mips_got_entry shndx() const { return this->shndx_; } + // Return whether this is a STT_SECTION symbol. + bool + is_section_symbol() const + { return this->is_section_symbol_; } + private: // The input object that needs the GOT entry. Mips_relobj* object_; @@ -522,6 +560,9 @@ class Mips_got_entry // symbol entry with r_symndx == 0. unsigned char tls_type_; + // Whether this is a STT_SECTION symbol. + bool is_section_symbol_; + // For local GOT entries, section index of the local symbol. unsigned int shndx_; }; @@ -645,7 +686,8 @@ class Mips_got_info void record_local_got_symbol(Mips_relobj* object, unsigned int symndx, Mips_address addend, - unsigned int r_type, unsigned int shndx); + unsigned int r_type, unsigned int shndx, + bool is_section_symbol); // Reserve GOT entry for a GOT relocation of type R_TYPE against MIPS_SYM, // in OBJECT. FOR_CALL is true if the caller is only interested in @@ -1495,7 +1537,6 @@ class Mips_relobj : public Sized_relobj_file { this->is_pic_ = (ehdr.get_e_flags() & elfcpp::EF_MIPS_PIC) != 0; this->is_n32_ = elfcpp::abi_n32(ehdr.get_e_flags()); - this->is_n64_ = elfcpp::abi_64(ehdr.get_e_ident()[elfcpp::EI_CLASS]); } ~Mips_relobj() @@ -1652,12 +1693,12 @@ class Mips_relobj : public Sized_relobj_file // Return whether the object uses N64 ABI. bool is_n64() const - { return this->is_n64_; } + { return size == 64; } // Return whether the object uses NewABI conventions. bool is_newabi() const - { return this->is_n32_ || this->is_n64_; } + { return this->is_n32() || this->is_n64(); } // Return Mips_got_info for this object. Mips_got_info* @@ -1764,6 +1805,10 @@ class Mips_relobj : public Sized_relobj_file do_read_symbols(Read_symbols_data* sd); private: + // The name of the options section. + const char* mips_elf_options_section_name() + { return this->is_newabi() ? ".MIPS.options" : ".options"; } + // processor-specific flags in ELF file header. elfcpp::Elf_Word processor_specific_flags_; @@ -1802,8 +1847,6 @@ class Mips_relobj : public Sized_relobj_file bool is_pic_ : 1; // Whether the object uses N32 ABI. bool is_n32_ : 1; - // Whether the object uses N64 ABI. - bool is_n64_ : 1; // The Mips_got_info for this object. Mips_got_info* got_info_; @@ -1861,10 +1904,12 @@ class Mips_output_data_got : public Output_data_got void record_local_got_symbol(Mips_relobj* object, unsigned int symndx, Mips_address addend, - unsigned int r_type, unsigned int shndx) + unsigned int r_type, unsigned int shndx, + bool is_section_symbol) { this->master_got_info_->record_local_got_symbol(object, symndx, addend, - r_type, shndx); + r_type, shndx, + is_section_symbol); } // Reserve GOT entry for a GOT relocation of type R_TYPE against MIPS_SYM, @@ -2002,8 +2047,9 @@ class Mips_output_data_got : public Output_data_got // SYMNDX. unsigned int got_offset(unsigned int symndx, unsigned int got_type, - Sized_relobj_file* object) const - { return object->local_got_offset(symndx, got_type); } + Sized_relobj_file* object, + uint64_t addend) const + { return object->local_got_offset(symndx, got_type, addend); } // Return the offset of TLS LDM entry. For multi-GOT links, use OBJECT's GOT. unsigned int @@ -2246,6 +2292,11 @@ class Mips_output_data_la25_stub : public Output_section_data create_stub_symbol(Mips_symbol* sym, Symbol_table* symtab, Target_mips* target, uint64_t symsize); + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _(".LA25.stubs")); } + // Write out the LA25 stub section. void do_write(Output_file*); @@ -2254,14 +2305,73 @@ class Mips_output_data_la25_stub : public Output_section_data Unordered_set*> symbols_; }; +// MIPS-specific relocation writer. + +template +struct Mips_output_reloc_writer; + +template +struct Mips_output_reloc_writer +{ + typedef Output_reloc Output_reloc_type; + typedef std::vector Relocs; + + static void + write(typename Relocs::const_iterator p, unsigned char* pov) + { p->write(pov); } +}; + +template +struct Mips_output_reloc_writer +{ + typedef Output_reloc Output_reloc_type; + typedef std::vector Relocs; + + static void + write(typename Relocs::const_iterator p, unsigned char* pov) + { + elfcpp::Mips64_rel_write orel(pov); + orel.put_r_offset(p->get_address()); + orel.put_r_sym(p->get_symbol_index()); + orel.put_r_ssym(RSS_UNDEF); + orel.put_r_type(p->type()); + if (p->type() == elfcpp::R_MIPS_REL32) + orel.put_r_type2(elfcpp::R_MIPS_64); + else + orel.put_r_type2(elfcpp::R_MIPS_NONE); + orel.put_r_type3(elfcpp::R_MIPS_NONE); + } +}; + +template +class Mips_output_data_reloc : public Output_data_reloc +{ + public: + Mips_output_data_reloc(bool sort_relocs) + : Output_data_reloc(sort_relocs) + { } + + protected: + // Write out the data. + void + do_write(Output_file* of) + { + typedef Mips_output_reloc_writer Writer; + this->template do_write_generic(of); + } +}; + + // A class to handle the PLT data. template class Mips_output_data_plt : public Output_section_data { typedef typename elfcpp::Elf_types::Elf_Addr Mips_address; - typedef Output_data_reloc Reloc_section; + typedef Mips_output_data_reloc Reloc_section; public: // Create the PLT section. The ordinary .got section is an argument, @@ -2872,7 +2982,7 @@ struct Mips_reloc_types typedef typename elfcpp::Rel<32, big_endian> Reloc; typedef typename elfcpp::Rel_write<32, big_endian> Reloc_write; - static unsigned typename elfcpp::Elf_types<32>::Elf_Swxword + static typename elfcpp::Elf_types<32>::Elf_Swxword get_r_addend(const Reloc*) { return 0; } @@ -2888,7 +2998,7 @@ struct Mips_reloc_types typedef typename elfcpp::Rela<32, big_endian> Reloc; typedef typename elfcpp::Rela_write<32, big_endian> Reloc_write; - static unsigned typename elfcpp::Elf_types<32>::Elf_Swxword + static typename elfcpp::Elf_types<32>::Elf_Swxword get_r_addend(const Reloc* reloc) { return reloc->get_r_addend(); } @@ -2904,7 +3014,7 @@ struct Mips_reloc_types typedef typename elfcpp::Mips64_rel Reloc; typedef typename elfcpp::Mips64_rel_write Reloc_write; - static unsigned typename elfcpp::Elf_types<64>::Elf_Swxword + static typename elfcpp::Elf_types<64>::Elf_Swxword get_r_addend(const Reloc*) { return 0; } @@ -2920,7 +3030,7 @@ struct Mips_reloc_types typedef typename elfcpp::Mips64_rela Reloc; typedef typename elfcpp::Mips64_rela_write Reloc_write; - static unsigned typename elfcpp::Elf_types<64>::Elf_Swxword + static typename elfcpp::Elf_types<64>::Elf_Swxword get_r_addend(const Reloc* reloc) { return reloc->get_r_addend(); } @@ -2961,10 +3071,26 @@ class Mips_classify_reloc : get_r_type(const Reltype* reloc) { return elfcpp::elf_r_type<32>(reloc->get_r_info()); } + static inline unsigned int + get_r_type2(const Reltype*) + { return 0; } + + static inline unsigned int + get_r_type3(const Reltype*) + { return 0; } + + static inline unsigned int + get_r_ssym(const Reltype*) + { return 0; } + // Return the explicit addend of the relocation (return 0 for SHT_REL). static inline unsigned int get_r_addend(const Reltype* reloc) - { return Mips_reloc_types::get_r_addend(reloc); } + { + if (sh_type_ == elfcpp::SHT_REL) + return 0; + return Mips_reloc_types::get_r_addend(reloc); + } // Write the r_info field to a new reloc, using the r_info field from // the original reloc, replacing the r_sym field with R_SYM. @@ -2972,7 +3098,7 @@ class Mips_classify_reloc : put_r_info(Reltype_write* new_reloc, Reltype* reloc, unsigned int r_sym) { unsigned int r_type = elfcpp::elf_r_type<32>(reloc->get_r_info()); - new_reloc->put_r_info(elfcpp::elf_r_info<64>(r_sym, r_type)); + new_reloc->put_r_info(elfcpp::elf_r_info<32>(r_sym, r_type)); } // Write the r_addend field to a new reloc. @@ -3002,15 +3128,34 @@ class Mips_classify_reloc : get_r_sym(const Reltype* reloc) { return reloc->get_r_sym(); } - // Return the type of the relocation. + // Return the r_type of the relocation. static inline unsigned int get_r_type(const Reltype* reloc) { return reloc->get_r_type(); } + // Return the r_type2 of the relocation. + static inline unsigned int + get_r_type2(const Reltype* reloc) + { return reloc->get_r_type2(); } + + // Return the r_type3 of the relocation. + static inline unsigned int + get_r_type3(const Reltype* reloc) + { return reloc->get_r_type3(); } + + // Return the special symbol of the relocation. + static inline unsigned int + get_r_ssym(const Reltype* reloc) + { return reloc->get_r_ssym(); } + // Return the explicit addend of the relocation (return 0 for SHT_REL). static inline typename elfcpp::Elf_types<64>::Elf_Swxword get_r_addend(const Reltype* reloc) - { return Mips_reloc_types::get_r_addend(reloc); } + { + if (sh_type_ == elfcpp::SHT_REL) + return 0; + return Mips_reloc_types::get_r_addend(reloc); + } // Write the r_info field to a new reloc, using the r_info field from // the original reloc, replacing the r_sym field with R_SYM. @@ -3040,10 +3185,8 @@ template class Target_mips : public Sized_target { typedef typename elfcpp::Elf_types::Elf_Addr Mips_address; - typedef Output_data_reloc + typedef Mips_output_data_reloc Reloc_section; - typedef Output_data_reloc - Reloca_section; typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype32; typedef typename elfcpp::Swap::Valtype Valtype; typedef typename Mips_reloc_types::Reloc @@ -3056,8 +3199,8 @@ class Target_mips : public Sized_target : Sized_target(info), got_(NULL), gp_(NULL), plt_(NULL), got_plt_(NULL), rel_dyn_(NULL), copy_relocs_(), dyn_relocs_(), la25_stub_(NULL), mips_mach_extensions_(), - mips_stubs_(NULL), ei_class_(0), mach_(0), layout_(NULL), - got16_addends_(), entry_symbol_is_compressed_(false), insn32_(false) + mips_stubs_(NULL), mach_(0), layout_(NULL), got16_addends_(), + entry_symbol_is_compressed_(false), insn32_(false) { this->add_machine_extensions(); } @@ -3071,7 +3214,7 @@ class Target_mips : public Sized_target // Make a new symbol table entry for the Mips target. Sized_symbol* - make_symbol() const + make_symbol(const char*, elfcpp::STT, Object*, unsigned int, uint64_t) { return new Mips_symbol(); } // Process the relocations to determine unreferenced sections for @@ -3339,14 +3482,10 @@ class Target_mips : public Sized_target return elfcpp::abi_n32(this->processor_specific_flags()); } - // Whether the output uses N64 ABI. This is valid only after - // merge_processor_specific_flags() is called. + // Whether the output uses N64 ABI. bool is_output_n64() const - { - gold_assert(this->are_processor_specific_flags_set()); - return elfcpp::abi_64(this->ei_class_); - } + { return size == 64; } // Whether the output uses NEWABI. This is valid only after // merge_processor_specific_flags() is called. @@ -3587,12 +3726,12 @@ class Target_mips : public Sized_target ~Relocate() { } - // Return whether the R_MIPS_32 relocation needs to be applied. + // Return whether a R_MIPS_32/R_MIPS_64 relocation needs to be applied. inline bool - should_apply_r_mips_32_reloc(const Mips_symbol* gsym, - unsigned int r_type, - Output_section* output_section, - Target_mips* target); + should_apply_static_reloc(const Mips_symbol* gsym, + unsigned int r_type, + Output_section* output_section, + Target_mips* target); // Do a relocation. Return false if the caller should not issue // any warnings about this relocation. @@ -3714,8 +3853,7 @@ class Target_mips : public Sized_target // Merge processor specific flags. void - merge_processor_specific_flags(const std::string&, elfcpp::Elf_Word, - unsigned char, bool); + merge_processor_specific_flags(const std::string&, elfcpp::Elf_Word, bool); // True if we are linking for CPUs that are faster if JAL is converted to BAL. static inline bool @@ -3770,15 +3908,12 @@ class Target_mips : public Sized_target copy_reloc(Symbol_table* symtab, Layout* layout, Sized_relobj_file* object, unsigned int shndx, Output_section* output_section, - Symbol* sym, const Reltype& reloc) + Symbol* sym, unsigned int r_type, Mips_address r_offset) { - unsigned int r_type = - Mips_classify_reloc:: - get_r_type(&reloc); this->copy_relocs_.copy_reloc(symtab, layout, symtab->get_sized_symbol(sym), object, shndx, output_section, - r_type, reloc.get_r_offset(), 0, + r_type, r_offset, 0, this->rel_dyn_section(layout)); } @@ -3797,7 +3932,7 @@ class Target_mips : public Sized_target set_gp(Layout*, Symbol_table*); const char* - elf_mips_abi_name(elfcpp::Elf_Word e_flags, unsigned char ei_class); + elf_mips_abi_name(elfcpp::Elf_Word e_flags); const char* elf_mips_mach_name(elfcpp::Elf_Word e_flags); @@ -3910,7 +4045,6 @@ class Target_mips : public Sized_target // .MIPS.stubs Mips_output_data_mips_stubs* mips_stubs_; - unsigned char ei_class_; unsigned int mach_; Layout* layout_; @@ -3956,8 +4090,10 @@ template class Mips_relocate_functions : public Relocate_functions { typedef typename elfcpp::Elf_types::Elf_Addr Mips_address; + typedef typename elfcpp::Swap::Valtype Valtype; typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype16; typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype32; + typedef typename elfcpp::Swap<64, big_endian>::Valtype Valtype64; public: typedef enum @@ -3974,6 +4110,29 @@ class Mips_relocate_functions : public Relocate_functions static typename std::list > hi16_relocs; static typename std::list > got16_relocs; + template + static inline typename This::Status + check_overflow(Valtype value) + { + if (size == 32) + return (Bits::has_overflow32(value) + ? This::STATUS_OVERFLOW + : This::STATUS_OKAY); + + return (Bits::has_overflow(value) + ? This::STATUS_OVERFLOW + : This::STATUS_OKAY); + } + + static inline bool + should_shuffle_micromips_reloc(unsigned int r_type) + { + return (micromips_reloc(r_type) + && r_type != elfcpp::R_MICROMIPS_PC7_S1 + && r_type != elfcpp::R_MICROMIPS_PC10_S1); + } + + public: // R_MIPS16_26 is used for the mips16 jal and jalx instructions. // Most mips16 instructions are 16 bits, but these instructions // are 32 bits. @@ -4063,14 +4222,6 @@ class Mips_relocate_functions : public Relocate_functions // on a little-endian system. This does not apply to R_MICROMIPS_PC7_S1 // and R_MICROMIPS_PC10_S1 relocs that apply to 16-bit instructions. - static inline bool - should_shuffle_micromips_reloc(unsigned int r_type) - { - return (micromips_reloc(r_type) - && r_type != elfcpp::R_MICROMIPS_PC7_S1 - && r_type != elfcpp::R_MICROMIPS_PC10_S1); - } - static void mips_reloc_unshuffle(unsigned char* view, unsigned int r_type, bool jal_shuffle) @@ -4129,43 +4280,49 @@ class Mips_relocate_functions : public Relocate_functions elfcpp::Swap<16, big_endian>::writeval(view, first); } - public: // R_MIPS_16: S + sign-extend(A) static inline typename This::Status rel16(unsigned char* view, const Mips_relobj* object, const Symbol_value* psymval, Mips_address addend_a, - bool extract_addend, unsigned int r_type) + bool extract_addend, bool calculate_only, Valtype* calculated_value) { - mips_reloc_unshuffle(view, r_type, false); Valtype16* wv = reinterpret_cast(view); Valtype16 val = elfcpp::Swap<16, big_endian>::readval(wv); - Valtype32 addend = (extract_addend ? Bits<16>::sign_extend32(val) - : Bits<16>::sign_extend32(addend_a)); + Valtype addend = (extract_addend ? Bits<16>::sign_extend32(val) + : addend_a); - Valtype32 x = psymval->value(object, addend); + Valtype x = psymval->value(object, addend); val = Bits<16>::bit_select32(val, x, 0xffffU); - elfcpp::Swap<16, big_endian>::writeval(wv, val); - mips_reloc_shuffle(view, r_type, false); - return (Bits<16>::has_overflow32(x) - ? This::STATUS_OVERFLOW - : This::STATUS_OKAY); + + if (calculate_only) + { + *calculated_value = x; + return This::STATUS_OKAY; + } + else + elfcpp::Swap<16, big_endian>::writeval(wv, val); + + return check_overflow<16>(x); } // R_MIPS_32: S + A static inline typename This::Status rel32(unsigned char* view, const Mips_relobj* object, const Symbol_value* psymval, Mips_address addend_a, - bool extract_addend, unsigned int r_type) + bool extract_addend, bool calculate_only, Valtype* calculated_value) { - mips_reloc_unshuffle(view, r_type, false); Valtype32* wv = reinterpret_cast(view); - Valtype32 addend = (extract_addend + Valtype addend = (extract_addend ? elfcpp::Swap<32, big_endian>::readval(wv) - : Bits<32>::sign_extend32(addend_a)); - Valtype32 x = psymval->value(object, addend); - elfcpp::Swap<32, big_endian>::writeval(wv, x); - mips_reloc_shuffle(view, r_type, false); + : addend_a); + Valtype x = psymval->value(object, addend); + + if (calculate_only) + *calculated_value = x; + else + elfcpp::Swap<32, big_endian>::writeval(wv, x); + return This::STATUS_OKAY; } @@ -4174,11 +4331,11 @@ class Mips_relocate_functions : public Relocate_functions reljalr(unsigned char* view, const Mips_relobj* object, const Symbol_value* psymval, Mips_address address, Mips_address addend_a, bool extract_addend, bool cross_mode_jump, - unsigned int r_type, bool jalr_to_bal, bool jr_to_b) + unsigned int r_type, bool jalr_to_bal, bool jr_to_b, + bool calculate_only, Valtype* calculated_value) { - mips_reloc_unshuffle(view, r_type, false); Valtype32* wv = reinterpret_cast(view); - Valtype32 addend = extract_addend ? 0 : addend_a; + Valtype addend = extract_addend ? 0 : addend_a; Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv); // Try converting J(AL)R to B(AL), if the target is in range. @@ -4198,8 +4355,11 @@ class Mips_relocate_functions : public Relocate_functions } } - elfcpp::Swap<32, big_endian>::writeval(wv, val); - mips_reloc_shuffle(view, r_type, false); + if (calculate_only) + *calculated_value = val; + else + elfcpp::Swap<32, big_endian>::writeval(wv, val); + return This::STATUS_OKAY; } @@ -4207,16 +4367,20 @@ class Mips_relocate_functions : public Relocate_functions static inline typename This::Status relpc32(unsigned char* view, const Mips_relobj* object, const Symbol_value* psymval, Mips_address address, - Mips_address addend_a, bool extract_addend, unsigned int r_type) + Mips_address addend_a, bool extract_addend, bool calculate_only, + Valtype* calculated_value) { - mips_reloc_unshuffle(view, r_type, false); Valtype32* wv = reinterpret_cast(view); - Valtype32 addend = (extract_addend + Valtype addend = (extract_addend ? elfcpp::Swap<32, big_endian>::readval(wv) - : Bits<32>::sign_extend32(addend_a)); - Valtype32 x = psymval->value(object, addend) - address; - elfcpp::Swap<32, big_endian>::writeval(wv, x); - mips_reloc_shuffle(view, r_type, false); + : addend_a); + Valtype x = psymval->value(object, addend) - address; + + if (calculate_only) + *calculated_value = x; + else + elfcpp::Swap<32, big_endian>::writeval(wv, x); + return This::STATUS_OKAY; } @@ -4226,13 +4390,12 @@ class Mips_relocate_functions : public Relocate_functions const Symbol_value* psymval, Mips_address address, bool local, Mips_address addend_a, bool extract_addend, const Symbol* gsym, bool cross_mode_jump, unsigned int r_type, - bool jal_to_bal) + bool jal_to_bal, bool calculate_only, Valtype* calculated_value) { - mips_reloc_unshuffle(view, r_type, false); Valtype32* wv = reinterpret_cast(view); Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv); - Valtype32 addend; + Valtype addend; if (extract_addend) { if (r_type == elfcpp::R_MICROMIPS_26_S1) @@ -4245,11 +4408,10 @@ class Mips_relocate_functions : public Relocate_functions // Make sure the target of JALX is word-aligned. Bit 0 must be // the correct ISA mode selector and bit 1 must be 0. - if (cross_mode_jump + if (!calculate_only && cross_mode_jump && (psymval->value(object, 0) & 3) != (r_type == elfcpp::R_MIPS_26)) { gold_warning(_("JALX to a non-word-aligned address")); - mips_reloc_shuffle(view, r_type, !parameters->options().relocatable()); return This::STATUS_BAD_RELOC; } @@ -4257,7 +4419,7 @@ class Mips_relocate_functions : public Relocate_functions unsigned int shift = (!cross_mode_jump && r_type == elfcpp::R_MICROMIPS_26_S1) ? 1 : 2; - Valtype32 x; + Valtype x; if (local) x = addend | ((address + 4) & (0xfc000000 << shift)); else @@ -4269,7 +4431,7 @@ class Mips_relocate_functions : public Relocate_functions } x = psymval->value(object, x) >> shift; - if (!local && !gsym->is_weak_undefined()) + if (!calculate_only && !local && !gsym->is_weak_undefined()) { if ((x >> 26) != ((address + 4) >> (26 + shift))) { @@ -4307,7 +4469,7 @@ class Mips_relocate_functions : public Relocate_functions // If the opcode is not JAL or JALX, there's a problem. We cannot // convert J or JALS to JALX. - if (!ok) + if (!calculate_only && !ok) { gold_error(_("Unsupported jump between ISA modes; consider " "recompiling with interlinking enabled.")); @@ -4336,8 +4498,11 @@ class Mips_relocate_functions : public Relocate_functions } } - elfcpp::Swap<32, big_endian>::writeval(wv, val); - mips_reloc_shuffle(view, r_type, !parameters->options().relocatable()); + if (calculate_only) + *calculated_value = val; + else + elfcpp::Swap<32, big_endian>::writeval(wv, val); + return This::STATUS_OKAY; } @@ -4345,22 +4510,28 @@ class Mips_relocate_functions : public Relocate_functions static inline typename This::Status relpc16(unsigned char* view, const Mips_relobj* object, const Symbol_value* psymval, Mips_address address, - Mips_address addend_a, bool extract_addend, unsigned int r_type) + Mips_address addend_a, bool extract_addend, bool calculate_only, + Valtype* calculated_value) { - mips_reloc_unshuffle(view, r_type, false); Valtype32* wv = reinterpret_cast(view); Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv); - Valtype32 addend = extract_addend ? (val & 0xffff) << 2 : addend_a; - addend = Bits<18>::sign_extend32(addend); + Valtype addend = (extract_addend + ? Bits<18>::sign_extend32((val & 0xffff) << 2) + : addend_a); - Valtype32 x = psymval->value(object, addend) - address; + Valtype x = psymval->value(object, addend) - address; val = Bits<16>::bit_select32(val, x >> 2, 0xffff); - elfcpp::Swap<32, big_endian>::writeval(wv, val); - mips_reloc_shuffle(view, r_type, false); - return (Bits<18>::has_overflow32(x) - ? This::STATUS_OVERFLOW - : This::STATUS_OKAY); + + if (calculate_only) + { + *calculated_value = x >> 2; + return This::STATUS_OKAY; + } + else + elfcpp::Swap<32, big_endian>::writeval(wv, val); + + return check_overflow<18>(x); } // R_MICROMIPS_PC7_S1 @@ -4369,22 +4540,26 @@ class Mips_relocate_functions : public Relocate_functions const Mips_relobj* object, const Symbol_value* psymval, Mips_address address, Mips_address addend_a, bool extract_addend, - unsigned int r_type) + bool calculate_only, Valtype* calculated_value) { - mips_reloc_unshuffle(view, r_type, false); Valtype32* wv = reinterpret_cast(view); Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv); - Valtype32 addend = extract_addend ? (val & 0x7f) << 1 : addend_a; - addend = Bits<8>::sign_extend32(addend); + Valtype addend = extract_addend ? Bits<8>::sign_extend32((val & 0x7f) << 1) + : addend_a; - Valtype32 x = psymval->value(object, addend) - address; + Valtype x = psymval->value(object, addend) - address; val = Bits<16>::bit_select32(val, x >> 1, 0x7f); - elfcpp::Swap<32, big_endian>::writeval(wv, val); - mips_reloc_shuffle(view, r_type, false); - return (Bits<8>::has_overflow32(x) - ? This::STATUS_OVERFLOW - : This::STATUS_OKAY); + + if (calculate_only) + { + *calculated_value = x >> 1; + return This::STATUS_OKAY; + } + else + elfcpp::Swap<32, big_endian>::writeval(wv, val); + + return check_overflow<8>(x); } // R_MICROMIPS_PC10_S1 @@ -4393,22 +4568,27 @@ class Mips_relocate_functions : public Relocate_functions const Mips_relobj* object, const Symbol_value* psymval, Mips_address address, Mips_address addend_a, bool extract_addend, - unsigned int r_type) + bool calculate_only, Valtype* calculated_value) { - mips_reloc_unshuffle(view, r_type, false); Valtype32* wv = reinterpret_cast(view); Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv); - Valtype32 addend = extract_addend ? (val & 0x3ff) << 1 : addend_a; - addend = Bits<11>::sign_extend32(addend); + Valtype addend = (extract_addend + ? Bits<11>::sign_extend32((val & 0x3ff) << 1) + : addend_a); - Valtype32 x = psymval->value(object, addend) - address; + Valtype x = psymval->value(object, addend) - address; val = Bits<16>::bit_select32(val, x >> 1, 0x3ff); - elfcpp::Swap<32, big_endian>::writeval(wv, val); - mips_reloc_shuffle(view, r_type, false); - return (Bits<11>::has_overflow32(x) - ? This::STATUS_OVERFLOW - : This::STATUS_OKAY); + + if (calculate_only) + { + *calculated_value = x >> 1; + return This::STATUS_OKAY; + } + else + elfcpp::Swap<32, big_endian>::writeval(wv, val); + + return check_overflow<11>(x); } // R_MICROMIPS_PC16_S1 @@ -4417,22 +4597,27 @@ class Mips_relocate_functions : public Relocate_functions const Mips_relobj* object, const Symbol_value* psymval, Mips_address address, Mips_address addend_a, bool extract_addend, - unsigned int r_type) + bool calculate_only, Valtype* calculated_value) { - mips_reloc_unshuffle(view, r_type, false); Valtype32* wv = reinterpret_cast(view); Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv); - Valtype32 addend = extract_addend ? (val & 0xffff) << 1 : addend_a; - addend = Bits<17>::sign_extend32(addend); + Valtype addend = (extract_addend + ? Bits<17>::sign_extend32((val & 0xffff) << 1) + : addend_a); - Valtype32 x = psymval->value(object, addend) - address; + Valtype x = psymval->value(object, addend) - address; val = Bits<16>::bit_select32(val, x >> 1, 0xffff); - elfcpp::Swap<32, big_endian>::writeval(wv, val); - mips_reloc_shuffle(view, r_type, false); - return (Bits<17>::has_overflow32(x) - ? This::STATUS_OVERFLOW - : This::STATUS_OKAY); + + if (calculate_only) + { + *calculated_value = x >> 1; + return This::STATUS_OKAY; + } + else + elfcpp::Swap<32, big_endian>::writeval(wv, val); + + return check_overflow<17>(x); } // R_MIPS_HI16, R_MIPS16_HI16, R_MICROMIPS_HI16, @@ -4455,13 +4640,13 @@ class Mips_relocate_functions : public Relocate_functions const Symbol_value* psymval, Mips_address addend_hi, Mips_address address, bool is_gp_disp, unsigned int r_type, bool extract_addend, Valtype32 addend_lo, - Target_mips* target) + Target_mips* target, bool calculate_only, + Valtype* calculated_value) { - mips_reloc_unshuffle(view, r_type, false); Valtype32* wv = reinterpret_cast(view); Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv); - Valtype32 addend = (extract_addend ? ((val & 0xffff) << 16) + addend_lo + Valtype addend = (extract_addend ? ((val & 0xffff) << 16) + addend_lo : addend_hi); Valtype32 value; @@ -4492,13 +4677,19 @@ class Mips_relocate_functions : public Relocate_functions gp_disp = target->adjusted_gp_value(object) - address; value = gp_disp + addend; } - Valtype32 x = ((value + 0x8000) >> 16) & 0xffff; + Valtype x = ((value + 0x8000) >> 16) & 0xffff; val = Bits<32>::bit_select32(val, x, 0xffff); - elfcpp::Swap<32, big_endian>::writeval(wv, val); - mips_reloc_shuffle(view, r_type, false); - return (is_gp_disp && Bits<16>::has_overflow32(x) - ? This::STATUS_OVERFLOW - : This::STATUS_OKAY); + + if (calculate_only) + { + *calculated_value = x; + return This::STATUS_OKAY; + } + else + elfcpp::Swap<32, big_endian>::writeval(wv, val); + + return (is_gp_disp ? check_overflow<16>(x) + : This::STATUS_OKAY); } // R_MIPS_GOT16, R_MIPS16_GOT16, R_MICROMIPS_GOT16 @@ -4519,14 +4710,14 @@ class Mips_relocate_functions : public Relocate_functions do_relgot16_local(unsigned char* view, const Mips_relobj* object, const Symbol_value* psymval, Mips_address addend_hi, - unsigned int r_type, bool extract_addend, - Valtype32 addend_lo, Target_mips* target) + bool extract_addend, Valtype32 addend_lo, + Target_mips* target, bool calculate_only, + Valtype* calculated_value) { - mips_reloc_unshuffle(view, r_type, false); Valtype32* wv = reinterpret_cast(view); Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv); - Valtype32 addend = (extract_addend ? ((val & 0xffff) << 16) + addend_lo + Valtype addend = (extract_addend ? ((val & 0xffff) << 16) + addend_lo : addend_hi); // Find GOT page entry. @@ -4537,13 +4728,18 @@ class Mips_relocate_functions : public Relocate_functions target->got_section()->get_got_page_offset(value, object); // Resolve the relocation. - Valtype32 x = target->got_section()->gp_offset(got_offset, object); + Valtype x = target->got_section()->gp_offset(got_offset, object); val = Bits<32>::bit_select32(val, x, 0xffff); - elfcpp::Swap<32, big_endian>::writeval(wv, val); - mips_reloc_shuffle(view, r_type, false); - return (Bits<16>::has_overflow32(x) - ? This::STATUS_OVERFLOW - : This::STATUS_OKAY); + + if (calculate_only) + { + *calculated_value = x; + return This::STATUS_OKAY; + } + else + elfcpp::Swap<32, big_endian>::writeval(wv, val); + + return check_overflow<16>(x); } // R_MIPS_LO16, R_MIPS16_LO16, R_MICROMIPS_LO16, R_MICROMIPS_HI0_LO16 @@ -4552,57 +4748,69 @@ class Mips_relocate_functions : public Relocate_functions const Mips_relobj* object, const Symbol_value* psymval, Mips_address addend_a, bool extract_addend, Mips_address address, bool is_gp_disp, - unsigned int r_type, unsigned int r_sym) + unsigned int r_type, unsigned int r_sym, unsigned int rel_type, + bool calculate_only, Valtype* calculated_value) { - mips_reloc_unshuffle(view, r_type, false); Valtype32* wv = reinterpret_cast(view); Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv); - Valtype32 addend = (extract_addend ? Bits<16>::sign_extend32(val & 0xffff) - : addend_a); + Valtype addend = (extract_addend ? Bits<16>::sign_extend32(val & 0xffff) + : addend_a); - // Resolve pending R_MIPS_HI16 relocations. - typename std::list >::iterator it = - hi16_relocs.begin(); - while (it != hi16_relocs.end()) + if (rel_type == elfcpp::SHT_REL) { - reloc_high hi16 = *it; - if (hi16.r_sym == r_sym - && is_matching_lo16_reloc(hi16.r_type, r_type)) + typename This::Status reloc_status = This::STATUS_OKAY; + // Resolve pending R_MIPS_HI16 relocations. + typename std::list >::iterator it = + hi16_relocs.begin(); + while (it != hi16_relocs.end()) { - if (do_relhi16(hi16.view, hi16.object, hi16.psymval, hi16.addend, - hi16.address, hi16.gp_disp, hi16.r_type, - hi16.extract_addend, addend, target) - == This::STATUS_OVERFLOW) - return This::STATUS_OVERFLOW; - it = hi16_relocs.erase(it); + reloc_high hi16 = *it; + if (hi16.r_sym == r_sym + && is_matching_lo16_reloc(hi16.r_type, r_type)) + { + mips_reloc_unshuffle(hi16.view, hi16.r_type, false); + reloc_status = do_relhi16(hi16.view, hi16.object, hi16.psymval, + hi16.addend, hi16.address, hi16.gp_disp, + hi16.r_type, hi16.extract_addend, addend, + target, calculate_only, calculated_value); + mips_reloc_shuffle(hi16.view, hi16.r_type, false); + if (reloc_status == This::STATUS_OVERFLOW) + return This::STATUS_OVERFLOW; + it = hi16_relocs.erase(it); + } + else + ++it; } - else - ++it; - } - // Resolve pending local R_MIPS_GOT16 relocations. - typename std::list >::iterator it2 = - got16_relocs.begin(); - while (it2 != got16_relocs.end()) - { - reloc_high got16 = *it2; - if (got16.r_sym == r_sym - && is_matching_lo16_reloc(got16.r_type, r_type)) + // Resolve pending local R_MIPS_GOT16 relocations. + typename std::list >::iterator it2 = + got16_relocs.begin(); + while (it2 != got16_relocs.end()) { - if (do_relgot16_local(got16.view, got16.object, got16.psymval, - got16.addend, got16.r_type, - got16.extract_addend, addend, - target) == This::STATUS_OVERFLOW) - return This::STATUS_OVERFLOW; - it2 = got16_relocs.erase(it2); + reloc_high got16 = *it2; + if (got16.r_sym == r_sym + && is_matching_lo16_reloc(got16.r_type, r_type)) + { + mips_reloc_unshuffle(got16.view, got16.r_type, false); + + reloc_status = do_relgot16_local(got16.view, got16.object, + got16.psymval, got16.addend, + got16.extract_addend, addend, target, + calculate_only, calculated_value); + + mips_reloc_shuffle(got16.view, got16.r_type, false); + if (reloc_status == This::STATUS_OVERFLOW) + return This::STATUS_OVERFLOW; + it2 = got16_relocs.erase(it2); + } + else + ++it2; } - else - ++it2; } // Resolve R_MIPS_LO16 relocation. - Valtype32 x; + Valtype x; if (!is_gp_disp) x = psymval->value(object, addend); else @@ -4635,8 +4843,12 @@ class Mips_relocate_functions : public Relocate_functions x = gp_disp + addend; } val = Bits<32>::bit_select32(val, x, 0xffff); - elfcpp::Swap<32, big_endian>::writeval(wv, val); - mips_reloc_shuffle(view, r_type, false); + + if (calculate_only) + *calculated_value = x; + else + elfcpp::Swap<32, big_endian>::writeval(wv, val); + return This::STATUS_OKAY; } @@ -4647,18 +4859,42 @@ class Mips_relocate_functions : public Relocate_functions // R_MIPS_TLS_LDM, R_MIPS16_TLS_LDM, R_MICROMIPS_TLS_LDM // R_MIPS_GOT_DISP, R_MICROMIPS_GOT_DISP static inline typename This::Status - relgot(unsigned char* view, int gp_offset, unsigned int r_type) + relgot(unsigned char* view, int gp_offset, bool calculate_only, + Valtype* calculated_value) { - mips_reloc_unshuffle(view, r_type, false); Valtype32* wv = reinterpret_cast(view); Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv); - Valtype32 x = gp_offset; + Valtype x = gp_offset; val = Bits<32>::bit_select32(val, x, 0xffff); - elfcpp::Swap<32, big_endian>::writeval(wv, val); - mips_reloc_shuffle(view, r_type, false); - return (Bits<16>::has_overflow32(x) - ? This::STATUS_OVERFLOW - : This::STATUS_OKAY); + + if (calculate_only) + { + *calculated_value = x; + return This::STATUS_OKAY; + } + else + elfcpp::Swap<32, big_endian>::writeval(wv, val); + + return check_overflow<16>(x); + } + + // R_MIPS_EH + static inline typename This::Status + releh(unsigned char* view, int gp_offset, bool calculate_only, + Valtype* calculated_value) + { + Valtype32* wv = reinterpret_cast(view); + Valtype x = gp_offset; + + if (calculate_only) + { + *calculated_value = x; + return This::STATUS_OKAY; + } + else + elfcpp::Swap<32, big_endian>::writeval(wv, x); + + return check_overflow<32>(x); } // R_MIPS_GOT_PAGE, R_MICROMIPS_GOT_PAGE @@ -4666,25 +4902,30 @@ class Mips_relocate_functions : public Relocate_functions relgotpage(Target_mips* target, unsigned char* view, const Mips_relobj* object, const Symbol_value* psymval, Mips_address addend_a, - bool extract_addend, unsigned int r_type) + bool extract_addend, bool calculate_only, + Valtype* calculated_value) { - mips_reloc_unshuffle(view, r_type, false); Valtype32* wv = reinterpret_cast(view); Valtype32 val = elfcpp::Swap<32, big_endian>::readval(view); - Valtype32 addend = extract_addend ? val & 0xffff : addend_a; + Valtype addend = extract_addend ? val & 0xffff : addend_a; // Find a GOT page entry that points to within 32KB of symbol + addend. Mips_address value = (psymval->value(object, addend) + 0x8000) & ~0xffff; unsigned int got_offset = target->got_section()->get_got_page_offset(value, object); - Valtype32 x = target->got_section()->gp_offset(got_offset, object); + Valtype x = target->got_section()->gp_offset(got_offset, object); val = Bits<32>::bit_select32(val, x, 0xffff); - elfcpp::Swap<32, big_endian>::writeval(wv, val); - mips_reloc_shuffle(view, r_type, false); - return (Bits<16>::has_overflow32(x) - ? This::STATUS_OVERFLOW - : This::STATUS_OKAY); + + if (calculate_only) + { + *calculated_value = x; + return This::STATUS_OKAY; + } + else + elfcpp::Swap<32, big_endian>::writeval(wv, val); + + return check_overflow<16>(x); } // R_MIPS_GOT_OFST, R_MICROMIPS_GOT_OFST @@ -4692,18 +4933,18 @@ class Mips_relocate_functions : public Relocate_functions relgotofst(Target_mips* target, unsigned char* view, const Mips_relobj* object, const Symbol_value* psymval, Mips_address addend_a, - bool extract_addend, bool local, unsigned int r_type) + bool extract_addend, bool local, bool calculate_only, + Valtype* calculated_value) { - mips_reloc_unshuffle(view, r_type, false); Valtype32* wv = reinterpret_cast(view); Valtype32 val = elfcpp::Swap<32, big_endian>::readval(view); - Valtype32 addend = extract_addend ? val & 0xffff : addend_a; + Valtype addend = extract_addend ? val & 0xffff : addend_a; // For a local symbol, find a GOT page entry that points to within 32KB of // symbol + addend. Relocation value is the offset of the GOT page entry's // value from symbol + addend. // For a global symbol, relocation value is addend. - Valtype32 x; + Valtype x; if (local) { // Find GOT page entry. @@ -4716,41 +4957,54 @@ class Mips_relocate_functions : public Relocate_functions else x = addend; val = Bits<32>::bit_select32(val, x, 0xffff); - elfcpp::Swap<32, big_endian>::writeval(wv, val); - mips_reloc_shuffle(view, r_type, false); - return (Bits<16>::has_overflow32(x) - ? This::STATUS_OVERFLOW - : This::STATUS_OKAY); + + if (calculate_only) + { + *calculated_value = x; + return This::STATUS_OKAY; + } + else + elfcpp::Swap<32, big_endian>::writeval(wv, val); + + return check_overflow<16>(x); } // R_MIPS_GOT_HI16, R_MIPS_CALL_HI16, // R_MICROMIPS_GOT_HI16, R_MICROMIPS_CALL_HI16 static inline typename This::Status - relgot_hi16(unsigned char* view, int gp_offset, unsigned int r_type) + relgot_hi16(unsigned char* view, int gp_offset, bool calculate_only, + Valtype* calculated_value) { - mips_reloc_unshuffle(view, r_type, false); Valtype32* wv = reinterpret_cast(view); Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv); - Valtype32 x = gp_offset; + Valtype x = gp_offset; x = ((x + 0x8000) >> 16) & 0xffff; val = Bits<32>::bit_select32(val, x, 0xffff); - elfcpp::Swap<32, big_endian>::writeval(wv, val); - mips_reloc_shuffle(view, r_type, false); + + if (calculate_only) + *calculated_value = x; + else + elfcpp::Swap<32, big_endian>::writeval(wv, val); + return This::STATUS_OKAY; } // R_MIPS_GOT_LO16, R_MIPS_CALL_LO16, // R_MICROMIPS_GOT_LO16, R_MICROMIPS_CALL_LO16 static inline typename This::Status - relgot_lo16(unsigned char* view, int gp_offset, unsigned int r_type) + relgot_lo16(unsigned char* view, int gp_offset, bool calculate_only, + Valtype* calculated_value) { - mips_reloc_unshuffle(view, r_type, false); Valtype32* wv = reinterpret_cast(view); Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv); - Valtype32 x = gp_offset; + Valtype x = gp_offset; val = Bits<32>::bit_select32(val, x, 0xffff); - elfcpp::Swap<32, big_endian>::writeval(wv, val); - mips_reloc_shuffle(view, r_type, false); + + if (calculate_only) + *calculated_value = x; + else + elfcpp::Swap<32, big_endian>::writeval(wv, val); + return This::STATUS_OKAY; } @@ -4760,13 +5014,13 @@ class Mips_relocate_functions : public Relocate_functions relgprel(unsigned char* view, const Mips_relobj* object, const Symbol_value* psymval, Mips_address gp, Mips_address addend_a, bool extract_addend, bool local, - unsigned int r_type) + unsigned int r_type, bool calculate_only, + Valtype* calculated_value) { - mips_reloc_unshuffle(view, r_type, false); Valtype32* wv = reinterpret_cast(view); Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv); - Valtype32 addend; + Valtype addend; if (extract_addend) { if (r_type == elfcpp::R_MICROMIPS_GPREL7_S2) @@ -4781,7 +5035,7 @@ class Mips_relocate_functions : public Relocate_functions else addend = addend_a; - Valtype32 x = psymval->value(object, addend) - gp; + Valtype x = psymval->value(object, addend) - gp; // If the symbol was local, any earlier relocatable links will // have adjusted its addend with the gp offset, so compensate @@ -4795,9 +5049,16 @@ class Mips_relocate_functions : public Relocate_functions val = Bits<32>::bit_select32(val, x, 0x7f); else val = Bits<32>::bit_select32(val, x, 0xffff); - elfcpp::Swap<32, big_endian>::writeval(wv, val); - mips_reloc_shuffle(view, r_type, false); - if (Bits<16>::has_overflow32(x)) + + if (calculate_only) + { + *calculated_value = x; + return This::STATUS_OKAY; + } + else + elfcpp::Swap<32, big_endian>::writeval(wv, val); + + if (check_overflow<16>(x) == This::STATUS_OVERFLOW) { gold_error(_("small-data section exceeds 64KB; lower small-data size " "limit (see option -G)")); @@ -4810,17 +5071,21 @@ class Mips_relocate_functions : public Relocate_functions static inline typename This::Status relgprel32(unsigned char* view, const Mips_relobj* object, const Symbol_value* psymval, Mips_address gp, - Mips_address addend_a, bool extract_addend, unsigned int r_type) + Mips_address addend_a, bool extract_addend, bool calculate_only, + Valtype* calculated_value) { - mips_reloc_unshuffle(view, r_type, false); Valtype32* wv = reinterpret_cast(view); Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv); - Valtype32 addend = extract_addend ? val : addend_a; + Valtype addend = extract_addend ? val : addend_a; // R_MIPS_GPREL32 relocations are defined for local symbols only. - Valtype32 x = psymval->value(object, addend) + object->gp_value() - gp; - elfcpp::Swap<32, big_endian>::writeval(wv, x); - mips_reloc_shuffle(view, r_type, false); + Valtype x = psymval->value(object, addend) + object->gp_value() - gp; + + if (calculate_only) + *calculated_value = x; + else + elfcpp::Swap<32, big_endian>::writeval(wv, x); + return This::STATUS_OKAY; } @@ -4830,18 +5095,22 @@ class Mips_relocate_functions : public Relocate_functions static inline typename This::Status tlsrelhi16(unsigned char* view, const Mips_relobj* object, const Symbol_value* psymval, Valtype32 tp_offset, - Mips_address addend_a, bool extract_addend, unsigned int r_type) + Mips_address addend_a, bool extract_addend, bool calculate_only, + Valtype* calculated_value) { - mips_reloc_unshuffle(view, r_type, false); Valtype32* wv = reinterpret_cast(view); Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv); - Valtype32 addend = extract_addend ? val & 0xffff : addend_a; + Valtype addend = extract_addend ? val & 0xffff : addend_a; // tls symbol values are relative to tls_segment()->vaddr() - Valtype32 x = ((psymval->value(object, addend) - tp_offset) + 0x8000) >> 16; + Valtype x = ((psymval->value(object, addend) - tp_offset) + 0x8000) >> 16; val = Bits<32>::bit_select32(val, x, 0xffff); - elfcpp::Swap<32, big_endian>::writeval(wv, val); - mips_reloc_shuffle(view, r_type, false); + + if (calculate_only) + *calculated_value = x; + else + elfcpp::Swap<32, big_endian>::writeval(wv, val); + return This::STATUS_OKAY; } @@ -4851,18 +5120,22 @@ class Mips_relocate_functions : public Relocate_functions static inline typename This::Status tlsrello16(unsigned char* view, const Mips_relobj* object, const Symbol_value* psymval, Valtype32 tp_offset, - Mips_address addend_a, bool extract_addend, unsigned int r_type) + Mips_address addend_a, bool extract_addend, bool calculate_only, + Valtype* calculated_value) { - mips_reloc_unshuffle(view, r_type, false); Valtype32* wv = reinterpret_cast(view); Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv); - Valtype32 addend = extract_addend ? val & 0xffff : addend_a; + Valtype addend = extract_addend ? val & 0xffff : addend_a; // tls symbol values are relative to tls_segment()->vaddr() - Valtype32 x = psymval->value(object, addend) - tp_offset; + Valtype x = psymval->value(object, addend) - tp_offset; val = Bits<32>::bit_select32(val, x, 0xffff); - elfcpp::Swap<32, big_endian>::writeval(wv, val); - mips_reloc_shuffle(view, r_type, false); + + if (calculate_only) + *calculated_value = x; + else + elfcpp::Swap<32, big_endian>::writeval(wv, val); + return This::STATUS_OKAY; } @@ -4871,17 +5144,21 @@ class Mips_relocate_functions : public Relocate_functions static inline typename This::Status tlsrel32(unsigned char* view, const Mips_relobj* object, const Symbol_value* psymval, Valtype32 tp_offset, - Mips_address addend_a, bool extract_addend, unsigned int r_type) + Mips_address addend_a, bool extract_addend, bool calculate_only, + Valtype* calculated_value) { - mips_reloc_unshuffle(view, r_type, false); Valtype32* wv = reinterpret_cast(view); Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv); - Valtype32 addend = extract_addend ? val : addend_a; + Valtype addend = extract_addend ? val : addend_a; // tls symbol values are relative to tls_segment()->vaddr() - Valtype32 x = psymval->value(object, addend) - tp_offset; - elfcpp::Swap<32, big_endian>::writeval(wv, x); - mips_reloc_shuffle(view, r_type, false); + Valtype x = psymval->value(object, addend) - tp_offset; + + if (calculate_only) + *calculated_value = x; + else + elfcpp::Swap<32, big_endian>::writeval(wv, x); + return This::STATUS_OKAY; } @@ -4889,18 +5166,47 @@ class Mips_relocate_functions : public Relocate_functions static inline typename This::Status relsub(unsigned char* view, const Mips_relobj* object, const Symbol_value* psymval, Mips_address addend_a, - bool extract_addend, unsigned int r_type) + bool extract_addend, bool calculate_only, Valtype* calculated_value) { - mips_reloc_unshuffle(view, r_type, false); - Valtype32* wv = reinterpret_cast(view); - Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv); - Valtype32 addend = extract_addend ? val : addend_a; + Valtype64* wv = reinterpret_cast(view); + Valtype64 addend = (extract_addend + ? elfcpp::Swap<64, big_endian>::readval(wv) + : addend_a); + + Valtype64 x = psymval->value(object, -addend); + if (calculate_only) + *calculated_value = x; + else + elfcpp::Swap<64, big_endian>::writeval(wv, x); - Valtype32 x = psymval->value(object, -addend); - elfcpp::Swap<32, big_endian>::writeval(wv, x); - mips_reloc_shuffle(view, r_type, false); return This::STATUS_OKAY; - } + } + + // R_MIPS_64: S + A + static inline typename This::Status + rel64(unsigned char* view, const Mips_relobj* object, + const Symbol_value* psymval, Mips_address addend_a, + bool extract_addend, bool calculate_only, Valtype* calculated_value, + bool apply_addend_only) + { + Valtype64* wv = reinterpret_cast(view); + Valtype64 addend = (extract_addend + ? elfcpp::Swap<64, big_endian>::readval(wv) + : addend_a); + + Valtype64 x = psymval->value(object, addend); + if (calculate_only) + *calculated_value = x; + else + { + if (apply_addend_only) + x = addend; + elfcpp::Swap<64, big_endian>::writeval(wv, x); + } + + return This::STATUS_OKAY; + } + }; template @@ -4920,12 +5226,13 @@ template void Mips_got_info::record_local_got_symbol( Mips_relobj* object, unsigned int symndx, - Mips_address addend, unsigned int r_type, unsigned int shndx) + Mips_address addend, unsigned int r_type, unsigned int shndx, + bool is_section_symbol) { Mips_got_entry* entry = new Mips_got_entry(object, symndx, addend, mips_elf_reloc_tls_type(r_type), - shndx); + shndx, is_section_symbol); this->record_got_entry(entry, object); } @@ -5105,13 +5412,20 @@ Mips_got_info::add_local_entries( if (entry->is_for_local_symbol() && !entry->is_tls_entry()) { got->add_local(entry->object(), entry->symndx(), - GOT_TYPE_STANDARD); + GOT_TYPE_STANDARD, entry->addend()); unsigned int got_offset = entry->object()->local_got_offset( - entry->symndx(), GOT_TYPE_STANDARD); + entry->symndx(), GOT_TYPE_STANDARD, entry->addend()); if (got->multi_got() && this->index_ > 0 && parameters->options().output_is_position_independent()) - target->rel_dyn_section(layout)->add_local(entry->object(), - entry->symndx(), elfcpp::R_MIPS_REL32, got, got_offset); + { + if (!entry->is_section_symbol()) + target->rel_dyn_section(layout)->add_local(entry->object(), + entry->symndx(), elfcpp::R_MIPS_REL32, got, got_offset); + else + target->rel_dyn_section(layout)->add_symbolless_local_addend( + entry->object(), entry->symndx(), elfcpp::R_MIPS_REL32, + got, got_offset); + } } } @@ -5309,9 +5623,10 @@ Mips_got_info::add_tls_entries( got->add_local_pair_with_rel(entry->object(), entry->symndx(), entry->shndx(), got_type, target->rel_dyn_section(layout), - r_type1); + r_type1, entry->addend()); unsigned int got_offset = - entry->object()->local_got_offset(entry->symndx(), got_type); + entry->object()->local_got_offset(entry->symndx(), got_type, + entry->addend()); got->add_static_reloc(got_offset + size/8, r_type2, entry->object(), entry->symndx()); } @@ -5321,7 +5636,8 @@ Mips_got_info::add_tls_entries( // the executable. unsigned int got_offset = got->add_constant(1); entry->object()->set_local_got_offset(entry->symndx(), got_type, - got_offset); + got_offset, + entry->addend()); got->add_constant(0); got->add_static_reloc(got_offset + size/8, r_type2, entry->object(), entry->symndx()); @@ -5334,12 +5650,15 @@ Mips_got_info::add_tls_entries( : elfcpp::R_MIPS_TLS_TPREL64); if (!parameters->doing_static_link()) got->add_local_with_rel(entry->object(), entry->symndx(), got_type, - target->rel_dyn_section(layout), r_type); + target->rel_dyn_section(layout), r_type, + entry->addend()); else { - got->add_local(entry->object(), entry->symndx(), got_type); + got->add_local(entry->object(), entry->symndx(), got_type, + entry->addend()); unsigned int got_offset = - entry->object()->local_got_offset(entry->symndx(), got_type); + entry->object()->local_got_offset(entry->symndx(), got_type, + entry->addend()); got->add_static_reloc(got_offset, r_type, entry->object(), entry->symndx()); } @@ -6081,7 +6400,90 @@ Mips_relobj::do_read_symbols(Read_symbols_data* sd) this->cprmask4_ = elfcpp::Swap::readval(view + 16); } - const char* name = pnames + shdr.get_sh_name(); + // In the 64-bit ABI, .MIPS.options section holds register information. + // A SHT_MIPS_OPTIONS section contains a series of options, each of which + // starts with this header: + // + // typedef struct + // { + // // Type of option. + // unsigned char kind[1]; + // // Size of option descriptor, including header. + // unsigned char size[1]; + // // Section index of affected section, or 0 for global option. + // unsigned char section[2]; + // // Information specific to this kind of option. + // unsigned char info[4]; + // }; + // + // For a SHT_MIPS_OPTIONS section, look for a ODK_REGINFO entry, and set + // the gp value based on what we find. We may see both SHT_MIPS_REGINFO + // and SHT_MIPS_OPTIONS/ODK_REGINFO; in that case, they should agree. + + if (shdr.get_sh_type() == elfcpp::SHT_MIPS_OPTIONS) + { + section_offset_type section_offset = shdr.get_sh_offset(); + section_size_type section_size = + convert_to_section_size_type(shdr.get_sh_size()); + const unsigned char* view = + this->get_view(section_offset, section_size, true, false); + const unsigned char* end = view + section_size; + + while (view + 8 <= end) + { + unsigned char kind = elfcpp::Swap<8, big_endian>::readval(view); + unsigned char sz = elfcpp::Swap<8, big_endian>::readval(view + 1); + if (sz < 8) + { + gold_error(_("%s: Warning: bad `%s' option size %u smaller " + "than its header"), + this->name().c_str(), + this->mips_elf_options_section_name(), sz); + break; + } + + if (this->is_n64() && kind == elfcpp::ODK_REGINFO) + { + // In the 64 bit ABI, an ODK_REGINFO option is the following + // structure. The info field of the options header is not + // used. + // + // typedef struct + // { + // // Mask of general purpose registers used. + // unsigned char ri_gprmask[4]; + // // Padding. + // unsigned char ri_pad[4]; + // // Mask of co-processor registers used. + // unsigned char ri_cprmask[4][4]; + // // GP register value for this object file. + // unsigned char ri_gp_value[8]; + // }; + + this->gp_ = elfcpp::Swap::readval(view + + 32); + } + else if (kind == elfcpp::ODK_REGINFO) + { + // In the 32 bit ABI, an ODK_REGINFO option is the following + // structure. The info field of the options header is not + // used. The same structure is used in .reginfo section. + // + // typedef struct + // { + // unsigned char ri_gprmask[4]; + // unsigned char ri_cprmask[4][4]; + // unsigned char ri_gp_value[4]; + // }; + + this->gp_ = elfcpp::Swap::readval(view + + 28); + } + view += sz; + } + } + + const char* name = pnames + shdr.get_sh_name(); this->section_is_mips16_fn_stub_[i] = is_prefix_of(".mips16.fn", name); this->section_is_mips16_call_stub_[i] = is_prefix_of(".mips16.call.", name); @@ -6413,7 +6815,7 @@ template const uint32_t Mips_output_data_plt::plt_entry[] = { 0x3c0f0000, // lui $15, %hi(.got.plt entry) - 0x8df90000, // l[wd] $25, %lo(.got.plt entry)($15) + 0x01f90000, // l[wd] $25, %lo(.got.plt entry)($15) 0x03200008, // jr $25 0x25f80000 // addiu $24, $15, %lo(.got.plt entry) }; @@ -7699,7 +8101,7 @@ Target_mips::gc_process_relocs( Layout* layout, Sized_relobj_file* object, unsigned int data_shndx, - unsigned int, + unsigned int sh_type, const unsigned char* prelocs, size_t reloc_count, Output_section* output_section, @@ -7708,21 +8110,45 @@ Target_mips::gc_process_relocs( const unsigned char* plocal_symbols) { typedef Target_mips Mips; - typedef Mips_classify_reloc - Classify_reloc; - gold::gc_process_relocs( - symtab, - layout, - this, - object, - data_shndx, - prelocs, - reloc_count, - output_section, - needs_special_offset_handling, - local_symbol_count, - plocal_symbols); + if (sh_type == elfcpp::SHT_REL) + { + typedef Mips_classify_reloc + Classify_reloc; + + gold::gc_process_relocs( + symtab, + layout, + this, + object, + data_shndx, + prelocs, + reloc_count, + output_section, + needs_special_offset_handling, + local_symbol_count, + plocal_symbols); + } + else if (sh_type == elfcpp::SHT_RELA) + { + typedef Mips_classify_reloc + Classify_reloc; + + gold::gc_process_relocs( + symtab, + layout, + this, + object, + data_shndx, + prelocs, + reloc_count, + output_section, + needs_special_offset_handling, + local_symbol_count, + plocal_symbols); + } + else + gold_unreachable(); } // Scan relocations for a section. @@ -7917,14 +8343,12 @@ Target_mips::mips_mach_extends(unsigned int base, template void Target_mips::merge_processor_specific_flags( - const std::string& name, elfcpp::Elf_Word in_flags, - unsigned char in_ei_class, bool dyn_obj) + const std::string& name, elfcpp::Elf_Word in_flags, bool dyn_obj) { // If flags are not set yet, just copy them. if (!this->are_processor_specific_flags_set()) { this->set_processor_specific_flags(in_flags); - this->ei_class_ = in_ei_class; this->mach_ = this->elf_mips_mach(in_flags); return; } @@ -8006,19 +8430,16 @@ Target_mips::merge_processor_specific_flags( old_flags &= (~(elfcpp::EF_MIPS_ARCH | elfcpp::EF_MIPS_MACH | elfcpp::EF_MIPS_32BITMODE)); - // Compare ABIs. The 64-bit ABI does not use EF_MIPS_ABI. But, it does set - // EI_CLASS differently from any 32-bit ABI. - if ((new_flags & elfcpp::EF_MIPS_ABI) != (old_flags & elfcpp::EF_MIPS_ABI) - || (in_ei_class != this->ei_class_)) + // Compare ABIs. + if ((new_flags & elfcpp::EF_MIPS_ABI) != (old_flags & elfcpp::EF_MIPS_ABI)) { // Only error if both are set (to different values). - if (((new_flags & elfcpp::EF_MIPS_ABI) + if ((new_flags & elfcpp::EF_MIPS_ABI) && (old_flags & elfcpp::EF_MIPS_ABI)) - || (in_ei_class != this->ei_class_)) gold_error(_("%s: ABI mismatch: linking %s module with " "previous %s modules"), name.c_str(), - this->elf_mips_abi_name(in_flags, in_ei_class), - this->elf_mips_abi_name(merged_flags, this->ei_class_)); + this->elf_mips_abi_name(in_flags), + this->elf_mips_abi_name(merged_flags)); new_flags &= ~elfcpp::EF_MIPS_ABI; old_flags &= ~elfcpp::EF_MIPS_ABI; @@ -8066,16 +8487,13 @@ Target_mips::do_adjust_elf_header( { gold_assert(len == elfcpp::Elf_sizes::ehdr_size); - elfcpp::Ehdr ehdr(view); - unsigned char e_ident[elfcpp::EI_NIDENT]; - memcpy(e_ident, ehdr.get_e_ident(), elfcpp::EI_NIDENT); - - e_ident[elfcpp::EI_CLASS] = this->ei_class_; + if (!this->entry_symbol_is_compressed_) + return; + elfcpp::Ehdr ehdr(view); elfcpp::Ehdr_write oehdr(view); - oehdr.put_e_ident(e_ident); - if (this->entry_symbol_is_compressed_) - oehdr.put_e_entry(ehdr.get_e_entry() + 1); + + oehdr.put_e_entry(ehdr.get_e_entry() + 1); } // do_make_elf_object to override the same function in the base class. @@ -8190,10 +8608,20 @@ Target_mips::do_finalize_sections(Layout* layout, elfcpp::Ehdr ehdr(pehdr); elfcpp::Elf_Word in_flags = ehdr.get_e_flags(); - unsigned char ei_class = ehdr.get_e_ident()[elfcpp::EI_CLASS]; + // If all input sections will be discarded, don't use this object + // file for merging processor specific flags. + bool should_merge_processor_specific_flags = false; + + for (unsigned int i = 1; i < relobj->shnum(); ++i) + if (relobj->output_section(i) != NULL) + { + should_merge_processor_specific_flags = true; + break; + } - this->merge_processor_specific_flags(relobj->name(), in_flags, - ei_class, false); + if (should_merge_processor_specific_flags) + this->merge_processor_specific_flags(relobj->name(), in_flags, + false); } } @@ -8211,10 +8639,8 @@ Target_mips::do_finalize_sections(Layout* layout, elfcpp::Ehdr ehdr(pehdr); elfcpp::Elf_Word in_flags = ehdr.get_e_flags(); - unsigned char ei_class = ehdr.get_e_ident()[elfcpp::EI_CLASS]; - this->merge_processor_specific_flags(dynobj->name(), in_flags, ei_class, - true); + this->merge_processor_specific_flags(dynobj->name(), in_flags, true); } // Merge .reginfo contents of input objects. @@ -8493,6 +8919,7 @@ mips_get_size_for_reloc(unsigned int r_type, Relobj* object) case elfcpp::R_MIPS_PC32: case elfcpp::R_MIPS_GPREL32: case elfcpp::R_MIPS_JALR: + case elfcpp::R_MIPS_EH: return 4; case elfcpp::R_MIPS_16: @@ -8558,25 +8985,48 @@ Target_mips::scan_relocatable_relocs( const unsigned char* plocal_symbols, Relocatable_relocs* rr) { - typedef Mips_classify_reloc - Classify_reloc; - typedef Mips_scan_relocatable_relocs - Scan_relocatable_relocs; - - gold_assert(sh_type == elfcpp::SHT_REL); - - gold::scan_relocatable_relocs( - symtab, - layout, - object, - data_shndx, - prelocs, - reloc_count, - output_section, - needs_special_offset_handling, - local_symbol_count, - plocal_symbols, - rr); + if (sh_type == elfcpp::SHT_REL) + { + typedef Mips_classify_reloc + Classify_reloc; + typedef Mips_scan_relocatable_relocs + Scan_relocatable_relocs; + + gold::scan_relocatable_relocs( + symtab, + layout, + object, + data_shndx, + prelocs, + reloc_count, + output_section, + needs_special_offset_handling, + local_symbol_count, + plocal_symbols, + rr); + } + else if (sh_type == elfcpp::SHT_RELA) + { + typedef Mips_classify_reloc + Classify_reloc; + typedef Mips_scan_relocatable_relocs + Scan_relocatable_relocs; + + gold::scan_relocatable_relocs( + symtab, + layout, + object, + data_shndx, + prelocs, + reloc_count, + output_section, + needs_special_offset_handling, + local_symbol_count, + plocal_symbols, + rr); + } + else + gold_unreachable(); } // Scan the relocs for --emit-relocs. @@ -8597,25 +9047,48 @@ Target_mips::emit_relocs_scan( const unsigned char* plocal_syms, Relocatable_relocs* rr) { - typedef Mips_classify_reloc - Classify_reloc; - typedef gold::Default_emit_relocs_strategy - Emit_relocs_strategy; - - gold_assert(sh_type == elfcpp::SHT_REL); - - gold::scan_relocatable_relocs( - symtab, - layout, - object, - data_shndx, - prelocs, - reloc_count, - output_section, - needs_special_offset_handling, - local_symbol_count, - plocal_syms, - rr); + if (sh_type == elfcpp::SHT_REL) + { + typedef Mips_classify_reloc + Classify_reloc; + typedef gold::Default_emit_relocs_strategy + Emit_relocs_strategy; + + gold::scan_relocatable_relocs( + symtab, + layout, + object, + data_shndx, + prelocs, + reloc_count, + output_section, + needs_special_offset_handling, + local_symbol_count, + plocal_syms, + rr); + } + else if (sh_type == elfcpp::SHT_RELA) + { + typedef Mips_classify_reloc + Classify_reloc; + typedef gold::Default_emit_relocs_strategy + Emit_relocs_strategy; + + gold::scan_relocatable_relocs( + symtab, + layout, + object, + data_shndx, + prelocs, + reloc_count, + output_section, + needs_special_offset_handling, + local_symbol_count, + plocal_syms, + rr); + } + else + gold_unreachable(); } // Emit relocations for a section. @@ -8636,22 +9109,42 @@ Target_mips::relocate_relocs( unsigned char* reloc_view, section_size_type reloc_view_size) { - typedef Mips_classify_reloc - Classify_reloc; - - gold_assert(sh_type == elfcpp::SHT_REL); - - gold::relocate_relocs( - relinfo, - prelocs, - reloc_count, - output_section, - offset_in_output_section, - view, - view_address, - view_size, - reloc_view, - reloc_view_size); + if (sh_type == elfcpp::SHT_REL) + { + typedef Mips_classify_reloc + Classify_reloc; + + gold::relocate_relocs( + relinfo, + prelocs, + reloc_count, + output_section, + offset_in_output_section, + view, + view_address, + view_size, + reloc_view, + reloc_view_size); + } + else if (sh_type == elfcpp::SHT_RELA) + { + typedef Mips_classify_reloc + Classify_reloc; + + gold::relocate_relocs( + relinfo, + prelocs, + reloc_count, + output_section, + offset_in_output_section, + view, + view_address, + view_size, + reloc_view, + reloc_view_size); + } + else + gold_unreachable(); } // Perform target-specific processing in a relocatable link. This is @@ -8749,7 +9242,7 @@ Target_mips::relocate_special_relocatable( // file to refer to that same address. This adjustment to // the addend is the same calculation we use for a simple // absolute relocation for the input section symbol. - + Valtype calculated_value = 0; const Symbol_value* psymval = object->local_symbol(r_sym); unsigned char* paddend = view + offset; @@ -8759,7 +9252,8 @@ Target_mips::relocate_special_relocatable( case elfcpp::R_MIPS_26: reloc_status = Reloc_funcs::rel26(paddend, object, psymval, offset_in_output_section, true, 0, sh_type == elfcpp::SHT_REL, NULL, - false /*TODO(sasa): cross mode jump*/, r_type, this->jal_to_bal()); + false /*TODO(sasa): cross mode jump*/, r_type, this->jal_to_bal(), + false, &calculated_value); break; default: @@ -8892,6 +9386,7 @@ Target_mips::Scan::local( case elfcpp::R_MICROMIPS_TLS_GOTTPREL: case elfcpp::R_MICROMIPS_TLS_GD: case elfcpp::R_MICROMIPS_TLS_LDM: + case elfcpp::R_MIPS_EH: // We need a GOT section. target->got_section(symtab, layout); break; @@ -8902,7 +9397,8 @@ Target_mips::Scan::local( if (call_lo16_reloc(r_type) || got_lo16_reloc(r_type) - || got_disp_reloc(r_type)) + || got_disp_reloc(r_type) + || eh_reloc(r_type)) { // We may need a local GOT entry for this relocation. We // don't count R_MIPS_GOT_PAGE because we can estimate the @@ -8913,7 +9409,9 @@ Target_mips::Scan::local( // R_MIPS_GOT_LO16 or R_MIPS_CALL_LO16. Mips_output_data_got* got = target->got_section(symtab, layout); - got->record_local_got_symbol(mips_obj, r_sym, r_addend, r_type, -1U); + bool is_section_symbol = lsym.get_st_type() == elfcpp::STT_SECTION; + got->record_local_got_symbol(mips_obj, r_sym, r_addend, r_type, -1U, + is_section_symbol); } switch (r_type) @@ -9046,6 +9544,8 @@ Target_mips::Scan::local( // If building a shared library (or a position-independent // executable), we need to create a dynamic relocation for // this location. + if (is_readonly_section(output_section)) + break; Reloc_section* rel_dyn = target->rel_dyn_section(layout); rel_dyn->add_symbolless_local_addend(object, r_sym, elfcpp::R_MIPS_REL32, @@ -9090,7 +9590,7 @@ Target_mips::Scan::local( break; } got->record_local_got_symbol(mips_obj, r_sym, r_addend, r_type, - shndx); + shndx, false); } else { @@ -9107,7 +9607,7 @@ Target_mips::Scan::local( // We always record LDM symbols as local with index 0. target->got_section()->record_local_got_symbol(mips_obj, 0, r_addend, r_type, - -1U); + -1U, false); } else { @@ -9125,7 +9625,7 @@ Target_mips::Scan::local( Mips_output_data_got* got = target->got_section(symtab, layout); got->record_local_got_symbol(mips_obj, r_sym, r_addend, r_type, - -1U); + -1U, false); } else { @@ -9346,6 +9846,7 @@ Target_mips::Scan::global( case elfcpp::R_MICROMIPS_TLS_GOTTPREL: case elfcpp::R_MICROMIPS_TLS_GD: case elfcpp::R_MICROMIPS_TLS_LDM: + case elfcpp::R_MIPS_EH: // We need a GOT section. target->got_section(symtab, layout); break; @@ -9372,14 +9873,14 @@ Target_mips::Scan::global( case elfcpp::R_MIPS_32: case elfcpp::R_MIPS_REL32: case elfcpp::R_MIPS_64: - if (parameters->options().shared() - || strcmp(gsym->name(), "__gnu_local_gp") != 0) + if ((parameters->options().shared() + || (strcmp(gsym->name(), "__gnu_local_gp") != 0 + && (!is_readonly_section(output_section) + || mips_obj->is_pic()))) + && (output_section->flags() & elfcpp::SHF_ALLOC) != 0) { if (r_type != elfcpp::R_MIPS_REL32) - { - static_reloc = true; - mips_sym->set_pointer_equality_needed(); - } + mips_sym->set_pointer_equality_needed(); can_make_dynamic = true; break; } @@ -9476,8 +9977,8 @@ Target_mips::Scan::global( { if (gsym->may_need_copy_reloc()) { - target->copy_reloc(symtab, layout, object, - data_shndx, output_section, gsym, *rel); + target->copy_reloc(symtab, layout, object, data_shndx, + output_section, gsym, r_type, r_offset); } else if (can_make_dynamic) { @@ -9514,6 +10015,7 @@ Target_mips::Scan::global( case elfcpp::R_MICROMIPS_GOT_LO16: case elfcpp::R_MIPS_GOT_DISP: case elfcpp::R_MICROMIPS_GOT_DISP: + case elfcpp::R_MIPS_EH: { // The symbol requires a GOT entry. Mips_output_data_got* got = @@ -9601,7 +10103,7 @@ Target_mips::Scan::global( // We always record LDM symbols as local with index 0. target->got_section()->record_local_got_symbol(mips_obj, 0, r_addend, r_type, - -1U); + -1U, false); } else { @@ -9735,11 +10237,14 @@ Target_mips::Scan::global( gsym); } -// Return whether a R_MIPS_32 relocation needs to be applied. +// Return whether a R_MIPS_32/R_MIPS64 relocation needs to be applied. +// In cases where Scan::local() or Scan::global() has created +// a dynamic relocation, the addend of the relocation is carried +// in the data, and we must not apply the static relocation. template inline bool -Target_mips::Relocate::should_apply_r_mips_32_reloc( +Target_mips::Relocate::should_apply_static_reloc( const Mips_symbol* gsym, unsigned int r_type, Output_section* output_section, @@ -9804,6 +10309,9 @@ Target_mips::Relocate::relocate( Mips_address r_offset; unsigned int r_sym; unsigned int r_type; + unsigned int r_type2; + unsigned int r_type3; + unsigned char r_ssym; typename elfcpp::Elf_types::Elf_Swxword r_addend; if (rel_type == elfcpp::SHT_RELA) @@ -9814,17 +10322,25 @@ Target_mips::Relocate::relocate( get_r_sym(&rela); r_type = Mips_classify_reloc:: get_r_type(&rela); + r_type2 = Mips_classify_reloc:: + get_r_type2(&rela); + r_type3 = Mips_classify_reloc:: + get_r_type3(&rela); + r_ssym = Mips_classify_reloc:: + get_r_ssym(&rela); r_addend = rela.get_r_addend(); } else { - const Reltype rel(preloc); r_offset = rel.get_r_offset(); r_sym = Mips_classify_reloc:: get_r_sym(&rel); r_type = Mips_classify_reloc:: get_r_type(&rel); + r_ssym = 0; + r_type2 = 0; + r_type3 = 0; r_addend = 0; } @@ -10088,320 +10604,479 @@ Target_mips::Relocate::relocate( unsigned int got_offset = 0; int gp_offset = 0; - bool update_got_entry = false; + bool calculate_only = false; + Valtype calculated_value = 0; bool extract_addend = rel_type == elfcpp::SHT_REL; - switch (r_type) + unsigned int r_types[3] = { r_type, r_type2, r_type3 }; + + Reloc_funcs::mips_reloc_unshuffle(view, r_type, false); + + // For Mips64 N64 ABI, there may be up to three operations specified per + // record, by the fields r_type, r_type2, and r_type3. The first operation + // takes its addend from the relocation record. Each subsequent operation + // takes as its addend the result of the previous operation. + // The first operation in a record which references a symbol uses the symbol + // implied by r_sym. The next operation in a record which references a symbol + // uses the special symbol value given by the r_ssym field. A third operation + // in a record which references a symbol will assume a NULL symbol, + // i.e. value zero. + + // TODO(Vladimir) + // Check if a record references to a symbol. + for (unsigned int i = 0; i < 3; ++i) { - case elfcpp::R_MIPS_NONE: - break; - case elfcpp::R_MIPS_16: - reloc_status = Reloc_funcs::rel16(view, object, psymval, r_addend, - extract_addend, r_type); - break; + if (r_types[i] == elfcpp::R_MIPS_NONE) + break; - case elfcpp::R_MIPS_32: - if (should_apply_r_mips_32_reloc(mips_sym, r_type, output_section, - target)) - reloc_status = Reloc_funcs::rel32(view, object, psymval, r_addend, - extract_addend, r_type); - if (mips_sym != NULL - && (mips_sym->is_mips16() || mips_sym->is_micromips()) - && mips_sym->global_got_area() == GGA_RELOC_ONLY) + // TODO(Vladimir) + // Check if the next relocation is for the same instruction. + calculate_only = i == 2 ? false + : r_types[i+1] != elfcpp::R_MIPS_NONE; + + if (object->is_n64()) { - // If mips_sym->has_mips16_fn_stub() is false, symbol value is - // already updated by adding +1. - if (mips_sym->has_mips16_fn_stub()) + if (i == 1) { - gold_assert(mips_sym->need_fn_stub()); - Mips16_stub_section* fn_stub = - mips_sym->template get_mips16_fn_stub(); - - symval.set_output_value(fn_stub->output_address()); + // Handle special symbol for r_type2 relocation type. + switch (r_ssym) + { + case RSS_UNDEF: + symval.set_output_value(0); + break; + case RSS_GP: + symval.set_output_value(target->gp_value()); + break; + case RSS_GP0: + symval.set_output_value(object->gp_value()); + break; + case RSS_LOC: + symval.set_output_value(address); + break; + default: + gold_unreachable(); + } psymval = &symval; } - got_offset = mips_sym->global_gotoffset(); - update_got_entry = true; + else if (i == 2) + { + // For r_type3 symbol value is 0. + symval.set_output_value(0); + } } - break; - case elfcpp::R_MIPS_REL32: - gold_unreachable(); + bool update_got_entry = false; + switch (r_types[i]) + { + case elfcpp::R_MIPS_NONE: + break; + case elfcpp::R_MIPS_16: + reloc_status = Reloc_funcs::rel16(view, object, psymval, r_addend, + extract_addend, calculate_only, + &calculated_value); + break; - case elfcpp::R_MIPS_PC32: - reloc_status = Reloc_funcs::relpc32(view, object, psymval, address, - r_addend, extract_addend, r_type); - break; + case elfcpp::R_MIPS_32: + if (should_apply_static_reloc(mips_sym, r_types[i], output_section, + target)) + reloc_status = Reloc_funcs::rel32(view, object, psymval, r_addend, + extract_addend, calculate_only, + &calculated_value); + if (mips_sym != NULL + && (mips_sym->is_mips16() || mips_sym->is_micromips()) + && mips_sym->global_got_area() == GGA_RELOC_ONLY) + { + // If mips_sym->has_mips16_fn_stub() is false, symbol value is + // already updated by adding +1. + if (mips_sym->has_mips16_fn_stub()) + { + gold_assert(mips_sym->need_fn_stub()); + Mips16_stub_section* fn_stub = + mips_sym->template get_mips16_fn_stub(); - case elfcpp::R_MIPS16_26: - // The calculation for R_MIPS16_26 is just the same as for an - // R_MIPS_26. It's only the storage of the relocated field into - // the output file that's different. So, we just fall through to the - // R_MIPS_26 case here. - case elfcpp::R_MIPS_26: - case elfcpp::R_MICROMIPS_26_S1: - reloc_status = Reloc_funcs::rel26(view, object, psymval, address, - gsym == NULL, r_addend, extract_addend, gsym, cross_mode_jump, r_type, - target->jal_to_bal()); - break; + symval.set_output_value(fn_stub->output_address()); + psymval = &symval; + } + got_offset = mips_sym->global_gotoffset(); + update_got_entry = true; + } + break; - case elfcpp::R_MIPS_HI16: - case elfcpp::R_MIPS16_HI16: - case elfcpp::R_MICROMIPS_HI16: - reloc_status = Reloc_funcs::relhi16(view, object, psymval, r_addend, - address, gp_disp, r_type, r_sym, - extract_addend); - break; + case elfcpp::R_MIPS_64: + if (should_apply_static_reloc(mips_sym, r_types[i], output_section, + target)) + reloc_status = Reloc_funcs::rel64(view, object, psymval, r_addend, + extract_addend, calculate_only, + &calculated_value, false); + else if (target->is_output_n64() && r_addend != 0) + // Only apply the addend. The static relocation was RELA, but the + // dynamic relocation is REL, so we need to apply the addend. + reloc_status = Reloc_funcs::rel64(view, object, psymval, r_addend, + extract_addend, calculate_only, + &calculated_value, true); + break; + case elfcpp::R_MIPS_REL32: + gold_unreachable(); - case elfcpp::R_MIPS_LO16: - case elfcpp::R_MIPS16_LO16: - case elfcpp::R_MICROMIPS_LO16: - case elfcpp::R_MICROMIPS_HI0_LO16: - reloc_status = Reloc_funcs::rello16(target, view, object, psymval, - r_addend, extract_addend, address, - gp_disp, r_type, r_sym); - break; + case elfcpp::R_MIPS_PC32: + reloc_status = Reloc_funcs::relpc32(view, object, psymval, address, + r_addend, extract_addend, + calculate_only, + &calculated_value); + break; - case elfcpp::R_MIPS_LITERAL: - case elfcpp::R_MICROMIPS_LITERAL: - // Because we don't merge literal sections, we can handle this - // just like R_MIPS_GPREL16. In the long run, we should merge - // shared literals, and then we will need to additional work - // here. + case elfcpp::R_MIPS16_26: + // The calculation for R_MIPS16_26 is just the same as for an + // R_MIPS_26. It's only the storage of the relocated field into + // the output file that's different. So, we just fall through to the + // R_MIPS_26 case here. + case elfcpp::R_MIPS_26: + case elfcpp::R_MICROMIPS_26_S1: + reloc_status = Reloc_funcs::rel26(view, object, psymval, address, + gsym == NULL, r_addend, extract_addend, gsym, cross_mode_jump, + r_types[i], target->jal_to_bal(), calculate_only, + &calculated_value); + break; - // Fall through. + case elfcpp::R_MIPS_HI16: + case elfcpp::R_MIPS16_HI16: + case elfcpp::R_MICROMIPS_HI16: + if (rel_type == elfcpp::SHT_RELA) + reloc_status = Reloc_funcs::do_relhi16(view, object, psymval, + r_addend, address, + gp_disp, r_types[i], + extract_addend, 0, + target, calculate_only, + &calculated_value); + else if (rel_type == elfcpp::SHT_REL) + reloc_status = Reloc_funcs::relhi16(view, object, psymval, r_addend, + address, gp_disp, r_types[i], + r_sym, extract_addend); + else + gold_unreachable(); + break; - case elfcpp::R_MIPS_GPREL16: - case elfcpp::R_MIPS16_GPREL: - case elfcpp::R_MICROMIPS_GPREL7_S2: - case elfcpp::R_MICROMIPS_GPREL16: - reloc_status = Reloc_funcs::relgprel(view, object, psymval, - target->adjusted_gp_value(object), - r_addend, extract_addend, - gsym == NULL, r_type); - break; + case elfcpp::R_MIPS_LO16: + case elfcpp::R_MIPS16_LO16: + case elfcpp::R_MICROMIPS_LO16: + case elfcpp::R_MICROMIPS_HI0_LO16: + reloc_status = Reloc_funcs::rello16(target, view, object, psymval, + r_addend, extract_addend, address, + gp_disp, r_types[i], r_sym, + rel_type, calculate_only, + &calculated_value); + break; - case elfcpp::R_MIPS_PC16: - reloc_status = Reloc_funcs::relpc16(view, object, psymval, address, - r_addend, extract_addend, r_type); - break; - case elfcpp::R_MICROMIPS_PC7_S1: - reloc_status = Reloc_funcs::relmicromips_pc7_s1(view, object, psymval, - address, r_addend, - extract_addend, r_type); - break; - case elfcpp::R_MICROMIPS_PC10_S1: - reloc_status = Reloc_funcs::relmicromips_pc10_s1(view, object, psymval, - address, r_addend, - extract_addend, r_type); - break; - case elfcpp::R_MICROMIPS_PC16_S1: - reloc_status = Reloc_funcs::relmicromips_pc16_s1(view, object, psymval, - address, r_addend, - extract_addend, r_type); - break; - case elfcpp::R_MIPS_GPREL32: - reloc_status = Reloc_funcs::relgprel32(view, object, psymval, - target->adjusted_gp_value(object), - r_addend, extract_addend, r_type); - break; - case elfcpp::R_MIPS_GOT_HI16: - case elfcpp::R_MIPS_CALL_HI16: - case elfcpp::R_MICROMIPS_GOT_HI16: - case elfcpp::R_MICROMIPS_CALL_HI16: - if (gsym != NULL) - got_offset = target->got_section()->got_offset(gsym, GOT_TYPE_STANDARD, - object); - else - got_offset = target->got_section()->got_offset(r_sym, GOT_TYPE_STANDARD, - object); - gp_offset = target->got_section()->gp_offset(got_offset, object); - reloc_status = Reloc_funcs::relgot_hi16(view, gp_offset, r_type); - update_got_entry = changed_symbol_value; - break; + case elfcpp::R_MIPS_LITERAL: + case elfcpp::R_MICROMIPS_LITERAL: + // Because we don't merge literal sections, we can handle this + // just like R_MIPS_GPREL16. In the long run, we should merge + // shared literals, and then we will need to additional work + // here. - case elfcpp::R_MIPS_GOT_LO16: - case elfcpp::R_MIPS_CALL_LO16: - case elfcpp::R_MICROMIPS_GOT_LO16: - case elfcpp::R_MICROMIPS_CALL_LO16: - if (gsym != NULL) - got_offset = target->got_section()->got_offset(gsym, GOT_TYPE_STANDARD, - object); - else - got_offset = target->got_section()->got_offset(r_sym, GOT_TYPE_STANDARD, - object); - gp_offset = target->got_section()->gp_offset(got_offset, object); - reloc_status = Reloc_funcs::relgot_lo16(view, gp_offset, r_type); - update_got_entry = changed_symbol_value; - break; + // Fall through. - case elfcpp::R_MIPS_GOT_DISP: - case elfcpp::R_MICROMIPS_GOT_DISP: - if (gsym != NULL) - got_offset = target->got_section()->got_offset(gsym, GOT_TYPE_STANDARD, - object); - else - got_offset = target->got_section()->got_offset(r_sym, GOT_TYPE_STANDARD, - object); - gp_offset = target->got_section()->gp_offset(got_offset, object); - reloc_status = Reloc_funcs::relgot(view, gp_offset, r_type); - break; + case elfcpp::R_MIPS_GPREL16: + case elfcpp::R_MIPS16_GPREL: + case elfcpp::R_MICROMIPS_GPREL7_S2: + case elfcpp::R_MICROMIPS_GPREL16: + reloc_status = Reloc_funcs::relgprel(view, object, psymval, + target->adjusted_gp_value(object), + r_addend, extract_addend, + gsym == NULL, r_types[i], + calculate_only, &calculated_value); + break; - case elfcpp::R_MIPS_CALL16: - case elfcpp::R_MIPS16_CALL16: - case elfcpp::R_MICROMIPS_CALL16: - gold_assert(gsym != NULL); - got_offset = target->got_section()->got_offset(gsym, GOT_TYPE_STANDARD, - object); - gp_offset = target->got_section()->gp_offset(got_offset, object); - reloc_status = Reloc_funcs::relgot(view, gp_offset, r_type); - // TODO(sasa): We should also initialize update_got_entry in other places - // where relgot is called. - update_got_entry = changed_symbol_value; - break; + case elfcpp::R_MIPS_PC16: + reloc_status = Reloc_funcs::relpc16(view, object, psymval, address, + r_addend, extract_addend, + calculate_only, + &calculated_value); + break; + case elfcpp::R_MICROMIPS_PC7_S1: + reloc_status = Reloc_funcs::relmicromips_pc7_s1(view, object, psymval, + address, r_addend, + extract_addend, + calculate_only, + &calculated_value); + break; + case elfcpp::R_MICROMIPS_PC10_S1: + reloc_status = Reloc_funcs::relmicromips_pc10_s1(view, object, + psymval, address, + r_addend, extract_addend, + calculate_only, + &calculated_value); + break; + case elfcpp::R_MICROMIPS_PC16_S1: + reloc_status = Reloc_funcs::relmicromips_pc16_s1(view, object, + psymval, address, + r_addend, extract_addend, + calculate_only, + &calculated_value); + break; + case elfcpp::R_MIPS_GPREL32: + reloc_status = Reloc_funcs::relgprel32(view, object, psymval, + target->adjusted_gp_value(object), + r_addend, extract_addend, + calculate_only, + &calculated_value); + break; + case elfcpp::R_MIPS_GOT_HI16: + case elfcpp::R_MIPS_CALL_HI16: + case elfcpp::R_MICROMIPS_GOT_HI16: + case elfcpp::R_MICROMIPS_CALL_HI16: + if (gsym != NULL) + got_offset = target->got_section()->got_offset(gsym, + GOT_TYPE_STANDARD, + object); + else + got_offset = target->got_section()->got_offset(r_sym, + GOT_TYPE_STANDARD, + object, r_addend); + gp_offset = target->got_section()->gp_offset(got_offset, object); + reloc_status = Reloc_funcs::relgot_hi16(view, gp_offset, + calculate_only, + &calculated_value); + update_got_entry = changed_symbol_value; + break; - case elfcpp::R_MIPS_GOT16: - case elfcpp::R_MIPS16_GOT16: - case elfcpp::R_MICROMIPS_GOT16: - if (gsym != NULL) - { + case elfcpp::R_MIPS_GOT_LO16: + case elfcpp::R_MIPS_CALL_LO16: + case elfcpp::R_MICROMIPS_GOT_LO16: + case elfcpp::R_MICROMIPS_CALL_LO16: + if (gsym != NULL) + got_offset = target->got_section()->got_offset(gsym, + GOT_TYPE_STANDARD, + object); + else + got_offset = target->got_section()->got_offset(r_sym, + GOT_TYPE_STANDARD, + object, r_addend); + gp_offset = target->got_section()->gp_offset(got_offset, object); + reloc_status = Reloc_funcs::relgot_lo16(view, gp_offset, + calculate_only, + &calculated_value); + update_got_entry = changed_symbol_value; + break; + + case elfcpp::R_MIPS_GOT_DISP: + case elfcpp::R_MICROMIPS_GOT_DISP: + case elfcpp::R_MIPS_EH: + if (gsym != NULL) + got_offset = target->got_section()->got_offset(gsym, + GOT_TYPE_STANDARD, + object); + else + got_offset = target->got_section()->got_offset(r_sym, + GOT_TYPE_STANDARD, + object, r_addend); + gp_offset = target->got_section()->gp_offset(got_offset, object); + if (eh_reloc(r_types[i])) + reloc_status = Reloc_funcs::releh(view, gp_offset, + calculate_only, + &calculated_value); + else + reloc_status = Reloc_funcs::relgot(view, gp_offset, + calculate_only, + &calculated_value); + break; + case elfcpp::R_MIPS_CALL16: + case elfcpp::R_MIPS16_CALL16: + case elfcpp::R_MICROMIPS_CALL16: + gold_assert(gsym != NULL); got_offset = target->got_section()->got_offset(gsym, GOT_TYPE_STANDARD, object); gp_offset = target->got_section()->gp_offset(got_offset, object); - reloc_status = Reloc_funcs::relgot(view, gp_offset, r_type); - } - else - reloc_status = Reloc_funcs::relgot16_local(view, object, psymval, - r_addend, extract_addend, - r_type, r_sym); - update_got_entry = changed_symbol_value; - break; + reloc_status = Reloc_funcs::relgot(view, gp_offset, + calculate_only, &calculated_value); + // TODO(sasa): We should also initialize update_got_entry + // in other place swhere relgot is called. + update_got_entry = changed_symbol_value; + break; - case elfcpp::R_MIPS_TLS_GD: - case elfcpp::R_MIPS16_TLS_GD: - case elfcpp::R_MICROMIPS_TLS_GD: - if (gsym != NULL) - got_offset = target->got_section()->got_offset(gsym, GOT_TYPE_TLS_PAIR, - object); - else - got_offset = target->got_section()->got_offset(r_sym, GOT_TYPE_TLS_PAIR, - object); - gp_offset = target->got_section()->gp_offset(got_offset, object); - reloc_status = Reloc_funcs::relgot(view, gp_offset, r_type); - break; + case elfcpp::R_MIPS_GOT16: + case elfcpp::R_MIPS16_GOT16: + case elfcpp::R_MICROMIPS_GOT16: + if (gsym != NULL) + { + got_offset = target->got_section()->got_offset(gsym, + GOT_TYPE_STANDARD, + object); + gp_offset = target->got_section()->gp_offset(got_offset, object); + reloc_status = Reloc_funcs::relgot(view, gp_offset, + calculate_only, + &calculated_value); + } + else + { + if (rel_type == elfcpp::SHT_RELA) + reloc_status = Reloc_funcs::do_relgot16_local(view, object, + psymval, r_addend, + extract_addend, 0, + target, + calculate_only, + &calculated_value); + else if (rel_type == elfcpp::SHT_REL) + reloc_status = Reloc_funcs::relgot16_local(view, object, + psymval, r_addend, + extract_addend, + r_types[i], r_sym); + else + gold_unreachable(); + } + update_got_entry = changed_symbol_value; + break; - case elfcpp::R_MIPS_TLS_GOTTPREL: - case elfcpp::R_MIPS16_TLS_GOTTPREL: - case elfcpp::R_MICROMIPS_TLS_GOTTPREL: - if (gsym != NULL) - got_offset = target->got_section()->got_offset(gsym, - GOT_TYPE_TLS_OFFSET, - object); - else - got_offset = target->got_section()->got_offset(r_sym, - GOT_TYPE_TLS_OFFSET, - object); - gp_offset = target->got_section()->gp_offset(got_offset, object); - reloc_status = Reloc_funcs::relgot(view, gp_offset, r_type); - break; + case elfcpp::R_MIPS_TLS_GD: + case elfcpp::R_MIPS16_TLS_GD: + case elfcpp::R_MICROMIPS_TLS_GD: + if (gsym != NULL) + got_offset = target->got_section()->got_offset(gsym, + GOT_TYPE_TLS_PAIR, + object); + else + got_offset = target->got_section()->got_offset(r_sym, + GOT_TYPE_TLS_PAIR, + object, r_addend); + gp_offset = target->got_section()->gp_offset(got_offset, object); + reloc_status = Reloc_funcs::relgot(view, gp_offset, calculate_only, + &calculated_value); + break; - case elfcpp::R_MIPS_TLS_LDM: - case elfcpp::R_MIPS16_TLS_LDM: - case elfcpp::R_MICROMIPS_TLS_LDM: - // Relocate the field with the offset of the GOT entry for - // the module index. - got_offset = target->got_section()->tls_ldm_offset(object); - gp_offset = target->got_section()->gp_offset(got_offset, object); - reloc_status = Reloc_funcs::relgot(view, gp_offset, r_type); - break; + case elfcpp::R_MIPS_TLS_GOTTPREL: + case elfcpp::R_MIPS16_TLS_GOTTPREL: + case elfcpp::R_MICROMIPS_TLS_GOTTPREL: + if (gsym != NULL) + got_offset = target->got_section()->got_offset(gsym, + GOT_TYPE_TLS_OFFSET, + object); + else + got_offset = target->got_section()->got_offset(r_sym, + GOT_TYPE_TLS_OFFSET, + object, r_addend); + gp_offset = target->got_section()->gp_offset(got_offset, object); + reloc_status = Reloc_funcs::relgot(view, gp_offset, calculate_only, + &calculated_value); + break; - case elfcpp::R_MIPS_GOT_PAGE: - case elfcpp::R_MICROMIPS_GOT_PAGE: - reloc_status = Reloc_funcs::relgotpage(target, view, object, psymval, - r_addend, extract_addend, r_type); - break; + case elfcpp::R_MIPS_TLS_LDM: + case elfcpp::R_MIPS16_TLS_LDM: + case elfcpp::R_MICROMIPS_TLS_LDM: + // Relocate the field with the offset of the GOT entry for + // the module index. + got_offset = target->got_section()->tls_ldm_offset(object); + gp_offset = target->got_section()->gp_offset(got_offset, object); + reloc_status = Reloc_funcs::relgot(view, gp_offset, calculate_only, + &calculated_value); + break; - case elfcpp::R_MIPS_GOT_OFST: - case elfcpp::R_MICROMIPS_GOT_OFST: - reloc_status = Reloc_funcs::relgotofst(target, view, object, psymval, - r_addend, extract_addend, local, - r_type); - break; + case elfcpp::R_MIPS_GOT_PAGE: + case elfcpp::R_MICROMIPS_GOT_PAGE: + reloc_status = Reloc_funcs::relgotpage(target, view, object, psymval, + r_addend, extract_addend, + calculate_only, + &calculated_value); + break; - case elfcpp::R_MIPS_JALR: - case elfcpp::R_MICROMIPS_JALR: - // This relocation is only a hint. In some cases, we optimize - // it into a bal instruction. But we don't try to optimize - // when the symbol does not resolve locally. - if (gsym == NULL || symbol_calls_local(gsym, gsym->has_dynsym_index())) - reloc_status = Reloc_funcs::reljalr(view, object, psymval, address, - r_addend, extract_addend, - cross_mode_jump, r_type, - target->jalr_to_bal(), - target->jr_to_b()); - break; + case elfcpp::R_MIPS_GOT_OFST: + case elfcpp::R_MICROMIPS_GOT_OFST: + reloc_status = Reloc_funcs::relgotofst(target, view, object, psymval, + r_addend, extract_addend, + local, calculate_only, + &calculated_value); + break; - case elfcpp::R_MIPS_TLS_DTPREL_HI16: - case elfcpp::R_MIPS16_TLS_DTPREL_HI16: - case elfcpp::R_MICROMIPS_TLS_DTPREL_HI16: - reloc_status = Reloc_funcs::tlsrelhi16(view, object, psymval, - elfcpp::DTP_OFFSET, r_addend, - extract_addend, r_type); - break; - case elfcpp::R_MIPS_TLS_DTPREL_LO16: - case elfcpp::R_MIPS16_TLS_DTPREL_LO16: - case elfcpp::R_MICROMIPS_TLS_DTPREL_LO16: - reloc_status = Reloc_funcs::tlsrello16(view, object, psymval, - elfcpp::DTP_OFFSET, r_addend, - extract_addend, r_type); - break; - case elfcpp::R_MIPS_TLS_DTPREL32: - case elfcpp::R_MIPS_TLS_DTPREL64: - reloc_status = Reloc_funcs::tlsrel32(view, object, psymval, - elfcpp::DTP_OFFSET, r_addend, - extract_addend, r_type); - break; - case elfcpp::R_MIPS_TLS_TPREL_HI16: - case elfcpp::R_MIPS16_TLS_TPREL_HI16: - case elfcpp::R_MICROMIPS_TLS_TPREL_HI16: - reloc_status = Reloc_funcs::tlsrelhi16(view, object, psymval, - elfcpp::TP_OFFSET, r_addend, - extract_addend, r_type); - break; - case elfcpp::R_MIPS_TLS_TPREL_LO16: - case elfcpp::R_MIPS16_TLS_TPREL_LO16: - case elfcpp::R_MICROMIPS_TLS_TPREL_LO16: - reloc_status = Reloc_funcs::tlsrello16(view, object, psymval, - elfcpp::TP_OFFSET, r_addend, - extract_addend, r_type); - break; - case elfcpp::R_MIPS_TLS_TPREL32: - case elfcpp::R_MIPS_TLS_TPREL64: - reloc_status = Reloc_funcs::tlsrel32(view, object, psymval, - elfcpp::TP_OFFSET, r_addend, - extract_addend, r_type); - break; - case elfcpp::R_MIPS_SUB: - case elfcpp::R_MICROMIPS_SUB: - reloc_status = Reloc_funcs::relsub(view, object, psymval, r_addend, - extract_addend, r_type); - break; - default: - gold_error_at_location(relinfo, relnum, r_offset, - _("unsupported reloc %u"), r_type); - break; - } + case elfcpp::R_MIPS_JALR: + case elfcpp::R_MICROMIPS_JALR: + // This relocation is only a hint. In some cases, we optimize + // it into a bal instruction. But we don't try to optimize + // when the symbol does not resolve locally. + if (gsym == NULL + || symbol_calls_local(gsym, gsym->has_dynsym_index())) + reloc_status = Reloc_funcs::reljalr(view, object, psymval, address, + r_addend, extract_addend, + cross_mode_jump, r_types[i], + target->jalr_to_bal(), + target->jr_to_b(), + calculate_only, + &calculated_value); + break; - if (update_got_entry) - { - Mips_output_data_got* got = target->got_section(); - if (mips_sym != NULL && mips_sym->get_applied_secondary_got_fixup()) - got->update_got_entry(got->get_primary_got_offset(mips_sym), - psymval->value(object, 0)); - else - got->update_got_entry(got_offset, psymval->value(object, 0)); + case elfcpp::R_MIPS_TLS_DTPREL_HI16: + case elfcpp::R_MIPS16_TLS_DTPREL_HI16: + case elfcpp::R_MICROMIPS_TLS_DTPREL_HI16: + reloc_status = Reloc_funcs::tlsrelhi16(view, object, psymval, + elfcpp::DTP_OFFSET, r_addend, + extract_addend, calculate_only, + &calculated_value); + break; + case elfcpp::R_MIPS_TLS_DTPREL_LO16: + case elfcpp::R_MIPS16_TLS_DTPREL_LO16: + case elfcpp::R_MICROMIPS_TLS_DTPREL_LO16: + reloc_status = Reloc_funcs::tlsrello16(view, object, psymval, + elfcpp::DTP_OFFSET, r_addend, + extract_addend, calculate_only, + &calculated_value); + break; + case elfcpp::R_MIPS_TLS_DTPREL32: + case elfcpp::R_MIPS_TLS_DTPREL64: + reloc_status = Reloc_funcs::tlsrel32(view, object, psymval, + elfcpp::DTP_OFFSET, r_addend, + extract_addend, calculate_only, + &calculated_value); + break; + case elfcpp::R_MIPS_TLS_TPREL_HI16: + case elfcpp::R_MIPS16_TLS_TPREL_HI16: + case elfcpp::R_MICROMIPS_TLS_TPREL_HI16: + reloc_status = Reloc_funcs::tlsrelhi16(view, object, psymval, + elfcpp::TP_OFFSET, r_addend, + extract_addend, calculate_only, + &calculated_value); + break; + case elfcpp::R_MIPS_TLS_TPREL_LO16: + case elfcpp::R_MIPS16_TLS_TPREL_LO16: + case elfcpp::R_MICROMIPS_TLS_TPREL_LO16: + reloc_status = Reloc_funcs::tlsrello16(view, object, psymval, + elfcpp::TP_OFFSET, r_addend, + extract_addend, calculate_only, + &calculated_value); + break; + case elfcpp::R_MIPS_TLS_TPREL32: + case elfcpp::R_MIPS_TLS_TPREL64: + reloc_status = Reloc_funcs::tlsrel32(view, object, psymval, + elfcpp::TP_OFFSET, r_addend, + extract_addend, calculate_only, + &calculated_value); + break; + case elfcpp::R_MIPS_SUB: + case elfcpp::R_MICROMIPS_SUB: + reloc_status = Reloc_funcs::relsub(view, object, psymval, r_addend, + extract_addend, + calculate_only, &calculated_value); + break; + default: + gold_error_at_location(relinfo, relnum, r_offset, + _("unsupported reloc %u"), r_types[i]); + break; + } + + if (update_got_entry) + { + Mips_output_data_got* got = target->got_section(); + if (mips_sym != NULL && mips_sym->get_applied_secondary_got_fixup()) + got->update_got_entry(got->get_primary_got_offset(mips_sym), + psymval->value(object, 0)); + else + got->update_got_entry(got_offset, psymval->value(object, 0)); + } + + r_addend = calculated_value; } + bool jal_shuffle = jal_reloc(r_type) ? !parameters->options().relocatable() + : false; + Reloc_funcs::mips_reloc_shuffle(view, r_type, jal_shuffle); + // Report any errors. switch (reloc_status) { @@ -10481,6 +11156,7 @@ Target_mips::Scan::get_reference_flags( case elfcpp::R_MICROMIPS_GOT_LO16: case elfcpp::R_MICROMIPS_CALL_HI16: case elfcpp::R_MICROMIPS_CALL_LO16: + case elfcpp::R_MIPS_EH: // Absolute in GOT. return Symbol::RELATIVE_REF; @@ -10542,15 +11218,14 @@ Target_mips::Scan::unsupported_reloc_global( // Return printable name for ABI. template const char* -Target_mips::elf_mips_abi_name(elfcpp::Elf_Word e_flags, - unsigned char ei_class) +Target_mips::elf_mips_abi_name(elfcpp::Elf_Word e_flags) { switch (e_flags & elfcpp::EF_MIPS_ABI) { case 0: if ((e_flags & elfcpp::EF_MIPS_ABI2) != 0) return "N32"; - else if (elfcpp::abi_64(ei_class)) + else if (size == 64) return "64"; else return "none"; @@ -10652,7 +11327,7 @@ const Target::Target_info Target_mips::mips_info = true, // is_default_stack_executable false, // can_icf_inline_merge_sections '\0', // wrap_char - "/lib/ld.so.1", // dynamic_linker + size == 32 ? "/lib/ld.so.1" : "/lib64/ld.so.1", // dynamic_linker 0x400000, // default_text_segment_address 64 * 1024, // abi_pagesize (overridable by -z max-page-size) 4 * 1024, // common_pagesize (overridable by -z common-page-size) @@ -10721,8 +11396,8 @@ public: (big_endian ? "elf64-tradbigmips" : "elf64-tradlittlemips") : (big_endian ? "elf32-tradbigmips" : "elf32-tradlittlemips")), (size == 64 ? - (big_endian ? "elf64-tradbigmips" : "elf64-tradlittlemips") : - (big_endian ? "elf32-tradbigmips" : "elf32-tradlittlemips"))) + (big_endian ? "elf64btsmip" : "elf64ltsmip") : + (big_endian ? "elf32btsmip" : "elf32ltsmip"))) { } Target* do_instantiate_target()