// mips.cc -- mips target support for gold.
-// Copyright (C) 2011-2014 Free Software Foundation, Inc.
+// Copyright (C) 2011-2016 Free Software Foundation, Inc.
// Written by Sasa Stankovic <sasa.stankovic@imgtec.com>
// and Aleksandar Simeonov <aleksandar.simeonov@rt-rk.com>.
// This file contains borrowed and adapted code from bfd/elfxx-mips.c.
#include "tls.h"
#include "errors.h"
#include "gc.h"
+#include "nacl.h"
namespace
{
// The MIPS target has relocation types which default handling of relocatable
// relocation cannot process. So we have to extend the default code.
-template<bool big_endian, int sh_type, typename Classify_reloc>
+template<bool big_endian, typename Classify_reloc>
class Mips_scan_relocatable_relocs :
- public Default_scan_relocatable_relocs<sh_type, Classify_reloc>
+ public Default_scan_relocatable_relocs<Classify_reloc>
{
public:
// Return the strategy to use for a local symbol which is a section
inline Relocatable_relocs::Reloc_strategy
local_section_strategy(unsigned int r_type, Relobj* object)
{
- if (sh_type == elfcpp::SHT_RELA)
+ if (Classify_reloc::sh_type == elfcpp::SHT_RELA)
return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA;
else
{
return Relocatable_relocs::RELOC_SPECIAL;
default:
- return Default_scan_relocatable_relocs<sh_type, Classify_reloc>::
+ return Default_scan_relocatable_relocs<Classify_reloc>::
local_section_strategy(r_type, object);
}
}
Symbol_table* symtab_;
};
+// Relocation types, parameterized by SHT_REL vs. SHT_RELA, size,
+// and endianness. The relocation format for MIPS-64 is non-standard.
+
+template<int sh_type, int size, bool big_endian>
+struct Mips_reloc_types;
+
+template<bool big_endian>
+struct Mips_reloc_types<elfcpp::SHT_REL, 32, big_endian>
+{
+ 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
+ get_r_addend(const Reloc*)
+ { return 0; }
+
+ static inline void
+ set_reloc_addend(Reloc_write*,
+ typename elfcpp::Elf_types<32>::Elf_Swxword)
+ { gold_unreachable(); }
+};
+
+template<bool big_endian>
+struct Mips_reloc_types<elfcpp::SHT_RELA, 32, big_endian>
+{
+ 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
+ get_r_addend(const Reloc* reloc)
+ { return reloc->get_r_addend(); }
+
+ static inline void
+ set_reloc_addend(Reloc_write* p,
+ typename elfcpp::Elf_types<32>::Elf_Swxword val)
+ { p->put_r_addend(val); }
+};
+
+template<bool big_endian>
+struct Mips_reloc_types<elfcpp::SHT_REL, 64, big_endian>
+{
+ 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
+ get_r_addend(const Reloc*)
+ { return 0; }
+
+ static inline void
+ set_reloc_addend(Reloc_write*,
+ typename elfcpp::Elf_types<64>::Elf_Swxword)
+ { gold_unreachable(); }
+};
+
+template<bool big_endian>
+struct Mips_reloc_types<elfcpp::SHT_RELA, 64, big_endian>
+{
+ 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
+ get_r_addend(const Reloc* reloc)
+ { return reloc->get_r_addend(); }
+
+ static inline void
+ set_reloc_addend(Reloc_write* p,
+ typename elfcpp::Elf_types<64>::Elf_Swxword val)
+ { p->put_r_addend(val); }
+};
+
+// Forward declaration.
+static unsigned int
+mips_get_size_for_reloc(unsigned int, Relobj*);
+
+// A class for inquiring about properties of a relocation,
+// used while scanning relocs during a relocatable link and
+// garbage collection.
+
+template<int sh_type_, int size, bool big_endian>
+class Mips_classify_reloc;
+
+template<int sh_type_, bool big_endian>
+class Mips_classify_reloc<sh_type_, 32, big_endian> :
+ public gold::Default_classify_reloc<sh_type_, 32, big_endian>
+{
+ public:
+ typedef typename Mips_reloc_types<sh_type_, 32, big_endian>::Reloc
+ Reltype;
+ typedef typename Mips_reloc_types<sh_type_, 32, big_endian>::Reloc_write
+ Reltype_write;
+
+ // Return the symbol referred to by the relocation.
+ static inline unsigned int
+ get_r_sym(const Reltype* reloc)
+ { return elfcpp::elf_r_sym<32>(reloc->get_r_info()); }
+
+ // Return the type of the relocation.
+ static inline unsigned int
+ get_r_type(const Reltype* reloc)
+ { return elfcpp::elf_r_type<32>(reloc->get_r_info()); }
+
+ // 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<sh_type_, 32, big_endian>::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.
+ static inline void
+ 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));
+ }
+
+ // Write the r_addend field to a new reloc.
+ static inline void
+ put_r_addend(Reltype_write* to,
+ typename elfcpp::Elf_types<32>::Elf_Swxword addend)
+ { Mips_reloc_types<sh_type_, 32, big_endian>::set_reloc_addend(to, addend); }
+
+ // Return the size of the addend of the relocation (only used for SHT_REL).
+ static unsigned int
+ get_size_for_reloc(unsigned int r_type, Relobj* obj)
+ { return mips_get_size_for_reloc(r_type, obj); }
+};
+
+template<int sh_type_, bool big_endian>
+class Mips_classify_reloc<sh_type_, 64, big_endian> :
+ public gold::Default_classify_reloc<sh_type_, 64, big_endian>
+{
+ public:
+ typedef typename Mips_reloc_types<sh_type_, 64, big_endian>::Reloc
+ Reltype;
+ typedef typename Mips_reloc_types<sh_type_, 64, big_endian>::Reloc_write
+ Reltype_write;
+
+ // Return the symbol referred to by the relocation.
+ static inline unsigned int
+ get_r_sym(const Reltype* reloc)
+ { return reloc->get_r_sym(); }
+
+ // Return the type of the relocation.
+ static inline unsigned int
+ get_r_type(const Reltype* reloc)
+ { return reloc->get_r_type(); }
+
+ // 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<sh_type_, 64, big_endian>::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.
+ static inline void
+ put_r_info(Reltype_write* new_reloc, Reltype* reloc, unsigned int r_sym)
+ {
+ new_reloc->put_r_sym(r_sym);
+ new_reloc->put_r_ssym(reloc->get_r_ssym());
+ new_reloc->put_r_type3(reloc->get_r_type3());
+ new_reloc->put_r_type2(reloc->get_r_type2());
+ new_reloc->put_r_type(reloc->get_r_type());
+ }
+
+ // Write the r_addend field to a new reloc.
+ static inline void
+ put_r_addend(Reltype_write* to,
+ typename elfcpp::Elf_types<64>::Elf_Swxword addend)
+ { Mips_reloc_types<sh_type_, 64, big_endian>::set_reloc_addend(to, addend); }
+
+ // Return the size of the addend of the relocation (only used for SHT_REL).
+ static unsigned int
+ get_size_for_reloc(unsigned int r_type, Relobj* obj)
+ { return mips_get_size_for_reloc(r_type, obj); }
+};
+
template<int size, bool big_endian>
class Target_mips : public Sized_target<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
+ Reltype;
+ typedef typename Mips_reloc_types<elfcpp::SHT_RELA, size, big_endian>::Reloc
+ Relatype;
public:
Target_mips(const Target::Target_info* info = &mips_info)
const unsigned char* plocal_symbols,
Relocatable_relocs*);
+ // Scan the relocs for --emit-relocs.
+ void
+ emit_relocs_scan(Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_syms,
+ Relocatable_relocs* rr);
+
// Emit relocations for a section.
void
relocate_relocs(const Relocate_info<size, big_endian>*,
Output_section* output_section,
typename elfcpp::Elf_types<size>::Elf_Off
offset_in_output_section,
- const Relocatable_relocs*,
unsigned char* view,
Mips_address view_address,
section_size_type view_size,
use_32bit_micromips_instructions() const
{ return this->insn32_; }
+ // Return the r_sym field from a relocation.
+ unsigned int
+ get_r_sym(const unsigned char* preloc) const
+ {
+ // Since REL and RELA relocs share the same structure through
+ // the r_info field, we can just use REL here.
+ Reltype rel(preloc);
+ return Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>::
+ get_r_sym(&rel);
+ }
+
protected:
// Return the value to use for a dynamic symbol which requires special
// treatment. This is how we support equality comparisons of function
Sized_relobj_file<size, big_endian>* object,
unsigned int data_shndx,
Output_section* output_section,
- const elfcpp::Rel<size, big_endian>& reloc, unsigned int r_type,
+ const Reltype& reloc, unsigned int r_type,
const elfcpp::Sym<size, big_endian>& lsym,
bool is_discarded);
Sized_relobj_file<size, big_endian>* object,
unsigned int data_shndx,
Output_section* output_section,
- const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
+ const Relatype& reloc, unsigned int r_type,
const elfcpp::Sym<size, big_endian>& lsym,
bool is_discarded);
Sized_relobj_file<size, big_endian>* object,
unsigned int data_shndx,
Output_section* output_section,
- const elfcpp::Rela<size, big_endian>* rela,
- const elfcpp::Rel<size, big_endian>* rel,
+ const Relatype* rela,
+ const Reltype* rel,
unsigned int rel_type,
unsigned int r_type,
const elfcpp::Sym<size, big_endian>& lsym,
Sized_relobj_file<size, big_endian>* object,
unsigned int data_shndx,
Output_section* output_section,
- const elfcpp::Rel<size, big_endian>& reloc, unsigned int r_type,
+ const Reltype& reloc, unsigned int r_type,
Symbol* gsym);
inline void
Sized_relobj_file<size, big_endian>* object,
unsigned int data_shndx,
Output_section* output_section,
- const elfcpp::Rela<size, big_endian>& reloc, unsigned int r_type,
+ const Relatype& reloc, unsigned int r_type,
Symbol* gsym);
inline void
Sized_relobj_file<size, big_endian>* object,
unsigned int data_shndx,
Output_section* output_section,
- const elfcpp::Rela<size, big_endian>* rela,
- const elfcpp::Rel<size, big_endian>* rel,
+ const Relatype* rela,
+ const Reltype* rel,
unsigned int rel_type,
unsigned int r_type,
Symbol* gsym);
Sized_relobj_file<size, big_endian>*,
unsigned int,
Output_section*,
- const elfcpp::Rel<size, big_endian>&,
+ const Reltype&,
unsigned int,
const elfcpp::Sym<size, big_endian>&)
{ return false; }
Sized_relobj_file<size, big_endian>*,
unsigned int,
Output_section*,
- const elfcpp::Rel<size, big_endian>&,
+ const Reltype&,
unsigned int, Symbol*)
{ return false; }
Sized_relobj_file<size, big_endian>*,
unsigned int,
Output_section*,
- const elfcpp::Rela<size, big_endian>&,
+ const Relatype&,
unsigned int,
const elfcpp::Sym<size, big_endian>&)
{ return false; }
Sized_relobj_file<size, big_endian>*,
unsigned int,
Output_section*,
- const elfcpp::Rela<size, big_endian>&,
+ const Relatype&,
unsigned int, Symbol*)
{ return false; }
private:
// Do a relocation. Return false if the caller should not issue
// any warnings about this relocation.
inline bool
- relocate(const Relocate_info<size, big_endian>*, Target_mips*,
- Output_section*, size_t relnum,
- const elfcpp::Rela<size, big_endian>*,
- const elfcpp::Rel<size, big_endian>*,
- unsigned int,
- unsigned int, const Sized_symbol<size>*,
- const Symbol_value<size>*,
- unsigned char*,
- Mips_address,
- section_size_type);
-
- inline bool
- relocate(const Relocate_info<size, big_endian>*, Target_mips*,
- Output_section*, size_t relnum,
- const elfcpp::Rel<size, big_endian>&,
- unsigned int, const Sized_symbol<size>*,
- const Symbol_value<size>*,
- unsigned char*,
- Mips_address,
- section_size_type);
-
- inline bool
- relocate(const Relocate_info<size, big_endian>*, Target_mips*,
- Output_section*, size_t relnum,
- const elfcpp::Rela<size, big_endian>&,
- unsigned int, const Sized_symbol<size>*,
- const Symbol_value<size>*,
- unsigned char*,
- Mips_address,
- section_size_type);
- };
-
- // A class which returns the size required for a relocation type,
- // used while scanning relocs during a relocatable link.
- class Relocatable_size_for_reloc
- {
- public:
- unsigned int
- get_size_for_reloc(unsigned int, Relobj*);
+ relocate(const Relocate_info<size, big_endian>*, unsigned int,
+ Target_mips*, Output_section*, size_t, const unsigned char*,
+ const Sized_symbol<size>*, const Symbol_value<size>*,
+ unsigned char*, Mips_address, section_size_type);
};
// This POD class holds the dynamic relocations that should be emitted instead
copy_reloc(Symbol_table* symtab, Layout* layout,
Sized_relobj_file<size, big_endian>* object,
unsigned int shndx, Output_section* output_section,
- Symbol* sym, const elfcpp::Rel<size, big_endian>& reloc)
+ Symbol* sym, const Reltype& reloc)
{
+ 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,
- reloc, this->rel_dyn_section(layout));
+ r_type, reloc.get_r_offset(), 0,
+ this->rel_dyn_section(layout));
}
void
// Information about this specific target which we pass to the
// general Target structure.
- static Target::Target_info mips_info;
+ static const Target::Target_info mips_info;
// The GOT section.
Mips_output_data_got<size, big_endian>* got_;
// gp symbol. It has the value of .got + 0x7FF0.
bool insn32_;
};
-
// Helper structure for R_MIPS*_HI16/LO16 and R_MIPS*_GOT16/LO16 relocations.
// It records high part of the relocation pair.
reloc_high(unsigned char* _view, const Mips_relobj<size, big_endian>* _object,
const Symbol_value<size>* _psymval, Mips_address _addend,
- unsigned int _r_type, bool _extract_addend,
+ unsigned int _r_type, unsigned int _r_sym, bool _extract_addend,
Mips_address _address = 0, bool _gp_disp = false)
: view(_view), object(_object), psymval(_psymval), addend(_addend),
- r_type(_r_type), extract_addend(_extract_addend), address(_address),
- gp_disp(_gp_disp)
+ r_type(_r_type), r_sym(_r_sym), extract_addend(_extract_addend),
+ address(_address), gp_disp(_gp_disp)
{ }
unsigned char* view;
const Symbol_value<size>* psymval;
Mips_address addend;
unsigned int r_type;
+ unsigned int r_sym;
bool extract_addend;
Mips_address address;
bool gp_disp;
relhi16(unsigned char* view, const Mips_relobj<size, big_endian>* object,
const Symbol_value<size>* psymval, Mips_address addend,
Mips_address address, bool gp_disp, unsigned int r_type,
- bool extract_addend)
+ unsigned int r_sym, bool extract_addend)
{
// Record the relocation. It will be resolved when we find lo16 part.
hi16_relocs.push_back(reloc_high<size, big_endian>(view, object, psymval,
- addend, r_type, extract_addend, address, gp_disp));
+ addend, r_type, r_sym, extract_addend, address,
+ gp_disp));
return This::STATUS_OKAY;
}
relgot16_local(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, unsigned int r_type, unsigned int r_sym)
{
// Record the relocation. It will be resolved when we find lo16 part.
got16_relocs.push_back(reloc_high<size, big_endian>(view, object, psymval,
- addend_a, r_type, extract_addend));
+ addend_a, r_type, r_sym, extract_addend));
return This::STATUS_OKAY;
}
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_type, unsigned int r_sym)
{
mips_reloc_unshuffle(view, r_type, false);
Valtype32* wv = reinterpret_cast<Valtype32*>(view);
while (it != hi16_relocs.end())
{
reloc_high<size, big_endian> hi16 = *it;
- if (hi16.psymval->value(hi16.object, 0) == psymval->value(object, 0))
+ if (hi16.r_sym == r_sym
+ && is_matching_lo16_reloc(hi16.r_type, r_type))
{
if (do_relhi16(hi16.view, hi16.object, hi16.psymval, hi16.addend,
hi16.address, hi16.gp_disp, hi16.r_type,
while (it2 != got16_relocs.end())
{
reloc_high<size, big_endian> got16 = *it2;
- if (got16.psymval->value(got16.object, 0) == psymval->value(object, 0))
+ if (got16.r_sym == r_sym
+ && is_matching_lo16_reloc(got16.r_type, r_type))
{
if (do_relgot16_local(got16.view, got16.object, got16.psymval,
got16.addend, got16.r_type,
0x8f990000, // lw $25, %lo(&GOTPLT[0])($28)
0x279c0000, // addiu $28, $28, %lo(&GOTPLT[0])
0x031cc023, // subu $24, $24, $28
- 0x03e07821, // move $15, $31 # 32-bit move (addu)
+ 0x03e07825, // or $15, $31, zero
0x0018c082, // srl $24, $24, 2
0x0320f809, // jalr $25
0x2718fffe // subu $24, $24, 2
0x8dd90000, // lw $25, %lo(&GOTPLT[0])($14)
0x25ce0000, // addiu $14, $14, %lo(&GOTPLT[0])
0x030ec023, // subu $24, $24, $14
- 0x03e07821, // move $15, $31 # 32-bit move (addu)
+ 0x03e07825, // or $15, $31, zero
0x0018c082, // srl $24, $24, 2
0x0320f809, // jalr $25
0x2718fffe // subu $24, $24, 2
0xddd90000, // ld $25, %lo(&GOTPLT[0])($14)
0x25ce0000, // addiu $14, $14, %lo(&GOTPLT[0])
0x030ec023, // subu $24, $24, $14
- 0x03e07821, // move $15, $31 # 64-bit move (daddu)
+ 0x03e07825, // or $15, $31, zero
0x0018c0c2, // srl $24, $24, 3
0x0320f809, // jalr $25
0x2718fffe // subu $24, $24, 2
0xff3c, 0x0000, // lw $25, %lo(&GOTPLT[0])($28)
0x339c, 0x0000, // addiu $28, $28, %lo(&GOTPLT[0])
0x0398, 0xc1d0, // subu $24, $24, $28
- 0x001f, 0x7950, // move $15, $31
+ 0x001f, 0x7a90, // or $15, $31, zero
0x0318, 0x1040, // srl $24, $24, 2
0x03f9, 0x0f3c, // jalr $25
0x3318, 0xfffe // subu $24, $24, 2
Mips_output_data_mips_stubs<size, big_endian>::lazy_stub_normal_1[4] =
{
0x8f998010, // lw t9,0x8010(gp)
- 0x03e07821, // addu t7,ra,zero
+ 0x03e07825, // or t7,ra,zero
0x0320f809, // jalr t9,ra
0x24180000 // addiu t8,zero,DYN_INDEX sign extended
};
Mips_output_data_mips_stubs<size, big_endian>::lazy_stub_normal_1_n64[4] =
{
0xdf998010, // ld t9,0x8010(gp)
- 0x03e0782d, // daddu t7,ra,zero
+ 0x03e07825, // or t7,ra,zero
0x0320f809, // jalr t9,ra
0x64180000 // daddiu t8,zero,DYN_INDEX sign extended
};
Mips_output_data_mips_stubs<size, big_endian>::lazy_stub_normal_2[4] =
{
0x8f998010, // lw t9,0x8010(gp)
- 0x03e07821, // addu t7,ra,zero
+ 0x03e07825, // or t7,ra,zero
0x0320f809, // jalr t9,ra
0x34180000 // ori t8,zero,DYN_INDEX unsigned
};
Mips_output_data_mips_stubs<size, big_endian>::lazy_stub_normal_2_n64[4] =
{
0xdf998010, // ld t9,0x8010(gp)
- 0x03e0782d, // daddu t7,ra,zero
+ 0x03e07825, // or t7,ra,zero
0x0320f809, // jalr t9,ra
0x34180000 // ori t8,zero,DYN_INDEX unsigned
};
const uint32_t Mips_output_data_mips_stubs<size, big_endian>::lazy_stub_big[5] =
{
0x8f998010, // lw t9,0x8010(gp)
- 0x03e07821, // addu t7,ra,zero
+ 0x03e07825, // or t7,ra,zero
0x3c180000, // lui t8,DYN_INDEX
0x0320f809, // jalr t9,ra
0x37180000 // ori t8,t8,DYN_INDEX
Mips_output_data_mips_stubs<size, big_endian>::lazy_stub_big_n64[5] =
{
0xdf998010, // ld t9,0x8010(gp)
- 0x03e0782d, // daddu t7,ra,zero
+ 0x03e07825, // or t7,ra,zero
0x3c180000, // lui t8,DYN_INDEX
0x0320f809, // jalr t9,ra
0x37180000 // ori t8,t8,DYN_INDEX
lazy_stub_micromips32_normal_1[] =
{
0xff3c, 0x8010, // lw t9,0x8010(gp)
- 0x001f, 0x7950, // addu t7,ra,zero
+ 0x001f, 0x7a90, // or t7,ra,zero
0x03f9, 0x0f3c, // jalr ra,t9
0x3300, 0x0000 // addiu t8,zero,DYN_INDEX sign extended
};
lazy_stub_micromips32_normal_1_n64[] =
{
0xdf3c, 0x8010, // ld t9,0x8010(gp)
- 0x581f, 0x7950, // daddu t7,ra,zero
+ 0x001f, 0x7a90, // or t7,ra,zero
0x03f9, 0x0f3c, // jalr ra,t9
0x5f00, 0x0000 // daddiu t8,zero,DYN_INDEX sign extended
};
lazy_stub_micromips32_normal_2[] =
{
0xff3c, 0x8010, // lw t9,0x8010(gp)
- 0x001f, 0x7950, // addu t7,ra,zero
+ 0x001f, 0x7a90, // or t7,ra,zero
0x03f9, 0x0f3c, // jalr ra,t9
0x5300, 0x0000 // ori t8,zero,DYN_INDEX unsigned
};
lazy_stub_micromips32_normal_2_n64[] =
{
0xdf3c, 0x8010, // ld t9,0x8010(gp)
- 0x581f, 0x7950, // daddu t7,ra,zero
+ 0x001f, 0x7a90, // or t7,ra,zero
0x03f9, 0x0f3c, // jalr ra,t9
0x5300, 0x0000 // ori t8,zero,DYN_INDEX unsigned
};
Mips_output_data_mips_stubs<size, big_endian>::lazy_stub_micromips32_big[] =
{
0xff3c, 0x8010, // lw t9,0x8010(gp)
- 0x001f, 0x7950, // addu t7,ra,zero
+ 0x001f, 0x7a90, // or t7,ra,zero
0x41b8, 0x0000, // lui t8,DYN_INDEX
0x03f9, 0x0f3c, // jalr ra,t9
0x5318, 0x0000 // ori t8,t8,DYN_INDEX
Mips_output_data_mips_stubs<size, big_endian>::lazy_stub_micromips32_big_n64[] =
{
0xdf3c, 0x8010, // ld t9,0x8010(gp)
- 0x581f, 0x7950, // daddu t7,ra,zero
+ 0x001f, 0x7a90, // or t7,ra,zero
0x41b8, 0x0000, // lui t8,DYN_INDEX
0x03f9, 0x0f3c, // jalr ra,t9
0x5318, 0x0000 // ori t8,t8,DYN_INDEX
const unsigned char* plocal_symbols)
{
typedef Target_mips<size, big_endian> Mips;
- typedef typename Target_mips<size, big_endian>::Scan Scan;
+ typedef Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>
+ Classify_reloc;
- gold::gc_process_relocs<size, big_endian, Mips, elfcpp::SHT_REL, Scan,
- typename Target_mips::Relocatable_size_for_reloc>(
+ gold::gc_process_relocs<size, big_endian, Mips, Scan, Classify_reloc>(
symtab,
layout,
this,
const unsigned char* plocal_symbols)
{
typedef Target_mips<size, big_endian> Mips;
- typedef typename Target_mips<size, big_endian>::Scan Scan;
if (sh_type == elfcpp::SHT_REL)
- gold::scan_relocs<size, big_endian, Mips, elfcpp::SHT_REL, Scan>(
- symtab,
- layout,
- this,
- object,
- data_shndx,
- prelocs,
- reloc_count,
- output_section,
- needs_special_offset_handling,
- local_symbol_count,
- plocal_symbols);
+ {
+ typedef Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>
+ Classify_reloc;
+
+ gold::scan_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)
- gold::scan_relocs<size, big_endian, Mips, elfcpp::SHT_RELA, Scan>(
- symtab,
- layout,
- this,
- object,
- data_shndx,
- prelocs,
- reloc_count,
- output_section,
- needs_special_offset_handling,
- local_symbol_count,
- plocal_symbols);
+ {
+ typedef Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+ Classify_reloc;
+
+ gold::scan_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);
+ }
}
template<int size, bool big_endian>
typedef typename Target_mips<size, big_endian>::Relocate Mips_relocate;
if (sh_type == elfcpp::SHT_REL)
- gold::relocate_section<size, big_endian, Mips, elfcpp::SHT_REL,
- Mips_relocate, gold::Default_comdat_behavior>(
- relinfo,
- this,
- prelocs,
- reloc_count,
- output_section,
- needs_special_offset_handling,
- view,
- address,
- view_size,
- reloc_symbol_changes);
+ {
+ typedef Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>
+ Classify_reloc;
+
+ gold::relocate_section<size, big_endian, Mips, Mips_relocate,
+ gold::Default_comdat_behavior, Classify_reloc>(
+ relinfo,
+ this,
+ prelocs,
+ reloc_count,
+ output_section,
+ needs_special_offset_handling,
+ view,
+ address,
+ view_size,
+ reloc_symbol_changes);
+ }
else if (sh_type == elfcpp::SHT_RELA)
- gold::relocate_section<size, big_endian, Mips, elfcpp::SHT_RELA,
- Mips_relocate, gold::Default_comdat_behavior>(
- relinfo,
- this,
- prelocs,
- reloc_count,
- output_section,
- needs_special_offset_handling,
- view,
- address,
- view_size,
- reloc_symbol_changes);
+ {
+ typedef Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>
+ Classify_reloc;
+
+ gold::relocate_section<size, big_endian, Mips, Mips_relocate,
+ gold::Default_comdat_behavior, Classify_reloc>(
+ relinfo,
+ this,
+ prelocs,
+ reloc_count,
+ output_section,
+ needs_special_offset_handling,
+ view,
+ address,
+ view_size,
+ reloc_symbol_changes);
+ }
}
// Return the size of a relocation while scanning during a relocatable
// link.
-template<int size, bool big_endian>
unsigned int
-Target_mips<size, big_endian>::Relocatable_size_for_reloc::get_size_for_reloc(
- unsigned int r_type,
- Relobj* object)
+mips_get_size_for_reloc(unsigned int r_type, Relobj* object)
{
switch (r_type)
{
const unsigned char* plocal_symbols,
Relocatable_relocs* rr)
{
- gold_assert(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;
- typedef Mips_scan_relocatable_relocs<big_endian, elfcpp::SHT_REL,
- Relocatable_size_for_reloc> Scan_relocatable_relocs;
+ gold_assert(sh_type == elfcpp::SHT_REL);
- gold::scan_relocatable_relocs<size, big_endian, elfcpp::SHT_REL,
- Scan_relocatable_relocs>(
+ gold::scan_relocatable_relocs<size, big_endian, Scan_relocatable_relocs>(
symtab,
layout,
object,
rr);
}
+// Scan the relocs for --emit-relocs.
+
+template<int size, bool big_endian>
+void
+Target_mips<size, big_endian>::emit_relocs_scan(
+ Symbol_table* symtab,
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ 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);
+}
+
// Emit relocations for a section.
template<int size, bool big_endian>
Output_section* output_section,
typename elfcpp::Elf_types<size>::Elf_Off
offset_in_output_section,
- const Relocatable_relocs* rr,
unsigned char* view,
Mips_address view_address,
section_size_type view_size,
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, elfcpp::SHT_REL>(
+ gold::relocate_relocs<size, big_endian, Classify_reloc>(
relinfo,
prelocs,
reloc_count,
output_section,
offset_in_output_section,
- rr,
view,
view_address,
view_size,
Sized_relobj_file<size, big_endian>* object,
unsigned int data_shndx,
Output_section* output_section,
- const elfcpp::Rela<size, big_endian>* rela,
- const elfcpp::Rel<size, big_endian>* rel,
+ const Relatype* rela,
+ const Reltype* rel,
unsigned int rel_type,
unsigned int r_type,
const elfcpp::Sym<size, big_endian>& lsym,
return;
Mips_address r_offset;
- typename elfcpp::Elf_types<size>::Elf_WXword r_info;
+ unsigned int r_sym;
typename elfcpp::Elf_types<size>::Elf_Swxword r_addend;
if (rel_type == elfcpp::SHT_RELA)
{
r_offset = rela->get_r_offset();
- r_info = rela->get_r_info();
+ r_sym = Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>::
+ get_r_sym(rela);
r_addend = rela->get_r_addend();
}
else
{
r_offset = rel->get_r_offset();
- r_info = rel->get_r_info();
+ r_sym = Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>::
+ get_r_sym(rel);
r_addend = 0;
}
- unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
Mips_relobj<size, big_endian>* mips_obj =
Mips_relobj<size, big_endian>::as_mips_relobj(object);
// R_MIPS_GOT_LO16 or R_MIPS_CALL_LO16.
Mips_output_data_got<size, big_endian>* got =
target->got_section(symtab, layout);
- unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
got->record_local_got_symbol(mips_obj, r_sym, r_addend, r_type, -1U);
}
// executable), we need to create a dynamic relocation for
// this location.
Reloc_section* rel_dyn = target->rel_dyn_section(layout);
- unsigned int r_sym = elfcpp::elf_r_sym<32>(r_info);
rel_dyn->add_symbolless_local_addend(object, r_sym,
elfcpp::R_MIPS_REL32,
output_section, data_shndx,
case elfcpp::R_MIPS16_TLS_GD:
case elfcpp::R_MICROMIPS_TLS_GD:
{
- unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
bool output_is_shared = parameters->options().shared();
const tls::Tls_optimization optimized_type
= Target_mips<size, big_endian>::optimize_tls_reloc(
Sized_relobj_file<size, big_endian>* object,
unsigned int data_shndx,
Output_section* output_section,
- const elfcpp::Rel<size, big_endian>& reloc,
+ const Reltype& reloc,
unsigned int r_type,
const elfcpp::Sym<size, big_endian>& lsym,
bool is_discarded)
object,
data_shndx,
output_section,
- (const elfcpp::Rela<size, big_endian>*) NULL,
+ (const Relatype*) NULL,
&reloc,
elfcpp::SHT_REL,
r_type,
Sized_relobj_file<size, big_endian>* object,
unsigned int data_shndx,
Output_section* output_section,
- const elfcpp::Rela<size, big_endian>& reloc,
+ const Relatype& reloc,
unsigned int r_type,
const elfcpp::Sym<size, big_endian>& lsym,
bool is_discarded)
data_shndx,
output_section,
&reloc,
- (const elfcpp::Rel<size, big_endian>*) NULL,
+ (const Reltype*) NULL,
elfcpp::SHT_RELA,
r_type,
lsym, is_discarded);
Sized_relobj_file<size, big_endian>* object,
unsigned int data_shndx,
Output_section* output_section,
- const elfcpp::Rela<size, big_endian>* rela,
- const elfcpp::Rel<size, big_endian>* rel,
+ const Relatype* rela,
+ const Reltype* rel,
unsigned int rel_type,
unsigned int r_type,
Symbol* gsym)
{
Mips_address r_offset;
- typename elfcpp::Elf_types<size>::Elf_WXword r_info;
+ unsigned int r_sym;
typename elfcpp::Elf_types<size>::Elf_Swxword r_addend;
if (rel_type == elfcpp::SHT_RELA)
{
r_offset = rela->get_r_offset();
- r_info = rela->get_r_info();
+ r_sym = Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>::
+ get_r_sym(rela);
r_addend = rela->get_r_addend();
}
else
{
r_offset = rel->get_r_offset();
- r_info = rel->get_r_info();
+ r_sym = Mips_classify_reloc<elfcpp::SHT_REL, size, big_endian>::
+ get_r_sym(rel);
r_addend = 0;
}
- unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
Mips_relobj<size, big_endian>* mips_obj =
Mips_relobj<size, big_endian>::as_mips_relobj(object);
Mips_symbol<size>* mips_sym = Mips_symbol<size>::as_mips_sym(gsym);
Sized_relobj_file<size, big_endian>* object,
unsigned int data_shndx,
Output_section* output_section,
- const elfcpp::Rela<size, big_endian>& reloc,
+ const Relatype& reloc,
unsigned int r_type,
Symbol* gsym)
{
data_shndx,
output_section,
&reloc,
- (const elfcpp::Rel<size, big_endian>*) NULL,
+ (const Reltype*) NULL,
elfcpp::SHT_RELA,
r_type,
gsym);
Sized_relobj_file<size, big_endian>* object,
unsigned int data_shndx,
Output_section* output_section,
- const elfcpp::Rel<size, big_endian>& reloc,
+ const Reltype& reloc,
unsigned int r_type,
Symbol* gsym)
{
object,
data_shndx,
output_section,
- (const elfcpp::Rela<size, big_endian>*) NULL,
+ (const Relatype*) NULL,
&reloc,
elfcpp::SHT_REL,
r_type,
inline bool
Target_mips<size, big_endian>::Relocate::relocate(
const Relocate_info<size, big_endian>* relinfo,
+ unsigned int rel_type,
Target_mips* target,
Output_section* output_section,
size_t relnum,
- const elfcpp::Rela<size, big_endian>* rela,
- const elfcpp::Rel<size, big_endian>* rel,
- unsigned int rel_type,
- unsigned int r_type,
+ const unsigned char* preloc,
const Sized_symbol<size>* gsym,
const Symbol_value<size>* psymval,
unsigned char* view,
section_size_type)
{
Mips_address r_offset;
- typename elfcpp::Elf_types<size>::Elf_WXword r_info;
+ unsigned int r_sym;
+ unsigned int r_type;
typename elfcpp::Elf_types<size>::Elf_Swxword r_addend;
if (rel_type == elfcpp::SHT_RELA)
{
- r_offset = rela->get_r_offset();
- r_info = rela->get_r_info();
- r_addend = rela->get_r_addend();
+ const Relatype rela(preloc);
+ r_offset = rela.get_r_offset();
+ r_sym = Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>::
+ get_r_sym(&rela);
+ r_type = Mips_classify_reloc<elfcpp::SHT_RELA, size, big_endian>::
+ get_r_type(&rela);
+ r_addend = rela.get_r_addend();
}
else
{
- r_offset = rel->get_r_offset();
- r_info = rel->get_r_info();
+
+ 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_addend = 0;
}
typename Reloc_funcs::Status reloc_status = Reloc_funcs::STATUS_OKAY;
Mips_relobj<size, big_endian>* object =
- Mips_relobj<size, big_endian>::as_mips_relobj(relinfo->object);
+ Mips_relobj<size, big_endian>::as_mips_relobj(relinfo->object);
- unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
bool target_is_16_bit_code = false;
bool target_is_micromips_code = false;
bool cross_mode_jump;
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,
+ address, gp_disp, r_type, r_sym,
extract_addend);
break;
case elfcpp::R_MICROMIPS_HI0_LO16:
reloc_status = Reloc_funcs::rello16(target, view, object, psymval,
r_addend, extract_addend, address,
- gp_disp, r_type);
+ gp_disp, r_type, r_sym);
break;
case elfcpp::R_MIPS_LITERAL:
else
reloc_status = Reloc_funcs::relgot16_local(view, object, psymval,
r_addend, extract_addend,
- r_type);
+ r_type, r_sym);
update_got_entry = changed_symbol_value;
break;
return true;
}
-template<int size, bool big_endian>
-inline bool
-Target_mips<size, big_endian>::Relocate::relocate(
- const Relocate_info<size, big_endian>* relinfo,
- Target_mips* target,
- Output_section* output_section,
- size_t relnum,
- const elfcpp::Rela<size, big_endian>& reloc,
- unsigned int r_type,
- const Sized_symbol<size>* gsym,
- const Symbol_value<size>* psymval,
- unsigned char* view,
- Mips_address address,
- section_size_type view_size)
-{
- return relocate(
- relinfo,
- target,
- output_section,
- relnum,
- &reloc,
- (const elfcpp::Rel<size, big_endian>*) NULL,
- elfcpp::SHT_RELA,
- r_type,
- gsym,
- psymval,
- view,
- address,
- view_size);
-}
-
-template<int size, bool big_endian>
-inline bool
-Target_mips<size, big_endian>::Relocate::relocate(
- const Relocate_info<size, big_endian>* relinfo,
- Target_mips* target,
- Output_section* output_section,
- size_t relnum,
- const elfcpp::Rel<size, big_endian>& reloc,
- unsigned int r_type,
- const Sized_symbol<size>* gsym,
- const Symbol_value<size>* psymval,
- unsigned char* view,
- Mips_address address,
- section_size_type view_size)
-{
- return relocate(
- relinfo,
- target,
- output_section,
- relnum,
- (const elfcpp::Rela<size, big_endian>*) NULL,
- &reloc,
- elfcpp::SHT_REL,
- r_type,
- gsym,
- psymval,
- view,
- address,
- view_size);
-}
-
// Get the Reference_flags for a particular relocation.
template<int size, bool big_endian>
}
template<int size, bool big_endian>
-Target::Target_info Target_mips<size, big_endian>::mips_info =
+const Target::Target_info Target_mips<size, big_endian>::mips_info =
{
size, // size
big_endian, // is_big_endian
0, // large_common_section_flags
NULL, // attributes_section
NULL, // attributes_vendor
- "__start" // entry_symbol_name
+ "__start", // entry_symbol_name
+ 32, // hash_entry_size
+};
+
+template<int size, bool big_endian>
+class Target_mips_nacl : public Target_mips<size, big_endian>
+{
+ public:
+ Target_mips_nacl()
+ : Target_mips<size, big_endian>(&mips_nacl_info)
+ { }
+
+ private:
+ static const Target::Target_info mips_nacl_info;
+};
+
+template<int size, bool big_endian>
+const Target::Target_info Target_mips_nacl<size, big_endian>::mips_nacl_info =
+{
+ size, // size
+ big_endian, // is_big_endian
+ elfcpp::EM_MIPS, // machine_code
+ true, // has_make_symbol
+ false, // has_resolve
+ false, // has_code_fill
+ true, // is_default_stack_executable
+ false, // can_icf_inline_merge_sections
+ '\0', // wrap_char
+ "/lib/ld.so.1", // dynamic_linker
+ 0x20000, // default_text_segment_address
+ 0x10000, // abi_pagesize (overridable by -z max-page-size)
+ 0x10000, // common_pagesize (overridable by -z common-page-size)
+ true, // isolate_execinstr
+ 0x10000000, // rosegment_gap
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_UNDEF, // large_common_shndx
+ 0, // small_common_section_flags
+ 0, // large_common_section_flags
+ NULL, // attributes_section
+ NULL, // attributes_vendor
+ "_start", // entry_symbol_name
+ 32, // hash_entry_size
};
-// The selector for mips object files.
+// Target selector for Mips. Note this is never instantiated directly.
+// It's only used in Target_selector_mips_nacl, below.
template<int size, bool big_endian>
class Target_selector_mips : public Target_selector
{ return new Target_mips<size, big_endian>(); }
};
-Target_selector_mips<32, true> target_selector_mips32be;
-Target_selector_mips<32, false> target_selector_mips32;
-Target_selector_mips<64, true> target_selector_mips64be;
-Target_selector_mips<64, false> target_selector_mips64;
+template<int size, bool big_endian>
+class Target_selector_mips_nacl
+ : public Target_selector_nacl<Target_selector_mips<size, big_endian>,
+ Target_mips_nacl<size, big_endian> >
+{
+ public:
+ Target_selector_mips_nacl()
+ : Target_selector_nacl<Target_selector_mips<size, big_endian>,
+ Target_mips_nacl<size, big_endian> >(
+ // NaCl currently supports only MIPS32 little-endian.
+ "mipsel", "elf32-tradlittlemips-nacl", "elf32-tradlittlemips-nacl")
+ { }
+};
+Target_selector_mips_nacl<32, true> target_selector_mips32;
+Target_selector_mips_nacl<32, false> target_selector_mips32el;
+Target_selector_mips_nacl<64, true> target_selector_mips64;
+Target_selector_mips_nacl<64, false> target_selector_mips64el;
} // End anonymous namespace.