From 436ca963fd42564971f2906e4ba7263d513e483c Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 16 Oct 2007 23:23:08 +0000 Subject: [PATCH] From Cary Coutant: preliminary shared library support. --- gold/gold.cc | 3 ++- gold/i386.cc | 59 +++++++++++++++++++++++++++++++++------------ gold/layout.cc | 4 +-- gold/output.cc | 8 +++++- gold/parameters.cc | 3 ++- gold/parameters.h | 15 ++++++++++++ gold/symtab.cc | 26 +++++++++++++++++--- gold/symtab.h | 15 ++++++++++++ gold/target-reloc.h | 11 +++++---- 9 files changed, 114 insertions(+), 30 deletions(-) diff --git a/gold/gold.cc b/gold/gold.cc index 139652430b0..8c86b9ed72e 100644 --- a/gold/gold.cc +++ b/gold/gold.cc @@ -153,7 +153,8 @@ queue_middle_tasks(const General_options& options, Workqueue* workqueue) { // Now we have seen all the input files. - const bool doing_static_link = !input_objects->any_dynamic(); + const bool doing_static_link = (!input_objects->any_dynamic() + && !parameters->output_is_shared()); set_parameters_doing_static_link(doing_static_link); if (!doing_static_link && options.is_static()) { diff --git a/gold/i386.cc b/gold/i386.cc index 3dda0c2e30e..e091f1889b1 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -752,9 +752,18 @@ Target_i386::Scan::local(const General_options&, case elfcpp::R_386_32: case elfcpp::R_386_16: case elfcpp::R_386_8: - // FIXME: If we are generating a shared object we need to copy - // this relocation into the object. - gold_assert(!parameters->output_is_shared()); + // If building a shared library (or a position-independent + // executable), we need to create a dynamic relocation for + // this location. The relocation applied at link time will + // apply the link-time value, so we flag the location with + // an R_386_RELATIVE relocation so the dynamic loader can + // relocate it easily. + 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, data_shndx, + reloc.get_r_offset()); + } break; case elfcpp::R_386_PC32: @@ -777,7 +786,7 @@ Target_i386::Scan::local(const General_options&, { // If we are generating a shared object, we need to add a // dynamic RELATIVE relocation for this symbol. - if (parameters->output_is_shared()) + 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, @@ -915,17 +924,17 @@ Target_i386::Scan::global(const General_options& options, case elfcpp::R_386_PC16: case elfcpp::R_386_8: case elfcpp::R_386_PC8: - // FIXME: If we are generating a shared object we may need to - // copy this relocation into the object. If this symbol is - // defined in a shared object, we may need to copy this - // relocation in order to avoid a COPY relocation. - gold_assert(!parameters->output_is_shared()); - - if (gsym->is_from_dynobj()) + if (gsym->is_from_dynobj() + || (parameters->output_is_shared() + && gsym->is_preemptible())) { - // This symbol is defined in a dynamic object. If it is a + // (a) This symbol is defined in a dynamic object. If it is a // function, we make a PLT entry. Otherwise we need to // either generate a COPY reloc or copy this reloc. + // (b) We are building a shared object and this symbol is + // preemptible. If it is a function, we make a PLT entry. + // Otherwise, we copy the reloc. We do not make COPY relocs + // in shared objects. if (gsym->type() == elfcpp::STT_FUNC) { target->make_plt_entry(symtab, layout, gsym); @@ -936,9 +945,16 @@ Target_i386::Scan::global(const General_options& options, // to the address of the PLT entry. if (r_type != elfcpp::R_386_PC32 && r_type != elfcpp::R_386_PC16 - && r_type != elfcpp::R_386_PC8) + && r_type != elfcpp::R_386_PC8 + && gsym->is_from_dynobj()) gsym->set_needs_dynsym_value(); } + else if (parameters->output_is_shared()) + { + Reloc_section* rel_dyn = target->rel_dyn_section(layout); + rel_dyn->add_global(gsym, r_type, object, data_shndx, + reloc.get_r_offset()); + } else target->copy_reloc(&options, symtab, layout, object, data_shndx, gsym, reloc); @@ -969,6 +985,13 @@ Target_i386::Scan::global(const General_options& options, // Otherwise we need a PLT entry. if (gsym->final_value_is_known()) break; + // If building a shared library, we can also skip the PLT entry + // if the symbol is defined in the output file and is protected + // or hidden. + if (gsym->is_defined() + && !gsym->is_from_dynobj() + && !gsym->is_preemptible()) + break; target->make_plt_entry(symtab, layout, gsym); break; @@ -1185,7 +1208,11 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, // Pick the value to use for symbols defined in shared objects. Symbol_value<32> symval; - if (gsym != NULL && gsym->is_from_dynobj() && gsym->has_plt_offset()) + if (gsym != NULL + && (gsym->is_from_dynobj() + || (parameters->output_is_shared() + && gsym->is_preemptible())) + && gsym->has_plt_offset()) { symval.set_output_value(target->plt_section()->address() + gsym->plt_offset()); @@ -1250,7 +1277,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, case elfcpp::R_386_PLT32: gold_assert(gsym->has_plt_offset() - || gsym->final_value_is_known()); + || gsym->final_value_is_known()); Relocate_functions<32, false>::pcrel32(view, object, psymval, address); break; @@ -1352,7 +1379,7 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, elfcpp::Elf_types<32>::Elf_Addr value = psymval->value(relinfo->object, 0); const bool is_final = (gsym == NULL - ? !parameters->output_is_shared() + ? !parameters->output_is_position_independent() : gsym->final_value_is_known()); const tls::Tls_optimization optimized_type = Target_i386::optimize_tls_reloc(is_final, r_type); diff --git a/gold/layout.cc b/gold/layout.cc index 4f5abac98f2..8fafdcbaabf 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -411,7 +411,7 @@ void Layout::create_initial_dynamic_sections(const Input_objects* input_objects, Symbol_table* symtab) { - if (!input_objects->any_dynamic()) + if (parameters->doing_static_link()) return; const char* dynamic_name = this->namepool_.add(".dynamic", false, NULL); @@ -545,7 +545,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab) this->create_note_section(); Output_segment* phdr_seg = NULL; - if (input_objects->any_dynamic()) + if (!parameters->doing_static_link()) { // There was a dynamic object in the link. We need to create // some information for the dynamic linker. diff --git a/gold/output.cc b/gold/output.cc index 6406c780e0a..9aaa7e97410 100644 --- a/gold/output.cc +++ b/gold/output.cc @@ -401,9 +401,10 @@ Output_file_header::do_sized_write(Output_file* of) oehdr.put_e_ident(e_ident); elfcpp::ET e_type; - // FIXME: ET_DYN. if (parameters->output_is_object()) e_type = elfcpp::ET_REL; + else if (parameters->output_is_shared()) + e_type = elfcpp::ET_DYN; else e_type = elfcpp::ET_EXEC; oehdr.put_e_type(e_type); @@ -531,6 +532,11 @@ Output_reloc::get_symbol_index() index = this->u1_.os->symtab_index(); break; + case 0: + // Relocations without symbols use a symbol index of 0. + index = 0; + break; + default: if (dynamic) { diff --git a/gold/parameters.cc b/gold/parameters.cc index 817268b1624..7fe9ceb1c76 100644 --- a/gold/parameters.cc +++ b/gold/parameters.cc @@ -35,7 +35,8 @@ Parameters::Parameters(const General_options* options, Errors* errors) sysroot_(options->sysroot()), is_doing_static_link_valid_(false), doing_static_link_(false), is_size_and_endian_valid_(false), size_(0), is_big_endian_(false), - optimization_level_(options->optimization_level()) + optimization_level_(options->optimization_level()), + export_dynamic_(options->export_dynamic()) { if (options->is_shared()) this->output_file_type_ = OUTPUT_SHARED; diff --git a/gold/parameters.h b/gold/parameters.h index c4e3fe311e9..4a19cb67217 100644 --- a/gold/parameters.h +++ b/gold/parameters.h @@ -67,6 +67,14 @@ class Parameters output_is_object() const { return this->output_file_type_ == OUTPUT_OBJECT; } + // Whether we are generating position-independent output. + // This is the case when generating either a shared library + // or a regular executable with the --pic-executable option. + // FIXME: support --pic-executable + bool + output_is_position_independent() const + { return output_is_shared(); } + // The target system root directory. This is NULL if there isn't // one. const std::string& @@ -115,6 +123,11 @@ class Parameters optimization_level() const { return this->optimization_level_; } + // Whether the -E/--export-dynamic flag is set. + bool + export_dynamic() const + { return this->export_dynamic_; } + // Set whether we are doing a static link. void set_doing_static_link(bool doing_static_link); @@ -170,6 +183,8 @@ class Parameters bool is_big_endian_; // The optimization level. int optimization_level_; + // Whether the -E/--export-dynamic flag is set. + bool export_dynamic_; }; // This is a global variable. diff --git a/gold/symtab.cc b/gold/symtab.cc index 7e0af342a88..3eee9be8545 100644 --- a/gold/symtab.cc +++ b/gold/symtab.cc @@ -188,6 +188,27 @@ Sized_symbol::init(const char* name, Value_type value, Size_type symsize, this->symsize_ = symsize; } +// Return true if this symbol should be added to the dynamic symbol +// table. + +inline bool +Symbol::should_add_dynsym_entry() const +{ + // If the symbol is used by a dynamic relocation, we need to add it. + if (this->needs_dynsym_entry()) + return true; + + // If exporting all symbols or building a shared library, + // and the symbol is defined in a regular object and is + // externally visible, we need to add it. + if ((parameters->export_dynamic() || parameters->output_is_shared()) + && !this->is_from_dynobj() + && this->is_externally_visible()) + return true; + + return false; +} + // Return true if the final value of this symbol is known at link // time. @@ -1225,10 +1246,7 @@ Symbol_table::set_dynsym_indexes(const General_options* options, // some symbols appear more than once in the symbol table, with // and without a version. - if (!sym->needs_dynsym_entry() - && (!options->export_dynamic() - || !sym->in_reg() - || !sym->is_externally_visible())) + if (!sym->should_add_dynsym_entry()) sym->set_dynsym_index(-1U); else if (!sym->has_dynsym_index()) { diff --git a/gold/symtab.h b/gold/symtab.h index b46510d4c9d..d8e68a02769 100644 --- a/gold/symtab.h +++ b/gold/symtab.h @@ -220,6 +220,11 @@ class Symbol set_needs_dynsym_entry() { this->needs_dynsym_entry_ = true; } + // Return whether this symbol should be added to the dynamic symbol + // table. + bool + should_add_dynsym_entry() const; + // Return whether this symbol has been seen in a regular object. bool in_reg() const @@ -395,6 +400,16 @@ class Symbol || this->visibility_ == elfcpp::STV_PROTECTED); } + // Return true if this symbol can be preempted by a definition in + // another link unit. + bool + is_preemptible() const + { + return (this->visibility_ != elfcpp::STV_INTERNAL + && this->visibility_ != elfcpp::STV_HIDDEN + && this->visibility_ != elfcpp::STV_PROTECTED); + } + // Return whether there should be a warning for references to this // symbol. bool diff --git a/gold/target-reloc.h b/gold/target-reloc.h index 8b87963f57b..c38d5f6a74b 100644 --- a/gold/target-reloc.h +++ b/gold/target-reloc.h @@ -32,10 +32,10 @@ namespace gold { // This function implements the generic part of reloc scanning. This -// is an inline function which takes a class whose operator() -// implements the machine specific part of scanning. We do it this -// way to avoidmaking a function call for each relocation, and to -// avoid repeating the generic code for each target. +// is an inline function which takes a class whose member functions +// local() and global() implement the machine specific part of scanning. +// We do it this way to avoidmaking a function call for each relocation, +// and to avoid repeating the generic code for each target. template @@ -195,7 +195,8 @@ relocate_section( if (sym != NULL && sym->is_undefined() - && sym->binding() != elfcpp::STB_WEAK) + && sym->binding() != elfcpp::STB_WEAK + && !parameters->output_is_shared()) gold_undefined_symbol(sym, relinfo, i, offset); if (sym != NULL && sym->has_warning()) -- 2.30.2