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())
{
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:
{
// 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,
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);
// 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);
// 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;
// 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());
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;
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);
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);
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.
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);
index = this->u1_.os->symtab_index();
break;
+ case 0:
+ // Relocations without symbols use a symbol index of 0.
+ index = 0;
+ break;
+
default:
if (dynamic)
{
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;
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&
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);
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.
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.
// 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())
{
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
|| 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
{
// 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>
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())