From Cary Coutant: preliminary shared library support.

This commit is contained in:
Ian Lance Taylor 2007-10-16 23:23:08 +00:00
parent a360aedd0f
commit 436ca963fd
9 changed files with 114 additions and 30 deletions

View file

@ -153,7 +153,8 @@ queue_middle_tasks(const General_options& options,
Workqueue* workqueue) Workqueue* workqueue)
{ {
// Now we have seen all the input files. // 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); set_parameters_doing_static_link(doing_static_link);
if (!doing_static_link && options.is_static()) if (!doing_static_link && options.is_static())
{ {

View file

@ -752,9 +752,18 @@ Target_i386::Scan::local(const General_options&,
case elfcpp::R_386_32: case elfcpp::R_386_32:
case elfcpp::R_386_16: case elfcpp::R_386_16:
case elfcpp::R_386_8: case elfcpp::R_386_8:
// FIXME: If we are generating a shared object we need to copy // If building a shared library (or a position-independent
// this relocation into the object. // executable), we need to create a dynamic relocation for
gold_assert(!parameters->output_is_shared()); // 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; break;
case elfcpp::R_386_PC32: 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 // If we are generating a shared object, we need to add a
// dynamic RELATIVE relocation for this symbol. // 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); Reloc_section* rel_dyn = target->rel_dyn_section(layout);
rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, 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_PC16:
case elfcpp::R_386_8: case elfcpp::R_386_8:
case elfcpp::R_386_PC8: case elfcpp::R_386_PC8:
// FIXME: If we are generating a shared object we may need to if (gsym->is_from_dynobj()
// copy this relocation into the object. If this symbol is || (parameters->output_is_shared()
// defined in a shared object, we may need to copy this && gsym->is_preemptible()))
// relocation in order to avoid a COPY relocation.
gold_assert(!parameters->output_is_shared());
if (gsym->is_from_dynobj())
{ {
// 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 // function, we make a PLT entry. Otherwise we need to
// either generate a COPY reloc or copy this reloc. // 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) if (gsym->type() == elfcpp::STT_FUNC)
{ {
target->make_plt_entry(symtab, layout, gsym); 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. // to the address of the PLT entry.
if (r_type != elfcpp::R_386_PC32 if (r_type != elfcpp::R_386_PC32
&& r_type != elfcpp::R_386_PC16 && 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(); 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 else
target->copy_reloc(&options, symtab, layout, object, data_shndx, target->copy_reloc(&options, symtab, layout, object, data_shndx,
gsym, reloc); gsym, reloc);
@ -969,6 +985,13 @@ Target_i386::Scan::global(const General_options& options,
// Otherwise we need a PLT entry. // Otherwise we need a PLT entry.
if (gsym->final_value_is_known()) if (gsym->final_value_is_known())
break; 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); target->make_plt_entry(symtab, layout, gsym);
break; 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. // Pick the value to use for symbols defined in shared objects.
Symbol_value<32> symval; 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() symval.set_output_value(target->plt_section()->address()
+ gsym->plt_offset()); + gsym->plt_offset());
@ -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); elfcpp::Elf_types<32>::Elf_Addr value = psymval->value(relinfo->object, 0);
const bool is_final = (gsym == NULL const bool is_final = (gsym == NULL
? !parameters->output_is_shared() ? !parameters->output_is_position_independent()
: gsym->final_value_is_known()); : gsym->final_value_is_known());
const tls::Tls_optimization optimized_type const tls::Tls_optimization optimized_type
= Target_i386::optimize_tls_reloc(is_final, r_type); = Target_i386::optimize_tls_reloc(is_final, r_type);

View file

@ -411,7 +411,7 @@ void
Layout::create_initial_dynamic_sections(const Input_objects* input_objects, Layout::create_initial_dynamic_sections(const Input_objects* input_objects,
Symbol_table* symtab) Symbol_table* symtab)
{ {
if (!input_objects->any_dynamic()) if (parameters->doing_static_link())
return; return;
const char* dynamic_name = this->namepool_.add(".dynamic", false, NULL); 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(); this->create_note_section();
Output_segment* phdr_seg = NULL; 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 // There was a dynamic object in the link. We need to create
// some information for the dynamic linker. // some information for the dynamic linker.

View file

@ -401,9 +401,10 @@ Output_file_header::do_sized_write(Output_file* of)
oehdr.put_e_ident(e_ident); oehdr.put_e_ident(e_ident);
elfcpp::ET e_type; elfcpp::ET e_type;
// FIXME: ET_DYN.
if (parameters->output_is_object()) if (parameters->output_is_object())
e_type = elfcpp::ET_REL; e_type = elfcpp::ET_REL;
else if (parameters->output_is_shared())
e_type = elfcpp::ET_DYN;
else else
e_type = elfcpp::ET_EXEC; e_type = elfcpp::ET_EXEC;
oehdr.put_e_type(e_type); oehdr.put_e_type(e_type);
@ -531,6 +532,11 @@ Output_reloc<elfcpp::SHT_REL, dynamic, size, big_endian>::get_symbol_index()
index = this->u1_.os->symtab_index(); index = this->u1_.os->symtab_index();
break; break;
case 0:
// Relocations without symbols use a symbol index of 0.
index = 0;
break;
default: default:
if (dynamic) if (dynamic)
{ {

View file

@ -35,7 +35,8 @@ Parameters::Parameters(const General_options* options, Errors* errors)
sysroot_(options->sysroot()), sysroot_(options->sysroot()),
is_doing_static_link_valid_(false), doing_static_link_(false), is_doing_static_link_valid_(false), doing_static_link_(false),
is_size_and_endian_valid_(false), size_(0), is_big_endian_(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()) if (options->is_shared())
this->output_file_type_ = OUTPUT_SHARED; this->output_file_type_ = OUTPUT_SHARED;

View file

@ -67,6 +67,14 @@ class Parameters
output_is_object() const output_is_object() const
{ return this->output_file_type_ == OUTPUT_OBJECT; } { 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 // The target system root directory. This is NULL if there isn't
// one. // one.
const std::string& const std::string&
@ -115,6 +123,11 @@ class Parameters
optimization_level() const optimization_level() const
{ return this->optimization_level_; } { 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. // Set whether we are doing a static link.
void void
set_doing_static_link(bool doing_static_link); set_doing_static_link(bool doing_static_link);
@ -170,6 +183,8 @@ class Parameters
bool is_big_endian_; bool is_big_endian_;
// The optimization level. // The optimization level.
int optimization_level_; int optimization_level_;
// Whether the -E/--export-dynamic flag is set.
bool export_dynamic_;
}; };
// This is a global variable. // This is a global variable.

View file

@ -188,6 +188,27 @@ Sized_symbol<size>::init(const char* name, Value_type value, Size_type symsize,
this->symsize_ = 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 // Return true if the final value of this symbol is known at link
// time. // 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 // some symbols appear more than once in the symbol table, with
// and without a version. // and without a version.
if (!sym->needs_dynsym_entry() if (!sym->should_add_dynsym_entry())
&& (!options->export_dynamic()
|| !sym->in_reg()
|| !sym->is_externally_visible()))
sym->set_dynsym_index(-1U); sym->set_dynsym_index(-1U);
else if (!sym->has_dynsym_index()) else if (!sym->has_dynsym_index())
{ {

View file

@ -220,6 +220,11 @@ class Symbol
set_needs_dynsym_entry() set_needs_dynsym_entry()
{ this->needs_dynsym_entry_ = true; } { 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. // Return whether this symbol has been seen in a regular object.
bool bool
in_reg() const in_reg() const
@ -395,6 +400,16 @@ class Symbol
|| this->visibility_ == elfcpp::STV_PROTECTED); || 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 // Return whether there should be a warning for references to this
// symbol. // symbol.
bool bool

View file

@ -32,10 +32,10 @@ namespace gold
{ {
// This function implements the generic part of reloc scanning. This // This function implements the generic part of reloc scanning. This
// is an inline function which takes a class whose operator() // is an inline function which takes a class whose member functions
// implements the machine specific part of scanning. We do it this // local() and global() implement the machine specific part of scanning.
// way to avoidmaking a function call for each relocation, and to // We do it this way to avoidmaking a function call for each relocation,
// avoid repeating the generic code for each target. // and to avoid repeating the generic code for each target.
template<int size, bool big_endian, typename Target_type, int sh_type, template<int size, bool big_endian, typename Target_type, int sh_type,
typename Scan> typename Scan>
@ -195,7 +195,8 @@ relocate_section(
if (sym != NULL if (sym != NULL
&& sym->is_undefined() && sym->is_undefined()
&& sym->binding() != elfcpp::STB_WEAK) && sym->binding() != elfcpp::STB_WEAK
&& !parameters->output_is_shared())
gold_undefined_symbol(sym, relinfo, i, offset); gold_undefined_symbol(sym, relinfo, i, offset);
if (sym != NULL && sym->has_warning()) if (sym != NULL && sym->has_warning())