From Cary Coutant: preliminary shared library support.
This commit is contained in:
parent
a360aedd0f
commit
436ca963fd
9 changed files with 114 additions and 30 deletions
|
@ -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())
|
||||||
{
|
{
|
||||||
|
|
57
gold/i386.cc
57
gold/i386.cc
|
@ -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);
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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())
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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())
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue