From Cary Coutant: More support for generating shared libraries.
This commit is contained in:
parent
fd6940ea27
commit
7bf1f8020f
230
gold/i386.cc
230
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)
|
||||
{
|
||||
// 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);
|
||||
if (got->add_global(gsym))
|
||||
{
|
||||
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);
|
||||
}
|
||||
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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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*);
|
||||
|
253
gold/object.cc
253
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,47 +881,63 @@ 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 (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;
|
||||
}
|
||||
|
||||
const char* name = pnames + sym.get_st_name();
|
||||
pool->add(name, true, NULL);
|
||||
lv.set_output_symtab_index(index);
|
||||
++index;
|
||||
++count;
|
||||
if (lv.needs_output_symtab_entry())
|
||||
{
|
||||
lv.set_output_symtab_index(index);
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
this->output_local_symbol_count_ = count;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
// Set the output dynamic symbol table indexes for the local variables.
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
||||
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.
|
||||
template<int size, bool big_endian>
|
||||
typename elfcpp::Elf_types<size>::Elf_Addr
|
||||
@ -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);
|
||||
// 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);
|
||||
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
|
||||
|
160
gold/object.h
160
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,
|
||||
Stringpool_template<char>* pool)
|
||||
{ return this->do_finalize_local_symbols(index, off, pool); }
|
||||
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
|
||||
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
|
||||
|
363
gold/output.cc
363
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
|
||||
|
163
gold/output.h
163
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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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:
|
||||
|
300
gold/x86_64.cc
300
gold/x86_64.cc
@ -186,12 +186,21 @@ 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,
|
||||
@ -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
|
||||
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)
|
||||
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:
|
||||
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
|
||||
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)
|
||||
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:
|
||||
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.
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user