aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gold/gold.cc3
-rw-r--r--gold/i386.cc59
-rw-r--r--gold/layout.cc4
-rw-r--r--gold/output.cc8
-rw-r--r--gold/parameters.cc3
-rw-r--r--gold/parameters.h15
-rw-r--r--gold/symtab.cc26
-rw-r--r--gold/symtab.h15
-rw-r--r--gold/target-reloc.h11
9 files changed, 114 insertions, 30 deletions
diff --git a/gold/gold.cc b/gold/gold.cc
index 1396524..8c86b9e 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 3dda0c2..e091f18 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 4f5abac..8fafdcb 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 6406c78..9aaa7e9 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<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)
{
diff --git a/gold/parameters.cc b/gold/parameters.cc
index 817268b..7fe9ceb 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 c4e3fe3..4a19cb6 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 7e0af34..3eee9be 100644
--- a/gold/symtab.cc
+++ b/gold/symtab.cc
@@ -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())
{
diff --git a/gold/symtab.h b/gold/symtab.h
index b46510d..d8e68a0 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 8b87963..c38d5f6 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<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())