aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gold/ChangeLog9
-rw-r--r--gold/i386.cc35
2 files changed, 43 insertions, 1 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog
index 4840179..eab140b 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,3 +1,12 @@
+2009-10-06 Ian Lance Taylor <iant@google.com>
+
+ * i386.cc (class Target_i386::Relocate): Add ldo_addrs_ field.
+ (Target_i386::Relocate::relocate_tls): Call fix_up_ldo before
+ changing local_dynamic_type_ from LOCAL_DYNAMIC_NONE. When
+ handling R_386_TLS_LDO_32, if local_dynamic_type_ is NONE, push
+ the address on ldo_addrs_.
+ (Target_i386::Relocate::fix_up_ldo): New function.
+
2009-10-06 Rafael Espindola <espindola@google.com>
* plugin.cc (add_input_library): New.
diff --git a/gold/i386.cc b/gold/i386.cc
index 27e1cc9..0c43761 100644
--- a/gold/i386.cc
+++ b/gold/i386.cc
@@ -212,7 +212,7 @@ class Target_i386 : public Target_freebsd<32, false>
public:
Relocate()
: skip_call_tls_get_addr_(false),
- local_dynamic_type_(LOCAL_DYNAMIC_NONE)
+ local_dynamic_type_(LOCAL_DYNAMIC_NONE), ldo_addrs_()
{ }
~Relocate()
@@ -307,6 +307,10 @@ class Target_i386 : public Target_freebsd<32, false>
unsigned char* view,
section_size_type view_size);
+ // Fix up LDO_32 relocations we've already seen.
+ void
+ fix_up_ldo(const Relocate_info<32, false>*);
+
// We need to keep track of which type of local dynamic relocation
// we have seen, so that we can optimize R_386_TLS_LDO_32 correctly.
enum Local_dynamic_type
@@ -322,6 +326,8 @@ class Target_i386 : public Target_freebsd<32, false>
// The type of local dynamic relocation we have seen in the section
// being relocated, if any.
Local_dynamic_type local_dynamic_type_;
+ // A list of LDO_32 offsets, in case we find LDM after LDO_32.
+ std::vector<unsigned char*> ldo_addrs_;
};
// A class which returns the size required for a relocation type,
@@ -1922,6 +1928,8 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (from ~oliva url)
case elfcpp::R_386_TLS_DESC_CALL:
+ if (this->local_dynamic_type_ == LOCAL_DYNAMIC_NONE)
+ this->fix_up_ldo(relinfo);
this->local_dynamic_type_ = LOCAL_DYNAMIC_GNU;
if (optimized_type == tls::TLSOPT_TO_LE)
{
@@ -1980,6 +1988,8 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
"TLS relocations"));
break;
}
+ else if (this->local_dynamic_type_ == LOCAL_DYNAMIC_NONE)
+ this->fix_up_ldo(relinfo);
this->local_dynamic_type_ = LOCAL_DYNAMIC_GNU;
if (optimized_type == tls::TLSOPT_TO_LE)
{
@@ -2013,6 +2023,11 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
gold_assert(tls_segment != NULL);
value -= tls_segment->memsz();
}
+ else
+ {
+ // We may see the LDM later.
+ this->ldo_addrs_.push_back(view);
+ }
Relocate_functions<32, false>::rel32(view, value);
break;
@@ -2419,6 +2434,24 @@ Target_i386::Relocate::tls_ie_to_le(const Relocate_info<32, false>* relinfo,
Relocate_functions<32, false>::rel32(view, value);
}
+// If we see an LDM reloc after we handled any LDO_32 relocs, fix up
+// the LDO_32 relocs.
+
+void
+Target_i386::Relocate::fix_up_ldo(const Relocate_info<32, false>* relinfo)
+{
+ if (this->ldo_addrs_.empty())
+ return;
+ Output_segment* tls_segment = relinfo->layout->tls_segment();
+ gold_assert(tls_segment != NULL);
+ elfcpp::Elf_types<32>::Elf_Addr value = - tls_segment->memsz();
+ for (std::vector<unsigned char*>::const_iterator p = this->ldo_addrs_.begin();
+ p != this->ldo_addrs_.end();
+ ++p)
+ Relocate_functions<32, false>::rel32(*p, value);
+ this->ldo_addrs_.clear();
+}
+
// Relocate section data.
void