X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gold%2Fi386.cc;h=2d8efdd5ecb2ed3d6b7695fd4a495c359a825530;hb=dceae3c154edcb9aada9f94452a72548a82914f5;hp=6c359401929e15012ecd03b1e9dc5f435be70887;hpb=99f8facac923848a9496cc34235b608e05a7f160;p=deliverable%2Fbinutils-gdb.git diff --git a/gold/i386.cc b/gold/i386.cc index 6c35940192..2d8efdd5ec 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -96,6 +96,37 @@ class Target_i386 : public Sized_target<32, false> elfcpp::Elf_types<32>::Elf_Addr view_address, section_size_type view_size); + // Scan the relocs during a relocatable link. + void + scan_relocatable_relocs(const General_options& options, + Symbol_table* symtab, + Layout* layout, + Sized_relobj<32, false>* object, + unsigned int data_shndx, + unsigned int sh_type, + const unsigned char* prelocs, + size_t reloc_count, + Output_section* output_section, + bool needs_special_offset_handling, + size_t local_symbol_count, + const unsigned char* plocal_symbols, + Relocatable_relocs*); + + // Relocate a section during a relocatable link. + void + relocate_for_relocatable(const Relocate_info<32, false>*, + unsigned int sh_type, + const unsigned char* prelocs, + size_t reloc_count, + Output_section* output_section, + off_t offset_in_output_section, + const Relocatable_relocs*, + unsigned char* view, + elfcpp::Elf_types<32>::Elf_Addr view_address, + section_size_type view_size, + unsigned char* reloc_view, + section_size_type reloc_view_size); + // Return a string used to fill a code section with nops. std::string do_code_fill(section_size_type length); @@ -164,8 +195,7 @@ 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_absolute_ref, - bool is_function_call, + int ref_flags, bool is_32bit); // Do a relocation. Return false if the caller should not issue @@ -241,6 +271,15 @@ class Target_i386 : public Sized_target<32, false> Local_dynamic_type local_dynamic_type_; }; + // A class which returns the size required for a relocation type, + // used while scanning relocs during a relocatable link. + class Relocatable_size_for_reloc + { + public: + unsigned int + get_size_for_reloc(unsigned int, Relobj*); + }; + // Adjust TLS relocation type based on the options and whether this // is a local symbol. static tls::Tls_optimization @@ -359,7 +398,7 @@ Target_i386::got_section(Symbol_table* symtab, Layout* layout) this->got_plt_->set_current_data_size(3 * 4); // Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT. - symtab->define_in_output_data(this, "_GLOBAL_OFFSET_TABLE_", NULL, + symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL, this->got_plt_, 0, 0, elfcpp::STT_OBJECT, elfcpp::STB_LOCAL, @@ -736,7 +775,7 @@ Target_i386::copy_reloc(const General_options* options, section_size_type offset = dynbss_size; dynbss->set_current_data_size(dynbss_size + symsize); - symtab->define_with_copy_reloc(this, ssym, dynbss, offset); + symtab->define_with_copy_reloc(ssym, dynbss, offset); // Add the COPY reloc. Reloc_section* rel_dyn = this->rel_dyn_section(layout); @@ -859,9 +898,19 @@ Target_i386::Scan::local(const General_options&, 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, output_section, data_shndx, - reloc.get_r_offset()); + if (lsym.get_st_type() != elfcpp::STT_SECTION) + { + unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); + rel_dyn->add_local(object, r_sym, r_type, output_section, + data_shndx, reloc.get_r_offset()); + } + else + { + gold_assert(lsym.get_st_value() == 0); + rel_dyn->add_local_section(object, lsym.get_st_shndx(), + r_type, output_section, + data_shndx, reloc.get_r_offset()); + } } break; @@ -1014,6 +1063,7 @@ Target_i386::Scan::local(const General_options&, if (output_is_shared) { // We need to create a dynamic relocation. + gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION); unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_LE_32 ? elfcpp::R_386_TLS_TPOFF32 @@ -1090,11 +1140,11 @@ Target_i386::Scan::global(const General_options& options, // 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()) + if (gsym->is_from_dynobj() && !parameters->output_is_shared()) gsym->set_needs_dynsym_value(); } // Make a dynamic relocation if necessary. - if (gsym->needs_dynamic_reloc(true, false)) + if (gsym->needs_dynamic_reloc(Symbol::ABSOLUTE_REF)) { if (target->may_need_copy_reloc(gsym)) { @@ -1137,8 +1187,10 @@ Target_i386::Scan::global(const General_options& options, 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)) + int flags = Symbol::NON_PIC_REF; + if (gsym->type() == elfcpp::STT_FUNC) + flags |= Symbol::FUNCTION_CALL; + if (gsym->needs_dynamic_reloc(flags)) { if (target->may_need_copy_reloc(gsym)) { @@ -1166,7 +1218,9 @@ Target_i386::Scan::global(const General_options& options, // If this symbol is not fully resolved, we need to add a // GOT entry with a dynamic relocation. Reloc_section* rel_dyn = target->rel_dyn_section(layout); - if (gsym->is_from_dynobj() || gsym->is_preemptible()) + if (gsym->is_from_dynobj() + || gsym->is_undefined() + || gsym->is_preemptible()) got->add_global_with_rel(gsym, rel_dyn, elfcpp::R_386_GLOB_DAT); else { @@ -1443,8 +1497,7 @@ Target_i386::do_finalize_sections(Layout* layout) inline bool Target_i386::Relocate::should_apply_static_reloc(const Sized_symbol<32>* gsym, - bool is_absolute_ref, - bool is_function_call, + int ref_flags, bool is_32bit) { // For local symbols, we will have created a non-RELATIVE dynamic @@ -1453,12 +1506,18 @@ Target_i386::Relocate::should_apply_static_reloc(const Sized_symbol<32>* gsym, // (c) the relocation is not 32 bits wide. if (gsym == NULL) return !(parameters->output_is_position_independent() - && is_absolute_ref + && (ref_flags & Symbol::ABSOLUTE_REF) && !is_32bit); - // 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)); + // For global symbols, we use the same helper routines used in the + // scan pass. If we did not create a dynamic relocation, or if we + // created a RELATIVE dynamic relocation, we should apply the static + // relocation. + bool has_dyn = gsym->needs_dynamic_reloc(ref_flags); + bool is_rel = (ref_flags & Symbol::ABSOLUTE_REF) + && gsym->can_use_relative_reloc(ref_flags + & Symbol::FUNCTION_CALL); + return !has_dyn || is_rel; } // Perform a relocation. @@ -1491,11 +1550,15 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, // Pick the value to use for symbols defined in shared objects. Symbol_value<32> symval; + bool is_nonpic = (r_type == elfcpp::R_386_PC8 + || r_type == elfcpp::R_386_PC16 + || r_type == elfcpp::R_386_PC32); if (gsym != NULL && (gsym->is_from_dynobj() || (parameters->output_is_shared() - && gsym->is_preemptible())) - && gsym->has_plt_offset()) + && (gsym->is_undefined() || gsym->is_preemptible()))) + && gsym->has_plt_offset() + && (!is_nonpic || !parameters->output_is_shared())) { symval.set_output_value(target->plt_section()->address() + gsym->plt_offset()); @@ -1539,43 +1602,46 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, break; case elfcpp::R_386_32: - if (should_apply_static_reloc(gsym, true, false, true)) + if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, true)) Relocate_functions<32, false>::rel32(view, object, psymval); break; case elfcpp::R_386_PC32: { - bool is_function_call = (gsym != NULL - && gsym->type() == elfcpp::STT_FUNC); - if (should_apply_static_reloc(gsym, false, is_function_call, true)) + int ref_flags = Symbol::NON_PIC_REF; + if (gsym != NULL && gsym->type() == elfcpp::STT_FUNC) + ref_flags |= Symbol::FUNCTION_CALL; + if (should_apply_static_reloc(gsym, ref_flags, true)) Relocate_functions<32, false>::pcrel32(view, object, psymval, address); } break; case elfcpp::R_386_16: - if (should_apply_static_reloc(gsym, true, false, false)) + if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false)) Relocate_functions<32, false>::rel16(view, object, psymval); break; case elfcpp::R_386_PC16: { - bool is_function_call = (gsym != NULL - && gsym->type() == elfcpp::STT_FUNC); - if (should_apply_static_reloc(gsym, false, is_function_call, false)) + int ref_flags = Symbol::NON_PIC_REF; + if (gsym != NULL && gsym->type() == elfcpp::STT_FUNC) + ref_flags |= Symbol::FUNCTION_CALL; + if (should_apply_static_reloc(gsym, ref_flags, false)) Relocate_functions<32, false>::pcrel32(view, object, psymval, address); } break; case elfcpp::R_386_8: - if (should_apply_static_reloc(gsym, true, false, false)) + if (should_apply_static_reloc(gsym, Symbol::ABSOLUTE_REF, false)) Relocate_functions<32, false>::rel8(view, object, psymval); break; case elfcpp::R_386_PC8: { - bool is_function_call = (gsym != NULL - && gsym->type() == elfcpp::STT_FUNC); - if (should_apply_static_reloc(gsym, false, is_function_call, false)) + int ref_flags = Symbol::NON_PIC_REF; + if (gsym != NULL && gsym->type() == elfcpp::STT_FUNC) + ref_flags |= Symbol::FUNCTION_CALL; + if (should_apply_static_reloc(gsym, ref_flags, false)) Relocate_functions<32, false>::pcrel32(view, object, psymval, address); } break; @@ -2138,6 +2204,148 @@ Target_i386::relocate_section(const Relocate_info<32, false>* relinfo, view_size); } +// Return the size of a relocation while scanning during a relocatable +// link. + +unsigned int +Target_i386::Relocatable_size_for_reloc::get_size_for_reloc( + unsigned int r_type, + Relobj* object) +{ + switch (r_type) + { + case elfcpp::R_386_NONE: + case elfcpp::R_386_GNU_VTINHERIT: + case elfcpp::R_386_GNU_VTENTRY: + case elfcpp::R_386_TLS_GD: // Global-dynamic + case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (from ~oliva url) + case elfcpp::R_386_TLS_DESC_CALL: + case elfcpp::R_386_TLS_LDM: // Local-dynamic + case elfcpp::R_386_TLS_LDO_32: // Alternate local-dynamic + case elfcpp::R_386_TLS_IE: // Initial-exec + case elfcpp::R_386_TLS_IE_32: + case elfcpp::R_386_TLS_GOTIE: + case elfcpp::R_386_TLS_LE: // Local-exec + case elfcpp::R_386_TLS_LE_32: + return 0; + + case elfcpp::R_386_32: + case elfcpp::R_386_PC32: + case elfcpp::R_386_GOT32: + case elfcpp::R_386_PLT32: + case elfcpp::R_386_GOTOFF: + case elfcpp::R_386_GOTPC: + return 4; + + case elfcpp::R_386_16: + case elfcpp::R_386_PC16: + return 2; + + case elfcpp::R_386_8: + case elfcpp::R_386_PC8: + return 1; + + // These are relocations which should only be seen by the + // dynamic linker, and should never be seen here. + case elfcpp::R_386_COPY: + case elfcpp::R_386_GLOB_DAT: + case elfcpp::R_386_JUMP_SLOT: + case elfcpp::R_386_RELATIVE: + case elfcpp::R_386_TLS_TPOFF: + case elfcpp::R_386_TLS_DTPMOD32: + case elfcpp::R_386_TLS_DTPOFF32: + case elfcpp::R_386_TLS_TPOFF32: + case elfcpp::R_386_TLS_DESC: + object->error(_("unexpected reloc %u in object file"), r_type); + return 0; + + case elfcpp::R_386_32PLT: + case elfcpp::R_386_TLS_GD_32: + case elfcpp::R_386_TLS_GD_PUSH: + case elfcpp::R_386_TLS_GD_CALL: + case elfcpp::R_386_TLS_GD_POP: + case elfcpp::R_386_TLS_LDM_32: + case elfcpp::R_386_TLS_LDM_PUSH: + case elfcpp::R_386_TLS_LDM_CALL: + case elfcpp::R_386_TLS_LDM_POP: + case elfcpp::R_386_USED_BY_INTEL_200: + default: + object->error(_("unsupported reloc %u in object file"), r_type); + return 0; + } +} + +// Scan the relocs during a relocatable link. + +void +Target_i386::scan_relocatable_relocs(const General_options& options, + Symbol_table* symtab, + Layout* layout, + Sized_relobj<32, false>* object, + unsigned int data_shndx, + unsigned int sh_type, + const unsigned char* prelocs, + size_t reloc_count, + Output_section* output_section, + bool needs_special_offset_handling, + size_t local_symbol_count, + const unsigned char* plocal_symbols, + Relocatable_relocs* rr) +{ + gold_assert(sh_type == elfcpp::SHT_REL); + + typedef gold::Default_scan_relocatable_relocs Scan_relocatable_relocs; + + gold::scan_relocatable_relocs<32, false, Target_i386, elfcpp::SHT_REL, + Scan_relocatable_relocs>( + options, + symtab, + layout, + object, + data_shndx, + prelocs, + reloc_count, + output_section, + needs_special_offset_handling, + local_symbol_count, + plocal_symbols, + rr); +} + +// Relocate a section during a relocatable link. + +void +Target_i386::relocate_for_relocatable( + const Relocate_info<32, false>* relinfo, + unsigned int sh_type, + const unsigned char* prelocs, + size_t reloc_count, + Output_section* output_section, + off_t offset_in_output_section, + const Relocatable_relocs* rr, + unsigned char* view, + elfcpp::Elf_types<32>::Elf_Addr view_address, + section_size_type view_size, + unsigned char* reloc_view, + section_size_type reloc_view_size) +{ + gold_assert(sh_type == elfcpp::SHT_REL); + + gold::relocate_for_relocatable<32, false, Target_i386, elfcpp::SHT_REL>( + relinfo, + prelocs, + reloc_count, + output_section, + offset_in_output_section, + rr, + view, + view_address, + view_size, + reloc_view, + reloc_view_size); +} + // Return the value to use for a dynamic which requires special // treatment. This is how we support equality comparisons of function // pointers across shared library boundaries, as described in the