// tilegx.cc -- tilegx target support for gold.
-// Copyright 2012 Free Software Foundation, Inc.
+// Copyright (C) 2012-2014 Free Software Foundation, Inc.
// Written by Jiong Wang (jiwang@tilera.com)
// This file is part of gold.
got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL),
global_offset_table_(NULL), tilegx_dynamic_(NULL), rela_dyn_(NULL),
rela_irelative_(NULL), copy_relocs_(elfcpp::R_TILEGX_COPY),
- dynbss_(NULL), got_mod_index_offset_(-1U),
+ got_mod_index_offset_(-1U),
tls_get_addr_sym_defined_(false)
{ }
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
- off_t offset_in_output_section,
+ typename elfcpp::Elf_types<size>::Elf_Off offset_in_output_section,
const Relocatable_relocs*,
unsigned char* view,
typename elfcpp::Elf_types<size>::Elf_Addr view_address,
Reloc_section* rela_irelative_;
// Relocs saved to avoid a COPY reloc.
Copy_relocs<elfcpp::SHT_RELA, size, big_endian> copy_relocs_;
- // Space for variables copied with a COPY reloc.
- Output_data_space* dynbss_;
// Offset of the GOT entry for the TLS module index.
unsigned int got_mod_index_offset_;
// True if the _tls_get_addr symbol has been defined.
0, // small_common_section_flags
0, // large_common_section_flags
NULL, // attributes_section
- NULL // attributes_vendor
+ NULL, // attributes_vendor
+ "_start" // entry_symbol_name
};
template<>
0, // small_common_section_flags
0, // large_common_section_flags
NULL, // attributes_section
- NULL // attributes_vendor
+ NULL, // attributes_vendor
+ "_start" // entry_symbol_name
};
template<>
0, // small_common_section_flags
0, // large_common_section_flags
NULL, // attributes_section
- NULL // attributes_vendor
+ NULL, // attributes_vendor
+ "_start" // entry_symbol_name
};
template<>
0, // small_common_section_flags
0, // large_common_section_flags
NULL, // attributes_section
- NULL // attributes_vendor
+ NULL, // attributes_vendor
+ "_start" // entry_symbol_name
};
// tilegx relocation handlers
// right shift operand by this number of bits.
unsigned char srshift;
- // the offset to apply relocation.
+ // the offset to apply relocation.
unsigned char doffset;
// set to 1 for pc-relative relocation.
Valtype* wv = reinterpret_cast<Valtype*>(view);
Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
Valtype reloc = 0;
- if (size == 32)
+ if (size == 32)
reloc = Bits<32>::sign_extend(psymval->value(object, addend) - address)
>> srshift;
else
Valtype;
unsigned char* wv = view;
Valtype reloc = 0;
- if (size == 32)
+ if (size == 32)
reloc = Bits<32>::sign_extend(psymval->value(object, addend) - address)
>> srshift;
else
Valtype* wv = reinterpret_cast<Valtype*>(view);
Valtype val = elfcpp::Swap<valsize, big_endian>::readval(wv);
Valtype reloc = 0;
- if (size == 32)
+ if (size == 32)
reloc = Bits<32>::sign_extend(psymval->value(object, addend) - address)
>> srshift;
else
const Symbol_value<size>* psymval,
typename elfcpp::Elf_types<size>::Elf_Addr addend,
Tilegx_howto &r_howto)
- {
+ {
This::template rela<64>(view, object, psymval, addend,
(elfcpp::Elf_Xword)(r_howto.srshift),
(elfcpp::Elf_Xword)(r_howto.doffset),
typename elfcpp::Elf_types<size>::Elf_Addr addend,
typename elfcpp::Elf_types<size>::Elf_Addr address,
Tilegx_howto &r_howto)
- {
+ {
This::template pcrela<64>(view, object, psymval, addend, address,
(elfcpp::Elf_Xword)(r_howto.srshift),
(elfcpp::Elf_Xword)(r_howto.doffset),
typename elfcpp::Elf_types<size>::Elf_Addr addend,
typename elfcpp::Elf_types<size>::Elf_Addr address,
unsigned int r_type)
- {
+ {
elfcpp::Elf_Xword doffset1 = 0llu;
elfcpp::Elf_Xword doffset2 = 0llu;
static inline void
tls_relax(unsigned char* view, unsigned int r_type,
tls::Tls_optimization opt_t)
- {
-
+ {
+
const uint64_t TILEGX_X_MOVE_R0_R0 = 0x283bf8005107f000llu;
const uint64_t TILEGX_Y_MOVE_R0_R0 = 0xae05f800540bf000llu;
const uint64_t TILEGX_X_LD = 0x286ae80000000000llu;
// LE: 1. copy dest operand into the first source operand
// 2. change the opcode to "move"
reloc = (val & 0x3Fllu) << 6;
- reloc |= (TILEGX_X_MOVE_R0_R0 & TILEGX_X0_RRR_SRCB_MASK);
+ reloc |= (TILEGX_X_MOVE_R0_R0 & TILEGX_X0_RRR_SRCB_MASK);
val &= ~R_TILEGX_IMM8_X0_TLS_ADD_LE_MASK;
} else
gold_unreachable();
break;
case elfcpp::R_TILEGX_IMM8_X0_TLS_GD_ADD:
if (opt_t == tls::TLSOPT_NONE) {
- // GD see comments for optimize_tls_reloc
+ // GD see comments for optimize_tls_reloc
reloc = TILEGX_X_MOVE_R0_R0 & TILEGX_X0_RRR_SRCB_MASK;
val &= ~TILEGX_X0_RRR_SRCB_MASK;
} else if (opt_t == tls::TLSOPT_TO_IE
false, false);
this->got_->add_global(this->tilegx_dynamic_, GOT_TYPE_STANDARD);
- } else
+ } else
// for executable, just set the first entry to zero.
this->got_->set_current_data_size(size / 8);
plt_index = *pcount;
// TILEGX .plt section layout
- //
+ //
// ----
// plt_header
// ----
// ----
// ...
// ----
- //
+ //
// TILEGX .got.plt section layout
- //
+ //
// ----
// reserv1
// ----
// entries for normal function
// ----
// ...
- // ----
+ // ----
// entries for ifunc
// ----
// ...
if (gsym->type() == elfcpp::STT_GNU_IFUNC
&& gsym->can_use_relative_reloc(false))
offset = (this->count_ + 1) * this->get_plt_entry_size();
- return this->address() + offset;
+ return this->address() + offset + gsym->plt_offset();
}
// Return the PLT address to use for a local symbol. These are always
template<int size, bool big_endian>
uint64_t
-Output_data_plt_tilegx<size, big_endian>::address_for_local(const Relobj*,
- unsigned int)
+Output_data_plt_tilegx<size, big_endian>::address_for_local(
+ const Relobj* object,
+ unsigned int r_sym)
{
- return this->address() + (this->count_ + 1) * this->get_plt_entry_size();
+ return (this->address()
+ + (this->count_ + 1) * this->get_plt_entry_size()
+ + object->local_plt_offset(r_sym));
}
// Set the final size.
// move r0, r0 Y0/Y1/X0/X1
// move r0, r0 Y0/Y1/X0/X1
// add adr, r0, tp Y0/Y1/X0/X1
-//
-//
+//
+//
// compiler IE reference
// |
// V
}
// We are about to emit a dynamic relocation of type R_TYPE. If the
-// dynamic linker does not support it, issue an error.
+// dynamic linker does not support it, issue an error.
template<int size, bool big_endian>
void
Target_tilegx<size, big_endian>::Scan::check_non_pic(Relobj* object,
data_shndx,
reloc.get_r_offset(),
reloc.get_r_addend());
-
+
}
}
break;
break;
// GD: requires two GOT entry for module index and offset
- // IE: requires one GOT entry for tp-relative offset
+ // IE: requires one GOT entry for tp-relative offset
// LE: shouldn't happen for global symbol
case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_GD:
case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_GD:
r_sym, shndx);
else
got->add_local_pair_with_rel(object, r_sym, shndx,
- GOT_TYPE_TLS_PAIR,
+ GOT_TYPE_TLS_PAIR,
target->rela_dyn_section(layout),
size == 32
? elfcpp::R_TILEGX_TLS_DTPMOD32
? elfcpp::R_TILEGX_TLS_TPOFF32
: elfcpp::R_TILEGX_TLS_TPOFF64,
got, off, 0);
- } else if (opt_t != tls::TLSOPT_TO_LE)
+ } else if (opt_t != tls::TLSOPT_TO_LE)
// only TO_LE is allowed for local symbol
unsupported_reloc_local(object, r_type);
}
// Make a dynamic relocation if necessary.
if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
{
- if (gsym->may_need_copy_reloc())
+ if (!parameters->options().output_is_position_independent()
+ && gsym->may_need_copy_reloc())
{
target->copy_reloc(symtab, layout, object,
data_shndx, output_section, gsym, reloc);
// Make a dynamic relocation if necessary.
if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
{
- if (gsym->may_need_copy_reloc())
+ if (parameters->options().output_is_executable()
+ && gsym->may_need_copy_reloc())
{
target->copy_reloc(symtab, layout, object,
data_shndx, output_section, gsym, reloc);
symtab->lookup("__tls_get_addr"));
}
break;
-
+
// only make effect when applying relocation
case elfcpp::R_TILEGX_TLS_IE_LOAD:
case elfcpp::R_TILEGX_IMM8_X0_TLS_ADD:
case elfcpp::R_TILEGX_IMM8_Y0_TLS_GD_ADD:
case elfcpp::R_TILEGX_IMM8_Y1_TLS_GD_ADD:
break;
-
+
// GD: requires two GOT entry for module index and offset
- // IE: requires one GOT entry for tp-relative offset
+ // IE: requires one GOT entry for tp-relative offset
// LE: shouldn't happen for global symbol
case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_GD:
case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_GD:
unsupported_reloc_global(object, r_type, gsym);
}
break;
-
+
// IE
case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_IE:
case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_IE:
unsupported_reloc_global(object, r_type, gsym);
}
break;
-
+
// LE
case elfcpp::R_TILEGX_IMM16_X0_HW0_TLS_LE:
case elfcpp::R_TILEGX_IMM16_X1_HW0_TLS_LE:
typename elfcpp::Elf_types<size>::Elf_Addr address,
section_size_type)
{
+ if (view == NULL)
+ return true;
+
typedef Tilegx_relocate_functions<size, big_endian> TilegxReloc;
typename TilegxReloc::Tilegx_howto r_howto;
if (gsym != NULL
&& gsym->use_plt_offset(Scan::get_reference_flags(r_type)))
{
- symval.set_output_value(target->plt_address_for_global(gsym)
- + gsym->plt_offset());
+ symval.set_output_value(target->plt_address_for_global(gsym));
psymval = &symval;
}
else if (gsym == NULL && psymval->is_ifunc_symbol())
unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
if (object->local_has_plt_offset(r_sym))
{
- symval.set_output_value(target->plt_address_for_local(object, r_sym)
- + object->local_plt_offset(r_sym));
+ symval.set_output_value(target->plt_address_for_local(object, r_sym));
psymval = &symval;
}
}
if (opt_t == tls::TLSOPT_NONE) {
Symbol *tls_sym = relinfo->symtab->lookup("__tls_get_addr");
symval.set_output_value(
- target->plt_address_for_global(tls_sym)
- + tls_sym->plt_offset());
+ target->plt_address_for_global(tls_sym));
psymval = &symval;
TilegxReloc::imm_x_pcrel_general(view, object, psymval,
addend, address, r_howto);
} // else if (opt_t == tls::TLSOPT_TO_LE)
// both GD/IE are turned into LE, which
// is absolute relocation.
- //
+ //
// | go through
- // |
+ // |
// V
// LE
- //
+ //
// tp
// |
// V
- // t_var1 | t_var2 | t_var3 | ...
+ // t_var1 | t_var2 | t_var3 | ...
// --------------------------------------------------
//
// so offset to tp should be negative, we get offset
|| issue_undefined_symbol_error(gsym));
return false;
}
-
+
typename elfcpp::Elf_types<size>::Elf_Addr value
= psymval->value(relinfo->object, 0);
symval.set_output_value(value);
gold_assert(sh_type == elfcpp::SHT_RELA);
- gold::relocate_section<size, big_endian, Tilegx,
- elfcpp::SHT_RELA, Tilegx_relocate>(
+ gold::relocate_section<size, big_endian, Tilegx, elfcpp::SHT_RELA,
+ Tilegx_relocate, gold::Default_comdat_behavior>(
relinfo,
this,
prelocs,
const unsigned char* prelocs,
size_t reloc_count,
Output_section* output_section,
- off_t offset_in_output_section,
+ typename elfcpp::Elf_types<size>::Elf_Off offset_in_output_section,
const Relocatable_relocs* rr,
unsigned char* view,
typename elfcpp::Elf_types<size>::Elf_Addr view_address,
Target_tilegx<size, big_endian>::do_dynsym_value(const Symbol* gsym) const
{
gold_assert(gsym->is_from_dynobj() && gsym->has_plt_offset());
- return this->plt_address_for_global(gsym) + gsym->plt_offset();
+ return this->plt_address_for_global(gsym);
}
// Return the value to use for the base of a DW_EH_PE_datarel offset
return ssym->value();
}
-// The selector for tilegx object files.
+// The selector for tilegx object files.
template<int size, bool big_endian>
class Target_selector_tilegx : public Target_selector