From Cary Coutant: More support for generating shared libraries.

This commit is contained in:
Ian Lance Taylor 2007-12-06 05:55:50 +00:00
parent fd6940ea27
commit 7bf1f8020f
12 changed files with 1289 additions and 364 deletions

View File

@ -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;

View File

@ -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

View File

@ -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*);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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.