aboutsummaryrefslogtreecommitdiff
path: root/gold/i386.cc
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@airs.com>2010-08-02 10:07:03 +0000
committerIan Lance Taylor <ian@airs.com>2010-08-02 10:07:03 +0000
commita8df5856e2174b21c341d926068f195624d5d089 (patch)
treeac21be63f1586266d08e42e8052c8f0c1f0be848 /gold/i386.cc
parentb27423bb543a28c11bdfb63dc5ea978a4a637f67 (diff)
downloadfsf-binutils-gdb-a8df5856e2174b21c341d926068f195624d5d089.zip
fsf-binutils-gdb-a8df5856e2174b21c341d926068f195624d5d089.tar.gz
fsf-binutils-gdb-a8df5856e2174b21c341d926068f195624d5d089.tar.bz2
* i386.cc (class Target_i386): Add got_tlsdesc_ field.
(Target_i386::Target_i386):: Initialize got_tlsdesc_. (Target_i386::got_tlsdesc_section): New function. (Target_i386::got_section): Create space for GOT entries for TLSDESC relocations. (Target_i386::Scan::local): Use TLSDESC GOT for unoptimized R_386_TLS_GOTDESC. (Target_i386::Scan::global): Likewise. (Target_i386::Relocate::relocate_tls): Adjust GOT offset when using TLSDESC GOT. * x86_64.cc (class Target_x86_64): Add got_tlsdesc_ field. (Target_x86_64::Target_x86_64):: Initialize got_tlsdesc_. (Target_x86_64::got_tlsdesc_section): New function. (Target_x86_64::got_section): Create space for GOT entries for TLSDESC relocations. (Target_x86_64::Scan::local): Use TLSDESC GOT for unoptimized R_386_TLS_GOTDESC. (Target_x86_64::Scan::global): Likewise. (Target_x86_64::Relocate::relocate_tls): Adjust GOT offset when using TLSDESC GOT.
Diffstat (limited to 'gold/i386.cc')
-rw-r--r--gold/i386.cc63
1 files changed, 50 insertions, 13 deletions
diff --git a/gold/i386.cc b/gold/i386.cc
index 19728c5..ce07588 100644
--- a/gold/i386.cc
+++ b/gold/i386.cc
@@ -1,6 +1,6 @@
// i386.cc -- i386 target support for gold.
-// Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
@@ -59,8 +59,9 @@ class Target_i386 : public Target_freebsd<32, false>
Target_i386()
: Target_freebsd<32, false>(&i386_info),
- got_(NULL), plt_(NULL), got_plt_(NULL), global_offset_table_(NULL),
- rel_dyn_(NULL), copy_relocs_(elfcpp::R_386_COPY), dynbss_(NULL),
+ got_(NULL), plt_(NULL), got_plt_(NULL), got_tlsdesc_(NULL),
+ global_offset_table_(NULL), rel_dyn_(NULL),
+ copy_relocs_(elfcpp::R_386_COPY), dynbss_(NULL),
got_mod_index_offset_(-1U), tls_base_symbol_defined_(false)
{ }
@@ -385,6 +386,14 @@ class Target_i386 : public Target_freebsd<32, false>
return this->got_plt_;
}
+ // Get the GOT section for TLSDESC entries.
+ Output_data_got<32, false>*
+ got_tlsdesc_section() const
+ {
+ gold_assert(this->got_tlsdesc_ != NULL);
+ return this->got_tlsdesc_;
+ }
+
// Create a PLT entry for a global symbol.
void
make_plt_entry(Symbol_table*, Layout*, Symbol*);
@@ -447,6 +456,8 @@ class Target_i386 : public Target_freebsd<32, false>
Output_data_plt_i386* plt_;
// The GOT PLT section.
Output_data_space* got_plt_;
+ // The GOT section for TLSDESC relocations.
+ Output_data_got<32, false>* got_tlsdesc_;
// The _GLOBAL_OFFSET_TABLE_ symbol.
Symbol* global_offset_table_;
// The dynamic reloc section.
@@ -521,6 +532,15 @@ Target_i386::got_section(Symbol_table* symtab, Layout* layout)
elfcpp::STB_LOCAL,
elfcpp::STV_HIDDEN, 0,
false, false);
+
+ // If there are any TLSDESC relocations, they get GOT entries in
+ // .got.plt after the jump slot entries.
+ this->got_tlsdesc_ = new Output_data_got<32, false>();
+ layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS,
+ (elfcpp::SHF_ALLOC
+ | elfcpp::SHF_WRITE),
+ this->got_tlsdesc_, false, false, false,
+ true);
}
return this->got_;
@@ -1117,9 +1137,13 @@ Target_i386::Scan::local(Symbol_table* symtab,
target->define_tls_base_symbol(symtab, layout);
if (optimized_type == tls::TLSOPT_NONE)
{
- // Create a double GOT entry with an R_386_TLS_DESC reloc.
- Output_data_got<32, false>* got
- = target->got_section(symtab, layout);
+ // Create a double GOT entry with an R_386_TLS_DESC
+ // reloc. The R_386_TLS_DESC reloc is resolved
+ // lazily, so the GOT entry needs to be in an area in
+ // .got.plt, not .got. Call got_section to make sure
+ // the section has been created.
+ target->got_section(symtab, layout);
+ Output_data_got<32, false>* got = target->got_tlsdesc_section();
unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
if (!object->local_has_got_offset(r_sym, GOT_TYPE_TLS_DESC))
{
@@ -1501,9 +1525,13 @@ Target_i386::Scan::global(Symbol_table* symtab,
target->define_tls_base_symbol(symtab, layout);
if (optimized_type == tls::TLSOPT_NONE)
{
- // Create a double GOT entry with an R_386_TLS_DESC reloc.
- Output_data_got<32, false>* got
- = target->got_section(symtab, layout);
+ // Create a double GOT entry with an R_386_TLS_DESC
+ // reloc. The R_386_TLS_DESC reloc is resolved
+ // lazily, so the GOT entry needs to be in an area in
+ // .got.plt, not .got. Call got_section to make sure
+ // the section has been created.
+ target->got_section(symtab, layout);
+ Output_data_got<32, false>* got = target->got_tlsdesc_section();
Reloc_section* rt = target->rel_tls_desc_section(layout);
got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_DESC, rt,
elfcpp::R_386_TLS_DESC, 0);
@@ -2046,18 +2074,27 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE
? GOT_TYPE_TLS_NOFFSET
: GOT_TYPE_TLS_DESC);
- unsigned int got_offset;
+ unsigned int got_offset = 0;
+ if (r_type == elfcpp::R_386_TLS_GOTDESC
+ && optimized_type == tls::TLSOPT_NONE)
+ {
+ // We created GOT entries in the .got.tlsdesc portion of
+ // the .got.plt section, but the offset stored in the
+ // symbol is the offset within .got.tlsdesc.
+ got_offset = (target->got_size()
+ + target->got_plt_section()->data_size());
+ }
if (gsym != NULL)
{
gold_assert(gsym->has_got_offset(got_type));
- got_offset = gsym->got_offset(got_type) - target->got_size();
+ got_offset += gsym->got_offset(got_type) - target->got_size();
}
else
{
unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
gold_assert(object->local_has_got_offset(r_sym, got_type));
- got_offset = (object->local_got_offset(r_sym, got_type)
- - target->got_size());
+ got_offset += (object->local_got_offset(r_sym, got_type)
+ - target->got_size());
}
if (optimized_type == tls::TLSOPT_TO_IE)
{