From 86849f1facff8e5639c539a6e455575f25649028 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 2 Nov 2007 04:08:52 +0000 Subject: [PATCH] From Cary Coutant: Correct generation of RELATIVE relocs. --- gold/i386.cc | 103 ++++++++++++++++++++++++++++++++++++------------- gold/x86_64.cc | 41 +++++++++++++------- 2 files changed, 105 insertions(+), 39 deletions(-) diff --git a/gold/i386.cc b/gold/i386.cc index 052b7d3fe88..699aa682a09 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 5597d599bba..223523eb5f7 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; -- 2.30.2