mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-20 01:50:24 +08:00
From Cary Coutant: More shared library support, some refactorization.
This commit is contained in:
233
gold/i386.cc
233
gold/i386.cc
@ -157,7 +157,8 @@ class Target_i386 : public Sized_target<32, false>
|
||||
// Return whether the static relocation needs to be applied.
|
||||
inline bool
|
||||
should_apply_static_reloc(const Sized_symbol<32>* gsym,
|
||||
bool is_pcrel,
|
||||
bool is_absolute_ref,
|
||||
bool is_function_call,
|
||||
bool is_32bit);
|
||||
|
||||
// Do a relocation. Return false if the caller should not issue
|
||||
@ -256,6 +257,17 @@ class Target_i386 : public Sized_target<32, false>
|
||||
Reloc_section*
|
||||
rel_dyn_section(Layout*);
|
||||
|
||||
// Return true if the symbol may need a COPY relocation.
|
||||
// References from an executable object to non-function symbols
|
||||
// defined in a dynamic object may need a COPY relocation.
|
||||
bool
|
||||
may_need_copy_reloc(Symbol* gsym)
|
||||
{
|
||||
return (!parameters->output_is_shared()
|
||||
&& gsym->is_from_dynobj()
|
||||
&& gsym->type() != elfcpp::STT_FUNC);
|
||||
}
|
||||
|
||||
// Copy a relocation against a global symbol.
|
||||
void
|
||||
copy_reloc(const General_options*, Symbol_table*, Layout*,
|
||||
@ -771,8 +783,6 @@ Target_i386::Scan::local(const General_options&,
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_32:
|
||||
case elfcpp::R_386_16:
|
||||
case elfcpp::R_386_8:
|
||||
// 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
|
||||
@ -782,15 +792,24 @@ Target_i386::Scan::local(const General_options&,
|
||||
if (parameters->output_is_position_independent())
|
||||
{
|
||||
Reloc_section* rel_dyn = target->rel_dyn_section(layout);
|
||||
if (r_type == elfcpp::R_386_32)
|
||||
rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, data_shndx,
|
||||
reloc.get_r_offset());
|
||||
else
|
||||
{
|
||||
unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
|
||||
rel_dyn->add_local(object, r_sym, r_type, data_shndx,
|
||||
reloc.get_r_offset());
|
||||
}
|
||||
rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, data_shndx,
|
||||
reloc.get_r_offset());
|
||||
}
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_16:
|
||||
case elfcpp::R_386_8:
|
||||
// If building a shared library (or a position-independent
|
||||
// executable), we need to create a dynamic relocation for
|
||||
// this location. Because the addend needs to remain in the
|
||||
// data section, we need to be careful not to apply this
|
||||
// relocation statically.
|
||||
if (parameters->output_is_position_independent())
|
||||
{
|
||||
Reloc_section* rel_dyn = target->rel_dyn_section(layout);
|
||||
unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
|
||||
rel_dyn->add_local(object, r_sym, r_type, data_shndx,
|
||||
reloc.get_r_offset());
|
||||
}
|
||||
break;
|
||||
|
||||
@ -951,71 +970,67 @@ Target_i386::Scan::global(const General_options& options,
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_32:
|
||||
case elfcpp::R_386_PC32:
|
||||
case elfcpp::R_386_16:
|
||||
case elfcpp::R_386_PC16:
|
||||
case elfcpp::R_386_8:
|
||||
case elfcpp::R_386_PC8:
|
||||
{
|
||||
bool is_pcrel = (r_type == elfcpp::R_386_PC32
|
||||
|| r_type == elfcpp::R_386_PC16
|
||||
|| r_type == elfcpp::R_386_PC8);
|
||||
|
||||
if (gsym->is_from_dynobj()
|
||||
|| (parameters->output_is_shared()
|
||||
&& gsym->is_preemptible()))
|
||||
{
|
||||
// (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.
|
||||
if (gsym->type() == elfcpp::STT_FUNC)
|
||||
{
|
||||
target->make_plt_entry(symtab, layout, gsym);
|
||||
|
||||
// If this is not a PC relative reference, then we may
|
||||
// be taking the address of the function. In that case
|
||||
// we need to set the entry in the dynamic symbol table
|
||||
// to the address of the PLT entry. We will also need to
|
||||
// create a dynamic relocation.
|
||||
if (!is_pcrel)
|
||||
{
|
||||
if (gsym->is_from_dynobj())
|
||||
gsym->set_needs_dynsym_value();
|
||||
if (parameters->output_is_position_independent())
|
||||
{
|
||||
Reloc_section* rel_dyn =
|
||||
target->rel_dyn_section(layout);
|
||||
rel_dyn->add_global(gsym, r_type, object, data_shndx,
|
||||
reloc.get_r_offset());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (parameters->output_is_shared())
|
||||
{
|
||||
// We do not make COPY relocs in shared objects.
|
||||
// Make a PLT entry if necessary.
|
||||
if (gsym->needs_plt_entry())
|
||||
{
|
||||
target->make_plt_entry(symtab, layout, gsym);
|
||||
// Since this is not a PC-relative relocation, we may be
|
||||
// taking the address of a function. In that case we need to
|
||||
// set the entry in the dynamic symbol table to the address of
|
||||
// the PLT entry.
|
||||
if (gsym->is_from_dynobj())
|
||||
gsym->set_needs_dynsym_value();
|
||||
}
|
||||
// Make a dynamic relocation if necessary.
|
||||
if (gsym->needs_dynamic_reloc(true, false))
|
||||
{
|
||||
if (target->may_need_copy_reloc(gsym))
|
||||
{
|
||||
target->copy_reloc(&options, symtab, layout, object, data_shndx,
|
||||
gsym, reloc);
|
||||
}
|
||||
else if (r_type == elfcpp::R_386_32
|
||||
&& gsym->can_use_relative_reloc(false))
|
||||
{
|
||||
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());
|
||||
}
|
||||
else
|
||||
{
|
||||
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);
|
||||
}
|
||||
else if (!is_pcrel && parameters->output_is_position_independent())
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_PC32:
|
||||
case elfcpp::R_386_PC16:
|
||||
case elfcpp::R_386_PC8:
|
||||
{
|
||||
// Make a PLT entry if necessary.
|
||||
if (gsym->needs_plt_entry())
|
||||
target->make_plt_entry(symtab, layout, gsym);
|
||||
// Make a dynamic relocation if necessary.
|
||||
bool is_function_call = (gsym->type() == elfcpp::STT_FUNC);
|
||||
if (gsym->needs_dynamic_reloc(false, is_function_call))
|
||||
{
|
||||
// This is not a PC-relative reference, so we need to generate
|
||||
// a dynamic relocation. At this point, we know the symbol
|
||||
// is not preemptible, so we can use the RELATIVE relocation.
|
||||
Reloc_section* rel_dyn = target->rel_dyn_section(layout);
|
||||
if (r_type == elfcpp::R_386_32)
|
||||
rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, data_shndx,
|
||||
reloc.get_r_offset());
|
||||
if (target->may_need_copy_reloc(gsym))
|
||||
{
|
||||
target->copy_reloc(&options, symtab, layout, object, data_shndx,
|
||||
gsym, reloc);
|
||||
}
|
||||
else
|
||||
rel_dyn->add_global(gsym, r_type, object, data_shndx,
|
||||
reloc.get_r_offset());
|
||||
{
|
||||
Reloc_section* rel_dyn = target->rel_dyn_section(layout);
|
||||
rel_dyn->add_global(gsym, r_type, object, data_shndx,
|
||||
reloc.get_r_offset());
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -1031,8 +1046,16 @@ Target_i386::Scan::global(const General_options& options,
|
||||
if (!gsym->final_value_is_known())
|
||||
{
|
||||
Reloc_section* rel_dyn = target->rel_dyn_section(layout);
|
||||
rel_dyn->add_global(gsym, elfcpp::R_386_GLOB_DAT, got,
|
||||
gsym->got_offset());
|
||||
if (gsym->is_preemptible())
|
||||
rel_dyn->add_global(gsym, elfcpp::R_386_GLOB_DAT, got,
|
||||
gsym->got_offset());
|
||||
else
|
||||
{
|
||||
rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE,
|
||||
got, gsym->got_offset());
|
||||
// Make sure we write the link-time value to the GOT.
|
||||
gsym->set_needs_value_in_got();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1246,36 +1269,22 @@ Target_i386::do_finalize_sections(Layout* layout)
|
||||
|
||||
inline bool
|
||||
Target_i386::Relocate::should_apply_static_reloc(const Sized_symbol<32>* gsym,
|
||||
bool is_pcrel,
|
||||
bool is_absolute_ref,
|
||||
bool is_function_call,
|
||||
bool is_32bit)
|
||||
{
|
||||
// For local symbols, return FALSE if a non-RELATIVE dynamic
|
||||
// relocation was created; return TRUE otherwise.
|
||||
// For local symbols, we will have created a non-RELATIVE dynamic
|
||||
// relocation only if (a) the output is position independent,
|
||||
// (b) the relocation is absolute (not pc- or segment-relative), and
|
||||
// (c) the relocation is not 32 bits wide.
|
||||
if (gsym == NULL)
|
||||
return (!parameters->output_is_position_independent() || is_32bit);
|
||||
return !(parameters->output_is_position_independent()
|
||||
&& is_absolute_ref
|
||||
&& !is_32bit);
|
||||
|
||||
// For global symbols, mimic the logic in Scan::global()
|
||||
// to decide whether a non-RELATIVE dynamic relocation was
|
||||
// created.
|
||||
// FIXME: This is ugly. Try to refactor this logic so it can be
|
||||
// shared by Scan::global() and Relocate::relocate().
|
||||
if (gsym->is_from_dynobj()
|
||||
|| (parameters->output_is_shared()
|
||||
&& gsym->is_preemptible()))
|
||||
{
|
||||
if (gsym->type() == elfcpp::STT_FUNC)
|
||||
{
|
||||
if (!is_pcrel && parameters->output_is_position_independent())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (!is_pcrel && parameters->output_is_position_independent())
|
||||
return is_32bit;
|
||||
|
||||
// For all other cases, return TRUE
|
||||
return true;
|
||||
// For global symbols, we use the same helper routines used in the scan pass.
|
||||
return !(gsym->needs_dynamic_reloc(is_absolute_ref, is_function_call)
|
||||
&& !gsym->can_use_relative_reloc(is_function_call));
|
||||
}
|
||||
|
||||
// Perform a relocation.
|
||||
@ -1355,33 +1364,45 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_32:
|
||||
if (should_apply_static_reloc(gsym, false, true))
|
||||
if (should_apply_static_reloc(gsym, true, false, true))
|
||||
Relocate_functions<32, false>::rel32(view, object, psymval);
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_PC32:
|
||||
if (should_apply_static_reloc(gsym, true, true))
|
||||
Relocate_functions<32, false>::pcrel32(view, object, psymval, address);
|
||||
{
|
||||
bool is_function_call = (gsym != NULL
|
||||
&& gsym->type() == elfcpp::STT_FUNC);
|
||||
if (should_apply_static_reloc(gsym, false, is_function_call, true))
|
||||
Relocate_functions<32, false>::pcrel32(view, object, psymval, address);
|
||||
}
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_16:
|
||||
if (should_apply_static_reloc(gsym, false, false))
|
||||
if (should_apply_static_reloc(gsym, true, false, false))
|
||||
Relocate_functions<32, false>::rel16(view, object, psymval);
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_PC16:
|
||||
if (should_apply_static_reloc(gsym, true, false))
|
||||
Relocate_functions<32, false>::pcrel16(view, object, psymval, address);
|
||||
{
|
||||
bool is_function_call = (gsym != NULL
|
||||
&& gsym->type() == elfcpp::STT_FUNC);
|
||||
if (should_apply_static_reloc(gsym, false, is_function_call, false))
|
||||
Relocate_functions<32, false>::pcrel32(view, object, psymval, address);
|
||||
}
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_8:
|
||||
if (should_apply_static_reloc(gsym, false, false))
|
||||
if (should_apply_static_reloc(gsym, true, false, false))
|
||||
Relocate_functions<32, false>::rel8(view, object, psymval);
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_PC8:
|
||||
if (should_apply_static_reloc(gsym, true, false))
|
||||
Relocate_functions<32, false>::pcrel8(view, object, psymval, address);
|
||||
{
|
||||
bool is_function_call = (gsym != NULL
|
||||
&& gsym->type() == elfcpp::STT_FUNC);
|
||||
if (should_apply_static_reloc(gsym, false, is_function_call, false))
|
||||
Relocate_functions<32, false>::pcrel32(view, object, psymval, address);
|
||||
}
|
||||
break;
|
||||
|
||||
case elfcpp::R_386_PLT32:
|
||||
|
@ -684,8 +684,11 @@ Output_data_got<size, big_endian>::Got_entry::write(unsigned char* pov) const
|
||||
// If the symbol is resolved locally, we need to write out its
|
||||
// value. Otherwise we just write zero. The target code is
|
||||
// responsible for creating a relocation entry to fill in the
|
||||
// value at runtime.
|
||||
if (gsym->final_value_is_known())
|
||||
// value at runtime. For non-preemptible symbols in a shared
|
||||
// library, the target will need to record whether or not the
|
||||
// value should be written (e.g., it may use a RELATIVE
|
||||
// relocation type).
|
||||
if (gsym->final_value_is_known() || gsym->needs_value_in_got())
|
||||
{
|
||||
Sized_symbol<size>* sgsym;
|
||||
// This cast is a bit ugly. We don't want to put a
|
||||
|
@ -67,6 +67,7 @@ Symbol::init_fields(const char* name, const char* version,
|
||||
this->has_plt_offset_ = false;
|
||||
this->has_warning_ = false;
|
||||
this->is_copied_from_dynobj_ = false;
|
||||
this->needs_value_in_got_ = false;
|
||||
}
|
||||
|
||||
// Initialize the fields in the base class Symbol for SYM in OBJECT.
|
||||
|
@ -408,9 +408,75 @@ class Symbol
|
||||
return (this->visibility_ != elfcpp::STV_INTERNAL
|
||||
&& this->visibility_ != elfcpp::STV_HIDDEN
|
||||
&& this->visibility_ != elfcpp::STV_PROTECTED
|
||||
&& parameters->output_is_shared()
|
||||
&& !parameters->symbolic());
|
||||
}
|
||||
|
||||
// Return true if this symbol is a function that needs a PLT entry.
|
||||
// If the symbol is defined in a dynamic object or if it is subject
|
||||
// to pre-emption, we need to make a PLT entry.
|
||||
bool
|
||||
needs_plt_entry() const
|
||||
{
|
||||
return (this->type() == elfcpp::STT_FUNC
|
||||
&& (this->is_from_dynobj() || this->is_preemptible()));
|
||||
}
|
||||
|
||||
// Given a direct absolute or pc-relative static relocation against
|
||||
// the global symbol, this function returns whether a dynamic relocation
|
||||
// is needed.
|
||||
|
||||
bool
|
||||
needs_dynamic_reloc(bool is_absolute_ref, bool is_function_call) const
|
||||
{
|
||||
// An absolute reference within a position-independent output file
|
||||
// will need a dynamic relocaion.
|
||||
if (is_absolute_ref && parameters->output_is_position_independent())
|
||||
return true;
|
||||
|
||||
// A function call that can branch to a local PLT entry does not need
|
||||
// a dynamic relocation.
|
||||
if (is_function_call && this->has_plt_offset())
|
||||
return false;
|
||||
|
||||
// A reference to any PLT entry in a non-position-independent executable
|
||||
// does not need a dynamic relocation.
|
||||
if (!parameters->output_is_position_independent()
|
||||
&& this->has_plt_offset())
|
||||
return false;
|
||||
|
||||
// A reference to a symbol defined in a dynamic object or to a
|
||||
// symbol that is preemptible will need a dynamic relocation.
|
||||
if (this->is_from_dynobj() || this->is_preemptible())
|
||||
return true;
|
||||
|
||||
// For all other cases, return FALSE.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Given a direct absolute static relocation against
|
||||
// the global symbol, where a dynamic relocation is needed, this
|
||||
// function returns whether a relative dynamic relocation can be used.
|
||||
// The caller must determine separately whether the static relocation
|
||||
// is compatible with a relative relocation.
|
||||
|
||||
bool
|
||||
can_use_relative_reloc(bool is_function_call) const
|
||||
{
|
||||
// A function call that can branch to a local PLT entry can
|
||||
// use a RELATIVE relocation.
|
||||
if (is_function_call && this->has_plt_offset())
|
||||
return true;
|
||||
|
||||
// A reference to a symbol defined in a dynamic object or to a
|
||||
// symbol that is preemptible can not use a RELATIVE relocaiton.
|
||||
if (this->is_from_dynobj() || this->is_preemptible())
|
||||
return false;
|
||||
|
||||
// For all other cases, return TRUE.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return whether there should be a warning for references to this
|
||||
// symbol.
|
||||
bool
|
||||
@ -433,6 +499,19 @@ class Symbol
|
||||
set_is_copied_from_dynobj()
|
||||
{ this->is_copied_from_dynobj_ = true; }
|
||||
|
||||
// Mark this symbol as needing its value written to the GOT even when
|
||||
// the value is subject to dynamic relocation (e.g., when the target
|
||||
// uses a RELATIVE relocation for the GOT entry).
|
||||
void
|
||||
set_needs_value_in_got()
|
||||
{ this->needs_value_in_got_ = true; }
|
||||
|
||||
// Return whether this symbol needs its value written to the GOT even
|
||||
// when the value is subject to dynamic relocation.
|
||||
bool
|
||||
needs_value_in_got() const
|
||||
{ return this->needs_value_in_got_; }
|
||||
|
||||
protected:
|
||||
// Instances of this class should always be created at a specific
|
||||
// size.
|
||||
@ -587,6 +666,9 @@ class Symbol
|
||||
// True if we are using a COPY reloc for this symbol, so that the
|
||||
// real definition lives in a dynamic object.
|
||||
bool is_copied_from_dynobj_ : 1;
|
||||
// True if the static value should be written to the GOT even
|
||||
// when the final value is subject to dynamic relocation.
|
||||
bool needs_value_in_got_ : 1;
|
||||
};
|
||||
|
||||
// The parts of a symbol which are size specific. Using a template
|
||||
|
175
gold/x86_64.cc
175
gold/x86_64.cc
@ -250,6 +250,17 @@ class Target_x86_64 : public Sized_target<64, false>
|
||||
Reloc_section*
|
||||
rela_dyn_section(Layout*);
|
||||
|
||||
// Return true if the symbol may need a COPY relocation.
|
||||
// References from an executable object to non-function symbols
|
||||
// defined in a dynamic object may need a COPY relocation.
|
||||
bool
|
||||
may_need_copy_reloc(Symbol* gsym)
|
||||
{
|
||||
return (!parameters->output_is_shared()
|
||||
&& gsym->is_from_dynobj()
|
||||
&& gsym->type() != elfcpp::STT_FUNC);
|
||||
}
|
||||
|
||||
// Copy a relocation against a global symbol.
|
||||
void
|
||||
copy_reloc(const General_options*, Symbol_table*, Layout*,
|
||||
@ -734,6 +745,20 @@ Target_x86_64::Scan::local(const General_options&,
|
||||
break;
|
||||
|
||||
case elfcpp::R_X86_64_64:
|
||||
// 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* rela_dyn = target->rela_dyn_section(layout);
|
||||
rela_dyn->add_local(object, 0, elfcpp::R_X86_64_RELATIVE,
|
||||
data_shndx, reloc.get_r_offset(), 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case elfcpp::R_X86_64_32:
|
||||
case elfcpp::R_X86_64_32S:
|
||||
case elfcpp::R_X86_64_16:
|
||||
@ -747,16 +772,10 @@ Target_x86_64::Scan::local(const General_options&,
|
||||
if (parameters->output_is_position_independent())
|
||||
{
|
||||
Reloc_section* rela_dyn = target->rela_dyn_section(layout);
|
||||
if (r_type == elfcpp::R_X86_64_64)
|
||||
rela_dyn->add_local(object, 0, elfcpp::R_X86_64_RELATIVE,
|
||||
data_shndx, reloc.get_r_offset(), 0);
|
||||
else
|
||||
{
|
||||
unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info());
|
||||
rela_dyn->add_local(object, r_sym, r_type, data_shndx,
|
||||
reloc.get_r_offset(),
|
||||
reloc.get_r_addend());
|
||||
}
|
||||
unsigned int r_sym = elfcpp::elf_r_sym<64>(reloc.get_r_info());
|
||||
rela_dyn->add_local(object, r_sym, r_type, data_shndx,
|
||||
reloc.get_r_offset(),
|
||||
reloc.get_r_addend());
|
||||
}
|
||||
break;
|
||||
|
||||
@ -915,81 +934,75 @@ Target_x86_64::Scan::global(const General_options& options,
|
||||
break;
|
||||
|
||||
case elfcpp::R_X86_64_64:
|
||||
case elfcpp::R_X86_64_PC64:
|
||||
case elfcpp::R_X86_64_32:
|
||||
case elfcpp::R_X86_64_32S:
|
||||
case elfcpp::R_X86_64_PC32:
|
||||
case elfcpp::R_X86_64_16:
|
||||
case elfcpp::R_X86_64_PC16:
|
||||
case elfcpp::R_X86_64_8:
|
||||
case elfcpp::R_X86_64_PC8:
|
||||
{
|
||||
bool is_pcrel = (r_type == elfcpp::R_X86_64_PC64
|
||||
|| r_type == elfcpp::R_X86_64_PC32
|
||||
|| r_type == elfcpp::R_X86_64_PC16
|
||||
|| r_type == elfcpp::R_X86_64_PC8);
|
||||
|
||||
if (gsym->is_from_dynobj()
|
||||
|| (parameters->output_is_shared()
|
||||
&& gsym->is_preemptible()))
|
||||
{
|
||||
// (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.
|
||||
if (gsym->type() == elfcpp::STT_FUNC)
|
||||
{
|
||||
target->make_plt_entry(symtab, layout, gsym);
|
||||
|
||||
// If this is not a PC relative reference, then we may
|
||||
// be taking the address of the function. In that case
|
||||
// we need to set the entry in the dynamic symbol table
|
||||
// to the address of the PLT entry. We will also need to
|
||||
// create a dynamic relocation.
|
||||
if (!is_pcrel)
|
||||
{
|
||||
if (gsym->is_from_dynobj())
|
||||
gsym->set_needs_dynsym_value();
|
||||
if (parameters->output_is_position_independent())
|
||||
{
|
||||
Reloc_section* rela_dyn =
|
||||
target->rela_dyn_section(layout);
|
||||
rela_dyn->add_global(gsym, r_type, object, data_shndx,
|
||||
reloc.get_r_offset(),
|
||||
reloc.get_r_addend());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (parameters->output_is_shared())
|
||||
{
|
||||
// We do not make COPY relocs in shared objects.
|
||||
// Make a PLT entry if necessary.
|
||||
if (gsym->needs_plt_entry())
|
||||
{
|
||||
target->make_plt_entry(symtab, layout, gsym);
|
||||
// Since this is not a PC-relative relocation, we may be
|
||||
// taking the address of a function. In that case we need to
|
||||
// set the entry in the dynamic symbol table to the address of
|
||||
// the PLT entry.
|
||||
if (gsym->is_from_dynobj())
|
||||
gsym->set_needs_dynsym_value();
|
||||
}
|
||||
// Make a dynamic relocation if necessary.
|
||||
if (gsym->needs_dynamic_reloc(true, false))
|
||||
{
|
||||
if (target->may_need_copy_reloc(gsym))
|
||||
{
|
||||
target->copy_reloc(&options, symtab, layout, object, data_shndx,
|
||||
gsym, reloc);
|
||||
}
|
||||
else if (r_type == elfcpp::R_X86_64_64
|
||||
&& gsym->can_use_relative_reloc(false))
|
||||
{
|
||||
Reloc_section* rela_dyn = target->rela_dyn_section(layout);
|
||||
rela_dyn->add_local(object, 0, elfcpp::R_X86_64_RELATIVE,
|
||||
data_shndx,
|
||||
reloc.get_r_offset(), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Reloc_section* rela_dyn = target->rela_dyn_section(layout);
|
||||
rela_dyn->add_global(gsym, r_type, object, data_shndx,
|
||||
reloc.get_r_offset(),
|
||||
reloc.get_r_addend());
|
||||
}
|
||||
else
|
||||
target->copy_reloc(&options, symtab, layout, object, data_shndx,
|
||||
gsym, reloc);
|
||||
}
|
||||
else if (!is_pcrel && parameters->output_is_position_independent())
|
||||
{
|
||||
// This is not a PC-relative reference, so we need to generate
|
||||
// a dynamic relocation. At this point, we know the symbol
|
||||
// is not preemptible, so we can use the RELATIVE relocation.
|
||||
Reloc_section* rela_dyn = target->rela_dyn_section(layout);
|
||||
if (r_type == elfcpp::R_X86_64_64)
|
||||
rela_dyn->add_local(object, 0, elfcpp::R_X86_64_RELATIVE,
|
||||
data_shndx,
|
||||
reloc.get_r_offset(), 0);
|
||||
else
|
||||
rela_dyn->add_global(gsym, r_type, object, data_shndx,
|
||||
reloc.get_r_offset(),
|
||||
reloc.get_r_addend());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case elfcpp::R_X86_64_PC64:
|
||||
case elfcpp::R_X86_64_PC32:
|
||||
case elfcpp::R_X86_64_PC16:
|
||||
case elfcpp::R_X86_64_PC8:
|
||||
{
|
||||
// Make a PLT entry if necessary.
|
||||
if (gsym->needs_plt_entry())
|
||||
target->make_plt_entry(symtab, layout, gsym);
|
||||
// Make a dynamic relocation if necessary.
|
||||
bool is_function_call = (gsym->type() == elfcpp::STT_FUNC);
|
||||
if (gsym->needs_dynamic_reloc(true, is_function_call))
|
||||
{
|
||||
if (target->may_need_copy_reloc(gsym))
|
||||
{
|
||||
target->copy_reloc(&options, symtab, layout, object, data_shndx,
|
||||
gsym, reloc);
|
||||
}
|
||||
else
|
||||
{
|
||||
Reloc_section* rela_dyn = target->rela_dyn_section(layout);
|
||||
rela_dyn->add_global(gsym, r_type, object, data_shndx,
|
||||
reloc.get_r_offset(),
|
||||
reloc.get_r_addend());
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case elfcpp::R_X86_64_GOT64:
|
||||
@ -1007,8 +1020,16 @@ Target_x86_64::Scan::global(const General_options& options,
|
||||
if (!gsym->final_value_is_known())
|
||||
{
|
||||
Reloc_section* rela_dyn = target->rela_dyn_section(layout);
|
||||
rela_dyn->add_global(gsym, elfcpp::R_X86_64_GLOB_DAT, got,
|
||||
gsym->got_offset(), 0);
|
||||
if (gsym->is_preemptible())
|
||||
rela_dyn->add_global(gsym, elfcpp::R_X86_64_GLOB_DAT, got,
|
||||
gsym->got_offset(), 0);
|
||||
else
|
||||
{
|
||||
rela_dyn->add_local(object, 0, elfcpp::R_X86_64_RELATIVE,
|
||||
got, gsym->got_offset(), 0);
|
||||
// Make sure we write the link-time value to the GOT.
|
||||
gsym->set_needs_value_in_got();
|
||||
}
|
||||
}
|
||||
}
|
||||
// For GOTPLT64, we also need a PLT entry (but only if the
|
||||
|
Reference in New Issue
Block a user