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

@ -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())
{

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

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

@ -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<elfcpp::SHT_REL, dynamic, size, big_endian>::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)
{

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

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

@ -188,6 +188,27 @@ Sized_symbol<size>::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())
{

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

@ -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<int size, bool big_endian, typename Target_type, int sh_type,
typename Scan>
@ -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())