aboutsummaryrefslogtreecommitdiff
path: root/gold
diff options
context:
space:
mode:
Diffstat (limited to 'gold')
-rw-r--r--gold/i386.cc230
-rw-r--r--gold/layout.cc67
-rw-r--r--gold/layout.h12
-rw-r--r--gold/object.cc249
-rw-r--r--gold/object.h160
-rw-r--r--gold/output.cc363
-rw-r--r--gold/output.h163
-rw-r--r--gold/reloc.cc2
-rw-r--r--gold/symtab.cc7
-rw-r--r--gold/testsuite/Makefile.am48
-rw-r--r--gold/testsuite/Makefile.in48
-rw-r--r--gold/x86_64.cc296
12 files changed, 1285 insertions, 360 deletions
diff --git a/gold/i386.cc b/gold/i386.cc
index 1bfc659..071940b 100644
--- a/gold/i386.cc
+++ b/gold/i386.cc
@@ -792,7 +792,7 @@ Target_i386::Scan::local(const General_options&,
Output_section* output_section,
const elfcpp::Rel<32, false>& reloc,
unsigned int r_type,
- const elfcpp::Sym<32, false>&)
+ const elfcpp::Sym<32, false>& lsym)
{
switch (r_type)
{
@@ -856,13 +856,12 @@ Target_i386::Scan::local(const General_options&,
if (got->add_local(object, r_sym))
{
// If we are generating a shared object, we need to add a
- // dynamic RELATIVE relocation for this symbol.
+ // dynamic RELATIVE relocation for this symbol's GOT entry.
if (parameters->output_is_position_independent())
{
Reloc_section* rel_dyn = target->rel_dyn_section(layout);
rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE,
- output_section, data_shndx,
- reloc.get_r_offset());
+ got, object->local_got_offset(r_sym));
}
}
}
@@ -909,18 +908,10 @@ Target_i386::Scan::local(const General_options&,
Output_data_got<32, false>* got
= target->got_section(symtab, layout);
unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
- if (got->add_local_tls(object, r_sym, true))
- {
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
- unsigned int got_off
- = object->local_tls_got_offset(r_sym, true);
- rel_dyn->add_local(object, r_sym,
- elfcpp::R_386_TLS_DTPMOD32,
- got, got_off);
- rel_dyn->add_local(object, r_sym,
- elfcpp::R_386_TLS_DTPOFF32,
- got, got_off + 4);
- }
+ got->add_local_tls_with_rel(object, r_sym,
+ lsym.get_st_shndx(), true,
+ target->rel_dyn_section(layout),
+ elfcpp::R_386_TLS_DTPMOD32);
}
else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_local(object, r_type);
@@ -928,7 +919,10 @@ Target_i386::Scan::local(const General_options&,
case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (from ~oliva)
case elfcpp::R_386_TLS_DESC_CALL:
- unsupported_reloc_local(object, r_type);
+ // FIXME: If not relaxing to LE, we need to generate
+ // a GOT entry with an R_386_TLS_DESC reloc.
+ if (optimized_type != tls::TLSOPT_TO_LE)
+ unsupported_reloc_local(object, r_type);
break;
case elfcpp::R_386_TLS_LDM: // Local-dynamic
@@ -938,15 +932,10 @@ Target_i386::Scan::local(const General_options&,
Output_data_got<32, false>* got
= target->got_section(symtab, layout);
unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
- if (got->add_local_tls(object, r_sym, false))
- {
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
- unsigned int got_off
- = object->local_tls_got_offset(r_sym, false);
- rel_dyn->add_local(object, r_sym,
- elfcpp::R_386_TLS_DTPMOD32, got,
- got_off);
- }
+ got->add_local_tls_with_rel(object, r_sym,
+ lsym.get_st_shndx(), false,
+ target->rel_dyn_section(layout),
+ elfcpp::R_386_TLS_DTPMOD32);
}
else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_local(object, r_type);
@@ -960,21 +949,26 @@ Target_i386::Scan::local(const General_options&,
case elfcpp::R_386_TLS_GOTIE:
if (optimized_type == tls::TLSOPT_NONE)
{
+ // For the R_386_TLS_IE relocation, we need to create a
+ // dynamic relocation when building a shared library.
+ if (r_type == elfcpp::R_386_TLS_IE
+ && parameters->output_is_shared())
+ {
+ Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+ rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE,
+ output_section, data_shndx,
+ reloc.get_r_offset());
+ }
// Create a GOT entry for the tp-relative offset.
Output_data_got<32, false>* got
= target->got_section(symtab, layout);
unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
- if (got->add_local(object, r_sym))
- {
- unsigned int dyn_r_type
- = (r_type == elfcpp::R_386_TLS_IE_32
- ? elfcpp::R_386_TLS_TPOFF32
- : elfcpp::R_386_TLS_TPOFF);
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
- unsigned int got_off = object->local_got_offset(r_sym);
- rel_dyn->add_local(object, r_sym, dyn_r_type, got,
- got_off);
- }
+ unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_IE_32
+ ? elfcpp::R_386_TLS_TPOFF32
+ : elfcpp::R_386_TLS_TPOFF);
+ got->add_local_with_rel(object, r_sym,
+ target->rel_dyn_section(layout),
+ dyn_r_type);
}
else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_local(object, r_type);
@@ -983,7 +977,16 @@ Target_i386::Scan::local(const General_options&,
case elfcpp::R_386_TLS_LE: // Local-exec
case elfcpp::R_386_TLS_LE_32:
if (output_is_shared)
- unsupported_reloc_local(object, r_type);
+ {
+ // We need to create a dynamic relocation.
+ unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
+ unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_LE_32
+ ? elfcpp::R_386_TLS_TPOFF32
+ : elfcpp::R_386_TLS_TPOFF);
+ Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+ rel_dyn->add_local(object, r_sym, dyn_r_type, output_section,
+ data_shndx, reloc.get_r_offset());
+ }
break;
default:
@@ -1087,7 +1090,17 @@ Target_i386::Scan::global(const General_options& options,
{
// Make a PLT entry if necessary.
if (gsym->needs_plt_entry())
- target->make_plt_entry(symtab, layout, gsym);
+ {
+ // These relocations are used for function calls only in
+ // non-PIC code. For a 32-bit relocation in a shared library,
+ // we'll need a text relocation anyway, so we can skip the
+ // PLT entry and let the dynamic linker bind the call directly
+ // to the target. For smaller relocations, we should use a
+ // PLT entry to ensure that the call can reach.
+ if (!parameters->output_is_shared()
+ || r_type != elfcpp::R_386_PC32)
+ target->make_plt_entry(symtab, layout, gsym);
+ }
// Make a dynamic relocation if necessary.
bool is_function_call = (gsym->type() == elfcpp::STT_FUNC);
if (gsym->needs_dynamic_reloc(false, is_function_call))
@@ -1111,18 +1124,18 @@ Target_i386::Scan::global(const General_options& options,
{
// The symbol requires a GOT entry.
Output_data_got<32, false>* got = target->got_section(symtab, layout);
- if (got->add_global(gsym))
- {
+ if (gsym->final_value_is_known())
+ got->add_global(gsym);
+ else
+ {
// If this symbol is not fully resolved, we need to add a
- // dynamic relocation for it.
- if (!gsym->final_value_is_known())
+ // GOT entry with a dynamic relocation.
+ Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+ if (gsym->is_from_dynobj() || gsym->is_preemptible())
+ got->add_global_with_rel(gsym, rel_dyn, elfcpp::R_386_GLOB_DAT);
+ else
{
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
- if (gsym->is_from_dynobj()
- || gsym->is_preemptible())
- rel_dyn->add_global(gsym, elfcpp::R_386_GLOB_DAT, got,
- gsym->got_offset());
- else
+ if (got->add_global(gsym))
{
rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE,
got, gsym->got_offset());
@@ -1195,28 +1208,18 @@ Target_i386::Scan::global(const General_options& options,
// dtv-relative offset.
Output_data_got<32, false>* got
= target->got_section(symtab, layout);
- if (got->add_global_tls(gsym, true))
- {
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
- unsigned int got_off = gsym->tls_got_offset(true);
- rel_dyn->add_global(gsym, elfcpp::R_386_TLS_DTPMOD32,
- got, got_off);
- rel_dyn->add_global(gsym, elfcpp::R_386_TLS_DTPOFF32,
- got, got_off + 4);
- }
+ got->add_global_tls_with_rel(gsym,
+ target->rel_dyn_section(layout),
+ elfcpp::R_386_TLS_DTPMOD32,
+ elfcpp::R_386_TLS_DTPOFF32);
}
else if (optimized_type == tls::TLSOPT_TO_IE)
{
// Create a GOT entry for the tp-relative offset.
Output_data_got<32, false>* got
= target->got_section(symtab, layout);
- if (got->add_global(gsym))
- {
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
- unsigned int got_off = gsym->got_offset();
- rel_dyn->add_global(gsym, elfcpp::R_386_TLS_TPOFF32,
- got, got_off);
- }
+ got->add_global_with_rel(gsym, target->rel_dyn_section(layout),
+ elfcpp::R_386_TLS_TPOFF32);
}
else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_global(object, r_type, gsym);
@@ -1224,6 +1227,10 @@ Target_i386::Scan::global(const General_options& options,
case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (~oliva url)
case elfcpp::R_386_TLS_DESC_CALL:
+ // FIXME: If not relaxing to LE, we need to generate
+ // a GOT entry with an R_386_TLS_DESC reloc.
+ if (optimized_type != tls::TLSOPT_TO_LE)
+ unsupported_reloc_global(object, r_type, gsym);
unsupported_reloc_global(object, r_type, gsym);
break;
@@ -1235,13 +1242,9 @@ Target_i386::Scan::global(const General_options& options,
// Create a GOT entry for the module index.
Output_data_got<32, false>* got
= target->got_section(symtab, layout);
- if (got->add_global_tls(gsym, false))
- {
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
- unsigned int got_off = gsym->tls_got_offset(false);
- rel_dyn->add_global(gsym, elfcpp::R_386_TLS_DTPMOD32,
- got, got_off);
- }
+ got->add_global_tls_with_rel(gsym,
+ target->rel_dyn_section(layout),
+ elfcpp::R_386_TLS_DTPMOD32);
}
else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_global(object, r_type, gsym);
@@ -1255,19 +1258,25 @@ Target_i386::Scan::global(const General_options& options,
case elfcpp::R_386_TLS_GOTIE:
if (optimized_type == tls::TLSOPT_NONE)
{
- // Create a GOT entry for the tp-relative offset.
- Output_data_got<32, false>* got
- = target->got_section(symtab, layout);
- if (got->add_global(gsym))
+ // For the R_386_TLS_IE relocation, we need to create a
+ // dynamic relocation when building a shared library.
+ if (r_type == elfcpp::R_386_TLS_IE
+ && parameters->output_is_shared())
{
- unsigned int dyn_r_type
- = (r_type == elfcpp::R_386_TLS_IE_32
- ? elfcpp::R_386_TLS_TPOFF32
- : elfcpp::R_386_TLS_TPOFF);
Reloc_section* rel_dyn = target->rel_dyn_section(layout);
- unsigned int got_off = gsym->got_offset();
- rel_dyn->add_global(gsym, dyn_r_type, got, got_off);
+ rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE,
+ output_section, data_shndx,
+ reloc.get_r_offset());
}
+ // Create a GOT entry for the tp-relative offset.
+ Output_data_got<32, false>* got
+ = target->got_section(symtab, layout);
+ unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_IE_32
+ ? elfcpp::R_386_TLS_TPOFF32
+ : elfcpp::R_386_TLS_TPOFF);
+ got->add_global_with_rel(gsym,
+ target->rel_dyn_section(layout),
+ dyn_r_type);
}
else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_global(object, r_type, gsym);
@@ -1276,7 +1285,15 @@ Target_i386::Scan::global(const General_options& options,
case elfcpp::R_386_TLS_LE: // Local-exec
case elfcpp::R_386_TLS_LE_32:
if (parameters->output_is_shared())
- unsupported_reloc_global(object, r_type, gsym);
+ {
+ // We need to create a dynamic relocation.
+ unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_LE_32
+ ? elfcpp::R_386_TLS_TPOFF32
+ : elfcpp::R_386_TLS_TPOFF);
+ Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+ rel_dyn->add_global(gsym, dyn_r_type, output_section, object,
+ data_shndx, reloc.get_r_offset());
+ }
break;
default:
@@ -1670,9 +1687,8 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
if (optimized_type == tls::TLSOPT_TO_IE)
{
gold_assert(tls_segment != NULL);
- this->tls_gd_to_ie(relinfo, relnum, tls_segment,
- rel, r_type, got_offset, view,
- view_size);
+ this->tls_gd_to_ie(relinfo, relnum, tls_segment, rel, r_type,
+ got_offset, view, view_size);
break;
}
else if (optimized_type == tls::TLSOPT_NONE)
@@ -1741,13 +1757,11 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
// won't see the TLS_LDM reloc. The local_dynamic_type field
// tells us this.
gold_assert(tls_segment != NULL);
- if (optimized_type != tls::TLSOPT_TO_LE
- || this->local_dynamic_type_ == LOCAL_DYNAMIC_NONE)
- value = value - tls_segment->vaddr();
- else if (this->local_dynamic_type_ == LOCAL_DYNAMIC_GNU)
- value = value - (tls_segment->vaddr() + tls_segment->memsz());
- else
- value = tls_segment->vaddr() + tls_segment->memsz() - value;
+ if (this->local_dynamic_type_ == LOCAL_DYNAMIC_GNU)
+ value -= tls_segment->memsz();
+ else if (optimized_type == tls::TLSOPT_TO_LE
+ && this->local_dynamic_type_ != LOCAL_DYNAMIC_NONE)
+ value = tls_segment->memsz() - value;
Relocate_functions<32, false>::rel32(view, value);
break;
@@ -1793,15 +1807,25 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
break;
case elfcpp::R_386_TLS_LE: // Local-exec
- gold_assert(tls_segment != NULL);
- value = value - (tls_segment->vaddr() + tls_segment->memsz());
- Relocate_functions<32, false>::rel32(view, value);
+ // If we're creating a shared library, a dynamic relocation will
+ // have been created for this location, so do not apply it now.
+ if (!parameters->output_is_shared())
+ {
+ gold_assert(tls_segment != NULL);
+ value -= tls_segment->memsz();
+ Relocate_functions<32, false>::rel32(view, value);
+ }
break;
case elfcpp::R_386_TLS_LE_32:
- gold_assert(tls_segment != NULL);
- value = tls_segment->vaddr() + tls_segment->memsz() - value;
- Relocate_functions<32, false>::rel32(view, value);
+ // If we're creating a shared library, a dynamic relocation will
+ // have been created for this location, so do not apply it now.
+ if (!parameters->output_is_shared())
+ {
+ gold_assert(tls_segment != NULL);
+ value = tls_segment->memsz() - value;
+ Relocate_functions<32, false>::rel32(view, value);
+ }
break;
}
}
@@ -1862,7 +1886,7 @@ Target_i386::Relocate::tls_gd_to_le(const Relocate_info<32, false>* relinfo,
}
}
- value = tls_segment->vaddr() + tls_segment->memsz() - value;
+ value = tls_segment->memsz() - value;
Relocate_functions<32, false>::rel32(view + roff, value);
// The next reloc should be a PLT32 reloc against __tls_get_addr.
@@ -1870,7 +1894,7 @@ Target_i386::Relocate::tls_gd_to_le(const Relocate_info<32, false>* relinfo,
this->skip_call_tls_get_addr_ = true;
}
-// Do a relocation in which we convert a TLS General-Dynamic to a
+// Do a relocation in which we convert a TLS General-Dynamic to an
// Initial-Exec.
inline void
@@ -1930,7 +1954,7 @@ Target_i386::Relocate::tls_gd_to_ie(const Relocate_info<32, false>* relinfo,
}
}
- value = tls_segment->vaddr() + tls_segment->memsz() - value;
+ value = tls_segment->memsz() - value;
Relocate_functions<32, false>::rel32(view + roff, value);
// The next reloc should be a PLT32 reloc against __tls_get_addr.
@@ -2059,7 +2083,7 @@ Target_i386::Relocate::tls_ie_to_le(const Relocate_info<32, false>* relinfo,
tls::check_tls(relinfo, relnum, rel.get_r_offset(), 0);
}
- value = tls_segment->vaddr() + tls_segment->memsz() - value;
+ value = tls_segment->memsz() - value;
if (r_type == elfcpp::R_386_TLS_IE || r_type == elfcpp::R_386_TLS_GOTIE)
value = - value;
diff --git a/gold/layout.cc b/gold/layout.cc
index 1139cf1..68ebc6b 100644
--- a/gold/layout.cc
+++ b/gold/layout.cc
@@ -658,6 +658,8 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
target->finalize_sections(this);
+ this->count_local_symbols(input_objects);
+
this->create_gold_note();
this->create_executable_stack_info(target);
@@ -677,7 +679,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
std::vector<Symbol*> dynamic_symbols;
unsigned int local_dynamic_count;
Versions versions;
- this->create_dynamic_symtab(target, symtab, &dynstr,
+ this->create_dynamic_symtab(input_objects, target, symtab, &dynstr,
&local_dynamic_count, &dynamic_symbols,
&versions);
@@ -728,6 +730,8 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab)
// Create the symbol table sections.
this->create_symtab_sections(input_objects, symtab, &off);
+ if (!parameters->doing_static_link())
+ this->assign_local_dynsym_offsets(input_objects);
// Create the .shstrtab section.
Output_section* shstrtab_section = this->create_shstrtab();
@@ -1076,6 +1080,10 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg,
(*p)->set_offset();
}
+ // Set the TLS offsets for each section in the PT_TLS segment.
+ if (this->tls_segment_ != NULL)
+ this->tls_segment_->set_tls_offsets();
+
return off;
}
@@ -1137,6 +1145,21 @@ Layout::set_section_indexes(unsigned int shndx)
return shndx;
}
+// Count the local symbols in the regular symbol table and the dynamic
+// symbol table, and build the respective string pools.
+
+void
+Layout::count_local_symbols(const Input_objects* input_objects)
+{
+ for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
+ p != input_objects->relobj_end();
+ ++p)
+ {
+ Task_lock_obj<Object> tlo(**p);
+ (*p)->count_local_symbols(&this->sympool_, &this->dynpool_);
+ }
+}
+
// Create the symbol table sections. Here we also set the final
// values of the symbols. At this point all the loadable sections are
// fully laid out.
@@ -1189,10 +1212,8 @@ Layout::create_symtab_sections(const Input_objects* input_objects,
p != input_objects->relobj_end();
++p)
{
- Task_lock_obj<Object> tlo(**p);
unsigned int index = (*p)->finalize_local_symbols(local_symbol_index,
- off,
- &this->sympool_);
+ off);
off += (index - local_symbol_index) * symsize;
local_symbol_index = index;
}
@@ -1300,7 +1321,8 @@ Layout::create_shdrs(off_t* poff)
// Create the dynamic symbol table.
void
-Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab,
+Layout::create_dynamic_symtab(const Input_objects* input_objects,
+ const Target* target, Symbol_table* symtab,
Output_section **pdynstr,
unsigned int* plocal_dynamic_count,
std::vector<Symbol*>* pdynamic_symbols,
@@ -1326,10 +1348,15 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab,
}
}
- // FIXME: Some targets apparently require local symbols in the
- // dynamic symbol table. Here is where we will have to count them,
- // and set the dynamic symbol indexes, and add the names to
- // this->dynpool_.
+ // Count the local symbols that need to go in the dynamic symbol table,
+ // and set the dynamic symbol indexes.
+ for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
+ p != input_objects->relobj_end();
+ ++p)
+ {
+ unsigned int new_index = (*p)->set_local_dynsym_indexes(index);
+ index = new_index;
+ }
unsigned int local_symcount = index;
*plocal_dynamic_count = local_symcount;
@@ -1419,6 +1446,28 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab,
odyn->add_section_address(elfcpp::DT_HASH, hashsec);
}
+// Assign offsets to each local portion of the dynamic symbol table.
+
+void
+Layout::assign_local_dynsym_offsets(const Input_objects* input_objects)
+{
+ Output_section* dynsym = this->dynsym_section_;
+ gold_assert(dynsym != NULL);
+
+ off_t off = dynsym->offset();
+
+ // Skip the dummy symbol at the start of the section.
+ off += dynsym->entsize();
+
+ for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
+ p != input_objects->relobj_end();
+ ++p)
+ {
+ unsigned int count = (*p)->set_local_dynsym_offset(off);
+ off += count * dynsym->entsize();
+ }
+}
+
// Create the version sections.
void
diff --git a/gold/layout.h b/gold/layout.h
index a790892..12f703f 100644
--- a/gold/layout.h
+++ b/gold/layout.h
@@ -270,6 +270,11 @@ class Layout
Output_segment*
find_first_load_seg();
+ // Count the local symbols in the regular symbol table and the dynamic
+ // symbol table, and build the respective string pools.
+ void
+ count_local_symbols(const Input_objects*);
+
// Create the output sections for the symbol table.
void
create_symtab_sections(const Input_objects*, Symbol_table*, off_t*);
@@ -284,11 +289,16 @@ class Layout
// Create the dynamic symbol table.
void
- create_dynamic_symtab(const Target*, Symbol_table*, Output_section** pdynstr,
+ create_dynamic_symtab(const Input_objects*, const Target*,
+ Symbol_table*, Output_section** pdynstr,
unsigned int* plocal_dynamic_count,
std::vector<Symbol*>* pdynamic_symbols,
Versions* versions);
+ // Assign offsets to each local portion of the dynamic symbol table.
+ void
+ assign_local_dynsym_offsets(const Input_objects*);
+
// Finish the .dynamic section and PT_DYNAMIC segment.
void
finish_dynamic_section(const Input_objects*, const Symbol_table*);
diff --git a/gold/object.cc b/gold/object.cc
index fee249f..ab1323a 100644
--- a/gold/object.cc
+++ b/gold/object.cc
@@ -142,8 +142,10 @@ Sized_relobj<size, big_endian>::Sized_relobj(
symtab_shndx_(-1U),
local_symbol_count_(0),
output_local_symbol_count_(0),
+ output_local_dynsym_count_(0),
symbols_(),
local_symbol_offset_(0),
+ local_dynsym_offset_(0),
local_values_(),
local_got_offsets_(),
has_eh_frame_(false)
@@ -290,6 +292,7 @@ Sized_relobj<size, big_endian>::do_read_symbols(Read_symbols_data* sd)
const int sym_size = This::sym_size;
const unsigned int loccount = symtabshdr.get_sh_info();
this->local_symbol_count_ = loccount;
+ this->local_values_.resize(loccount);
off_t locsize = loccount * sym_size;
off_t dataoff = symtabshdr.get_sh_offset();
off_t datasize = symtabshdr.get_sh_size();
@@ -722,29 +725,23 @@ Sized_relobj<size, big_endian>::do_add_symbols(Symbol_table* symtab,
sd->symbol_names = NULL;
}
-// Finalize the local symbols. Here we record the file offset at
-// which they should be output, we add their names to *POOL, and we
-// add their values to THIS->LOCAL_VALUES_. Return the symbol index.
+// Finalize the local symbols. Here we add their names to *POOL and
+// *DYNPOOL, and we add their values to THIS->LOCAL_VALUES_.
// This function is always called from the main thread. The actual
// output of the local symbols will occur in a separate task.
template<int size, bool big_endian>
-unsigned int
-Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
- off_t off,
- Stringpool* pool)
+void
+Sized_relobj<size, big_endian>::do_count_local_symbols(Stringpool* pool,
+ Stringpool* dynpool)
{
gold_assert(this->symtab_shndx_ != -1U);
if (this->symtab_shndx_ == 0)
{
// This object has no symbols. Weird but legal.
- return index;
+ return;
}
- gold_assert(off == static_cast<off_t>(align_address(off, size >> 3)));
-
- this->local_symbol_offset_ = off;
-
// Read the symbol table section header.
const unsigned int symtab_shndx = this->symtab_shndx_;
typename This::Shdr symtabshdr(this,
@@ -759,8 +756,6 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
locsize, true);
- this->local_values_.resize(loccount);
-
// Read the symbol names.
const unsigned int strtab_shndx = symtabshdr.get_sh_link();
off_t strtab_size;
@@ -774,6 +769,7 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
const std::vector<Map_to_output>& mo(this->map_to_output());
unsigned int shnum = this->shnum();
unsigned int count = 0;
+ unsigned int dyncount = 0;
// Skip the first, dummy, symbol.
psyms += sym_size;
for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size)
@@ -787,11 +783,82 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
if (sym.get_st_type() == elfcpp::STT_SECTION)
lv.set_is_section_symbol();
+ else if (sym.get_st_type() == elfcpp::STT_TLS)
+ lv.set_is_tls_symbol();
+
+ // Save the input symbol value for use in do_finalize_local_symbols().
+ lv.set_input_value(sym.get_st_value());
+
+ // Decide whether this symbol should go into the output file.
+
+ if (shndx < shnum && mo[shndx].output_section == NULL)
+ {
+ lv.set_no_output_symtab_entry();
+ continue;
+ }
+
+ if (sym.get_st_type() == elfcpp::STT_SECTION)
+ {
+ lv.set_no_output_symtab_entry();
+ continue;
+ }
+
+ if (sym.get_st_name() >= strtab_size)
+ {
+ this->error(_("local symbol %u section name out of range: %u >= %u"),
+ i, sym.get_st_name(),
+ static_cast<unsigned int>(strtab_size));
+ lv.set_no_output_symtab_entry();
+ continue;
+ }
+
+ // Add the symbol to the symbol table string pool.
+ const char* name = pnames + sym.get_st_name();
+ pool->add(name, true, NULL);
+ ++count;
+
+ // If needed, add the symbol to the dynamic symbol table string pool.
+ if (lv.needs_output_dynsym_entry())
+ {
+ dynpool->add(name, true, NULL);
+ ++dyncount;
+ }
+ }
+
+ this->output_local_symbol_count_ = count;
+ this->output_local_dynsym_count_ = dyncount;
+}
+
+// Finalize the local symbols. Here we add their values to
+// THIS->LOCAL_VALUES_ and set their output symbol table indexes.
+// This function is always called from the main thread. The actual
+// output of the local symbols will occur in a separate task.
+
+template<int size, bool big_endian>
+unsigned int
+Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
+ off_t off)
+{
+ gold_assert(off == static_cast<off_t>(align_address(off, size >> 3)));
+
+ const unsigned int loccount = this->local_symbol_count_;
+ this->local_symbol_offset_ = off;
+
+ const std::vector<Map_to_output>& mo(this->map_to_output());
+ unsigned int shnum = this->shnum();
+ for (unsigned int i = 1; i < loccount; ++i)
+ {
+ Symbol_value<size>& lv(this->local_values_[i]);
+
+ unsigned int shndx = lv.input_shndx();
+
+ // Set the output symbol value.
+
if (shndx >= elfcpp::SHN_LORESERVE)
{
if (shndx == elfcpp::SHN_ABS)
- lv.set_output_value(sym.get_st_value());
+ lv.set_output_value(lv.input_value());
else
{
// FIXME: Handle SHN_XINDEX.
@@ -814,45 +881,61 @@ Sized_relobj<size, big_endian>::do_finalize_local_symbols(unsigned int index,
if (os == NULL)
{
lv.set_output_value(0);
- lv.set_no_output_symtab_entry();
continue;
}
-
- if (mo[shndx].offset == -1)
- lv.set_input_value(sym.get_st_value());
+ else if (mo[shndx].offset == -1)
+ {
+ // Leave the input value in place for SHF_MERGE sections.
+ }
+ else if (lv.is_tls_symbol())
+ lv.set_output_value(mo[shndx].output_section->tls_offset()
+ + mo[shndx].offset
+ + lv.input_value());
else
lv.set_output_value(mo[shndx].output_section->address()
+ mo[shndx].offset
- + sym.get_st_value());
+ + lv.input_value());
}
- // Decide whether this symbol should go into the output file.
-
- if (sym.get_st_type() == elfcpp::STT_SECTION)
- {
- lv.set_no_output_symtab_entry();
- continue;
- }
+ if (lv.needs_output_symtab_entry())
+ {
+ lv.set_output_symtab_index(index);
+ ++index;
+ }
+ }
+ return index;
+}
- if (sym.get_st_name() >= strtab_size)
- {
- this->error(_("local symbol %u section name out of range: %u >= %u"),
- i, sym.get_st_name(),
- static_cast<unsigned int>(strtab_size));
- lv.set_no_output_symtab_entry();
- continue;
- }
+// Set the output dynamic symbol table indexes for the local variables.
- const char* name = pnames + sym.get_st_name();
- pool->add(name, true, NULL);
- lv.set_output_symtab_index(index);
- ++index;
- ++count;
+template<int size, bool big_endian>
+unsigned int
+Sized_relobj<size, big_endian>::do_set_local_dynsym_indexes(unsigned int index)
+{
+ const unsigned int loccount = this->local_symbol_count_;
+ for (unsigned int i = 1; i < loccount; ++i)
+ {
+ Symbol_value<size>& lv(this->local_values_[i]);
+ if (lv.needs_output_dynsym_entry())
+ {
+ lv.set_output_dynsym_index(index);
+ ++index;
+ }
}
+ return index;
+}
- this->output_local_symbol_count_ = count;
+// Set the offset where local dynamic symbol information will be stored.
+// Returns the count of local symbols contributed to the symbol table by
+// this object.
- return index;
+template<int size, bool big_endian>
+unsigned int
+Sized_relobj<size, big_endian>::do_set_local_dynsym_offset(off_t off)
+{
+ gold_assert(off == static_cast<off_t>(align_address(off, size >> 3)));
+ this->local_dynsym_offset_ = off;
+ return this->output_local_dynsym_count_;
}
// Return the value of the local symbol symndx.
@@ -905,9 +988,10 @@ Sized_relobj<size, big_endian>::local_value(unsigned int shndx,
template<int size, bool big_endian>
void
Sized_relobj<size, big_endian>::write_local_symbols(Output_file* of,
- const Stringpool* sympool)
+ const Stringpool* sympool,
+ const Stringpool* dynpool)
{
- if (parameters->strip_all())
+ if (parameters->strip_all() && this->output_local_dynsym_count_ == 0)
return;
gold_assert(this->symtab_shndx_ != -1U);
@@ -939,24 +1023,30 @@ Sized_relobj<size, big_endian>::write_local_symbols(Output_file* of,
true);
const char* pnames = reinterpret_cast<const char*>(pnamesu);
- // Get a view into the output file.
+ // Get views into the output file for the portions of the symbol table
+ // and the dynamic symbol table that we will be writing.
off_t output_size = this->output_local_symbol_count_ * sym_size;
- unsigned char* oview = of->get_output_view(this->local_symbol_offset_,
- output_size);
+ unsigned char* oview;
+ if (output_size > 0)
+ oview = of->get_output_view(this->local_symbol_offset_, output_size);
+
+ off_t dyn_output_size = this->output_local_dynsym_count_ * sym_size;
+ unsigned char* dyn_oview = NULL;
+ if (dyn_output_size > 0)
+ dyn_oview = of->get_output_view(this->local_dynsym_offset_,
+ dyn_output_size);
const std::vector<Map_to_output>& mo(this->map_to_output());
gold_assert(this->local_values_.size() == loccount);
unsigned char* ov = oview;
+ unsigned char* dyn_ov = dyn_oview;
psyms += sym_size;
for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size)
{
elfcpp::Sym<size, big_endian> isym(psyms);
- if (!this->local_values_[i].needs_output_symtab_entry())
- continue;
-
unsigned int st_shndx = isym.get_st_shndx();
if (st_shndx < elfcpp::SHN_LORESERVE)
{
@@ -966,23 +1056,56 @@ Sized_relobj<size, big_endian>::write_local_symbols(Output_file* of,
st_shndx = mo[st_shndx].output_section->out_shndx();
}
- elfcpp::Sym_write<size, big_endian> osym(ov);
-
- gold_assert(isym.get_st_name() < strtab_size);
- const char* name = pnames + isym.get_st_name();
- osym.put_st_name(sympool->get_offset(name));
- osym.put_st_value(this->local_values_[i].value(this, 0));
- osym.put_st_size(isym.get_st_size());
- osym.put_st_info(isym.get_st_info());
- osym.put_st_other(isym.get_st_other());
- osym.put_st_shndx(st_shndx);
+ // Write the symbol to the output symbol table.
+ if (!parameters->strip_all()
+ && this->local_values_[i].needs_output_symtab_entry())
+ {
+ elfcpp::Sym_write<size, big_endian> osym(ov);
+
+ gold_assert(isym.get_st_name() < strtab_size);
+ const char* name = pnames + isym.get_st_name();
+ osym.put_st_name(sympool->get_offset(name));
+ osym.put_st_value(this->local_values_[i].value(this, 0));
+ osym.put_st_size(isym.get_st_size());
+ osym.put_st_info(isym.get_st_info());
+ osym.put_st_other(isym.get_st_other());
+ osym.put_st_shndx(st_shndx);
+
+ ov += sym_size;
+ }
- ov += sym_size;
+ // Write the symbol to the output dynamic symbol table.
+ if (this->local_values_[i].needs_output_dynsym_entry())
+ {
+ gold_assert(dyn_ov < dyn_oview + dyn_output_size);
+ elfcpp::Sym_write<size, big_endian> osym(dyn_ov);
+
+ gold_assert(isym.get_st_name() < strtab_size);
+ const char* name = pnames + isym.get_st_name();
+ osym.put_st_name(dynpool->get_offset(name));
+ osym.put_st_value(this->local_values_[i].value(this, 0));
+ osym.put_st_size(isym.get_st_size());
+ osym.put_st_info(isym.get_st_info());
+ osym.put_st_other(isym.get_st_other());
+ osym.put_st_shndx(st_shndx);
+
+ dyn_ov += sym_size;
+ }
}
- gold_assert(ov - oview == output_size);
- of->write_output_view(this->local_symbol_offset_, output_size, oview);
+ if (output_size > 0)
+ {
+ gold_assert(ov - oview == output_size);
+ of->write_output_view(this->local_symbol_offset_, output_size, oview);
+ }
+
+ if (dyn_output_size > 0)
+ {
+ gold_assert(dyn_ov - dyn_oview == dyn_output_size);
+ of->write_output_view(this->local_dynsym_offset_, dyn_output_size,
+ dyn_oview);
+ }
}
// Set *INFO to symbolic information about the offset OFFSET in the
diff --git a/gold/object.h b/gold/object.h
index 40839bc..4b826cf 100644
--- a/gold/object.h
+++ b/gold/object.h
@@ -429,13 +429,30 @@ class Relobj : public Object
Layout* layout, Read_relocs_data* rd)
{ return this->do_scan_relocs(options, symtab, layout, rd); }
- // Initial local symbol processing: set the offset where local
- // symbol information will be stored; add local symbol names to
- // *POOL; return the new local symbol index.
+ // Initial local symbol processing: count the number of local symbols
+ // in the output symbol table and dynamic symbol table; add local symbol
+ // names to *POOL and *DYNPOOL.
+ void
+ count_local_symbols(Stringpool_template<char>* pool,
+ Stringpool_template<char>* dynpool)
+ { return this->do_count_local_symbols(pool, dynpool); }
+
+ // Set the values of the local symbols, set the output symbol table
+ // indexes for the local variables, and set the offset where local
+ // symbol information will be stored. Returns the new local symbol index.
+ unsigned int
+ finalize_local_symbols(unsigned int index, off_t off)
+ { return this->do_finalize_local_symbols(index, off); }
+
+ // Set the output dynamic symbol table indexes for the local variables.
unsigned int
- finalize_local_symbols(unsigned int index, off_t off,
- Stringpool_template<char>* pool)
- { return this->do_finalize_local_symbols(index, off, pool); }
+ set_local_dynsym_indexes(unsigned int index)
+ { return this->do_set_local_dynsym_indexes(index); }
+
+ // Set the offset where local dynamic symbol information will be stored.
+ unsigned int
+ set_local_dynsym_offset(off_t off)
+ { return this->do_set_local_dynsym_offset(off); }
// Relocate the input sections and write out the local symbols.
void
@@ -521,11 +538,24 @@ class Relobj : public Object
do_scan_relocs(const General_options&, Symbol_table*, Layout*,
Read_relocs_data*) = 0;
- // Finalize local symbols--implemented by child class.
- virtual unsigned int
- do_finalize_local_symbols(unsigned int, off_t,
+ // Count local symbols--implemented by child class.
+ virtual void
+ do_count_local_symbols(Stringpool_template<char>*,
Stringpool_template<char>*) = 0;
+ // Finalize the local symbols. Set the output symbol table indexes for the local variables, and set the
+ // offset where local symbol information will be stored.
+ virtual unsigned int
+ do_finalize_local_symbols(unsigned int, off_t) = 0;
+
+ // Set the output dynamic symbol table indexes for the local variables.
+ virtual unsigned int
+ do_set_local_dynsym_indexes(unsigned int) = 0;
+
+ // Set the offset where local dynamic symbol information will be stored.
+ virtual unsigned int
+ do_set_local_dynsym_offset(off_t) = 0;
+
// Relocate the input sections and write out the local
// symbols--implemented by child class.
virtual void
@@ -580,7 +610,8 @@ class Symbol_value
typedef typename elfcpp::Elf_types<size>::Elf_Addr Value;
Symbol_value()
- : output_symtab_index_(0), input_shndx_(0), is_section_symbol_(false),
+ : output_symtab_index_(0), output_dynsym_index_(-1U), input_shndx_(0),
+ is_section_symbol_(false), is_tls_symbol_(false),
needs_output_address_(false), value_(0)
{ }
@@ -604,9 +635,11 @@ class Symbol_value
this->needs_output_address_ = false;
}
- // If this symbol is mapped to an output section which requires
- // special handling to determine the output value, we store the
- // value of the symbol in the input file. This is used for
+ // Set the value of the symbol from the input file. This value
+ // will usually be replaced during finalization with the output
+ // value, but if the symbol is mapped to an output section which
+ // requires special handling to determine the output value, we
+ // leave the input value in place until later. This is used for
// SHF_MERGE sections.
void
set_input_value(Value value)
@@ -615,12 +648,20 @@ class Symbol_value
this->needs_output_address_ = true;
}
+ // Return the input value.
+ Value
+ input_value() const
+ {
+ gold_assert(this->needs_output_address_);
+ return this->value_;
+ }
+
// Return whether this symbol should go into the output symbol
// table.
bool
needs_output_symtab_entry() const
{
- gold_assert(this->output_symtab_index_ != 0);
+ // gold_assert(this->output_symtab_index_ != 0);
return this->output_symtab_index_ != -1U;
}
@@ -649,6 +690,37 @@ class Symbol_value
this->output_symtab_index_ = -1U;
}
+ // Set the index in the output dynamic symbol table.
+ void
+ set_needs_output_dynsym_entry()
+ {
+ this->output_dynsym_index_ = 0;
+ }
+
+ // Return whether this symbol should go into the output symbol
+ // table.
+ bool
+ needs_output_dynsym_entry() const
+ {
+ return this->output_dynsym_index_ != -1U;
+ }
+
+ // Record that this symbol should go into the dynamic symbol table.
+ void
+ set_output_dynsym_index(unsigned int i)
+ {
+ gold_assert(this->output_dynsym_index_ == 0);
+ this->output_dynsym_index_ = i;
+ }
+
+ // Return the index in the output dynamic symbol table.
+ unsigned int
+ output_dynsym_index() const
+ {
+ gold_assert(this->output_dynsym_index_ != 0);
+ return this->output_dynsym_index_;
+ }
+
// Set the index of the input section in the input file.
void
set_input_shndx(unsigned int i)
@@ -657,20 +729,40 @@ class Symbol_value
gold_assert(this->input_shndx_ == i);
}
+ // Return the index of the input section in the input file.
+ unsigned int
+ input_shndx() const
+ { return this->input_shndx_; }
+
// Record that this is a section symbol.
void
set_is_section_symbol()
{ this->is_section_symbol_ = true; }
+ // Record that this is a TLS symbol.
+ void
+ set_is_tls_symbol()
+ { this->is_tls_symbol_ = true; }
+
+ // Return TRUE if this is a TLS symbol.
+ bool
+ is_tls_symbol() const
+ { return this->is_tls_symbol_; }
+
private:
// The index of this local symbol in the output symbol table. This
// will be -1 if the symbol should not go into the symbol table.
unsigned int output_symtab_index_;
+ // The index of this local symbol in the dynamic symbol table. This
+ // will be -1 if the symbol should not go into the symbol table.
+ unsigned int output_dynsym_index_;
// The section index in the input file in which this symbol is
// defined.
- unsigned int input_shndx_ : 30;
+ unsigned int input_shndx_ : 29;
// Whether this is a STT_SECTION symbol.
bool is_section_symbol_ : 1;
+ // Whether this is a STT_TLS symbol.
+ bool is_tls_symbol_ : 1;
// Whether getting the value of this symbol requires calling an
// Output_section method. For example, this will be true of a
// symbol in a SHF_MERGE section.
@@ -744,6 +836,15 @@ class Sized_relobj : public Relobj
return this->local_values_[sym].output_symtab_index();
}
+ // Return the index of local symbol SYM in the dynamic symbol
+ // table. A value of -1U means that the symbol is not being output.
+ unsigned int
+ dynsym_index(unsigned int sym) const
+ {
+ gold_assert(sym < this->local_values_.size());
+ return this->local_values_[sym].output_dynsym_index();
+ }
+
// Return the appropriate Sized_target structure.
Sized_target<size, big_endian>*
sized_target()
@@ -765,6 +866,13 @@ class Sized_relobj : public Relobj
local_value(unsigned int shndx, Address value, bool is_section_symbol,
Address addend) const;
+ void
+ set_needs_output_dynsym_entry(unsigned int sym)
+ {
+ gold_assert(sym < this->local_values_.size());
+ this->local_values_[sym].set_needs_output_dynsym_entry();
+ }
+
// Return whether the local symbol SYMNDX has a GOT offset.
// For TLS symbols, the GOT entry will hold its tp-relative offset.
bool
@@ -878,10 +986,22 @@ class Sized_relobj : public Relobj
do_scan_relocs(const General_options&, Symbol_table*, Layout*,
Read_relocs_data*);
+ // Count the local symbols.
+ void
+ do_count_local_symbols(Stringpool_template<char>*,
+ Stringpool_template<char>*);
+
// Finalize the local symbols.
unsigned int
- do_finalize_local_symbols(unsigned int, off_t,
- Stringpool_template<char>*);
+ do_finalize_local_symbols(unsigned int, off_t);
+
+ // Set the offset where local dynamic symbol information will be stored.
+ unsigned int
+ do_set_local_dynsym_indexes(unsigned int);
+
+ // Set the offset where local dynamic symbol information will be stored.
+ unsigned int
+ do_set_local_dynsym_offset(off_t);
// Relocate the input sections and write out the local symbols.
void
@@ -978,6 +1098,7 @@ class Sized_relobj : public Relobj
// Write out the local symbols.
void
write_local_symbols(Output_file*,
+ const Stringpool_template<char>*,
const Stringpool_template<char>*);
// The GOT offsets of local symbols. This map also stores GOT offsets
@@ -1007,10 +1128,15 @@ class Sized_relobj : public Relobj
unsigned int local_symbol_count_;
// The number of local symbols which go into the output file.
unsigned int output_local_symbol_count_;
+ // The number of local symbols which go into the output file's dynamic
+ // symbol table.
+ unsigned int output_local_dynsym_count_;
// The entries in the symbol table for the external symbols.
Symbols symbols_;
// File offset for local symbols.
off_t local_symbol_offset_;
+ // File offset for local dynamic symbols.
+ off_t local_dynsym_offset_;
// Values of local symbols.
Local_values local_values_;
// GOT offsets for local non-TLS symbols, and tp-relative offsets
diff --git a/gold/output.cc b/gold/output.cc
index 6c4ed5c..7fd901c 100644
--- a/gold/output.cc
+++ b/gold/output.cc
@@ -505,6 +505,113 @@ Output_data_strtab::do_write(Output_file* of)
// Output_reloc methods.
+// A reloc against a global symbol.
+
+template<bool dynamic, int size, bool big_endian>
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
+ Symbol* gsym,
+ unsigned int type,
+ Output_data* od,
+ Address address)
+ : address_(address), local_sym_index_(GSYM_CODE), type_(type),
+ shndx_(INVALID_CODE)
+{
+ this->u1_.gsym = gsym;
+ this->u2_.od = od;
+ if (dynamic)
+ gsym->set_needs_dynsym_entry();
+}
+
+template<bool dynamic, int size, bool big_endian>
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
+ Symbol* gsym,
+ unsigned int type,
+ Relobj* relobj,
+ unsigned int shndx,
+ Address address)
+ : address_(address), local_sym_index_(GSYM_CODE), type_(type),
+ shndx_(shndx)
+{
+ gold_assert(shndx != INVALID_CODE);
+ this->u1_.gsym = gsym;
+ this->u2_.relobj = relobj;
+ if (dynamic)
+ gsym->set_needs_dynsym_entry();
+}
+
+// A reloc against a local symbol.
+
+template<bool dynamic, int size, bool big_endian>
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index,
+ unsigned int type,
+ Output_data* od,
+ Address address)
+ : address_(address), local_sym_index_(local_sym_index), type_(type),
+ shndx_(INVALID_CODE)
+{
+ gold_assert(local_sym_index != GSYM_CODE
+ && local_sym_index != INVALID_CODE);
+ this->u1_.relobj = relobj;
+ this->u2_.od = od;
+ if (dynamic && local_sym_index > 0)
+ relobj->set_needs_output_dynsym_entry(local_sym_index);
+}
+
+template<bool dynamic, int size, bool big_endian>
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
+ Sized_relobj<size, big_endian>* relobj,
+ unsigned int local_sym_index,
+ unsigned int type,
+ unsigned int shndx,
+ Address address)
+ : address_(address), local_sym_index_(local_sym_index), type_(type),
+ shndx_(shndx)
+{
+ gold_assert(local_sym_index != GSYM_CODE
+ && local_sym_index != INVALID_CODE);
+ gold_assert(shndx != INVALID_CODE);
+ this->u1_.relobj = relobj;
+ this->u2_.relobj = relobj;
+ if (dynamic && local_sym_index > 0)
+ relobj->set_needs_output_dynsym_entry(local_sym_index);
+}
+
+// A reloc against the STT_SECTION symbol of an output section.
+
+template<bool dynamic, int size, bool big_endian>
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
+ Output_section* os,
+ unsigned int type,
+ Output_data* od,
+ Address address)
+ : address_(address), local_sym_index_(SECTION_CODE), type_(type),
+ shndx_(INVALID_CODE)
+{
+ this->u1_.os = os;
+ this->u2_.od = od;
+ if (dynamic)
+ os->set_needs_dynsym_index();
+}
+
+template<bool dynamic, int size, bool big_endian>
+Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::Output_reloc(
+ Output_section* os,
+ unsigned int type,
+ Relobj* relobj,
+ unsigned int shndx,
+ Address address)
+ : address_(address), local_sym_index_(SECTION_CODE), type_(type),
+ shndx_(shndx)
+{
+ gold_assert(shndx != INVALID_CODE);
+ this->u1_.os = os;
+ this->u2_.relobj = relobj;
+ if (dynamic)
+ os->set_needs_dynsym_index();
+}
+
// Get the symbol index of a relocation.
template<bool dynamic, int size, bool big_endian>
@@ -541,12 +648,7 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::get_symbol_index()
default:
if (dynamic)
- {
- // FIXME: It seems that some targets may need to generate
- // dynamic relocations against local symbols for some
- // reasons. This will have to be addressed at some point.
- gold_unreachable();
- }
+ index = this->u1_.relobj->dynsym_index(this->local_sym_index_);
else
index = this->u1_.relobj->symtab_index(this->local_sym_index_);
break;
@@ -725,6 +827,42 @@ Output_data_got<size, big_endian>::add_global(Symbol* gsym)
return true;
}
+// Add an entry for a global symbol to the GOT, and add a dynamic
+// relocation of type R_TYPE for the GOT entry.
+template<int size, bool big_endian>
+void
+Output_data_got<size, big_endian>::add_global_with_rel(
+ Symbol* gsym,
+ Rel_dyn* rel_dyn,
+ unsigned int r_type)
+{
+ if (gsym->has_got_offset())
+ return;
+
+ this->entries_.push_back(Got_entry());
+ this->set_got_size();
+ unsigned int got_offset = this->last_got_offset();
+ gsym->set_got_offset(got_offset);
+ rel_dyn->add_global(gsym, r_type, this, got_offset);
+}
+
+template<int size, bool big_endian>
+void
+Output_data_got<size, big_endian>::add_global_with_rela(
+ Symbol* gsym,
+ Rela_dyn* rela_dyn,
+ unsigned int r_type)
+{
+ if (gsym->has_got_offset())
+ return;
+
+ this->entries_.push_back(Got_entry());
+ this->set_got_size();
+ unsigned int got_offset = this->last_got_offset();
+ gsym->set_got_offset(got_offset);
+ rela_dyn->add_global(gsym, r_type, this, got_offset, 0);
+}
+
// Add an entry for a local symbol to the GOT. This returns true if
// this is a new GOT entry, false if the symbol already has a GOT
// entry.
@@ -744,6 +882,44 @@ Output_data_got<size, big_endian>::add_local(
return true;
}
+// Add an entry for a local symbol to the GOT, and add a dynamic
+// relocation of type R_TYPE for the GOT entry.
+template<int size, bool big_endian>
+void
+Output_data_got<size, big_endian>::add_local_with_rel(
+ Sized_relobj<size, big_endian>* object,
+ unsigned int symndx,
+ Rel_dyn* rel_dyn,
+ unsigned int r_type)
+{
+ if (object->local_has_got_offset(symndx))
+ return;
+
+ this->entries_.push_back(Got_entry());
+ this->set_got_size();
+ unsigned int got_offset = this->last_got_offset();
+ object->set_local_got_offset(symndx, got_offset);
+ rel_dyn->add_local(object, symndx, r_type, this, got_offset);
+}
+
+template<int size, bool big_endian>
+void
+Output_data_got<size, big_endian>::add_local_with_rela(
+ Sized_relobj<size, big_endian>* object,
+ unsigned int symndx,
+ Rela_dyn* rela_dyn,
+ unsigned int r_type)
+{
+ if (object->local_has_got_offset(symndx))
+ return;
+
+ this->entries_.push_back(Got_entry());
+ this->set_got_size();
+ unsigned int got_offset = this->last_got_offset();
+ object->set_local_got_offset(symndx, got_offset);
+ rela_dyn->add_local(object, symndx, r_type, this, got_offset, 0);
+}
+
// Add an entry (or a pair of entries) for a global TLS symbol to the GOT.
// In a pair of entries, the first value in the pair will be used for the
// module index, and the second value will be used for the dtv-relative
@@ -752,8 +928,7 @@ Output_data_got<size, big_endian>::add_local(
template<int size, bool big_endian>
bool
-Output_data_got<size, big_endian>::add_global_tls(Symbol* gsym,
- bool need_pair)
+Output_data_got<size, big_endian>::add_global_tls(Symbol* gsym, bool need_pair)
{
if (gsym->has_tls_got_offset(need_pair))
return false;
@@ -766,6 +941,88 @@ Output_data_got<size, big_endian>::add_global_tls(Symbol* gsym,
return true;
}
+// Add an entry for a global TLS symbol to the GOT, and add a dynamic
+// relocation of type R_TYPE.
+template<int size, bool big_endian>
+void
+Output_data_got<size, big_endian>::add_global_tls_with_rel(
+ Symbol* gsym,
+ Rel_dyn* rel_dyn,
+ unsigned int r_type)
+{
+ if (gsym->has_tls_got_offset(false))
+ return;
+
+ this->entries_.push_back(Got_entry());
+ this->set_got_size();
+ unsigned int got_offset = this->last_got_offset();
+ gsym->set_tls_got_offset(got_offset, false);
+ rel_dyn->add_global(gsym, r_type, this, got_offset);
+}
+
+template<int size, bool big_endian>
+void
+Output_data_got<size, big_endian>::add_global_tls_with_rela(
+ Symbol* gsym,
+ Rela_dyn* rela_dyn,
+ unsigned int r_type)
+{
+ if (gsym->has_tls_got_offset(false))
+ return;
+
+ this->entries_.push_back(Got_entry());
+ this->set_got_size();
+ unsigned int got_offset = this->last_got_offset();
+ gsym->set_tls_got_offset(got_offset, false);
+ rela_dyn->add_global(gsym, r_type, this, got_offset, 0);
+}
+
+// Add a pair of entries for a global TLS symbol to the GOT, and add
+// dynamic relocations of type MOD_R_TYPE and DTV_R_TYPE, respectively.
+template<int size, bool big_endian>
+void
+Output_data_got<size, big_endian>::add_global_tls_with_rel(
+ Symbol* gsym,
+ Rel_dyn* rel_dyn,
+ unsigned int mod_r_type,
+ unsigned int dtv_r_type)
+{
+ if (gsym->has_tls_got_offset(true))
+ return;
+
+ this->entries_.push_back(Got_entry());
+ unsigned int got_offset = this->last_got_offset();
+ gsym->set_tls_got_offset(got_offset, true);
+ rel_dyn->add_global(gsym, mod_r_type, this, got_offset);
+
+ this->entries_.push_back(Got_entry());
+ this->set_got_size();
+ got_offset = this->last_got_offset();
+ rel_dyn->add_global(gsym, dtv_r_type, this, got_offset);
+}
+
+template<int size, bool big_endian>
+void
+Output_data_got<size, big_endian>::add_global_tls_with_rela(
+ Symbol* gsym,
+ Rela_dyn* rela_dyn,
+ unsigned int mod_r_type,
+ unsigned int dtv_r_type)
+{
+ if (gsym->has_tls_got_offset(true))
+ return;
+
+ this->entries_.push_back(Got_entry());
+ unsigned int got_offset = this->last_got_offset();
+ gsym->set_tls_got_offset(got_offset, true);
+ rela_dyn->add_global(gsym, mod_r_type, this, got_offset, 0);
+
+ this->entries_.push_back(Got_entry());
+ this->set_got_size();
+ got_offset = this->last_got_offset();
+ rela_dyn->add_global(gsym, dtv_r_type, this, got_offset, 0);
+}
+
// Add an entry (or a pair of entries) for a local TLS symbol to the GOT.
// In a pair of entries, the first value in the pair will be used for the
// module index, and the second value will be used for the dtv-relative
@@ -790,6 +1047,67 @@ Output_data_got<size, big_endian>::add_local_tls(
return true;
}
+// Add an entry (or pair of entries) for a local TLS symbol to the GOT,
+// and add a dynamic relocation of type R_TYPE for the first GOT entry.
+// Because this is a local symbol, the first GOT entry can be relocated
+// relative to a section symbol, and the second GOT entry will have an
+// dtv-relative value that can be computed at link time.
+template<int size, bool big_endian>
+void
+Output_data_got<size, big_endian>::add_local_tls_with_rel(
+ Sized_relobj<size, big_endian>* object,
+ unsigned int symndx,
+ unsigned int shndx,
+ bool need_pair,
+ Rel_dyn* rel_dyn,
+ unsigned int r_type)
+{
+ if (object->local_has_tls_got_offset(symndx, need_pair))
+ return;
+
+ this->entries_.push_back(Got_entry());
+ unsigned int got_offset = this->last_got_offset();
+ object->set_local_tls_got_offset(symndx, got_offset, need_pair);
+ off_t off;
+ Output_section* os = object->output_section(shndx, &off);
+ rel_dyn->add_output_section(os, r_type, this, got_offset);
+
+ // The second entry of the pair will be statically initialized
+ // with the TLS offset of the symbol.
+ if (need_pair)
+ this->entries_.push_back(Got_entry(object, symndx));
+
+ this->set_got_size();
+}
+
+template<int size, bool big_endian>
+void
+Output_data_got<size, big_endian>::add_local_tls_with_rela(
+ Sized_relobj<size, big_endian>* object,
+ unsigned int symndx,
+ unsigned int shndx,
+ bool need_pair,
+ Rela_dyn* rela_dyn,
+ unsigned int r_type)
+{
+ if (object->local_has_tls_got_offset(symndx, need_pair))
+ return;
+
+ this->entries_.push_back(Got_entry());
+ unsigned int got_offset = this->last_got_offset();
+ object->set_local_tls_got_offset(symndx, got_offset, need_pair);
+ off_t off;
+ Output_section* os = object->output_section(shndx, &off);
+ rela_dyn->add_output_section(os, r_type, this, got_offset, 0);
+
+ // The second entry of the pair will be statically initialized
+ // with the TLS offset of the symbol.
+ if (need_pair)
+ this->entries_.push_back(Got_entry(object, symndx));
+
+ this->set_got_size();
+}
+
// Write out the GOT.
template<int size, bool big_endian>
@@ -1083,7 +1401,8 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type,
should_link_to_symtab_(false),
should_link_to_dynsym_(false),
after_input_sections_(false),
- requires_postprocessing_(false)
+ requires_postprocessing_(false),
+ tls_offset_(0)
{
// An unallocated section has no address. Forcing this means that
// we don't need special treatment for symbols defined in debug
@@ -1403,6 +1722,14 @@ Output_section::set_final_data_size()
this->set_data_size(off - startoff);
}
+// Set the TLS offset. Called only for SHT_TLS sections.
+
+void
+Output_section::do_set_tls_offset(uint64_t tls_base)
+{
+ this->tls_offset_ = this->address() - tls_base;
+}
+
// Write the section header to *OSHDR.
template<int size, bool big_endian>
@@ -1829,6 +2156,24 @@ Output_segment::set_offset()
- this->vaddr_);
}
+// Set the TLS offsets of the sections in the PT_TLS segment.
+
+void
+Output_segment::set_tls_offsets()
+{
+ gold_assert(this->type_ == elfcpp::PT_TLS);
+
+ for (Output_data_list::iterator p = this->output_data_.begin();
+ p != this->output_data_.end();
+ ++p)
+ (*p)->set_tls_offset(this->vaddr_);
+
+ for (Output_data_list::iterator p = this->output_bss_.begin();
+ p != this->output_bss_.end();
+ ++p)
+ (*p)->set_tls_offset(this->vaddr_);
+}
+
// Return the number of Output_sections in an Output_segment.
unsigned int
diff --git a/gold/output.h b/gold/output.h
index fe42112..6c80d0a 100644
--- a/gold/output.h
+++ b/gold/output.h
@@ -160,6 +160,17 @@ class Output_data
}
}
+ // Set the TLS offset. Called only for SHT_TLS sections.
+ void
+ set_tls_offset(uint64_t tls_base)
+ { this->do_set_tls_offset(tls_base); }
+
+ // Return the TLS offset, relative to the base of the TLS segment.
+ // Valid only for SHT_TLS sections.
+ uint64_t
+ tls_offset() const
+ { return this->do_tls_offset(); }
+
// Write the data to the output file. This is called after
// Layout::finalize is complete.
void
@@ -232,6 +243,17 @@ class Output_data
set_final_data_size()
{ gold_unreachable(); }
+ // Set the TLS offset. Called only for SHT_TLS sections.
+ virtual void
+ do_set_tls_offset(uint64_t)
+ { gold_unreachable(); }
+
+ // Return the TLS offset, relative to the base of the TLS segment.
+ // Valid only for SHT_TLS sections.
+ virtual uint64_t
+ do_tls_offset() const
+ { gold_unreachable(); }
+
// Functions that child classes may call.
// Whether the address is valid.
@@ -681,75 +703,28 @@ class Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>
// A reloc against a global symbol.
Output_reloc(Symbol* gsym, unsigned int type, Output_data* od,
- Address address)
- : address_(address), local_sym_index_(GSYM_CODE), type_(type),
- shndx_(INVALID_CODE)
- {
- this->u1_.gsym = gsym;
- this->u2_.od = od;
- }
+ Address address);
Output_reloc(Symbol* gsym, unsigned int type, Relobj* relobj,
- unsigned int shndx, Address address)
- : address_(address), local_sym_index_(GSYM_CODE), type_(type),
- shndx_(shndx)
- {
- gold_assert(shndx != INVALID_CODE);
- this->u1_.gsym = gsym;
- this->u2_.relobj = relobj;
- }
+ unsigned int shndx, Address address);
// A reloc against a local symbol.
Output_reloc(Sized_relobj<size, big_endian>* relobj,
- unsigned int local_sym_index,
- unsigned int type,
- Output_data* od,
- Address address)
- : address_(address), local_sym_index_(local_sym_index), type_(type),
- shndx_(INVALID_CODE)
- {
- gold_assert(local_sym_index != GSYM_CODE
- && local_sym_index != INVALID_CODE);
- this->u1_.relobj = relobj;
- this->u2_.od = od;
- }
+ unsigned int local_sym_index, unsigned int type,
+ Output_data* od, Address address);
Output_reloc(Sized_relobj<size, big_endian>* relobj,
- unsigned int local_sym_index,
- unsigned int type,
- unsigned int shndx,
- Address address)
- : address_(address), local_sym_index_(local_sym_index), type_(type),
- shndx_(shndx)
- {
- gold_assert(local_sym_index != GSYM_CODE
- && local_sym_index != INVALID_CODE);
- gold_assert(shndx != INVALID_CODE);
- this->u1_.relobj = relobj;
- this->u2_.relobj = relobj;
- }
+ unsigned int local_sym_index, unsigned int type,
+ unsigned int shndx, Address address);
// A reloc against the STT_SECTION symbol of an output section.
Output_reloc(Output_section* os, unsigned int type, Output_data* od,
- Address address)
- : address_(address), local_sym_index_(SECTION_CODE), type_(type),
- shndx_(INVALID_CODE)
- {
- this->u1_.os = os;
- this->u2_.od = od;
- }
+ Address address);
Output_reloc(Output_section* os, unsigned int type, Relobj* relobj,
- unsigned int shndx, Address address)
- : address_(address), local_sym_index_(SECTION_CODE), type_(type),
- shndx_(shndx)
- {
- gold_assert(shndx != INVALID_CODE);
- this->u1_.os = os;
- this->u2_.relobj = relobj;
- }
+ unsigned int shndx, Address address);
// Write the reloc entry to an output view.
void
@@ -1070,6 +1045,8 @@ class Output_data_got : public Output_section_data_build
{
public:
typedef typename elfcpp::Elf_types<size>::Elf_Addr Valtype;
+ typedef Output_data_reloc<elfcpp::SHT_REL, true, size, big_endian> Rel_dyn;
+ typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, big_endian> Rela_dyn;
Output_data_got()
: Output_section_data_build(Output_data::default_alignment_for_size(size)),
@@ -1081,18 +1058,60 @@ class Output_data_got : public Output_section_data_build
bool
add_global(Symbol* gsym);
+ // Add an entry for a global symbol to the GOT, and add a dynamic
+ // relocation of type R_TYPE for the GOT entry.
+ void
+ add_global_with_rel(Symbol* gsym, Rel_dyn* rel_dyn, unsigned int r_type);
+
+ void
+ add_global_with_rela(Symbol* gsym, Rela_dyn* rela_dyn, unsigned int r_type);
+
// Add an entry for a local symbol to the GOT. This returns true if
// this is a new GOT entry, false if the symbol already has a GOT
// entry.
bool
add_local(Sized_relobj<size, big_endian>* object, unsigned int sym_index);
+ // Add an entry for a global symbol to the GOT, and add a dynamic
+ // relocation of type R_TYPE for the GOT entry.
+ void
+ add_local_with_rel(Sized_relobj<size, big_endian>* object,
+ unsigned int sym_index, Rel_dyn* rel_dyn,
+ unsigned int r_type);
+
+ void
+ add_local_with_rela(Sized_relobj<size, big_endian>* object,
+ unsigned int sym_index, Rela_dyn* rela_dyn,
+ unsigned int r_type);
+
// Add an entry (or pair of entries) for a global TLS symbol to the GOT.
// Return true if this is a new GOT entry, false if the symbol was
// already in the GOT.
bool
add_global_tls(Symbol* gsym, bool need_pair);
+ // Add an entry for a global TLS symbol to the GOT, and add a dynamic
+ // relocation of type R_TYPE.
+ void
+ add_global_tls_with_rel(Symbol* gsym, Rel_dyn* rel_dyn,
+ unsigned int r_type);
+
+ void
+ add_global_tls_with_rela(Symbol* gsym, Rela_dyn* rela_dyn,
+ unsigned int r_type);
+
+ // Add a pair of entries for a global TLS symbol to the GOT, and add
+ // dynamic relocations of type MOD_R_TYPE and DTV_R_TYPE, respectively.
+ void
+ add_global_tls_with_rel(Symbol* gsym, Rel_dyn* rel_dyn,
+ unsigned int mod_r_type,
+ unsigned int dtv_r_type);
+
+ void
+ add_global_tls_with_rela(Symbol* gsym, Rela_dyn* rela_dyn,
+ unsigned int mod_r_type,
+ unsigned int dtv_r_type);
+
// Add an entry (or pair of entries) for a local TLS symbol to the GOT.
// This returns true if this is a new GOT entry, false if the symbol
// already has a GOT entry.
@@ -1100,6 +1119,23 @@ class Output_data_got : public Output_section_data_build
add_local_tls(Sized_relobj<size, big_endian>* object,
unsigned int sym_index, bool need_pair);
+ // Add an entry (or pair of entries) for a local TLS symbol to the GOT,
+ // and add a dynamic relocation of type R_TYPE for the first GOT entry.
+ // Because this is a local symbol, the first GOT entry can be relocated
+ // relative to a section symbol, and the second GOT entry will have an
+ // dtv-relative value that can be computed at link time.
+ void
+ add_local_tls_with_rel(Sized_relobj<size, big_endian>* object,
+ unsigned int sym_index, unsigned int shndx,
+ bool need_pair, Rel_dyn* rel_dyn,
+ unsigned int r_type);
+
+ void
+ add_local_tls_with_rela(Sized_relobj<size, big_endian>* object,
+ unsigned int sym_index, unsigned int shndx,
+ bool need_pair, Rela_dyn* rela_dyn,
+ unsigned int r_type);
+
// Add a constant to the GOT. This returns the offset of the new
// entry from the start of the GOT.
unsigned int
@@ -1609,6 +1645,16 @@ class Output_section : public Output_data
do_is_section_flag_set(elfcpp::Elf_Xword flag) const
{ return (this->flags_ & flag) != 0; }
+ // Set the TLS offset. Called only for SHT_TLS sections.
+ void
+ do_set_tls_offset(uint64_t tls_base);
+
+ // Return the TLS offset, relative to the base of the TLS segment.
+ // Valid only for SHT_TLS sections.
+ uint64_t
+ do_tls_offset() const
+ { return this->tls_offset_; }
+
// Modify the section name. This is only permitted for an
// unallocated section, and only before the size has been finalized.
// Otherwise the name will not get into Layout::namepool_.
@@ -1933,6 +1979,9 @@ class Output_section : public Output_data
// Whether this section requires post processing after all
// relocations have been applied.
bool requires_postprocessing_ : 1;
+ // For SHT_TLS sections, the offset of this section relative to the base
+ // of the TLS segment.
+ uint64_t tls_offset_;
};
// An output segment. PT_LOAD segments are built from collections of
@@ -2021,6 +2070,10 @@ class Output_segment
void
set_offset();
+ // Set the TLS offsets of the sections contained in the PT_TLS segment.
+ void
+ set_tls_offsets();
+
// Return the number of output sections.
unsigned int
output_section_count() const;
diff --git a/gold/reloc.cc b/gold/reloc.cc
index 2763be5..e34cd04 100644
--- a/gold/reloc.cc
+++ b/gold/reloc.cc
@@ -390,7 +390,7 @@ Sized_relobj<size, big_endian>::do_relocate(const General_options& options,
}
// Write out the local symbols.
- this->write_local_symbols(of, layout->sympool());
+ this->write_local_symbols(of, layout->sympool(), layout->dynpool());
}
// Write section data to the output file. PSHDRS points to the
diff --git a/gold/symtab.cc b/gold/symtab.cc
index 40b3080..a18d3ae 100644
--- a/gold/symtab.cc
+++ b/gold/symtab.cc
@@ -1507,7 +1507,10 @@ Symbol_table::sized_finalize(unsigned index, off_t off, Stringpool* pool)
continue;
}
- value = sym->value() + os->address() + secoff;
+ if (sym->type() == elfcpp::STT_TLS)
+ value = sym->value() + os->tls_offset() + secoff;
+ else
+ value = sym->value() + os->address() + secoff;
}
}
break;
@@ -1920,7 +1923,7 @@ Symbol_table::print_stats() const
// that case.
// This struct is used to compare line information, as returned by
-// Dwarf_line_info::one_addr2line. It imlements a < comparison
+// Dwarf_line_info::one_addr2line. It implements a < comparison
// operator used with std::set.
struct Odr_violation_compare
diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am
index e3b263d..b11db39 100644
--- a/gold/testsuite/Makefile.am
+++ b/gold/testsuite/Makefile.am
@@ -177,8 +177,8 @@ debug_msg_ndebug.err: debug_msg_ndebug.so odr_violation1_ndebug.so odr_violation
undef_symbol.o: undef_symbol.cc
$(CXXCOMPILE) -O0 -g -c -fPIC $<
-undef_symbol.so: undef_symbol.o
- $(CXXLINK) -shared undef_symbol.o
+undef_symbol.so: undef_symbol.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared undef_symbol.o
undef_symbol.err: undef_symbol_main.o undef_symbol.so gcctestdir/ld
@echo $(CXXLINK) -Bgcctestdir/ -o undef_symbol_test undef_symbol_main.o undef_symbol.so "2>$@"
@if $(CXXLINK) -Bgcctestdir/ -o undef_symbol_test undef_symbol_main.o undef_symbol.so 2>$@; \
@@ -302,12 +302,12 @@ two_file_test_1_pic.o: two_file_test_1.cc
two_file_test_2_pic.o: two_file_test_2.cc
$(CXXCOMPILE) -c -fpic -o $@ $<
-two_file_shared_1.so: two_file_test_1_pic.o
- $(CXXLINK) -shared two_file_test_1_pic.o
-two_file_shared_2.so: two_file_test_2_pic.o
- $(CXXLINK) -shared two_file_test_2_pic.o
-two_file_shared.so: two_file_test_1_pic.o two_file_test_2_pic.o
- $(CXXLINK) -shared two_file_test_1_pic.o two_file_test_2_pic.o
+two_file_shared_1.so: two_file_test_1_pic.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1_pic.o
+two_file_shared_2.so: two_file_test_2_pic.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_2_pic.o
+two_file_shared.so: two_file_test_1_pic.o two_file_test_2_pic.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1_pic.o two_file_test_2_pic.o
# The nonpic tests will fail on platforms which can not put non-PIC
# code into shared libraries, so we just don't run them in that case.
@@ -348,12 +348,12 @@ two_file_separate_shared_21_nonpic_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
two_file_separate_shared_21_nonpic_test_LDADD = \
two_file_shared_2_nonpic.so two_file_shared_1_nonpic.so
-two_file_shared_1_nonpic.so: two_file_test_1.o
- $(CXXLINK) -shared two_file_test_1.o
-two_file_shared_2_nonpic.so: two_file_test_2.o
- $(CXXLINK) -shared two_file_test_2.o
-two_file_shared_nonpic.so: two_file_test_1.o two_file_test_2.o
- $(CXXLINK) -shared two_file_test_1.o two_file_test_2.o
+two_file_shared_1_nonpic.so: two_file_test_1.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1.o
+two_file_shared_2_nonpic.so: two_file_test_2.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_2.o
+two_file_shared_nonpic.so: two_file_test_1.o two_file_test_2.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1.o two_file_test_2.o
endif
@@ -406,12 +406,12 @@ exception_test_1_pic.o: exception_test_1.cc
exception_test_2_pic.o: exception_test_2.cc
$(CXXCOMPILE) -c -fpic -o $@ $<
-exception_shared_1.so: exception_test_1_pic.o
- $(CXXLINK) -shared exception_test_1_pic.o
-exception_shared_2.so: exception_test_2_pic.o
- $(CXXLINK) -shared exception_test_2_pic.o
-exception_shared.so: exception_test_1_pic.o exception_test_2_pic.o
- $(CXXLINK) -shared exception_test_1_pic.o exception_test_2_pic.o
+exception_shared_1.so: exception_test_1_pic.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared exception_test_1_pic.o
+exception_shared_2.so: exception_test_2_pic.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared exception_test_2_pic.o
+exception_shared.so: exception_test_1_pic.o exception_test_2_pic.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared exception_test_1_pic.o exception_test_2_pic.o
weak_test_SOURCES = weak_test.cc
weak_test_LDFLAGS = -Bgcctestdir/
@@ -449,8 +449,8 @@ tls_test_pic.o: tls_test.cc
tls_test_file2_pic.o: tls_test_file2.cc
$(CXXCOMPILE) -c -fpic -o $@ $<
-tls_test_shared.so: tls_test_pic.o tls_test_file2_pic.o
- $(CXXLINK) -shared tls_test_pic.o tls_test_file2_pic.o
+tls_test_shared.so: tls_test_pic.o tls_test_file2_pic.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared tls_test_pic.o tls_test_file2_pic.o
if FN_PTRS_IN_SO_WITHOUT_PIC
@@ -459,8 +459,8 @@ tls_shared_nonpic_test_DEPENDENCIES = gcctestdir/ld tls_test_shared_nonpic.so
tls_shared_nonpic_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,.
tls_shared_nonpic_test_LDADD = tls_test_shared_nonpic.so -lpthread
-tls_test_shared_nonpic.so: tls_test.o tls_test_file2.o
- $(CXXLINK) -shared tls_test.o tls_test_file2.o
+tls_test_shared_nonpic.so: tls_test.o tls_test_file2.o gcctestdir/ld
+ $(CXXLINK) -Bgcctestdir/ -shared tls_test.o tls_test_file2.o
endif
diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in
index 15d5f19..a4293a9 100644
--- a/gold/testsuite/Makefile.in
+++ b/gold/testsuite/Makefile.in
@@ -1330,8 +1330,8 @@ uninstall-am: uninstall-info-am
@GCC_TRUE@@NATIVE_LINKER_TRUE@undef_symbol.o: undef_symbol.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -g -c -fPIC $<
-@GCC_TRUE@@NATIVE_LINKER_TRUE@undef_symbol.so: undef_symbol.o
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -shared undef_symbol.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@undef_symbol.so: undef_symbol.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared undef_symbol.o
@GCC_TRUE@@NATIVE_LINKER_TRUE@undef_symbol.err: undef_symbol_main.o undef_symbol.so gcctestdir/ld
@GCC_TRUE@@NATIVE_LINKER_TRUE@ @echo $(CXXLINK) -Bgcctestdir/ -o undef_symbol_test undef_symbol_main.o undef_symbol.so "2>$@"
@GCC_TRUE@@NATIVE_LINKER_TRUE@ @if $(CXXLINK) -Bgcctestdir/ -o undef_symbol_test undef_symbol_main.o undef_symbol.so 2>$@; \
@@ -1386,31 +1386,31 @@ uninstall-am: uninstall-info-am
@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_2_pic.o: two_file_test_2.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
-@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1.so: two_file_test_1_pic.o
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -shared two_file_test_1_pic.o
-@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_2.so: two_file_test_2_pic.o
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -shared two_file_test_2_pic.o
-@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared.so: two_file_test_1_pic.o two_file_test_2_pic.o
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -shared two_file_test_1_pic.o two_file_test_2_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1.so: two_file_test_1_pic.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_2.so: two_file_test_2_pic.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_2_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared.so: two_file_test_1_pic.o two_file_test_2_pic.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1_pic.o two_file_test_2_pic.o
-@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1_nonpic.so: two_file_test_1.o
-@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -shared two_file_test_1.o
-@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_2_nonpic.so: two_file_test_2.o
-@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -shared two_file_test_2.o
-@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_nonpic.so: two_file_test_1.o two_file_test_2.o
-@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -shared two_file_test_1.o two_file_test_2.o
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1_nonpic.so: two_file_test_1.o gcctestdir/ld
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1.o
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_2_nonpic.so: two_file_test_2.o gcctestdir/ld
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_2.o
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_nonpic.so: two_file_test_1.o two_file_test_2.o gcctestdir/ld
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1.o two_file_test_2.o
@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_test_1_pic.o: exception_test_1.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_test_2_pic.o: exception_test_2.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
-@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_shared_1.so: exception_test_1_pic.o
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -shared exception_test_1_pic.o
-@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_shared_2.so: exception_test_2_pic.o
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -shared exception_test_2_pic.o
-@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_shared.so: exception_test_1_pic.o exception_test_2_pic.o
-@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -shared exception_test_1_pic.o exception_test_2_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_shared_1.so: exception_test_1_pic.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared exception_test_1_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_shared_2.so: exception_test_2_pic.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared exception_test_2_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_shared.so: exception_test_1_pic.o exception_test_2_pic.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared exception_test_1_pic.o exception_test_2_pic.o
@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_pic.o: tls_test.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
@@ -1418,11 +1418,11 @@ uninstall-am: uninstall-info-am
@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_file2_pic.o: tls_test_file2.cc
@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $<
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_shared.so: tls_test_pic.o tls_test_file2_pic.o
-@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXLINK) -shared tls_test_pic.o tls_test_file2_pic.o
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_shared.so: tls_test_pic.o tls_test_file2_pic.o gcctestdir/ld
+@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared tls_test_pic.o tls_test_file2_pic.o
-@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_shared_nonpic.so: tls_test.o tls_test_file2.o
-@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXLINK) -shared tls_test.o tls_test_file2.o
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_shared_nonpic.so: tls_test.o tls_test_file2.o gcctestdir/ld
+@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared tls_test.o tls_test_file2.o
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
diff --git a/gold/x86_64.cc b/gold/x86_64.cc
index f19fa9b..24f87b9 100644
--- a/gold/x86_64.cc
+++ b/gold/x86_64.cc
@@ -186,14 +186,23 @@ class Target_x86_64 : public Sized_target<64, false>
private:
// Do a TLS relocation.
inline void
- relocate_tls(const Relocate_info<64, false>*, size_t relnum,
- const elfcpp::Rela<64, false>&,
+ relocate_tls(const Relocate_info<64, false>*, Target_x86_64*,
+ size_t relnum, const elfcpp::Rela<64, false>&,
unsigned int r_type, const Sized_symbol<64>*,
const Symbol_value<64>*,
unsigned char*, elfcpp::Elf_types<64>::Elf_Addr, off_t);
// Do a TLS General-Dynamic to Local-Exec transition.
inline void
+ tls_gd_to_ie(const Relocate_info<64, false>*, size_t relnum,
+ Output_segment* tls_segment,
+ const elfcpp::Rela<64, false>&, unsigned int r_type,
+ elfcpp::Elf_types<64>::Elf_Addr value,
+ unsigned char* view,
+ off_t view_size);
+
+ // Do a TLS General-Dynamic to Local-Exec transition.
+ inline void
tls_gd_to_le(const Relocate_info<64, false>*, size_t relnum,
Output_segment* tls_segment,
const elfcpp::Rela<64, false>&, unsigned int r_type,
@@ -745,7 +754,7 @@ Target_x86_64::Scan::local(const General_options&,
Output_section* output_section,
const elfcpp::Rela<64, false>& reloc,
unsigned int r_type,
- const elfcpp::Sym<64, false>&)
+ const elfcpp::Sym<64, false>& lsym)
{
switch (r_type)
{
@@ -823,16 +832,17 @@ Target_x86_64::Scan::local(const General_options&,
if (got->add_local(object, r_sym))
{
// If we are generating a shared object, we need to add a
- // dynamic RELATIVE relocation for this symbol.
+ // dynamic relocation for this symbol's GOT entry.
if (parameters->output_is_position_independent())
{
- // FIXME: R_X86_64_RELATIVE assumes a 64-bit relocation.
- gold_assert(r_type != elfcpp::R_X86_64_GOT32);
-
Reloc_section* rela_dyn = target->rela_dyn_section(layout);
- rela_dyn->add_local(object, 0, elfcpp::R_X86_64_RELATIVE,
- output_section, data_shndx,
- reloc.get_r_offset(), 0);
+ // R_X86_64_RELATIVE assumes a 64-bit relocation.
+ if (r_type != elfcpp::R_X86_64_GOT32)
+ rela_dyn->add_local(object, 0, elfcpp::R_X86_64_RELATIVE,
+ got, object->local_got_offset(r_sym), 0);
+ else
+ rela_dyn->add_local(object, r_sym, r_type,
+ got, object->local_got_offset(r_sym), 0);
}
}
// For GOTPLT64, we'd normally want a PLT section, but since
@@ -868,34 +878,68 @@ Target_x86_64::Scan::local(const General_options&,
switch (r_type)
{
case elfcpp::R_X86_64_TLSGD: // General-dynamic
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a pair of GOT entries for the module index and
+ // dtv-relative offset.
+ Output_data_got<64, false>* got
+ = target->got_section(symtab, layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info());
+ got->add_local_tls_with_rela(object, r_sym,
+ lsym.get_st_shndx(), true,
+ target->rela_dyn_section(layout),
+ elfcpp::R_X86_64_DTPMOD64);
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
+ unsupported_reloc_local(object, r_type);
+ break;
+
case elfcpp::R_X86_64_GOTPC32_TLSDESC:
case elfcpp::R_X86_64_TLSDESC_CALL:
// FIXME: If not relaxing to LE, we need to generate
- // DTPMOD64 and DTPOFF64 relocs.
+ // a GOT entry with a R_x86_64_TLSDESC reloc.
if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_local(object, r_type);
break;
case elfcpp::R_X86_64_TLSLD: // Local-dynamic
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a GOT entry for the module index.
+ Output_data_got<64, false>* got
+ = target->got_section(symtab, layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info());
+ got->add_local_tls_with_rela(object, r_sym,
+ lsym.get_st_shndx(), false,
+ target->rela_dyn_section(layout),
+ elfcpp::R_X86_64_DTPMOD64);
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
+ unsupported_reloc_local(object, r_type);
+ break;
+
case elfcpp::R_X86_64_DTPOFF32:
case elfcpp::R_X86_64_DTPOFF64:
- // FIXME: If not relaxing to LE, we need to generate a
- // DTPMOD64 reloc.
- if (optimized_type != tls::TLSOPT_TO_LE)
- unsupported_reloc_local(object, r_type);
break;
case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
- // FIXME: If not relaxing to LE, we need to generate a
- // TPOFF64 reloc.
- if (optimized_type != tls::TLSOPT_TO_LE)
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a GOT entry for the tp-relative offset.
+ Output_data_got<64, false>* got
+ = target->got_section(symtab, layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info());
+ got->add_local_with_rela(object, r_sym,
+ target->rela_dyn_section(layout),
+ elfcpp::R_X86_64_TPOFF64);
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_local(object, r_type);
break;
case elfcpp::R_X86_64_TPOFF32: // Local-exec
- // FIXME: If generating a shared object, we need to copy
- // this relocation into the object.
- gold_assert(!output_is_shared);
+ if (output_is_shared)
+ unsupported_reloc_local(object, r_type);
break;
default:
@@ -968,8 +1012,8 @@ Target_x86_64::Scan::global(const General_options& options,
{
if (target->may_need_copy_reloc(gsym))
{
- target->copy_reloc(&options, symtab, layout, object, data_shndx,
- output_section, gsym, reloc);
+ target->copy_reloc(&options, symtab, layout, object,
+ data_shndx, output_section, gsym, reloc);
}
else if (r_type == elfcpp::R_X86_64_64
&& gsym->can_use_relative_reloc(false))
@@ -1004,8 +1048,8 @@ Target_x86_64::Scan::global(const General_options& options,
{
if (target->may_need_copy_reloc(gsym))
{
- target->copy_reloc(&options, symtab, layout, object, data_shndx,
- output_section, gsym, reloc);
+ target->copy_reloc(&options, symtab, layout, object,
+ data_shndx, output_section, gsym, reloc);
}
else
{
@@ -1026,18 +1070,19 @@ Target_x86_64::Scan::global(const General_options& options,
{
// The symbol requires a GOT entry.
Output_data_got<64, false>* got = target->got_section(symtab, layout);
- if (got->add_global(gsym))
- {
+ if (gsym->final_value_is_known())
+ got->add_global(gsym);
+ else
+ {
// If this symbol is not fully resolved, we need to add a
// dynamic relocation for it.
- if (!gsym->final_value_is_known())
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ if (gsym->is_from_dynobj() || gsym->is_preemptible())
+ got->add_global_with_rela(gsym, rela_dyn,
+ elfcpp::R_X86_64_GLOB_DAT);
+ else
{
- Reloc_section* rela_dyn = target->rela_dyn_section(layout);
- if (gsym->is_from_dynobj()
- || gsym->is_preemptible())
- rela_dyn->add_global(gsym, elfcpp::R_X86_64_GLOB_DAT, got,
- gsym->got_offset(), 0);
- else
+ if (got->add_global(gsym))
{
rela_dyn->add_local(object, 0, elfcpp::R_X86_64_RELATIVE,
got, gsym->got_offset(), 0);
@@ -1110,6 +1155,30 @@ Target_x86_64::Scan::global(const General_options& options,
switch (r_type)
{
case elfcpp::R_X86_64_TLSGD: // General-dynamic
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a pair of GOT entries for the module index and
+ // dtv-relative offset.
+ Output_data_got<64, false>* got
+ = target->got_section(symtab, layout);
+ got->add_global_tls_with_rela(gsym,
+ target->rela_dyn_section(layout),
+ elfcpp::R_X86_64_DTPMOD64,
+ elfcpp::R_X86_64_DTPOFF64);
+ }
+ else if (optimized_type == tls::TLSOPT_TO_IE)
+ {
+ // Create a GOT entry for the tp-relative offset.
+ Output_data_got<64, false>* got
+ = target->got_section(symtab, layout);
+ got->add_global_with_rela(gsym,
+ target->rela_dyn_section(layout),
+ elfcpp::R_X86_64_TPOFF64);
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
+ unsupported_reloc_global(object, r_type, gsym);
+ break;
+
case elfcpp::R_X86_64_GOTPC32_TLSDESC:
case elfcpp::R_X86_64_TLSDESC_CALL:
// FIXME: If not relaxing to LE, we need to generate
@@ -1119,25 +1188,40 @@ Target_x86_64::Scan::global(const General_options& options,
break;
case elfcpp::R_X86_64_TLSLD: // Local-dynamic
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a GOT entry for the module index.
+ Output_data_got<64, false>* got
+ = target->got_section(symtab, layout);
+ got->add_global_tls_with_rela(gsym,
+ target->rela_dyn_section(layout),
+ elfcpp::R_X86_64_DTPMOD64);
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
+ unsupported_reloc_global(object, r_type, gsym);
+ break;
+
case elfcpp::R_X86_64_DTPOFF32:
case elfcpp::R_X86_64_DTPOFF64:
- // FIXME: If not relaxing to LE, we need to generate a
- // DTPMOD64 reloc.
- if (optimized_type != tls::TLSOPT_TO_LE)
- unsupported_reloc_global(object, r_type, gsym);
break;
case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
- // FIXME: If not relaxing to LE, we need to generate a
- // TPOFF64 reloc.
- if (optimized_type != tls::TLSOPT_TO_LE)
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a GOT entry for the tp-relative offset.
+ Output_data_got<64, false>* got
+ = target->got_section(symtab, layout);
+ got->add_global_with_rela(gsym,
+ target->rela_dyn_section(layout),
+ elfcpp::R_X86_64_TPOFF64);
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_global(object, r_type, gsym);
break;
case elfcpp::R_X86_64_TPOFF32: // Local-exec
- // FIXME: If generating a shared object, we need to copy
- // this relocation into the object.
- gold_assert(is_final);
+ if (parameters->output_is_shared())
+ unsupported_reloc_local(object, r_type);
break;
default:
@@ -1312,6 +1396,7 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo,
else
{
unsigned int r_sym = elfcpp::elf_r_sym<64>(rela.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym));
got_offset = object->local_got_offset(r_sym) - target->got_size();
}
have_got_offset = true;
@@ -1477,8 +1562,8 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo,
case elfcpp::R_X86_64_DTPOFF64:
case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
case elfcpp::R_X86_64_TPOFF32: // Local-exec
- this->relocate_tls(relinfo, relnum, rela, r_type, gsym, psymval, view,
- address, view_size);
+ this->relocate_tls(relinfo, target, relnum, rela, r_type, gsym, psymval,
+ view, address, view_size);
break;
case elfcpp::R_X86_64_SIZE32:
@@ -1497,6 +1582,7 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo,
inline void
Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo,
+ Target_x86_64* target,
size_t relnum,
const elfcpp::Rela<64, false>& rela,
unsigned int r_type,
@@ -1507,12 +1593,8 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo,
off_t view_size)
{
Output_segment* tls_segment = relinfo->layout->tls_segment();
- if (tls_segment == NULL)
- {
- gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
- _("TLS reloc but no TLS segment"));
- return;
- }
+
+ const Sized_relobj<64, false>* object = relinfo->object;
elfcpp::Elf_types<64>::Elf_Addr value = psymval->value(relinfo->object, 0);
@@ -1528,11 +1610,42 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo,
case elfcpp::R_X86_64_TLSDESC_CALL:
if (optimized_type == tls::TLSOPT_TO_LE)
{
+ gold_assert(tls_segment != NULL);
this->tls_gd_to_le(relinfo, relnum, tls_segment,
rela, r_type, value, view,
view_size);
break;
}
+ else
+ {
+ unsigned int got_offset;
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_tls_got_offset(true));
+ got_offset = gsym->tls_got_offset(true) - target->got_size();
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<64>(rela.get_r_info());
+ gold_assert(object->local_has_tls_got_offset(r_sym, true));
+ got_offset = (object->local_tls_got_offset(r_sym, true)
+ - target->got_size());
+ }
+ if (optimized_type == tls::TLSOPT_TO_IE)
+ {
+ gold_assert(tls_segment != NULL);
+ this->tls_gd_to_ie(relinfo, relnum, tls_segment, rela, r_type,
+ got_offset, view, view_size);
+ break;
+ }
+ else if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Relocate the field with the offset of the pair of GOT
+ // entries.
+ Relocate_functions<64, false>::rel64(view, got_offset);
+ break;
+ }
+ }
gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
_("unsupported reloc %u"), r_type);
break;
@@ -1540,15 +1653,37 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo,
case elfcpp::R_X86_64_TLSLD: // Local-dynamic
if (optimized_type == tls::TLSOPT_TO_LE)
{
+ gold_assert(tls_segment != NULL);
this->tls_ld_to_le(relinfo, relnum, tls_segment, rela, r_type,
value, view, view_size);
break;
}
+ else if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Relocate the field with the offset of the GOT entry for
+ // the module index.
+ unsigned int got_offset;
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_tls_got_offset(false));
+ got_offset = gsym->tls_got_offset(false) - target->got_size();
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<64>(rela.get_r_info());
+ gold_assert(object->local_has_tls_got_offset(r_sym, false));
+ got_offset = (object->local_tls_got_offset(r_sym, false)
+ - target->got_size());
+ }
+ Relocate_functions<64, false>::rel64(view, got_offset);
+ break;
+ }
gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
_("unsupported reloc %u"), r_type);
break;
case elfcpp::R_X86_64_DTPOFF32:
+ gold_assert(tls_segment != NULL);
if (optimized_type == tls::TLSOPT_TO_LE)
value = value - (tls_segment->vaddr() + tls_segment->memsz());
else
@@ -1557,6 +1692,7 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo,
break;
case elfcpp::R_X86_64_DTPOFF64:
+ gold_assert(tls_segment != NULL);
if (optimized_type == tls::TLSOPT_TO_LE)
value = value - (tls_segment->vaddr() + tls_segment->memsz());
else
@@ -1567,11 +1703,32 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo,
case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
if (optimized_type == tls::TLSOPT_TO_LE)
{
+ gold_assert(tls_segment != NULL);
Target_x86_64::Relocate::tls_ie_to_le(relinfo, relnum, tls_segment,
rela, r_type, value, view,
view_size);
break;
}
+ else if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Relocate the field with the offset of the GOT entry for
+ // the tp-relative offset of the symbol.
+ unsigned int got_offset;
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_got_offset());
+ got_offset = gsym->got_offset() - target->got_size();
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<64>(rela.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym));
+ got_offset = (object->local_got_offset(r_sym)
+ - target->got_size());
+ }
+ Relocate_functions<64, false>::rel64(view, got_offset);
+ break;
+ }
gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
_("unsupported reloc type %u"),
r_type);
@@ -1584,6 +1741,41 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo,
}
}
+// Do a relocation in which we convert a TLS General-Dynamic to an
+// Initial-Exec.
+
+inline void
+Target_x86_64::Relocate::tls_gd_to_ie(const Relocate_info<64, false>* relinfo,
+ size_t relnum,
+ Output_segment* tls_segment,
+ const elfcpp::Rela<64, false>& rela,
+ unsigned int,
+ elfcpp::Elf_types<64>::Elf_Addr value,
+ unsigned char* view,
+ off_t view_size)
+{
+ // .byte 0x66; leaq foo@tlsgd(%rip),%rdi;
+ // .word 0x6666; rex64; call __tls_get_addr
+ // ==> movq %fs:0,%rax; addq x@gottpoff(%rip),%rax
+
+ tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -4);
+ tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 12);
+
+ tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+ (memcmp(view - 4, "\x66\x48\x8d\x3d", 4) == 0));
+ tls::check_tls(relinfo, relnum, rela.get_r_offset(),
+ (memcmp(view + 4, "\x66\x66\x48\xe8", 4) == 0));
+
+ memcpy(view - 4, "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0\0", 16);
+
+ value = value - (tls_segment->vaddr() + tls_segment->memsz());
+ Relocate_functions<64, false>::rela32(view + 8, value, 0);
+
+ // The next reloc should be a PLT32 reloc against __tls_get_addr.
+ // We can skip it.
+ this->skip_call_tls_get_addr_ = true;
+}
+
// Do a relocation in which we convert a TLS General-Dynamic to a
// Local-Exec.