From 7bf1f8020f64a69dc0d93a166c96547655c7eeb2 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 6 Dec 2007 05:55:50 +0000 Subject: [PATCH] From Cary Coutant: More support for generating shared libraries. --- gold/i386.cc | 230 +++++++++++++++------------- gold/layout.cc | 67 +++++++-- gold/layout.h | 12 +- gold/object.cc | 249 +++++++++++++++++++++++-------- gold/object.h | 160 +++++++++++++++++--- gold/output.cc | 363 +++++++++++++++++++++++++++++++++++++++++++-- gold/output.h | 163 +++++++++++++------- gold/reloc.cc | 2 +- gold/symtab.cc | 7 +- gold/testsuite/Makefile.am | 48 +++--- gold/testsuite/Makefile.in | 48 +++--- gold/x86_64.cc | 296 +++++++++++++++++++++++++++++------- 12 files changed, 1285 insertions(+), 360 deletions(-) diff --git a/gold/i386.cc b/gold/i386.cc index 1bfc659..071940b 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -792,7 +792,7 @@ Target_i386::Scan::local(const General_options&, Output_section* output_section, const elfcpp::Rel<32, false>& reloc, unsigned int r_type, - const elfcpp::Sym<32, false>&) + const elfcpp::Sym<32, false>& lsym) { switch (r_type) { @@ -856,13 +856,12 @@ Target_i386::Scan::local(const General_options&, if (got->add_local(object, r_sym)) { // If we are generating a shared object, we need to add a - // dynamic RELATIVE relocation for this symbol. + // dynamic RELATIVE relocation for this symbol's GOT entry. if (parameters->output_is_position_independent()) { Reloc_section* rel_dyn = target->rel_dyn_section(layout); rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, - output_section, data_shndx, - reloc.get_r_offset()); + got, object->local_got_offset(r_sym)); } } } @@ -909,18 +908,10 @@ Target_i386::Scan::local(const General_options&, Output_data_got<32, false>* got = target->got_section(symtab, layout); unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); - if (got->add_local_tls(object, r_sym, true)) - { - Reloc_section* rel_dyn = target->rel_dyn_section(layout); - unsigned int got_off - = object->local_tls_got_offset(r_sym, true); - rel_dyn->add_local(object, r_sym, - elfcpp::R_386_TLS_DTPMOD32, - got, got_off); - rel_dyn->add_local(object, r_sym, - elfcpp::R_386_TLS_DTPOFF32, - got, got_off + 4); - } + got->add_local_tls_with_rel(object, r_sym, + lsym.get_st_shndx(), true, + target->rel_dyn_section(layout), + elfcpp::R_386_TLS_DTPMOD32); } else if (optimized_type != tls::TLSOPT_TO_LE) unsupported_reloc_local(object, r_type); @@ -928,7 +919,10 @@ Target_i386::Scan::local(const General_options&, case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (from ~oliva) case elfcpp::R_386_TLS_DESC_CALL: - unsupported_reloc_local(object, r_type); + // FIXME: If not relaxing to LE, we need to generate + // a GOT entry with an R_386_TLS_DESC reloc. + if (optimized_type != tls::TLSOPT_TO_LE) + unsupported_reloc_local(object, r_type); break; case elfcpp::R_386_TLS_LDM: // Local-dynamic @@ -938,15 +932,10 @@ Target_i386::Scan::local(const General_options&, Output_data_got<32, false>* got = target->got_section(symtab, layout); unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); - if (got->add_local_tls(object, r_sym, false)) - { - Reloc_section* rel_dyn = target->rel_dyn_section(layout); - unsigned int got_off - = object->local_tls_got_offset(r_sym, false); - rel_dyn->add_local(object, r_sym, - elfcpp::R_386_TLS_DTPMOD32, got, - got_off); - } + got->add_local_tls_with_rel(object, r_sym, + lsym.get_st_shndx(), false, + target->rel_dyn_section(layout), + elfcpp::R_386_TLS_DTPMOD32); } else if (optimized_type != tls::TLSOPT_TO_LE) unsupported_reloc_local(object, r_type); @@ -960,21 +949,26 @@ Target_i386::Scan::local(const General_options&, case elfcpp::R_386_TLS_GOTIE: if (optimized_type == tls::TLSOPT_NONE) { + // For the R_386_TLS_IE relocation, we need to create a + // dynamic relocation when building a shared library. + if (r_type == elfcpp::R_386_TLS_IE + && parameters->output_is_shared()) + { + Reloc_section* rel_dyn = target->rel_dyn_section(layout); + rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, + output_section, data_shndx, + reloc.get_r_offset()); + } // Create a GOT entry for the tp-relative offset. Output_data_got<32, false>* got = target->got_section(symtab, layout); unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); - if (got->add_local(object, r_sym)) - { - unsigned int dyn_r_type - = (r_type == elfcpp::R_386_TLS_IE_32 - ? elfcpp::R_386_TLS_TPOFF32 - : elfcpp::R_386_TLS_TPOFF); - Reloc_section* rel_dyn = target->rel_dyn_section(layout); - unsigned int got_off = object->local_got_offset(r_sym); - rel_dyn->add_local(object, r_sym, dyn_r_type, got, - got_off); - } + unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_IE_32 + ? elfcpp::R_386_TLS_TPOFF32 + : elfcpp::R_386_TLS_TPOFF); + got->add_local_with_rel(object, r_sym, + target->rel_dyn_section(layout), + dyn_r_type); } else if (optimized_type != tls::TLSOPT_TO_LE) unsupported_reloc_local(object, r_type); @@ -983,7 +977,16 @@ Target_i386::Scan::local(const General_options&, case elfcpp::R_386_TLS_LE: // Local-exec case elfcpp::R_386_TLS_LE_32: if (output_is_shared) - unsupported_reloc_local(object, r_type); + { + // We need to create a dynamic relocation. + unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); + unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_LE_32 + ? elfcpp::R_386_TLS_TPOFF32 + : elfcpp::R_386_TLS_TPOFF); + Reloc_section* rel_dyn = target->rel_dyn_section(layout); + rel_dyn->add_local(object, r_sym, dyn_r_type, output_section, + data_shndx, reloc.get_r_offset()); + } break; default: @@ -1087,7 +1090,17 @@ Target_i386::Scan::global(const General_options& options, { // Make a PLT entry if necessary. if (gsym->needs_plt_entry()) - target->make_plt_entry(symtab, layout, gsym); + { + // These relocations are used for function calls only in + // non-PIC code. For a 32-bit relocation in a shared library, + // we'll need a text relocation anyway, so we can skip the + // PLT entry and let the dynamic linker bind the call directly + // to the target. For smaller relocations, we should use a + // PLT entry to ensure that the call can reach. + if (!parameters->output_is_shared() + || r_type != elfcpp::R_386_PC32) + target->make_plt_entry(symtab, layout, gsym); + } // Make a dynamic relocation if necessary. bool is_function_call = (gsym->type() == elfcpp::STT_FUNC); if (gsym->needs_dynamic_reloc(false, is_function_call)) @@ -1111,18 +1124,18 @@ Target_i386::Scan::global(const General_options& options, { // The symbol requires a GOT entry. Output_data_got<32, false>* got = target->got_section(symtab, layout); - if (got->add_global(gsym)) - { + if (gsym->final_value_is_known()) + got->add_global(gsym); + else + { // If this symbol is not fully resolved, we need to add a - // dynamic relocation for it. - if (!gsym->final_value_is_known()) + // GOT entry with a dynamic relocation. + Reloc_section* rel_dyn = target->rel_dyn_section(layout); + if (gsym->is_from_dynobj() || gsym->is_preemptible()) + got->add_global_with_rel(gsym, rel_dyn, elfcpp::R_386_GLOB_DAT); + else { - Reloc_section* rel_dyn = target->rel_dyn_section(layout); - if (gsym->is_from_dynobj() - || gsym->is_preemptible()) - rel_dyn->add_global(gsym, elfcpp::R_386_GLOB_DAT, got, - gsym->got_offset()); - else + if (got->add_global(gsym)) { rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, got, gsym->got_offset()); @@ -1195,28 +1208,18 @@ Target_i386::Scan::global(const General_options& options, // dtv-relative offset. Output_data_got<32, false>* got = target->got_section(symtab, layout); - if (got->add_global_tls(gsym, true)) - { - Reloc_section* rel_dyn = target->rel_dyn_section(layout); - unsigned int got_off = gsym->tls_got_offset(true); - rel_dyn->add_global(gsym, elfcpp::R_386_TLS_DTPMOD32, - got, got_off); - rel_dyn->add_global(gsym, elfcpp::R_386_TLS_DTPOFF32, - got, got_off + 4); - } + got->add_global_tls_with_rel(gsym, + target->rel_dyn_section(layout), + elfcpp::R_386_TLS_DTPMOD32, + elfcpp::R_386_TLS_DTPOFF32); } else if (optimized_type == tls::TLSOPT_TO_IE) { // Create a GOT entry for the tp-relative offset. Output_data_got<32, false>* got = target->got_section(symtab, layout); - if (got->add_global(gsym)) - { - Reloc_section* rel_dyn = target->rel_dyn_section(layout); - unsigned int got_off = gsym->got_offset(); - rel_dyn->add_global(gsym, elfcpp::R_386_TLS_TPOFF32, - got, got_off); - } + got->add_global_with_rel(gsym, target->rel_dyn_section(layout), + elfcpp::R_386_TLS_TPOFF32); } else if (optimized_type != tls::TLSOPT_TO_LE) unsupported_reloc_global(object, r_type, gsym); @@ -1224,6 +1227,10 @@ Target_i386::Scan::global(const General_options& options, case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (~oliva url) case elfcpp::R_386_TLS_DESC_CALL: + // FIXME: If not relaxing to LE, we need to generate + // a GOT entry with an R_386_TLS_DESC reloc. + if (optimized_type != tls::TLSOPT_TO_LE) + unsupported_reloc_global(object, r_type, gsym); unsupported_reloc_global(object, r_type, gsym); break; @@ -1235,13 +1242,9 @@ Target_i386::Scan::global(const General_options& options, // Create a GOT entry for the module index. Output_data_got<32, false>* got = target->got_section(symtab, layout); - if (got->add_global_tls(gsym, false)) - { - Reloc_section* rel_dyn = target->rel_dyn_section(layout); - unsigned int got_off = gsym->tls_got_offset(false); - rel_dyn->add_global(gsym, elfcpp::R_386_TLS_DTPMOD32, - got, got_off); - } + got->add_global_tls_with_rel(gsym, + target->rel_dyn_section(layout), + elfcpp::R_386_TLS_DTPMOD32); } else if (optimized_type != tls::TLSOPT_TO_LE) unsupported_reloc_global(object, r_type, gsym); @@ -1255,19 +1258,25 @@ Target_i386::Scan::global(const General_options& options, case elfcpp::R_386_TLS_GOTIE: if (optimized_type == tls::TLSOPT_NONE) { - // Create a GOT entry for the tp-relative offset. - Output_data_got<32, false>* got - = target->got_section(symtab, layout); - if (got->add_global(gsym)) + // For the R_386_TLS_IE relocation, we need to create a + // dynamic relocation when building a shared library. + if (r_type == elfcpp::R_386_TLS_IE + && parameters->output_is_shared()) { - unsigned int dyn_r_type - = (r_type == elfcpp::R_386_TLS_IE_32 - ? elfcpp::R_386_TLS_TPOFF32 - : elfcpp::R_386_TLS_TPOFF); Reloc_section* rel_dyn = target->rel_dyn_section(layout); - unsigned int got_off = gsym->got_offset(); - rel_dyn->add_global(gsym, dyn_r_type, got, got_off); + rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, + output_section, data_shndx, + reloc.get_r_offset()); } + // Create a GOT entry for the tp-relative offset. + Output_data_got<32, false>* got + = target->got_section(symtab, layout); + unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_IE_32 + ? elfcpp::R_386_TLS_TPOFF32 + : elfcpp::R_386_TLS_TPOFF); + got->add_global_with_rel(gsym, + target->rel_dyn_section(layout), + dyn_r_type); } else if (optimized_type != tls::TLSOPT_TO_LE) unsupported_reloc_global(object, r_type, gsym); @@ -1276,7 +1285,15 @@ Target_i386::Scan::global(const General_options& options, case elfcpp::R_386_TLS_LE: // Local-exec case elfcpp::R_386_TLS_LE_32: if (parameters->output_is_shared()) - unsupported_reloc_global(object, r_type, gsym); + { + // We need to create a dynamic relocation. + unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_LE_32 + ? elfcpp::R_386_TLS_TPOFF32 + : elfcpp::R_386_TLS_TPOFF); + Reloc_section* rel_dyn = target->rel_dyn_section(layout); + rel_dyn->add_global(gsym, dyn_r_type, output_section, object, + data_shndx, reloc.get_r_offset()); + } break; default: @@ -1670,9 +1687,8 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, if (optimized_type == tls::TLSOPT_TO_IE) { gold_assert(tls_segment != NULL); - this->tls_gd_to_ie(relinfo, relnum, tls_segment, - rel, r_type, got_offset, view, - view_size); + this->tls_gd_to_ie(relinfo, relnum, tls_segment, rel, r_type, + got_offset, view, view_size); break; } else if (optimized_type == tls::TLSOPT_NONE) @@ -1741,13 +1757,11 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, // won't see the TLS_LDM reloc. The local_dynamic_type field // tells us this. gold_assert(tls_segment != NULL); - if (optimized_type != tls::TLSOPT_TO_LE - || this->local_dynamic_type_ == LOCAL_DYNAMIC_NONE) - value = value - tls_segment->vaddr(); - else if (this->local_dynamic_type_ == LOCAL_DYNAMIC_GNU) - value = value - (tls_segment->vaddr() + tls_segment->memsz()); - else - value = tls_segment->vaddr() + tls_segment->memsz() - value; + if (this->local_dynamic_type_ == LOCAL_DYNAMIC_GNU) + value -= tls_segment->memsz(); + else if (optimized_type == tls::TLSOPT_TO_LE + && this->local_dynamic_type_ != LOCAL_DYNAMIC_NONE) + value = tls_segment->memsz() - value; Relocate_functions<32, false>::rel32(view, value); break; @@ -1793,15 +1807,25 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, break; case elfcpp::R_386_TLS_LE: // Local-exec - gold_assert(tls_segment != NULL); - value = value - (tls_segment->vaddr() + tls_segment->memsz()); - Relocate_functions<32, false>::rel32(view, value); + // If we're creating a shared library, a dynamic relocation will + // have been created for this location, so do not apply it now. + if (!parameters->output_is_shared()) + { + gold_assert(tls_segment != NULL); + value -= tls_segment->memsz(); + Relocate_functions<32, false>::rel32(view, value); + } break; case elfcpp::R_386_TLS_LE_32: - gold_assert(tls_segment != NULL); - value = tls_segment->vaddr() + tls_segment->memsz() - value; - Relocate_functions<32, false>::rel32(view, value); + // If we're creating a shared library, a dynamic relocation will + // have been created for this location, so do not apply it now. + if (!parameters->output_is_shared()) + { + gold_assert(tls_segment != NULL); + value = tls_segment->memsz() - value; + Relocate_functions<32, false>::rel32(view, value); + } break; } } @@ -1862,7 +1886,7 @@ Target_i386::Relocate::tls_gd_to_le(const Relocate_info<32, false>* relinfo, } } - value = tls_segment->vaddr() + tls_segment->memsz() - value; + value = tls_segment->memsz() - value; Relocate_functions<32, false>::rel32(view + roff, value); // The next reloc should be a PLT32 reloc against __tls_get_addr. @@ -1870,7 +1894,7 @@ Target_i386::Relocate::tls_gd_to_le(const Relocate_info<32, false>* relinfo, this->skip_call_tls_get_addr_ = true; } -// Do a relocation in which we convert a TLS General-Dynamic to a +// Do a relocation in which we convert a TLS General-Dynamic to an // Initial-Exec. inline void @@ -1930,7 +1954,7 @@ Target_i386::Relocate::tls_gd_to_ie(const Relocate_info<32, false>* relinfo, } } - value = tls_segment->vaddr() + tls_segment->memsz() - value; + value = tls_segment->memsz() - value; Relocate_functions<32, false>::rel32(view + roff, value); // The next reloc should be a PLT32 reloc against __tls_get_addr. @@ -2059,7 +2083,7 @@ Target_i386::Relocate::tls_ie_to_le(const Relocate_info<32, false>* relinfo, tls::check_tls(relinfo, relnum, rel.get_r_offset(), 0); } - value = tls_segment->vaddr() + tls_segment->memsz() - value; + value = tls_segment->memsz() - value; if (r_type == elfcpp::R_386_TLS_IE || r_type == elfcpp::R_386_TLS_GOTIE) value = - value; diff --git a/gold/layout.cc b/gold/layout.cc index 1139cf1..68ebc6b 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -658,6 +658,8 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab) target->finalize_sections(this); + this->count_local_symbols(input_objects); + this->create_gold_note(); this->create_executable_stack_info(target); @@ -677,7 +679,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab) std::vector 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 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 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* pdynamic_symbols, @@ -1326,10 +1348,15 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab, } } - // FIXME: Some targets apparently require local symbols in the - // dynamic symbol table. Here is where we will have to count them, - // and set the dynamic symbol indexes, and add the names to - // this->dynpool_. + // Count the local symbols that need to go in the dynamic symbol table, + // and set the dynamic symbol indexes. + for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); + p != input_objects->relobj_end(); + ++p) + { + unsigned int new_index = (*p)->set_local_dynsym_indexes(index); + index = new_index; + } unsigned int local_symcount = index; *plocal_dynamic_count = local_symcount; @@ -1419,6 +1446,28 @@ Layout::create_dynamic_symtab(const Target* target, Symbol_table* symtab, odyn->add_section_address(elfcpp::DT_HASH, hashsec); } +// Assign offsets to each local portion of the dynamic symbol table. + +void +Layout::assign_local_dynsym_offsets(const Input_objects* input_objects) +{ + Output_section* dynsym = this->dynsym_section_; + gold_assert(dynsym != NULL); + + off_t off = dynsym->offset(); + + // Skip the dummy symbol at the start of the section. + off += dynsym->entsize(); + + for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); + p != input_objects->relobj_end(); + ++p) + { + unsigned int count = (*p)->set_local_dynsym_offset(off); + off += count * dynsym->entsize(); + } +} + // Create the version sections. void diff --git a/gold/layout.h b/gold/layout.h index a790892..12f703f 100644 --- a/gold/layout.h +++ b/gold/layout.h @@ -270,6 +270,11 @@ class Layout Output_segment* find_first_load_seg(); + // Count the local symbols in the regular symbol table and the dynamic + // symbol table, and build the respective string pools. + void + count_local_symbols(const Input_objects*); + // Create the output sections for the symbol table. void create_symtab_sections(const Input_objects*, Symbol_table*, off_t*); @@ -284,11 +289,16 @@ class Layout // Create the dynamic symbol table. void - create_dynamic_symtab(const Target*, Symbol_table*, Output_section** pdynstr, + create_dynamic_symtab(const Input_objects*, const Target*, + Symbol_table*, Output_section** pdynstr, unsigned int* plocal_dynamic_count, std::vector* pdynamic_symbols, Versions* versions); + // Assign offsets to each local portion of the dynamic symbol table. + void + assign_local_dynsym_offsets(const Input_objects*); + // Finish the .dynamic section and PT_DYNAMIC segment. void finish_dynamic_section(const Input_objects*, const Symbol_table*); diff --git a/gold/object.cc b/gold/object.cc index fee249f..ab1323a 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -142,8 +142,10 @@ Sized_relobj::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::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::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 -unsigned int -Sized_relobj::do_finalize_local_symbols(unsigned int index, - off_t off, - Stringpool* pool) +void +Sized_relobj::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(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::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::do_finalize_local_symbols(unsigned int index, const std::vector& 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::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(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 +unsigned int +Sized_relobj::do_finalize_local_symbols(unsigned int index, + off_t off) +{ + gold_assert(off == static_cast(align_address(off, size >> 3))); + + const unsigned int loccount = this->local_symbol_count_; + this->local_symbol_offset_ = off; + + const std::vector& mo(this->map_to_output()); + unsigned int shnum = this->shnum(); + for (unsigned int i = 1; i < loccount; ++i) + { + Symbol_value& lv(this->local_values_[i]); + + unsigned int shndx = lv.input_shndx(); + + // Set the output symbol value. + if (shndx >= elfcpp::SHN_LORESERVE) { if (shndx == elfcpp::SHN_ABS) - lv.set_output_value(sym.get_st_value()); + lv.set_output_value(lv.input_value()); else { // FIXME: Handle SHN_XINDEX. @@ -814,45 +881,61 @@ Sized_relobj::do_finalize_local_symbols(unsigned int index, if (os == NULL) { lv.set_output_value(0); - lv.set_no_output_symtab_entry(); continue; } - - if (mo[shndx].offset == -1) - lv.set_input_value(sym.get_st_value()); + else if (mo[shndx].offset == -1) + { + // Leave the input value in place for SHF_MERGE sections. + } + else if (lv.is_tls_symbol()) + lv.set_output_value(mo[shndx].output_section->tls_offset() + + mo[shndx].offset + + lv.input_value()); else lv.set_output_value(mo[shndx].output_section->address() + mo[shndx].offset - + sym.get_st_value()); + + lv.input_value()); } - // Decide whether this symbol should go into the output file. - - if (sym.get_st_type() == elfcpp::STT_SECTION) - { - lv.set_no_output_symtab_entry(); - continue; - } + if (lv.needs_output_symtab_entry()) + { + lv.set_output_symtab_index(index); + ++index; + } + } + return index; +} - if (sym.get_st_name() >= strtab_size) - { - this->error(_("local symbol %u section name out of range: %u >= %u"), - i, sym.get_st_name(), - static_cast(strtab_size)); - lv.set_no_output_symtab_entry(); - continue; - } +// Set the output dynamic symbol table indexes for the local variables. - const char* name = pnames + sym.get_st_name(); - pool->add(name, true, NULL); - lv.set_output_symtab_index(index); - ++index; - ++count; +template +unsigned int +Sized_relobj::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& lv(this->local_values_[i]); + if (lv.needs_output_dynsym_entry()) + { + lv.set_output_dynsym_index(index); + ++index; + } } + return index; +} - this->output_local_symbol_count_ = count; +// Set the offset where local dynamic symbol information will be stored. +// Returns the count of local symbols contributed to the symbol table by +// this object. - return index; +template +unsigned int +Sized_relobj::do_set_local_dynsym_offset(off_t off) +{ + gold_assert(off == static_cast(align_address(off, size >> 3))); + this->local_dynsym_offset_ = off; + return this->output_local_dynsym_count_; } // Return the value of the local symbol symndx. @@ -905,9 +988,10 @@ Sized_relobj::local_value(unsigned int shndx, template void Sized_relobj::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::write_local_symbols(Output_file* of, true); const char* pnames = reinterpret_cast(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& 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 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::write_local_symbols(Output_file* of, st_shndx = mo[st_shndx].output_section->out_shndx(); } - elfcpp::Sym_write osym(ov); - - gold_assert(isym.get_st_name() < strtab_size); - const char* name = pnames + isym.get_st_name(); - osym.put_st_name(sympool->get_offset(name)); - osym.put_st_value(this->local_values_[i].value(this, 0)); - osym.put_st_size(isym.get_st_size()); - osym.put_st_info(isym.get_st_info()); - osym.put_st_other(isym.get_st_other()); - osym.put_st_shndx(st_shndx); + // Write the symbol to the output symbol table. + if (!parameters->strip_all() + && this->local_values_[i].needs_output_symtab_entry()) + { + elfcpp::Sym_write osym(ov); + + gold_assert(isym.get_st_name() < strtab_size); + const char* name = pnames + isym.get_st_name(); + osym.put_st_name(sympool->get_offset(name)); + osym.put_st_value(this->local_values_[i].value(this, 0)); + osym.put_st_size(isym.get_st_size()); + osym.put_st_info(isym.get_st_info()); + osym.put_st_other(isym.get_st_other()); + osym.put_st_shndx(st_shndx); + + ov += sym_size; + } - ov += sym_size; + // Write the symbol to the output dynamic symbol table. + if (this->local_values_[i].needs_output_dynsym_entry()) + { + gold_assert(dyn_ov < dyn_oview + dyn_output_size); + elfcpp::Sym_write osym(dyn_ov); + + gold_assert(isym.get_st_name() < strtab_size); + const char* name = pnames + isym.get_st_name(); + osym.put_st_name(dynpool->get_offset(name)); + osym.put_st_value(this->local_values_[i].value(this, 0)); + osym.put_st_size(isym.get_st_size()); + osym.put_st_info(isym.get_st_info()); + osym.put_st_other(isym.get_st_other()); + osym.put_st_shndx(st_shndx); + + dyn_ov += sym_size; + } } - gold_assert(ov - oview == output_size); - of->write_output_view(this->local_symbol_offset_, output_size, oview); + if (output_size > 0) + { + gold_assert(ov - oview == output_size); + of->write_output_view(this->local_symbol_offset_, output_size, oview); + } + + if (dyn_output_size > 0) + { + gold_assert(dyn_ov - dyn_oview == dyn_output_size); + of->write_output_view(this->local_dynsym_offset_, dyn_output_size, + dyn_oview); + } } // Set *INFO to symbolic information about the offset OFFSET in the diff --git a/gold/object.h b/gold/object.h index 40839bc..4b826cf 100644 --- a/gold/object.h +++ b/gold/object.h @@ -429,13 +429,30 @@ class Relobj : public Object Layout* layout, Read_relocs_data* rd) { return this->do_scan_relocs(options, symtab, layout, rd); } - // Initial local symbol processing: set the offset where local - // symbol information will be stored; add local symbol names to - // *POOL; return the new local symbol index. + // Initial local symbol processing: count the number of local symbols + // in the output symbol table and dynamic symbol table; add local symbol + // names to *POOL and *DYNPOOL. + void + count_local_symbols(Stringpool_template* pool, + Stringpool_template* dynpool) + { return this->do_count_local_symbols(pool, dynpool); } + + // Set the values of the local symbols, set the output symbol table + // indexes for the local variables, and set the offset where local + // symbol information will be stored. Returns the new local symbol index. + unsigned int + finalize_local_symbols(unsigned int index, off_t off) + { return this->do_finalize_local_symbols(index, off); } + + // Set the output dynamic symbol table indexes for the local variables. unsigned int - finalize_local_symbols(unsigned int index, off_t off, - Stringpool_template* pool) - { return this->do_finalize_local_symbols(index, off, pool); } + set_local_dynsym_indexes(unsigned int index) + { return this->do_set_local_dynsym_indexes(index); } + + // Set the offset where local dynamic symbol information will be stored. + unsigned int + set_local_dynsym_offset(off_t off) + { return this->do_set_local_dynsym_offset(off); } // Relocate the input sections and write out the local symbols. void @@ -521,11 +538,24 @@ class Relobj : public Object do_scan_relocs(const General_options&, Symbol_table*, Layout*, Read_relocs_data*) = 0; - // Finalize local symbols--implemented by child class. - virtual unsigned int - do_finalize_local_symbols(unsigned int, off_t, + // Count local symbols--implemented by child class. + virtual void + do_count_local_symbols(Stringpool_template*, Stringpool_template*) = 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::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* 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*, + Stringpool_template*); + // Finalize the local symbols. unsigned int - do_finalize_local_symbols(unsigned int, off_t, - Stringpool_template*); + 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*, const Stringpool_template*); // The GOT offsets of local symbols. This map also stores GOT offsets @@ -1007,10 +1128,15 @@ class Sized_relobj : public Relobj unsigned int local_symbol_count_; // The number of local symbols which go into the output file. unsigned int output_local_symbol_count_; + // The number of local symbols which go into the output file's dynamic + // symbol table. + unsigned int output_local_dynsym_count_; // The entries in the symbol table for the external symbols. Symbols symbols_; // File offset for local symbols. off_t local_symbol_offset_; + // File offset for local dynamic symbols. + off_t local_dynsym_offset_; // Values of local symbols. Local_values local_values_; // GOT offsets for local non-TLS symbols, and tp-relative offsets diff --git a/gold/output.cc b/gold/output.cc index 6c4ed5c..7fd901c 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -505,6 +505,113 @@ Output_data_strtab::do_write(Output_file* of) // Output_reloc methods. +// A reloc against a global symbol. + +template +Output_reloc::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 +Output_reloc::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 +Output_reloc::Output_reloc( + Sized_relobj* 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 +Output_reloc::Output_reloc( + Sized_relobj* 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 +Output_reloc::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 +Output_reloc::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 @@ -541,12 +648,7 @@ Output_reloc::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::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 +void +Output_data_got::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 +void +Output_data_got::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::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 +void +Output_data_got::add_local_with_rel( + Sized_relobj* 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 +void +Output_data_got::add_local_with_rela( + Sized_relobj* 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::add_local( template bool -Output_data_got::add_global_tls(Symbol* gsym, - bool need_pair) +Output_data_got::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::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 +void +Output_data_got::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 +void +Output_data_got::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 +void +Output_data_got::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 +void +Output_data_got::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::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 +void +Output_data_got::add_local_tls_with_rel( + Sized_relobj* 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 +void +Output_data_got::add_local_tls_with_rela( + Sized_relobj* 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 @@ -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 @@ -1829,6 +2156,24 @@ Output_segment::set_offset() - this->vaddr_); } +// Set the TLS offsets of the sections in the PT_TLS segment. + +void +Output_segment::set_tls_offsets() +{ + gold_assert(this->type_ == elfcpp::PT_TLS); + + for (Output_data_list::iterator p = this->output_data_.begin(); + p != this->output_data_.end(); + ++p) + (*p)->set_tls_offset(this->vaddr_); + + for (Output_data_list::iterator p = this->output_bss_.begin(); + p != this->output_bss_.end(); + ++p) + (*p)->set_tls_offset(this->vaddr_); +} + // Return the number of Output_sections in an Output_segment. unsigned int diff --git a/gold/output.h b/gold/output.h index fe42112..6c80d0a 100644 --- a/gold/output.h +++ b/gold/output.h @@ -160,6 +160,17 @@ class Output_data } } + // Set the TLS offset. Called only for SHT_TLS sections. + void + set_tls_offset(uint64_t tls_base) + { this->do_set_tls_offset(tls_base); } + + // Return the TLS offset, relative to the base of the TLS segment. + // Valid only for SHT_TLS sections. + uint64_t + tls_offset() const + { return this->do_tls_offset(); } + // Write the data to the output file. This is called after // Layout::finalize is complete. void @@ -232,6 +243,17 @@ class Output_data set_final_data_size() { gold_unreachable(); } + // Set the TLS offset. Called only for SHT_TLS sections. + virtual void + do_set_tls_offset(uint64_t) + { gold_unreachable(); } + + // Return the TLS offset, relative to the base of the TLS segment. + // Valid only for SHT_TLS sections. + virtual uint64_t + do_tls_offset() const + { gold_unreachable(); } + // Functions that child classes may call. // Whether the address is valid. @@ -681,75 +703,28 @@ class Output_reloc // 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* 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* 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::Elf_Addr Valtype; + typedef Output_data_reloc Rel_dyn; + typedef Output_data_reloc 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* 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* object, + unsigned int sym_index, Rel_dyn* rel_dyn, + unsigned int r_type); + + void + add_local_with_rela(Sized_relobj* 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* 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* 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* object, + unsigned int sym_index, unsigned int shndx, + bool need_pair, Rela_dyn* rela_dyn, + unsigned int r_type); + // Add a constant to the GOT. This returns the offset of the new // entry from the start of the GOT. unsigned int @@ -1609,6 +1645,16 @@ class Output_section : public Output_data do_is_section_flag_set(elfcpp::Elf_Xword flag) const { return (this->flags_ & flag) != 0; } + // Set the TLS offset. Called only for SHT_TLS sections. + void + do_set_tls_offset(uint64_t tls_base); + + // Return the TLS offset, relative to the base of the TLS segment. + // Valid only for SHT_TLS sections. + uint64_t + do_tls_offset() const + { return this->tls_offset_; } + // Modify the section name. This is only permitted for an // unallocated section, and only before the size has been finalized. // Otherwise the name will not get into Layout::namepool_. @@ -1933,6 +1979,9 @@ class Output_section : public Output_data // Whether this section requires post processing after all // relocations have been applied. bool requires_postprocessing_ : 1; + // For SHT_TLS sections, the offset of this section relative to the base + // of the TLS segment. + uint64_t tls_offset_; }; // An output segment. PT_LOAD segments are built from collections of @@ -2021,6 +2070,10 @@ class Output_segment void set_offset(); + // Set the TLS offsets of the sections contained in the PT_TLS segment. + void + set_tls_offsets(); + // Return the number of output sections. unsigned int output_section_count() const; diff --git a/gold/reloc.cc b/gold/reloc.cc index 2763be5..e34cd04 100644 --- a/gold/reloc.cc +++ b/gold/reloc.cc @@ -390,7 +390,7 @@ Sized_relobj::do_relocate(const General_options& options, } // Write out the local symbols. - this->write_local_symbols(of, layout->sympool()); + this->write_local_symbols(of, layout->sympool(), layout->dynpool()); } // Write section data to the output file. PSHDRS points to the diff --git a/gold/symtab.cc b/gold/symtab.cc index 40b3080..a18d3ae 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -1507,7 +1507,10 @@ Symbol_table::sized_finalize(unsigned index, off_t off, Stringpool* pool) continue; } - value = sym->value() + os->address() + secoff; + if (sym->type() == elfcpp::STT_TLS) + value = sym->value() + os->tls_offset() + secoff; + else + value = sym->value() + os->address() + secoff; } } break; @@ -1920,7 +1923,7 @@ Symbol_table::print_stats() const // that case. // This struct is used to compare line information, as returned by -// Dwarf_line_info::one_addr2line. It imlements a < comparison +// Dwarf_line_info::one_addr2line. It implements a < comparison // operator used with std::set. struct Odr_violation_compare diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am index e3b263d..b11db39 100644 --- a/gold/testsuite/Makefile.am +++ b/gold/testsuite/Makefile.am @@ -177,8 +177,8 @@ debug_msg_ndebug.err: debug_msg_ndebug.so odr_violation1_ndebug.so odr_violation undef_symbol.o: undef_symbol.cc $(CXXCOMPILE) -O0 -g -c -fPIC $< -undef_symbol.so: undef_symbol.o - $(CXXLINK) -shared undef_symbol.o +undef_symbol.so: undef_symbol.o gcctestdir/ld + $(CXXLINK) -Bgcctestdir/ -shared undef_symbol.o undef_symbol.err: undef_symbol_main.o undef_symbol.so gcctestdir/ld @echo $(CXXLINK) -Bgcctestdir/ -o undef_symbol_test undef_symbol_main.o undef_symbol.so "2>$@" @if $(CXXLINK) -Bgcctestdir/ -o undef_symbol_test undef_symbol_main.o undef_symbol.so 2>$@; \ @@ -302,12 +302,12 @@ two_file_test_1_pic.o: two_file_test_1.cc two_file_test_2_pic.o: two_file_test_2.cc $(CXXCOMPILE) -c -fpic -o $@ $< -two_file_shared_1.so: two_file_test_1_pic.o - $(CXXLINK) -shared two_file_test_1_pic.o -two_file_shared_2.so: two_file_test_2_pic.o - $(CXXLINK) -shared two_file_test_2_pic.o -two_file_shared.so: two_file_test_1_pic.o two_file_test_2_pic.o - $(CXXLINK) -shared two_file_test_1_pic.o two_file_test_2_pic.o +two_file_shared_1.so: two_file_test_1_pic.o gcctestdir/ld + $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1_pic.o +two_file_shared_2.so: two_file_test_2_pic.o gcctestdir/ld + $(CXXLINK) -Bgcctestdir/ -shared two_file_test_2_pic.o +two_file_shared.so: two_file_test_1_pic.o two_file_test_2_pic.o gcctestdir/ld + $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1_pic.o two_file_test_2_pic.o # The nonpic tests will fail on platforms which can not put non-PIC # code into shared libraries, so we just don't run them in that case. @@ -348,12 +348,12 @@ two_file_separate_shared_21_nonpic_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,. two_file_separate_shared_21_nonpic_test_LDADD = \ two_file_shared_2_nonpic.so two_file_shared_1_nonpic.so -two_file_shared_1_nonpic.so: two_file_test_1.o - $(CXXLINK) -shared two_file_test_1.o -two_file_shared_2_nonpic.so: two_file_test_2.o - $(CXXLINK) -shared two_file_test_2.o -two_file_shared_nonpic.so: two_file_test_1.o two_file_test_2.o - $(CXXLINK) -shared two_file_test_1.o two_file_test_2.o +two_file_shared_1_nonpic.so: two_file_test_1.o gcctestdir/ld + $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1.o +two_file_shared_2_nonpic.so: two_file_test_2.o gcctestdir/ld + $(CXXLINK) -Bgcctestdir/ -shared two_file_test_2.o +two_file_shared_nonpic.so: two_file_test_1.o two_file_test_2.o gcctestdir/ld + $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1.o two_file_test_2.o endif @@ -406,12 +406,12 @@ exception_test_1_pic.o: exception_test_1.cc exception_test_2_pic.o: exception_test_2.cc $(CXXCOMPILE) -c -fpic -o $@ $< -exception_shared_1.so: exception_test_1_pic.o - $(CXXLINK) -shared exception_test_1_pic.o -exception_shared_2.so: exception_test_2_pic.o - $(CXXLINK) -shared exception_test_2_pic.o -exception_shared.so: exception_test_1_pic.o exception_test_2_pic.o - $(CXXLINK) -shared exception_test_1_pic.o exception_test_2_pic.o +exception_shared_1.so: exception_test_1_pic.o gcctestdir/ld + $(CXXLINK) -Bgcctestdir/ -shared exception_test_1_pic.o +exception_shared_2.so: exception_test_2_pic.o gcctestdir/ld + $(CXXLINK) -Bgcctestdir/ -shared exception_test_2_pic.o +exception_shared.so: exception_test_1_pic.o exception_test_2_pic.o gcctestdir/ld + $(CXXLINK) -Bgcctestdir/ -shared exception_test_1_pic.o exception_test_2_pic.o weak_test_SOURCES = weak_test.cc weak_test_LDFLAGS = -Bgcctestdir/ @@ -449,8 +449,8 @@ tls_test_pic.o: tls_test.cc tls_test_file2_pic.o: tls_test_file2.cc $(CXXCOMPILE) -c -fpic -o $@ $< -tls_test_shared.so: tls_test_pic.o tls_test_file2_pic.o - $(CXXLINK) -shared tls_test_pic.o tls_test_file2_pic.o +tls_test_shared.so: tls_test_pic.o tls_test_file2_pic.o gcctestdir/ld + $(CXXLINK) -Bgcctestdir/ -shared tls_test_pic.o tls_test_file2_pic.o if FN_PTRS_IN_SO_WITHOUT_PIC @@ -459,8 +459,8 @@ tls_shared_nonpic_test_DEPENDENCIES = gcctestdir/ld tls_test_shared_nonpic.so tls_shared_nonpic_test_LDFLAGS = -Bgcctestdir/ -Wl,-R,. tls_shared_nonpic_test_LDADD = tls_test_shared_nonpic.so -lpthread -tls_test_shared_nonpic.so: tls_test.o tls_test_file2.o - $(CXXLINK) -shared tls_test.o tls_test_file2.o +tls_test_shared_nonpic.so: tls_test.o tls_test_file2.o gcctestdir/ld + $(CXXLINK) -Bgcctestdir/ -shared tls_test.o tls_test_file2.o endif diff --git a/gold/testsuite/Makefile.in b/gold/testsuite/Makefile.in index 15d5f19..a4293a9 100644 --- a/gold/testsuite/Makefile.in +++ b/gold/testsuite/Makefile.in @@ -1330,8 +1330,8 @@ uninstall-am: uninstall-info-am @GCC_TRUE@@NATIVE_LINKER_TRUE@undef_symbol.o: undef_symbol.cc @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -g -c -fPIC $< -@GCC_TRUE@@NATIVE_LINKER_TRUE@undef_symbol.so: undef_symbol.o -@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -shared undef_symbol.o +@GCC_TRUE@@NATIVE_LINKER_TRUE@undef_symbol.so: undef_symbol.o gcctestdir/ld +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared undef_symbol.o @GCC_TRUE@@NATIVE_LINKER_TRUE@undef_symbol.err: undef_symbol_main.o undef_symbol.so gcctestdir/ld @GCC_TRUE@@NATIVE_LINKER_TRUE@ @echo $(CXXLINK) -Bgcctestdir/ -o undef_symbol_test undef_symbol_main.o undef_symbol.so "2>$@" @GCC_TRUE@@NATIVE_LINKER_TRUE@ @if $(CXXLINK) -Bgcctestdir/ -o undef_symbol_test undef_symbol_main.o undef_symbol.so 2>$@; \ @@ -1386,31 +1386,31 @@ uninstall-am: uninstall-info-am @GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_test_2_pic.o: two_file_test_2.cc @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $< -@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1.so: two_file_test_1_pic.o -@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -shared two_file_test_1_pic.o -@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_2.so: two_file_test_2_pic.o -@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -shared two_file_test_2_pic.o -@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared.so: two_file_test_1_pic.o two_file_test_2_pic.o -@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -shared two_file_test_1_pic.o two_file_test_2_pic.o +@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1.so: two_file_test_1_pic.o gcctestdir/ld +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1_pic.o +@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_2.so: two_file_test_2_pic.o gcctestdir/ld +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_2_pic.o +@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared.so: two_file_test_1_pic.o two_file_test_2_pic.o gcctestdir/ld +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1_pic.o two_file_test_2_pic.o -@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1_nonpic.so: two_file_test_1.o -@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -shared two_file_test_1.o -@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_2_nonpic.so: two_file_test_2.o -@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -shared two_file_test_2.o -@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_nonpic.so: two_file_test_1.o two_file_test_2.o -@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -shared two_file_test_1.o two_file_test_2.o +@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_1_nonpic.so: two_file_test_1.o gcctestdir/ld +@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1.o +@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_2_nonpic.so: two_file_test_2.o gcctestdir/ld +@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_2.o +@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@two_file_shared_nonpic.so: two_file_test_1.o two_file_test_2.o gcctestdir/ld +@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared two_file_test_1.o two_file_test_2.o @GCC_TRUE@@NATIVE_LINKER_TRUE@exception_test_1_pic.o: exception_test_1.cc @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $< @GCC_TRUE@@NATIVE_LINKER_TRUE@exception_test_2_pic.o: exception_test_2.cc @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $< -@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_shared_1.so: exception_test_1_pic.o -@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -shared exception_test_1_pic.o -@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_shared_2.so: exception_test_2_pic.o -@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -shared exception_test_2_pic.o -@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_shared.so: exception_test_1_pic.o exception_test_2_pic.o -@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -shared exception_test_1_pic.o exception_test_2_pic.o +@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_shared_1.so: exception_test_1_pic.o gcctestdir/ld +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared exception_test_1_pic.o +@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_shared_2.so: exception_test_2_pic.o gcctestdir/ld +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared exception_test_2_pic.o +@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_shared.so: exception_test_1_pic.o exception_test_2_pic.o gcctestdir/ld +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared exception_test_1_pic.o exception_test_2_pic.o @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_pic.o: tls_test.cc @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $< @@ -1418,11 +1418,11 @@ uninstall-am: uninstall-info-am @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_file2_pic.o: tls_test_file2.cc @GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXCOMPILE) -c -fpic -o $@ $< -@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_shared.so: tls_test_pic.o tls_test_file2_pic.o -@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXLINK) -shared tls_test_pic.o tls_test_file2_pic.o +@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_shared.so: tls_test_pic.o tls_test_file2_pic.o gcctestdir/ld +@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared tls_test_pic.o tls_test_file2_pic.o -@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_shared_nonpic.so: tls_test.o tls_test_file2.o -@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXLINK) -shared tls_test.o tls_test_file2.o +@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@tls_test_shared_nonpic.so: tls_test.o tls_test_file2.o gcctestdir/ld +@FN_PTRS_IN_SO_WITHOUT_PIC_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@@TLS_TRUE@ $(CXXLINK) -Bgcctestdir/ -shared tls_test.o tls_test_file2.o # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff --git a/gold/x86_64.cc b/gold/x86_64.cc index f19fa9b..24f87b9 100644 --- a/gold/x86_64.cc +++ b/gold/x86_64.cc @@ -186,14 +186,23 @@ class Target_x86_64 : public Sized_target<64, false> private: // Do a TLS relocation. inline void - relocate_tls(const Relocate_info<64, false>*, size_t relnum, - const elfcpp::Rela<64, false>&, + relocate_tls(const Relocate_info<64, false>*, Target_x86_64*, + size_t relnum, const elfcpp::Rela<64, false>&, unsigned int r_type, const Sized_symbol<64>*, const Symbol_value<64>*, unsigned char*, elfcpp::Elf_types<64>::Elf_Addr, off_t); // Do a TLS General-Dynamic to Local-Exec transition. inline void + tls_gd_to_ie(const Relocate_info<64, false>*, size_t relnum, + Output_segment* tls_segment, + const elfcpp::Rela<64, false>&, unsigned int r_type, + elfcpp::Elf_types<64>::Elf_Addr value, + unsigned char* view, + off_t view_size); + + // Do a TLS General-Dynamic to Local-Exec transition. + inline void tls_gd_to_le(const Relocate_info<64, false>*, size_t relnum, Output_segment* tls_segment, const elfcpp::Rela<64, false>&, unsigned int r_type, @@ -745,7 +754,7 @@ Target_x86_64::Scan::local(const General_options&, Output_section* output_section, const elfcpp::Rela<64, false>& reloc, unsigned int r_type, - const elfcpp::Sym<64, false>&) + const elfcpp::Sym<64, false>& lsym) { switch (r_type) { @@ -823,16 +832,17 @@ Target_x86_64::Scan::local(const General_options&, if (got->add_local(object, r_sym)) { // If we are generating a shared object, we need to add a - // dynamic RELATIVE relocation for this symbol. + // dynamic relocation for this symbol's GOT entry. if (parameters->output_is_position_independent()) { - // FIXME: R_X86_64_RELATIVE assumes a 64-bit relocation. - gold_assert(r_type != elfcpp::R_X86_64_GOT32); - Reloc_section* rela_dyn = target->rela_dyn_section(layout); - rela_dyn->add_local(object, 0, elfcpp::R_X86_64_RELATIVE, - output_section, data_shndx, - reloc.get_r_offset(), 0); + // R_X86_64_RELATIVE assumes a 64-bit relocation. + if (r_type != elfcpp::R_X86_64_GOT32) + rela_dyn->add_local(object, 0, elfcpp::R_X86_64_RELATIVE, + got, object->local_got_offset(r_sym), 0); + else + rela_dyn->add_local(object, r_sym, r_type, + got, object->local_got_offset(r_sym), 0); } } // For GOTPLT64, we'd normally want a PLT section, but since @@ -868,34 +878,68 @@ Target_x86_64::Scan::local(const General_options&, switch (r_type) { case elfcpp::R_X86_64_TLSGD: // General-dynamic + if (optimized_type == tls::TLSOPT_NONE) + { + // Create a pair of GOT entries for the module index and + // dtv-relative offset. + Output_data_got<64, false>* got + = target->got_section(symtab, layout); + unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info()); + got->add_local_tls_with_rela(object, r_sym, + lsym.get_st_shndx(), true, + target->rela_dyn_section(layout), + elfcpp::R_X86_64_DTPMOD64); + } + else if (optimized_type != tls::TLSOPT_TO_LE) + unsupported_reloc_local(object, r_type); + break; + case elfcpp::R_X86_64_GOTPC32_TLSDESC: case elfcpp::R_X86_64_TLSDESC_CALL: // FIXME: If not relaxing to LE, we need to generate - // DTPMOD64 and DTPOFF64 relocs. + // a GOT entry with a R_x86_64_TLSDESC reloc. if (optimized_type != tls::TLSOPT_TO_LE) unsupported_reloc_local(object, r_type); break; case elfcpp::R_X86_64_TLSLD: // Local-dynamic + if (optimized_type == tls::TLSOPT_NONE) + { + // Create a GOT entry for the module index. + Output_data_got<64, false>* got + = target->got_section(symtab, layout); + unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info()); + got->add_local_tls_with_rela(object, r_sym, + lsym.get_st_shndx(), false, + target->rela_dyn_section(layout), + elfcpp::R_X86_64_DTPMOD64); + } + else if (optimized_type != tls::TLSOPT_TO_LE) + unsupported_reloc_local(object, r_type); + break; + case elfcpp::R_X86_64_DTPOFF32: case elfcpp::R_X86_64_DTPOFF64: - // FIXME: If not relaxing to LE, we need to generate a - // DTPMOD64 reloc. - if (optimized_type != tls::TLSOPT_TO_LE) - unsupported_reloc_local(object, r_type); break; case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec - // FIXME: If not relaxing to LE, we need to generate a - // TPOFF64 reloc. - if (optimized_type != tls::TLSOPT_TO_LE) + if (optimized_type == tls::TLSOPT_NONE) + { + // Create a GOT entry for the tp-relative offset. + Output_data_got<64, false>* got + = target->got_section(symtab, layout); + unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info()); + got->add_local_with_rela(object, r_sym, + target->rela_dyn_section(layout), + elfcpp::R_X86_64_TPOFF64); + } + else if (optimized_type != tls::TLSOPT_TO_LE) unsupported_reloc_local(object, r_type); break; case elfcpp::R_X86_64_TPOFF32: // Local-exec - // FIXME: If generating a shared object, we need to copy - // this relocation into the object. - gold_assert(!output_is_shared); + if (output_is_shared) + unsupported_reloc_local(object, r_type); break; default: @@ -968,8 +1012,8 @@ Target_x86_64::Scan::global(const General_options& options, { if (target->may_need_copy_reloc(gsym)) { - target->copy_reloc(&options, symtab, layout, object, data_shndx, - output_section, gsym, reloc); + target->copy_reloc(&options, symtab, layout, object, + data_shndx, output_section, gsym, reloc); } else if (r_type == elfcpp::R_X86_64_64 && gsym->can_use_relative_reloc(false)) @@ -1004,8 +1048,8 @@ Target_x86_64::Scan::global(const General_options& options, { if (target->may_need_copy_reloc(gsym)) { - target->copy_reloc(&options, symtab, layout, object, data_shndx, - output_section, gsym, reloc); + target->copy_reloc(&options, symtab, layout, object, + data_shndx, output_section, gsym, reloc); } else { @@ -1026,18 +1070,19 @@ Target_x86_64::Scan::global(const General_options& options, { // The symbol requires a GOT entry. Output_data_got<64, false>* got = target->got_section(symtab, layout); - if (got->add_global(gsym)) - { + if (gsym->final_value_is_known()) + got->add_global(gsym); + else + { // If this symbol is not fully resolved, we need to add a // dynamic relocation for it. - if (!gsym->final_value_is_known()) + Reloc_section* rela_dyn = target->rela_dyn_section(layout); + if (gsym->is_from_dynobj() || gsym->is_preemptible()) + got->add_global_with_rela(gsym, rela_dyn, + elfcpp::R_X86_64_GLOB_DAT); + else { - Reloc_section* rela_dyn = target->rela_dyn_section(layout); - if (gsym->is_from_dynobj() - || gsym->is_preemptible()) - rela_dyn->add_global(gsym, elfcpp::R_X86_64_GLOB_DAT, got, - gsym->got_offset(), 0); - else + if (got->add_global(gsym)) { rela_dyn->add_local(object, 0, elfcpp::R_X86_64_RELATIVE, got, gsym->got_offset(), 0); @@ -1110,6 +1155,30 @@ Target_x86_64::Scan::global(const General_options& options, switch (r_type) { case elfcpp::R_X86_64_TLSGD: // General-dynamic + if (optimized_type == tls::TLSOPT_NONE) + { + // Create a pair of GOT entries for the module index and + // dtv-relative offset. + Output_data_got<64, false>* got + = target->got_section(symtab, layout); + got->add_global_tls_with_rela(gsym, + target->rela_dyn_section(layout), + elfcpp::R_X86_64_DTPMOD64, + elfcpp::R_X86_64_DTPOFF64); + } + else if (optimized_type == tls::TLSOPT_TO_IE) + { + // Create a GOT entry for the tp-relative offset. + Output_data_got<64, false>* got + = target->got_section(symtab, layout); + got->add_global_with_rela(gsym, + target->rela_dyn_section(layout), + elfcpp::R_X86_64_TPOFF64); + } + else if (optimized_type != tls::TLSOPT_TO_LE) + unsupported_reloc_global(object, r_type, gsym); + break; + case elfcpp::R_X86_64_GOTPC32_TLSDESC: case elfcpp::R_X86_64_TLSDESC_CALL: // FIXME: If not relaxing to LE, we need to generate @@ -1119,25 +1188,40 @@ Target_x86_64::Scan::global(const General_options& options, break; case elfcpp::R_X86_64_TLSLD: // Local-dynamic + if (optimized_type == tls::TLSOPT_NONE) + { + // Create a GOT entry for the module index. + Output_data_got<64, false>* got + = target->got_section(symtab, layout); + got->add_global_tls_with_rela(gsym, + target->rela_dyn_section(layout), + elfcpp::R_X86_64_DTPMOD64); + } + else if (optimized_type != tls::TLSOPT_TO_LE) + unsupported_reloc_global(object, r_type, gsym); + break; + case elfcpp::R_X86_64_DTPOFF32: case elfcpp::R_X86_64_DTPOFF64: - // FIXME: If not relaxing to LE, we need to generate a - // DTPMOD64 reloc. - if (optimized_type != tls::TLSOPT_TO_LE) - unsupported_reloc_global(object, r_type, gsym); break; case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec - // FIXME: If not relaxing to LE, we need to generate a - // TPOFF64 reloc. - if (optimized_type != tls::TLSOPT_TO_LE) + if (optimized_type == tls::TLSOPT_NONE) + { + // Create a GOT entry for the tp-relative offset. + Output_data_got<64, false>* got + = target->got_section(symtab, layout); + got->add_global_with_rela(gsym, + target->rela_dyn_section(layout), + elfcpp::R_X86_64_TPOFF64); + } + else if (optimized_type != tls::TLSOPT_TO_LE) unsupported_reloc_global(object, r_type, gsym); break; case elfcpp::R_X86_64_TPOFF32: // Local-exec - // FIXME: If generating a shared object, we need to copy - // this relocation into the object. - gold_assert(is_final); + if (parameters->output_is_shared()) + unsupported_reloc_local(object, r_type); break; default: @@ -1312,6 +1396,7 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo, else { unsigned int r_sym = elfcpp::elf_r_sym<64>(rela.get_r_info()); + gold_assert(object->local_has_got_offset(r_sym)); got_offset = object->local_got_offset(r_sym) - target->got_size(); } have_got_offset = true; @@ -1477,8 +1562,8 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo, case elfcpp::R_X86_64_DTPOFF64: case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec case elfcpp::R_X86_64_TPOFF32: // Local-exec - this->relocate_tls(relinfo, relnum, rela, r_type, gsym, psymval, view, - address, view_size); + this->relocate_tls(relinfo, target, relnum, rela, r_type, gsym, psymval, + view, address, view_size); break; case elfcpp::R_X86_64_SIZE32: @@ -1497,6 +1582,7 @@ Target_x86_64::Relocate::relocate(const Relocate_info<64, false>* relinfo, inline void Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo, + Target_x86_64* target, size_t relnum, const elfcpp::Rela<64, false>& rela, unsigned int r_type, @@ -1507,12 +1593,8 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo, off_t view_size) { Output_segment* tls_segment = relinfo->layout->tls_segment(); - if (tls_segment == NULL) - { - gold_error_at_location(relinfo, relnum, rela.get_r_offset(), - _("TLS reloc but no TLS segment")); - return; - } + + const Sized_relobj<64, false>* object = relinfo->object; elfcpp::Elf_types<64>::Elf_Addr value = psymval->value(relinfo->object, 0); @@ -1528,11 +1610,42 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo, case elfcpp::R_X86_64_TLSDESC_CALL: if (optimized_type == tls::TLSOPT_TO_LE) { + gold_assert(tls_segment != NULL); this->tls_gd_to_le(relinfo, relnum, tls_segment, rela, r_type, value, view, view_size); break; } + else + { + unsigned int got_offset; + if (gsym != NULL) + { + gold_assert(gsym->has_tls_got_offset(true)); + got_offset = gsym->tls_got_offset(true) - target->got_size(); + } + else + { + unsigned int r_sym = elfcpp::elf_r_sym<64>(rela.get_r_info()); + gold_assert(object->local_has_tls_got_offset(r_sym, true)); + got_offset = (object->local_tls_got_offset(r_sym, true) + - target->got_size()); + } + if (optimized_type == tls::TLSOPT_TO_IE) + { + gold_assert(tls_segment != NULL); + this->tls_gd_to_ie(relinfo, relnum, tls_segment, rela, r_type, + got_offset, view, view_size); + break; + } + else if (optimized_type == tls::TLSOPT_NONE) + { + // Relocate the field with the offset of the pair of GOT + // entries. + Relocate_functions<64, false>::rel64(view, got_offset); + break; + } + } gold_error_at_location(relinfo, relnum, rela.get_r_offset(), _("unsupported reloc %u"), r_type); break; @@ -1540,15 +1653,37 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo, case elfcpp::R_X86_64_TLSLD: // Local-dynamic if (optimized_type == tls::TLSOPT_TO_LE) { + gold_assert(tls_segment != NULL); this->tls_ld_to_le(relinfo, relnum, tls_segment, rela, r_type, value, view, view_size); break; } + else if (optimized_type == tls::TLSOPT_NONE) + { + // Relocate the field with the offset of the GOT entry for + // the module index. + unsigned int got_offset; + if (gsym != NULL) + { + gold_assert(gsym->has_tls_got_offset(false)); + got_offset = gsym->tls_got_offset(false) - target->got_size(); + } + else + { + unsigned int r_sym = elfcpp::elf_r_sym<64>(rela.get_r_info()); + gold_assert(object->local_has_tls_got_offset(r_sym, false)); + got_offset = (object->local_tls_got_offset(r_sym, false) + - target->got_size()); + } + Relocate_functions<64, false>::rel64(view, got_offset); + break; + } gold_error_at_location(relinfo, relnum, rela.get_r_offset(), _("unsupported reloc %u"), r_type); break; case elfcpp::R_X86_64_DTPOFF32: + gold_assert(tls_segment != NULL); if (optimized_type == tls::TLSOPT_TO_LE) value = value - (tls_segment->vaddr() + tls_segment->memsz()); else @@ -1557,6 +1692,7 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo, break; case elfcpp::R_X86_64_DTPOFF64: + gold_assert(tls_segment != NULL); if (optimized_type == tls::TLSOPT_TO_LE) value = value - (tls_segment->vaddr() + tls_segment->memsz()); else @@ -1567,11 +1703,32 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo, case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec if (optimized_type == tls::TLSOPT_TO_LE) { + gold_assert(tls_segment != NULL); Target_x86_64::Relocate::tls_ie_to_le(relinfo, relnum, tls_segment, rela, r_type, value, view, view_size); break; } + else if (optimized_type == tls::TLSOPT_NONE) + { + // Relocate the field with the offset of the GOT entry for + // the tp-relative offset of the symbol. + unsigned int got_offset; + if (gsym != NULL) + { + gold_assert(gsym->has_got_offset()); + got_offset = gsym->got_offset() - target->got_size(); + } + else + { + unsigned int r_sym = elfcpp::elf_r_sym<64>(rela.get_r_info()); + gold_assert(object->local_has_got_offset(r_sym)); + got_offset = (object->local_got_offset(r_sym) + - target->got_size()); + } + Relocate_functions<64, false>::rel64(view, got_offset); + break; + } gold_error_at_location(relinfo, relnum, rela.get_r_offset(), _("unsupported reloc type %u"), r_type); @@ -1584,6 +1741,41 @@ Target_x86_64::Relocate::relocate_tls(const Relocate_info<64, false>* relinfo, } } +// Do a relocation in which we convert a TLS General-Dynamic to an +// Initial-Exec. + +inline void +Target_x86_64::Relocate::tls_gd_to_ie(const Relocate_info<64, false>* relinfo, + size_t relnum, + Output_segment* tls_segment, + const elfcpp::Rela<64, false>& rela, + unsigned int, + elfcpp::Elf_types<64>::Elf_Addr value, + unsigned char* view, + off_t view_size) +{ + // .byte 0x66; leaq foo@tlsgd(%rip),%rdi; + // .word 0x6666; rex64; call __tls_get_addr + // ==> movq %fs:0,%rax; addq x@gottpoff(%rip),%rax + + tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -4); + tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 12); + + tls::check_tls(relinfo, relnum, rela.get_r_offset(), + (memcmp(view - 4, "\x66\x48\x8d\x3d", 4) == 0)); + tls::check_tls(relinfo, relnum, rela.get_r_offset(), + (memcmp(view + 4, "\x66\x66\x48\xe8", 4) == 0)); + + memcpy(view - 4, "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0\0", 16); + + value = value - (tls_segment->vaddr() + tls_segment->memsz()); + Relocate_functions<64, false>::rela32(view + 8, value, 0); + + // The next reloc should be a PLT32 reloc against __tls_get_addr. + // We can skip it. + this->skip_call_tls_get_addr_ = true; +} + // Do a relocation in which we convert a TLS General-Dynamic to a // Local-Exec. -- 2.7.4