summaryrefslogtreecommitdiffstats
path: root/binutils-2.25/gold/i386.cc
diff options
context:
space:
mode:
Diffstat (limited to 'binutils-2.25/gold/i386.cc')
-rw-r--r--binutils-2.25/gold/i386.cc127
1 files changed, 94 insertions, 33 deletions
diff --git a/binutils-2.25/gold/i386.cc b/binutils-2.25/gold/i386.cc
index 24f41036..eb5fbf76 100644
--- a/binutils-2.25/gold/i386.cc
+++ b/binutils-2.25/gold/i386.cc
@@ -738,6 +738,26 @@ class Target_i386 : public Sized_target<32, false>
static tls::Tls_optimization
optimize_tls_reloc(bool is_final, int r_type);
+ // Check if relocation against this symbol is a candidate for
+ // conversion from
+ // mov foo@GOT(%reg), %reg
+ // to
+ // lea foo@GOTOFF(%reg), %reg.
+ static bool
+ can_convert_mov_to_lea(const Symbol* gsym)
+ {
+ gold_assert(gsym != NULL);
+ return (gsym->type() != elfcpp::STT_GNU_IFUNC
+ && !gsym->is_undefined ()
+ && !gsym->is_from_dynobj()
+ && !gsym->is_preemptible()
+ && (!parameters->options().shared()
+ || (gsym->visibility() != elfcpp::STV_DEFAULT
+ && gsym->visibility() != elfcpp::STV_PROTECTED)
+ || parameters->options().Bsymbolic())
+ && strcmp(gsym->name(), "_DYNAMIC") != 0);
+ }
+
// Get the GOT section, creating it if necessary.
Output_data_got<32, false>*
got_section(Symbol_table*, Layout*);
@@ -1835,8 +1855,26 @@ Target_i386::Scan::local(Symbol_table* symtab,
case elfcpp::R_386_GOT32:
{
- // The symbol requires a GOT entry.
+ // We need GOT section.
Output_data_got<32, false>* got = target->got_section(symtab, layout);
+
+ // If the relocation symbol isn't IFUNC,
+ // and is local, then we will convert
+ // mov foo@GOT(%reg), %reg
+ // to
+ // lea foo@GOTOFF(%reg), %reg
+ // in Relocate::relocate.
+ if (reloc.get_r_offset() >= 2
+ && lsym.get_st_type() != elfcpp::STT_GNU_IFUNC)
+ {
+ section_size_type stype;
+ const unsigned char* view = object->section_contents(data_shndx,
+ &stype, true);
+ if (view[reloc.get_r_offset() - 2] == 0x8b)
+ break;
+ }
+
+ // Otherwise, the symbol requires a GOT entry.
unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
// For a STT_GNU_IFUNC symbol we want the PLT offset. That
@@ -2229,8 +2267,24 @@ Target_i386::Scan::global(Symbol_table* symtab,
case elfcpp::R_386_GOT32:
{
- // The symbol requires a GOT entry.
+ // The symbol requires a GOT section.
Output_data_got<32, false>* got = target->got_section(symtab, layout);
+
+ // If we convert this from
+ // mov foo@GOT(%reg), %reg
+ // to
+ // lea foo@GOTOFF(%reg), %reg
+ // in Relocate::relocate, then there is nothing to do here.
+ if (reloc.get_r_offset() >= 2
+ && Target_i386::can_convert_mov_to_lea(gsym))
+ {
+ section_size_type stype;
+ const unsigned char* view = object->section_contents(data_shndx,
+ &stype, true);
+ if (view[reloc.get_r_offset() - 2] == 0x8b)
+ break;
+ }
+
if (gsym->final_value_is_known())
{
// For a STT_GNU_IFUNC symbol we want the PLT address.
@@ -2732,35 +2786,6 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
}
}
- // Get the GOT offset if needed.
- // The GOT pointer points to the end of the GOT section.
- // We need to subtract the size of the GOT section to get
- // the actual offset to use in the relocation.
- bool have_got_offset = false;
- unsigned int got_offset = 0;
- switch (r_type)
- {
- case elfcpp::R_386_GOT32:
- if (gsym != NULL)
- {
- gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
- got_offset = (gsym->got_offset(GOT_TYPE_STANDARD)
- - target->got_size());
- }
- else
- {
- unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
- gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD));
- got_offset = (object->local_got_offset(r_sym, GOT_TYPE_STANDARD)
- - target->got_size());
- }
- have_got_offset = true;
- break;
-
- default:
- break;
- }
-
switch (r_type)
{
case elfcpp::R_386_NONE:
@@ -2809,8 +2834,44 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
break;
case elfcpp::R_386_GOT32:
- gold_assert(have_got_offset);
- Relocate_functions<32, false>::rel32(view, got_offset);
+ // Convert
+ // mov foo@GOT(%reg), %reg
+ // to
+ // lea foo@GOTOFF(%reg), %reg
+ // if possible.
+ if (rel.get_r_offset() >= 2
+ && view[-2] == 0x8b
+ && ((gsym == NULL && !psymval->is_ifunc_symbol())
+ || (gsym != NULL
+ && Target_i386::can_convert_mov_to_lea(gsym))))
+ {
+ view[-2] = 0x8d;
+ elfcpp::Elf_types<32>::Elf_Addr value;
+ value = (psymval->value(object, 0)
+ - target->got_plt_section()->address());
+ Relocate_functions<32, false>::rel32(view, value);
+ }
+ else
+ {
+ // The GOT pointer points to the end of the GOT section.
+ // We need to subtract the size of the GOT section to get
+ // the actual offset to use in the relocation.
+ unsigned int got_offset = 0;
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
+ got_offset = (gsym->got_offset(GOT_TYPE_STANDARD)
+ - target->got_size());
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD));
+ got_offset = (object->local_got_offset(r_sym, GOT_TYPE_STANDARD)
+ - target->got_size());
+ }
+ Relocate_functions<32, false>::rel32(view, got_offset);
+ }
break;
case elfcpp::R_386_GOTOFF: