aboutsummaryrefslogtreecommitdiff
path: root/gold
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2007-11-02 04:08:52 +0000
committerIan Lance Taylor <iant@google.com>2007-11-02 04:08:52 +0000
commit86849f1facff8e5639c539a6e455575f25649028 (patch)
treee914f61eb7f0245374ee8aaede2a63dddddb16cc /gold
parentfe906b004d1558c79aee1d74f063b7d2cf8d08f5 (diff)
downloadgdb-86849f1facff8e5639c539a6e455575f25649028.zip
gdb-86849f1facff8e5639c539a6e455575f25649028.tar.gz
gdb-86849f1facff8e5639c539a6e455575f25649028.tar.bz2
From Cary Coutant: Correct generation of RELATIVE relocs.
Diffstat (limited to 'gold')
-rw-r--r--gold/i386.cc103
-rw-r--r--gold/x86_64.cc41
2 files changed, 105 insertions, 39 deletions
diff --git a/gold/i386.cc b/gold/i386.cc
index 052b7d3..699aa68 100644
--- a/gold/i386.cc
+++ b/gold/i386.cc
@@ -151,6 +151,12 @@ 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_32bit);
+
// Do a relocation. Return false if the caller should not issue
// any warnings about this relocation.
inline bool
@@ -772,12 +778,16 @@ Target_i386::Scan::local(const General_options&,
// relocate it easily.
if (parameters->output_is_position_independent())
{
- // FIXME: R_386_RELATIVE only works for a 32-bit relocation.
- gold_assert(r_type != elfcpp::R_386_16 && r_type != elfcpp::R_386_8);
-
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());
+ 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());
+ }
}
break;
@@ -973,15 +983,10 @@ Target_i386::Scan::global(const General_options& options,
gsym->set_needs_dynsym_value();
if (parameters->output_is_position_independent())
{
- // FIXME: If this is an 8-bit or 16-bit
- // relocation, R_386_RELATIVE won't work.
- gold_assert(r_type != elfcpp::R_386_16
- && r_type != elfcpp::R_386_8);
-
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());
+ rel_dyn->add_global(gsym, r_type, object, data_shndx,
+ reloc.get_r_offset());
}
}
}
@@ -998,16 +1003,16 @@ Target_i386::Scan::global(const General_options& options,
}
else if (!is_pcrel && parameters->output_is_position_independent())
{
- // FIXME: If this is an 8-bit or 16-bit relocation,
- // R_386_RELATIVE won't work.
- gold_assert(r_type != elfcpp::R_386_16
- && r_type != elfcpp::R_386_8);
-
// This is not a PC-relative reference, so we need to generate
- // a dynamic relocation.
+ // 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);
- rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, data_shndx,
- reloc.get_r_offset());
+ if (r_type == elfcpp::R_386_32)
+ rel_dyn->add_local(object, 0, elfcpp::R_386_RELATIVE, data_shndx,
+ reloc.get_r_offset());
+ else
+ rel_dyn->add_global(gsym, r_type, object, data_shndx,
+ reloc.get_r_offset());
}
}
break;
@@ -1228,6 +1233,46 @@ Target_i386::do_finalize_sections(Layout* layout)
this->copy_relocs_ = NULL;
}
+// Return whether a direct absolute static relocation needs to be applied.
+// In cases where Scan::local() or Scan::global() has created
+// a dynamic relocation other than R_386_RELATIVE, the addend
+// of the relocation is carried in the data, and we must not
+// apply the static relocation.
+
+inline bool
+Target_i386::Relocate::should_apply_static_reloc(const Sized_symbol<32>* gsym,
+ bool is_pcrel,
+ bool is_32bit)
+{
+ // For local symbols, return FALSE if a non-RELATIVE dynamic
+ // relocation was created; return TRUE otherwise.
+ if (gsym == NULL)
+ return (!parameters->output_is_position_independent() || 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;
+}
+
// Perform a relocation.
inline bool
@@ -1305,27 +1350,33 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
break;
case elfcpp::R_386_32:
- Relocate_functions<32, false>::rel32(view, object, psymval);
+ if (should_apply_static_reloc(gsym, false, true))
+ Relocate_functions<32, false>::rel32(view, object, psymval);
break;
case elfcpp::R_386_PC32:
- Relocate_functions<32, false>::pcrel32(view, object, psymval, address);
+ if (should_apply_static_reloc(gsym, true, true))
+ Relocate_functions<32, false>::pcrel32(view, object, psymval, address);
break;
case elfcpp::R_386_16:
- Relocate_functions<32, false>::rel16(view, object, psymval);
+ if (should_apply_static_reloc(gsym, false, false))
+ Relocate_functions<32, false>::rel16(view, object, psymval);
break;
case elfcpp::R_386_PC16:
- Relocate_functions<32, false>::pcrel16(view, object, psymval, address);
+ if (should_apply_static_reloc(gsym, true, false))
+ Relocate_functions<32, false>::pcrel16(view, object, psymval, address);
break;
case elfcpp::R_386_8:
- Relocate_functions<32, false>::rel8(view, object, psymval);
+ if (should_apply_static_reloc(gsym, false, false))
+ Relocate_functions<32, false>::rel8(view, object, psymval);
break;
case elfcpp::R_386_PC8:
- Relocate_functions<32, false>::pcrel8(view, object, psymval, address);
+ if (should_apply_static_reloc(gsym, true, false))
+ Relocate_functions<32, false>::pcrel8(view, object, psymval, address);
break;
case elfcpp::R_386_PLT32:
diff --git a/gold/x86_64.cc b/gold/x86_64.cc
index 5597d59..223523e 100644
--- a/gold/x86_64.cc
+++ b/gold/x86_64.cc
@@ -743,12 +743,17 @@ Target_x86_64::Scan::local(const General_options&,
// relocate it easily.
if (parameters->output_is_position_independent())
{
- // FIXME: R_X86_64_RELATIVE assumes a 64-bit relocation.
- gold_assert(r_type == elfcpp::R_X86_64_64);
-
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);
+ 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());
+ }
}
break;
@@ -946,16 +951,11 @@ Target_x86_64::Scan::global(const General_options& options,
gsym->set_needs_dynsym_value();
if (parameters->output_is_position_independent())
{
- // FIXME: R_X86_64_RELATIVE assumes a 64-bit
- // relocation.
- gold_assert(r_type == elfcpp::R_X86_64_64);
-
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);
+ rela_dyn->add_global(gsym, r_type, object, data_shndx,
+ reloc.get_r_offset(),
+ reloc.get_r_addend());
}
}
}
@@ -971,6 +971,21 @@ Target_x86_64::Scan::global(const General_options& options,
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;