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.
|| 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)
{
public:
Mips_got_entry(Mips_relobj<size, big_endian>* 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<size, big_endian>* object, Mips_symbol<size>* 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.
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<size, big_endian>* object_;
// 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_;
};
void
record_local_got_symbol(Mips_relobj<size, big_endian>* 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
{
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()
// 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<size, big_endian>*
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_;
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<size, big_endian>* got_info_;
void
record_local_got_symbol(Mips_relobj<size, big_endian>* 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,
// SYMNDX.
unsigned int
got_offset(unsigned int symndx, unsigned int got_type,
- Sized_relobj_file<size, big_endian>* object) const
- { return object->local_got_offset(symndx, got_type); }
+ Sized_relobj_file<size, big_endian>* 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
create_stub_symbol(Mips_symbol<size>* sym, Symbol_table* symtab,
Target_mips<size, big_endian>* 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*);
Unordered_set<Mips_symbol<size>*> symbols_;
};
+// MIPS-specific relocation writer.
+
+template<int sh_type, bool dynamic, int size, bool big_endian>
+struct Mips_output_reloc_writer;
+
+template<int sh_type, bool dynamic, bool big_endian>
+struct Mips_output_reloc_writer<sh_type, dynamic, 32, big_endian>
+{
+ typedef Output_reloc<sh_type, dynamic, 32, big_endian> Output_reloc_type;
+ typedef std::vector<Output_reloc_type> Relocs;
+
+ static void
+ write(typename Relocs::const_iterator p, unsigned char* pov)
+ { p->write(pov); }
+};
+
+template<int sh_type, bool dynamic, bool big_endian>
+struct Mips_output_reloc_writer<sh_type, dynamic, 64, big_endian>
+{
+ typedef Output_reloc<sh_type, dynamic, 64, big_endian> Output_reloc_type;
+ typedef std::vector<Output_reloc_type> Relocs;
+
+ static void
+ write(typename Relocs::const_iterator p, unsigned char* pov)
+ {
+ elfcpp::Mips64_rel_write<big_endian> 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<int sh_type, bool dynamic, int size, bool big_endian>
+class Mips_output_data_reloc : public Output_data_reloc<sh_type, dynamic,
+ size, big_endian>
+{
+ public:
+ Mips_output_data_reloc(bool sort_relocs)
+ : Output_data_reloc<sh_type, dynamic, size, big_endian>(sort_relocs)
+ { }
+
+ protected:
+ // Write out the data.
+ void
+ do_write(Output_file* of)
+ {
+ typedef Mips_output_reloc_writer<sh_type, dynamic, size,
+ big_endian> Writer;
+ this->template do_write_generic<Writer>(of);
+ }
+};
+
+
// A class to handle the PLT data.
template<int size, bool big_endian>
class Mips_output_data_plt : public Output_section_data
{
typedef typename elfcpp::Elf_types<size>::Elf_Addr Mips_address;
- typedef Output_data_reloc<elfcpp::SHT_REL, true,
- size, big_endian> Reloc_section;
+ typedef Mips_output_data_reloc<elfcpp::SHT_REL, true,
+ size, big_endian> Reloc_section;
public:
// Create the PLT section. The ordinary .got section is an argument,
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; }
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(); }
typedef typename elfcpp::Mips64_rel<big_endian> Reloc;
typedef typename elfcpp::Mips64_rel_write<big_endian> 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; }
typedef typename elfcpp::Mips64_rela<big_endian> Reloc;
typedef typename elfcpp::Mips64_rela_write<big_endian> 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(); }
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)
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)
class Target_mips : public Sized_target<size, big_endian>
{
typedef typename elfcpp::Elf_types<size>::Elf_Addr Mips_address;
- typedef Output_data_reloc<elfcpp::SHT_REL, true, size, big_endian>
+ typedef Mips_output_data_reloc<elfcpp::SHT_REL, true, size, big_endian>
Reloc_section;
- typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian>
- Reloca_section;
typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype32;
typedef typename elfcpp::Swap<size, big_endian>::Valtype Valtype;
typedef typename Mips_reloc_types<elfcpp::SHT_REL, size, big_endian>::Reloc
: Sized_target<size, big_endian>(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();
}
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.
~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<size>* gsym,
- unsigned int r_type,
- Output_section* output_section,
- Target_mips* target);
+ should_apply_static_reloc(const Mips_symbol<size>* 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.
// 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
copy_reloc(Symbol_table* symtab, Layout* layout,
Sized_relobj_file<size, big_endian>* 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<elfcpp::SHT_REL, size, big_endian>::
- get_r_type(&reloc);
this->copy_relocs_.copy_reloc(symtab, layout,
symtab->get_sized_symbol<size>(sym),
object, shndx, output_section,
- r_type, reloc.get_r_offset(), 0,
+ r_type, r_offset, 0,
this->rel_dyn_section(layout));
}
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);
// .MIPS.stubs
Mips_output_data_mips_stubs<size, big_endian>* mips_stubs_;
- unsigned char ei_class_;
unsigned int mach_;
Layout* layout_;
class Mips_relocate_functions : public Relocate_functions<size, big_endian>
{
typedef typename elfcpp::Elf_types<size>::Elf_Addr Mips_address;
+ typedef typename elfcpp::Swap<size, big_endian>::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
static typename std::list<reloc_high<size, big_endian> > hi16_relocs;
static typename std::list<reloc_high<size, big_endian> > got16_relocs;
+ template<int valsize>
+ static inline typename This::Status
+ check_overflow(Valtype value)
+ {
+ if (size == 32)
+ return (Bits<valsize>::has_overflow32(value)
+ ? This::STATUS_OVERFLOW
+ : This::STATUS_OKAY);
+
+ return (Bits<valsize>::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.
// 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)
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<size, big_endian>* object,
const Symbol_value<size>* 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<Valtype16*>(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<size, big_endian>* object,
const Symbol_value<size>* 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<Valtype32*>(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;
}
reljalr(unsigned char* view, const Mips_relobj<size, big_endian>* object,
const Symbol_value<size>* psymval, Mips_address address,
Mips_address addend_a, bool extract_addend, bool 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<Valtype32*>(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.
}
}
- 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;
}
static inline typename This::Status
relpc32(unsigned char* view, const Mips_relobj<size, big_endian>* object,
const Symbol_value<size>* psymval, Mips_address address,
- Mips_address addend_a, bool extract_addend, 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<Valtype32*>(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;
}
const Symbol_value<size>* 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<Valtype32*>(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)
// 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;
}
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
}
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)))
{
// 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."));
}
}
- 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;
}
static inline typename This::Status
relpc16(unsigned char* view, const Mips_relobj<size, big_endian>* object,
const Symbol_value<size>* psymval, Mips_address address,
- Mips_address addend_a, bool extract_addend, 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<Valtype32*>(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
const Mips_relobj<size, big_endian>* object,
const Symbol_value<size>* 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<Valtype32*>(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
const Mips_relobj<size, big_endian>* object,
const Symbol_value<size>* 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<Valtype32*>(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
const Mips_relobj<size, big_endian>* object,
const Symbol_value<size>* 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<Valtype32*>(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,
const Symbol_value<size>* psymval, Mips_address addend_hi,
Mips_address address, bool is_gp_disp, unsigned int r_type,
bool extract_addend, Valtype32 addend_lo,
- Target_mips<size, big_endian>* target)
+ Target_mips<size, big_endian>* target, bool calculate_only,
+ Valtype* calculated_value)
{
- mips_reloc_unshuffle(view, r_type, false);
Valtype32* wv = reinterpret_cast<Valtype32*>(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;
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
do_relgot16_local(unsigned char* view,
const Mips_relobj<size, big_endian>* object,
const Symbol_value<size>* psymval, Mips_address addend_hi,
- unsigned int r_type, bool extract_addend,
- Valtype32 addend_lo, Target_mips<size, big_endian>* target)
+ bool extract_addend, Valtype32 addend_lo,
+ Target_mips<size, big_endian>* target, bool calculate_only,
+ Valtype* calculated_value)
{
- mips_reloc_unshuffle(view, r_type, false);
Valtype32* wv = reinterpret_cast<Valtype32*>(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.
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
const Mips_relobj<size, big_endian>* object,
const Symbol_value<size>* 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<Valtype32*>(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<reloc_high<size, big_endian> >::iterator it =
- hi16_relocs.begin();
- while (it != hi16_relocs.end())
+ if (rel_type == elfcpp::SHT_REL)
{
- reloc_high<size, big_endian> 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<reloc_high<size, big_endian> >::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<size, big_endian> 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<reloc_high<size, big_endian> >::iterator it2 =
- got16_relocs.begin();
- while (it2 != got16_relocs.end())
- {
- reloc_high<size, big_endian> 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<reloc_high<size, big_endian> >::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<size, big_endian> 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
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;
}
// 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<Valtype32*>(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<Valtype32*>(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
relgotpage(Target_mips<size, big_endian>* target, unsigned char* view,
const Mips_relobj<size, big_endian>* object,
const Symbol_value<size>* 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<Valtype32*>(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
relgotofst(Target_mips<size, big_endian>* target, unsigned char* view,
const Mips_relobj<size, big_endian>* object,
const Symbol_value<size>* 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<Valtype32*>(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.
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<Valtype32*>(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<Valtype32*>(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;
}
relgprel(unsigned char* view, const Mips_relobj<size, big_endian>* object,
const Symbol_value<size>* 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<Valtype32*>(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)
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
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)"));
static inline typename This::Status
relgprel32(unsigned char* view, const Mips_relobj<size, big_endian>* object,
const Symbol_value<size>* 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<Valtype32*>(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;
}
static inline typename This::Status
tlsrelhi16(unsigned char* view, const Mips_relobj<size, big_endian>* object,
const Symbol_value<size>* 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<Valtype32*>(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;
}
static inline typename This::Status
tlsrello16(unsigned char* view, const Mips_relobj<size, big_endian>* object,
const Symbol_value<size>* 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<Valtype32*>(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;
}
static inline typename This::Status
tlsrel32(unsigned char* view, const Mips_relobj<size, big_endian>* object,
const Symbol_value<size>* 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<Valtype32*>(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;
}
static inline typename This::Status
relsub(unsigned char* view, const Mips_relobj<size, big_endian>* object,
const Symbol_value<size>* 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<Valtype32*>(view);
- Valtype32 val = elfcpp::Swap<32, big_endian>::readval(wv);
- Valtype32 addend = extract_addend ? val : addend_a;
+ Valtype64* wv = reinterpret_cast<Valtype64*>(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<size, big_endian>* object,
+ const Symbol_value<size>* psymval, Mips_address addend_a,
+ bool extract_addend, bool calculate_only, Valtype* calculated_value,
+ bool apply_addend_only)
+ {
+ Valtype64* wv = reinterpret_cast<Valtype64*>(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<int size, bool big_endian>
void
Mips_got_info<size, big_endian>::record_local_got_symbol(
Mips_relobj<size, big_endian>* 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<size, big_endian>* entry =
new Mips_got_entry<size, big_endian>(object, symndx, addend,
mips_elf_reloc_tls_type(r_type),
- shndx);
+ shndx, is_section_symbol);
this->record_got_entry(entry, object);
}
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);
+ }
}
}
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());
}
// 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());
: 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());
}
this->cprmask4_ = elfcpp::Swap<size, big_endian>::readval(view + 16);
}
- 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);
- this->section_is_mips16_call_fp_stub_[i] =
- is_prefix_of(".mips16.call.fp.", 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<size, big_endian>::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<size, big_endian>::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);
+ this->section_is_mips16_call_fp_stub_[i] =
+ is_prefix_of(".mips16.call.fp.", name);
+
if (strcmp(name, ".pdr") == 0)
{
gold_assert(this->pdr_shndx_ == -1U);
const uint32_t Mips_output_data_plt<size, big_endian>::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)
};
Layout* layout,
Sized_relobj_file<size, big_endian>* object,
unsigned int data_shndx,
- unsigned int,
+ unsigned int sh_type,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
const unsigned char* plocal_symbols)
{
typedef Target_mips<size, big_endian> Mips;
- typedef Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>
- Classify_reloc;
- gold::gc_process_relocs<size, big_endian, Mips, Scan, Classify_reloc>(
- 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<elfcpp::SHT_REL, size, big_endian>
+ Classify_reloc;
+
+ gold::gc_process_relocs<size, big_endian, Mips, Scan, Classify_reloc>(
+ 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<elfcpp::SHT_RELA, size, big_endian>
+ Classify_reloc;
+
+ gold::gc_process_relocs<size, big_endian, Mips, Scan, Classify_reloc>(
+ 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.
template<int size, bool big_endian>
void
Target_mips<size, big_endian>::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;
}
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;
{
gold_assert(len == elfcpp::Elf_sizes<size>::ehdr_size);
- elfcpp::Ehdr<size, big_endian> 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<size, big_endian> ehdr(view);
elfcpp::Ehdr_write<size, big_endian> 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.
elfcpp::Ehdr<size, big_endian> 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);
}
}
elfcpp::Ehdr<size, big_endian> 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.
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:
const unsigned char* plocal_symbols,
Relocatable_relocs* rr)
{
- typedef Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>
- Classify_reloc;
- typedef Mips_scan_relocatable_relocs<big_endian, Classify_reloc>
- Scan_relocatable_relocs;
-
- gold_assert(sh_type == elfcpp::SHT_REL);
-
- gold::scan_relocatable_relocs<size, big_endian, 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<elfcpp::SHT_REL, size, big_endian>
+ Classify_reloc;
+ typedef Mips_scan_relocatable_relocs<big_endian, Classify_reloc>
+ Scan_relocatable_relocs;
+
+ gold::scan_relocatable_relocs<size, big_endian, 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<elfcpp::SHT_RELA, size, big_endian>
+ Classify_reloc;
+ typedef Mips_scan_relocatable_relocs<big_endian, Classify_reloc>
+ Scan_relocatable_relocs;
+
+ gold::scan_relocatable_relocs<size, big_endian, 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.
const unsigned char* plocal_syms,
Relocatable_relocs* rr)
{
- typedef Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>
- Classify_reloc;
- typedef gold::Default_emit_relocs_strategy<Classify_reloc>
- Emit_relocs_strategy;
-
- gold_assert(sh_type == elfcpp::SHT_REL);
-
- gold::scan_relocatable_relocs<size, big_endian, Emit_relocs_strategy>(
- 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<elfcpp::SHT_REL, size, big_endian>
+ Classify_reloc;
+ typedef gold::Default_emit_relocs_strategy<Classify_reloc>
+ Emit_relocs_strategy;
+
+ gold::scan_relocatable_relocs<size, big_endian, Emit_relocs_strategy>(
+ 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<elfcpp::SHT_RELA, size, big_endian>
+ Classify_reloc;
+ typedef gold::Default_emit_relocs_strategy<Classify_reloc>
+ Emit_relocs_strategy;
+
+ gold::scan_relocatable_relocs<size, big_endian, Emit_relocs_strategy>(
+ 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.
unsigned char* reloc_view,
section_size_type reloc_view_size)
{
- typedef Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>
- Classify_reloc;
-
- gold_assert(sh_type == elfcpp::SHT_REL);
-
- gold::relocate_relocs<size, big_endian, Classify_reloc>(
- 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<elfcpp::SHT_REL, size, big_endian>
+ Classify_reloc;
+
+ gold::relocate_relocs<size, big_endian, Classify_reloc>(
+ 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<elfcpp::SHT_RELA, size, big_endian>
+ Classify_reloc;
+
+ gold::relocate_relocs<size, big_endian, Classify_reloc>(
+ 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
// 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<size>* psymval = object->local_symbol(r_sym);
unsigned char* paddend = view + offset;
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:
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;
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
// R_MIPS_GOT_LO16 or R_MIPS_CALL_LO16.
Mips_output_data_got<size, big_endian>* 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)
// 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,
break;
}
got->record_local_got_symbol(mips_obj, r_sym, r_addend, r_type,
- shndx);
+ shndx, false);
}
else
{
// 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
{
Mips_output_data_got<size, big_endian>* got =
target->got_section(symtab, layout);
got->record_local_got_symbol(mips_obj, r_sym, r_addend, r_type,
- -1U);
+ -1U, false);
}
else
{
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;
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;
}
{
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)
{
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<size, big_endian>* got =
// 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
{
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<int size, bool big_endian>
inline bool
-Target_mips<size, big_endian>::Relocate::should_apply_r_mips_32_reloc(
+Target_mips<size, big_endian>::Relocate::should_apply_static_reloc(
const Mips_symbol<size>* gsym,
unsigned int r_type,
Output_section* output_section,
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<size>::Elf_Swxword r_addend;
if (rel_type == elfcpp::SHT_RELA)
get_r_sym(&rela);
r_type = Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>::
get_r_type(&rela);
+ r_type2 = Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>::
+ get_r_type2(&rela);
+ r_type3 = Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>::
+ get_r_type3(&rela);
+ r_ssym = Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>::
+ 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<elfcpp::SHT_REL, size, big_endian>::
get_r_sym(&rel);
r_type = Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>::
get_r_type(&rel);
+ r_ssym = 0;
+ r_type2 = 0;
+ r_type3 = 0;
r_addend = 0;
}
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<size, big_endian>* fn_stub =
- mips_sym->template get_mips16_fn_stub<big_endian>();
-
- 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<size, big_endian>* fn_stub =
+ mips_sym->template get_mips16_fn_stub<big_endian>();
- 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<size, big_endian>* 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<size, big_endian>* 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)
{
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;
// Return printable name for ABI.
template<int size, bool big_endian>
const char*
-Target_mips<size, big_endian>::elf_mips_abi_name(elfcpp::Elf_Word e_flags,
- unsigned char ei_class)
+Target_mips<size, big_endian>::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";
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)
(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()