aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'gold/output.cc')
-rw-r--r--gold/output.cc70
1 files changed, 49 insertions, 21 deletions
diff --git a/gold/output.cc b/gold/output.cc
index 664e408bb1e..d75579b6152 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -1369,7 +1369,9 @@ Output_data_group<size, big_endian>::do_write(Output_file* of)
template<int size, bool big_endian>
void
-Output_data_got<size, big_endian>::Got_entry::write(unsigned char* pov) const
+Output_data_got<size, big_endian>::Got_entry::write(
+ unsigned int got_indx,
+ unsigned char* pov) const
{
Valtype val = 0;
@@ -1381,7 +1383,7 @@ Output_data_got<size, big_endian>::Got_entry::write(unsigned char* pov) const
// link-time value, which will be relocated dynamically by a
// RELATIVE relocation.
Symbol* gsym = this->u_.gsym;
- if (this->use_plt_offset_ && gsym->has_plt_offset())
+ if (this->use_plt_or_tls_offset_ && gsym->has_plt_offset())
val = (parameters->target().plt_address_for_global(gsym)
+ gsym->plt_offset());
else
@@ -1392,6 +1394,9 @@ Output_data_got<size, big_endian>::Got_entry::write(unsigned char* pov) const
// as small as possible.
sgsym = static_cast<Sized_symbol<size>*>(gsym);
val = sgsym->value();
+ if (this->use_plt_or_tls_offset_ && gsym->type() == elfcpp::STT_TLS)
+ val += parameters->target().tls_offset_for_global(gsym,
+ got_indx);
}
}
break;
@@ -1409,19 +1414,24 @@ Output_data_got<size, big_endian>::Got_entry::write(unsigned char* pov) const
default:
{
- const Relobj* object = this->u_.object;
+ const Sized_relobj_file<size, big_endian>* object
+ = static_cast<Sized_relobj_file<size, big_endian>*>(this->u_.object);
const unsigned int lsi = this->local_sym_index_;
- if (!this->use_plt_offset_)
- {
- uint64_t lval = object->local_symbol_value(lsi, 0);
- val = convert_types<Valtype, uint64_t>(lval);
- }
- else
+ bool is_tls = object->local_symbol(lsi)->is_tls_symbol();
+ if (this->use_plt_or_tls_offset_ && !is_tls)
{
uint64_t plt_address =
parameters->target().plt_address_for_local(object, lsi);
val = plt_address + object->local_plt_offset(lsi);
}
+ else
+ {
+ uint64_t lval = object->local_symbol_value(lsi, 0);
+ val = convert_types<Valtype, uint64_t>(lval);
+ if (this->use_plt_or_tls_offset_ && is_tls)
+ val += parameters->target().tls_offset_for_local(object, lsi,
+ got_indx);
+ }
}
break;
}
@@ -1566,8 +1576,10 @@ Output_data_got<size, big_endian>::add_local_with_rel(
}
// Add a pair of entries for a local symbol to the GOT, and add
-// dynamic relocations of type R_TYPE_1 and R_TYPE_2, respectively.
-// If R_TYPE_2 == 0, add the second entry with no relocation.
+// a dynamic relocation of type R_TYPE using the section symbol of
+// the output section to which input section SHNDX maps, on the first.
+// The first got entry will have a value of zero, the second the
+// value of the local symbol.
template<int size, bool big_endian>
void
Output_data_got<size, big_endian>::add_local_pair_with_rel(
@@ -1576,8 +1588,7 @@ Output_data_got<size, big_endian>::add_local_pair_with_rel(
unsigned int shndx,
unsigned int got_type,
Output_data_reloc_generic* rel_dyn,
- unsigned int r_type_1,
- unsigned int r_type_2)
+ unsigned int r_type)
{
if (object->local_has_got_offset(symndx, got_type))
return;
@@ -1587,11 +1598,30 @@ Output_data_got<size, big_endian>::add_local_pair_with_rel(
Got_entry(object, symndx, false));
object->set_local_got_offset(symndx, got_type, got_offset);
Output_section* os = object->output_section(shndx);
- rel_dyn->add_output_section_generic(os, r_type_1, this, got_offset, 0);
+ rel_dyn->add_output_section_generic(os, r_type, this, got_offset, 0);
+}
- if (r_type_2 != 0)
- rel_dyn->add_output_section_generic(os, r_type_2, this,
- got_offset + size / 8, 0);
+// Add a pair of entries for a local symbol to the GOT, and add
+// a dynamic relocation of type R_TYPE using STN_UNDEF on the first.
+// The first got entry will have a value of zero, the second the
+// value of the local symbol offset by Target::tls_offset_for_local.
+template<int size, bool big_endian>
+void
+Output_data_got<size, big_endian>::add_local_tls_pair(
+ Relobj* object,
+ unsigned int symndx,
+ unsigned int got_type,
+ Output_data_reloc_generic* rel_dyn,
+ unsigned int r_type)
+{
+ if (object->local_has_got_offset(symndx, got_type))
+ return;
+
+ unsigned int got_offset
+ = this->add_got_entry_pair(Got_entry(),
+ Got_entry(object, symndx, true));
+ object->set_local_got_offset(symndx, got_type, got_offset);
+ rel_dyn->add_local_generic(object, 0, r_type, this, got_offset, 0);
}
// Reserve a slot in the GOT for a local symbol or the second slot of a pair.
@@ -1634,11 +1664,9 @@ Output_data_got<size, big_endian>::do_write(Output_file* of)
unsigned char* const oview = of->get_output_view(off, oview_size);
unsigned char* pov = oview;
- for (typename Got_entries::const_iterator p = this->entries_.begin();
- p != this->entries_.end();
- ++p)
+ for (unsigned int i = 0; i < this->entries_.size(); ++i)
{
- p->write(pov);
+ this->entries_[i].write(i, pov);
pov += add;
}