From 5755afadf580726c7d9a34c575930d21c54a1f0a Mon Sep 17 00:00:00 2001 From: Jing Yu Date: Thu, 22 Jul 2010 14:35:55 -0700 Subject: A few binutils and gold patches to make gold and safe-icf work. Change-Id: I805434f4f616c822c979081a5a71b607ecd6cf26 --- binutils-2.19/README.android | 80 +++++ binutils-2.19/config.sub | 8 +- binutils-2.19/gold/arm-reloc-property.cc | 4 +- binutils-2.19/gold/arm-reloc-property.h | 7 + binutils-2.19/gold/arm.cc | 376 +++++++++++++++++---- binutils-2.19/gold/gc.h | 44 ++- binutils-2.19/gold/i386.cc | 88 ++++- binutils-2.19/gold/icf.cc | 41 ++- binutils-2.19/gold/icf.h | 6 +- binutils-2.19/gold/output.cc | 10 +- binutils-2.19/gold/output.h | 15 + binutils-2.19/gold/symtab.cc | 10 +- binutils-2.19/gold/symtab.h | 2 +- binutils-2.19/gold/target-reloc.h | 4 +- binutils-2.19/gold/target.h | 14 + binutils-2.19/gold/testsuite/Makefile.am | 27 ++ binutils-2.19/gold/testsuite/Makefile.in | 61 +++- .../testsuite/icf_preemptible_functions_test.cc | 47 +++ .../testsuite/icf_preemptible_functions_test.sh | 35 ++ binutils-2.19/gold/testsuite/icf_safe_so_test.cc | 3 +- binutils-2.19/gold/testsuite/icf_safe_so_test.sh | 60 +++- binutils-2.19/gold/testsuite/icf_safe_test.cc | 8 +- binutils-2.19/gold/testsuite/icf_safe_test.sh | 6 +- .../gold/testsuite/icf_string_merge_test.cc | 50 +++ .../gold/testsuite/icf_string_merge_test.sh | 37 ++ .../testsuite/icf_virtual_function_folding_test.cc | 70 ++++ binutils-2.19/gold/x86_64.cc | 11 +- binutils-2.19/ld/emultempl/armelf.em | 7 + 28 files changed, 971 insertions(+), 160 deletions(-) create mode 100644 binutils-2.19/gold/testsuite/icf_preemptible_functions_test.cc create mode 100755 binutils-2.19/gold/testsuite/icf_preemptible_functions_test.sh create mode 100644 binutils-2.19/gold/testsuite/icf_string_merge_test.cc create mode 100755 binutils-2.19/gold/testsuite/icf_string_merge_test.sh create mode 100644 binutils-2.19/gold/testsuite/icf_virtual_function_folding_test.cc diff --git a/binutils-2.19/README.android b/binutils-2.19/README.android index 1231282..b990281 100644 --- a/binutils-2.19/README.android +++ b/binutils-2.19/README.android @@ -1,3 +1,83 @@ +2010-07-15 Doug Kwan + + Backport upstream patches to enhance safe ICF and to fix + a linker crash and an EXIDX problem in the Linux kernel. + + http://www.cygwin.com/ml/binutils-cvs/2010-06/msg00118.html + http://www.cygwin.com/ml/binutils-cvs/2010-06/msg00148.html + http://www.cygwin.com/ml/binutils-cvs/2010-07/msg00080.html + + Changed file: + + gold/arm-reloc-property.cc + gold/arm-reloc-property.h + gold/arm.cc + gold/icf.h + gold/output.cc + gold/output.h + gold/target.h + +2010-07-09 Jing Yu + + Add support to androideabi target. + Backport the patch from binutils upstream. + + Changed file: + config.sub + +2010-06-23 Doug Kwan + + Add dummy --icf option to ld for compatiblity with gold. + + Changed file: + + ld/emultempl/armelf.em + +2010-06-19 Doug Kwan + + Integrate CL 40547. + + Changed files: + + gold/gc.h + gold/i386.cc + gold/icf.cc + gold/icf.h + gold/symtab.cc + gold/symtab.h + gold/target-reloc.h + gold/testsuite/Makefile.am + gold/testsuite/Makefile.in + gold/testsuite/icf_preemptible_functions_test.cc + gold/testsuite/icf_preemptible_functions_test.sh + gold/testsuite/icf_safe_so_test.cc + gold/testsuite/icf_safe_so_test.sh + gold/testsuite/icf_safe_test.cc + gold/testsuite/icf_safe_test.sh + gold/testsuite/icf_string_merge_test.cc + gold/testsuite/icf_string_merge_test.sh + gold/testsuite/icf_virtual_function_folding_test.cc + gold/x86_64.cc + +2010-06-15 Doug Kwan + + Fix ARM kernel build breakage due to merging EABI flags from + empty objects. This is not yet up-stream. + + Changed files: + + gold/arm.cc + +2010-06-08 Doug Kwan + + Backport upstream patch to fix too many stubs problem. + + http://sourceware.org/ml/binutils-cvs/2010-06/msg00027.html + + Changed files: + + gold/arm.cc + 2010-06-02 Doug Kwan Backport upstream patches to support dual-linker configuration. diff --git a/binutils-2.19/config.sub b/binutils-2.19/config.sub index 63bfff0..bfbf61d 100755 --- a/binutils-2.19/config.sub +++ b/binutils-2.19/config.sub @@ -120,8 +120,9 @@ esac # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in - nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ - uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` @@ -1258,7 +1259,8 @@ case $os in | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -mingw32* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ diff --git a/binutils-2.19/gold/arm-reloc-property.cc b/binutils-2.19/gold/arm-reloc-property.cc index 4f8fa9e..007653c 100644 --- a/binutils-2.19/gold/arm-reloc-property.cc +++ b/binutils-2.19/gold/arm-reloc-property.cc @@ -104,7 +104,8 @@ Arm_reloc_property::Arm_reloc_property( relative_address_base_(RAB_NONE), is_deprecated_(is_deprecated), is_implemented_(is_implemented), checks_overflow_(checks_overflow), uses_got_entry_(false), uses_got_origin_(false), uses_plt_entry_(false), - uses_thumb_bit_(false), uses_symbol_base_(false), uses_addend_(false) + uses_thumb_bit_(false), uses_symbol_base_(false), uses_addend_(false), + uses_symbol_(false) { // Set size and alignment of static and dynamic relocations. if (rtype == RT_STATIC) @@ -246,6 +247,7 @@ Arm_reloc_property::Arm_reloc_property( } gold_assert(node->is_leaf() && node->name() == "S"); + this->uses_symbol_ = true; delete root_node; } diff --git a/binutils-2.19/gold/arm-reloc-property.h b/binutils-2.19/gold/arm-reloc-property.h index 349d862..e7d7f50 100644 --- a/binutils-2.19/gold/arm-reloc-property.h +++ b/binutils-2.19/gold/arm-reloc-property.h @@ -132,6 +132,11 @@ class Arm_reloc_property uses_symbol_base() const { return this->uses_symbol_base_; } + // Whether relocation uses the symbol. + bool + uses_symbol() const + { return this->uses_symbol_; } + // Return the type of relative address base or RAB_NONE if this // is not a relative addressing relocation. Relative_address_base @@ -273,6 +278,8 @@ class Arm_reloc_property bool uses_symbol_base_ : 1; // Whether this uses an addend. bool uses_addend_ : 1; + // Whether this uses the symbol. + bool uses_symbol_ : 1; }; // Arm_reloc_property_table. This table is used for looking up propeties diff --git a/binutils-2.19/gold/arm.cc b/binutils-2.19/gold/arm.cc index 76f28be..566e326 100644 --- a/binutils-2.19/gold/arm.cc +++ b/binutils-2.19/gold/arm.cc @@ -1320,7 +1320,10 @@ class Arm_output_section : public Output_section Arm_output_section(const char* name, elfcpp::Elf_Word type, elfcpp::Elf_Xword flags) : Output_section(name, type, flags) - { } + { + if (type == elfcpp::SHT_ARM_EXIDX) + this->set_always_keeps_input_sections(); + } ~Arm_output_section() { } @@ -1347,6 +1350,10 @@ class Arm_output_section : public Output_section const Text_section_list& sorted_text_section, Symbol_table* symtab); + // Link an EXIDX section into its corresponding text section. + void + set_exidx_section_link(); + private: // For convenience. typedef Output_section::Input_section Input_section; @@ -1371,7 +1378,7 @@ class Arm_exidx_input_section Arm_exidx_input_section(Relobj* relobj, unsigned int shndx, unsigned int link, uint32_t size, uint32_t addralign) : relobj_(relobj), shndx_(shndx), link_(link), size_(size), - addralign_(addralign) + addralign_(addralign), has_errors_(false) { } ~Arm_exidx_input_section() @@ -1404,6 +1411,16 @@ class Arm_exidx_input_section addralign() const { return this->addralign_; } + // Whether there are any errors in the EXIDX input section. + bool + has_errors() const + { return this->has_errors_; } + + // Set has-errors flag. + void + set_has_errors() + { this->has_errors_ = true; } + private: // Object containing this. Relobj* relobj_; @@ -1415,6 +1432,8 @@ class Arm_exidx_input_section uint32_t size_; // Address alignment of this. For ARM 32-bit is sufficient. uint32_t addralign_; + // Whether this has any errors. + bool has_errors_; }; // Arm_relobj class. @@ -1576,6 +1595,22 @@ class Arm_relobj : public Sized_relobj<32, big_endian> merge_flags_and_attributes() const { return this->merge_flags_and_attributes_; } + // Export list of EXIDX section indices. + void + get_exidx_shndx_list(std::vector* list) const + { + list->clear(); + for (Exidx_section_map::const_iterator p = this->exidx_section_map_.begin(); + p != this->exidx_section_map_.end(); + ++p) + { + if (p->second->shndx() == p->first) + list->push_back(p->first); + } + // Sort list to make result independent of implementation of map. + std::sort(list->begin(), list->end()); + } + protected: // Post constructor setup. void @@ -1648,7 +1683,8 @@ class Arm_relobj : public Sized_relobj<32, big_endian> void make_exidx_input_section(unsigned int shndx, const elfcpp::Shdr<32, big_endian>& shdr, - unsigned int text_shndx); + unsigned int text_shndx, + const elfcpp::Shdr<32, big_endian>& text_shdr); // Return the output address of either a plain input section or a // relaxed input section. SHNDX is the section index. @@ -2104,6 +2140,23 @@ class Target_arm : public Sized_target<32, big_endian> fix_cortex_a8_(false), cortex_a8_relocs_info_() { } + // Virtual function which is set to return true by a target if + // it can use relocation types to determine if a function's + // pointer is taken. + virtual bool + can_check_for_function_pointers() const + { return true; } + + // Whether a section called SECTION_NAME may have function pointers to + // sections not eligible for safe ICF folding. + virtual bool + section_may_have_icf_unsafe_pointers(const char* section_name) const + { + return (!is_prefix_of(".ARM.exidx", section_name) + && !is_prefix_of(".ARM.extab", section_name) + && Target::section_may_have_icf_unsafe_pointers(section_name)); + } + // Whether we can use BLX. bool may_use_blx() const @@ -2460,8 +2513,7 @@ class Target_arm : public Sized_target<32, big_endian> Output_section* , const elfcpp::Rel<32, big_endian>& , unsigned int , - const elfcpp::Sym<32, big_endian>&) - { return false; } + const elfcpp::Sym<32, big_endian>&); inline bool global_reloc_may_be_function_pointer(Symbol_table* , Layout* , Target_arm* , @@ -2469,8 +2521,7 @@ class Target_arm : public Sized_target<32, big_endian> unsigned int , Output_section* , const elfcpp::Rel<32, big_endian>& , - unsigned int , Symbol*) - { return false; } + unsigned int , Symbol*); private: static void @@ -2501,6 +2552,9 @@ class Target_arm : public Sized_target<32, big_endian> || sym->is_preemptible())); } + inline bool + possible_function_pointer_reloc(unsigned int r_type); + // Whether we have issued an error about a non-PIC compilation. bool issued_non_pic_error_; }; @@ -2732,7 +2786,8 @@ class Target_arm : public Sized_target<32, big_endian> // Fix .ARM.exidx section coverage. void - fix_exidx_coverage(Layout*, Arm_output_section*, Symbol_table*); + fix_exidx_coverage(Layout*, const Input_objects*, + Arm_output_section*, Symbol_table*); // Functors for STL set. struct output_section_address_less_than @@ -5624,10 +5679,6 @@ void Arm_output_section::append_text_sections_to_list( Text_section_list* list) { - // We only care about text sections. - if ((this->flags() & elfcpp::SHF_EXECINSTR) == 0) - return; - gold_assert((this->flags() & elfcpp::SHF_ALLOC) != 0); for (Input_section_list::const_iterator p = this->input_sections().begin(); @@ -5699,9 +5750,10 @@ Arm_output_section::fix_exidx_coverage( const Arm_exidx_input_section* exidx_input_section = arm_relobj->exidx_input_section_by_link(shndx); - // If this text section has no EXIDX section, force an EXIDX_CANTUNWIND - // entry pointing to the end of the last seen EXIDX section. - if (exidx_input_section == NULL) + // If this text section has no EXIDX section or if the EXIDX section + // has errors, force an EXIDX_CANTUNWIND entry pointing to the end + // of the last seen EXIDX section. + if (exidx_input_section == NULL || exidx_input_section->has_errors()) { exidx_fixup.add_exidx_cantunwind_as_needed(); continue; @@ -5785,15 +5837,20 @@ Arm_output_section::fix_exidx_coverage( if (processed_input_sections.find(Section_id(p->relobj(), p->shndx())) == processed_input_sections.end()) { - // We only discard a known EXIDX section because its linked - // text section has been folded by ICF. + // We discard a known EXIDX section because its linked + // text section has been folded by ICF. We also discard an + // EXIDX section with error, the output does not matter in this + // case. We do this to avoid triggering asserts. Arm_relobj* arm_relobj = Arm_relobj::as_arm_relobj(p->relobj()); const Arm_exidx_input_section* exidx_input_section = arm_relobj->exidx_input_section_by_shndx(p->shndx()); gold_assert(exidx_input_section != NULL); - unsigned int text_shndx = exidx_input_section->link(); - gold_assert(symtab->is_section_folded(p->relobj(), text_shndx)); + if (!exidx_input_section->has_errors()) + { + unsigned int text_shndx = exidx_input_section->link(); + gold_assert(symtab->is_section_folded(p->relobj(), text_shndx)); + } // Remove this from link. We also need to recount the // local symbols. @@ -5812,6 +5869,28 @@ Arm_output_section::fix_exidx_coverage( this->set_section_offsets_need_adjustment(); } +// Link EXIDX output sections to text output sections. + +template +void +Arm_output_section::set_exidx_section_link() +{ + gold_assert(this->type() == elfcpp::SHT_ARM_EXIDX); + if (!this->input_sections().empty()) + { + Input_section_list::const_iterator p = this->input_sections().begin(); + Arm_relobj* arm_relobj = + Arm_relobj::as_arm_relobj(p->relobj()); + unsigned exidx_shndx = p->shndx(); + const Arm_exidx_input_section* exidx_input_section = + arm_relobj->exidx_input_section_by_shndx(exidx_shndx); + gold_assert(exidx_input_section != NULL); + unsigned int text_shndx = exidx_input_section->link(); + Output_section* os = arm_relobj->output_section(text_shndx); + this->set_link_section(os); + } +} + // Arm_relobj methods. // Determine if an input section is scannable for stub processing. SHDR is @@ -6413,28 +6492,57 @@ void Arm_relobj::make_exidx_input_section( unsigned int shndx, const elfcpp::Shdr<32, big_endian>& shdr, - unsigned int text_shndx) + unsigned int text_shndx, + const elfcpp::Shdr<32, big_endian>& text_shdr) { - // Issue an error and ignore this EXIDX section if it points to a text - // section already has an EXIDX section. - if (this->exidx_section_map_[text_shndx] != NULL) - { - gold_error(_("EXIDX sections %u and %u both link to text section %u " - "in %s"), - shndx, this->exidx_section_map_[text_shndx]->shndx(), - text_shndx, this->name().c_str()); - return; - } - // Create an Arm_exidx_input_section object for this EXIDX section. Arm_exidx_input_section* exidx_input_section = new Arm_exidx_input_section(this, shndx, text_shndx, shdr.get_sh_size(), shdr.get_sh_addralign()); - this->exidx_section_map_[text_shndx] = exidx_input_section; - // Also map the EXIDX section index to this. gold_assert(this->exidx_section_map_[shndx] == NULL); this->exidx_section_map_[shndx] = exidx_input_section; + + if (text_shndx == elfcpp::SHN_UNDEF || text_shndx >= this->shnum()) + { + gold_error(_("EXIDX section %s(%u) links to invalid section %u in %s"), + this->section_name(shndx).c_str(), shndx, text_shndx, + this->name().c_str()); + exidx_input_section->set_has_errors(); + } + else if (this->exidx_section_map_[text_shndx] != NULL) + { + unsigned other_exidx_shndx = + this->exidx_section_map_[text_shndx]->shndx(); + gold_error(_("EXIDX sections %s(%u) and %s(%u) both link to text section" + "%s(%u) in %s"), + this->section_name(shndx).c_str(), shndx, + this->section_name(other_exidx_shndx).c_str(), + other_exidx_shndx, this->section_name(text_shndx).c_str(), + text_shndx, this->name().c_str()); + exidx_input_section->set_has_errors(); + } + else + this->exidx_section_map_[text_shndx] = exidx_input_section; + + // Check section flags of text section. + if ((text_shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0) + { + gold_error(_("EXIDX section %s(%u) links to non-allocated section %s(%u) " + " in %s"), + this->section_name(shndx).c_str(), shndx, + this->section_name(text_shndx).c_str(), text_shndx, + this->name().c_str()); + exidx_input_section->set_has_errors(); + } + else if ((text_shdr.get_sh_flags() & elfcpp::SHF_EXECINSTR) == 0) + // I would like to make this an error but currenlty ld just ignores + // this. + gold_warning(_("EXIDX section %s(%u) links to non-executable section " + "%s(%u) in %s"), + this->section_name(shndx).c_str(), shndx, + this->section_name(text_shndx).c_str(), text_shndx, + this->name().c_str()); } // Read the symbol information. @@ -6504,19 +6612,21 @@ Arm_relobj::do_read_symbols(Read_symbols_data* sd) else if (shdr.get_sh_type() == elfcpp::SHT_ARM_EXIDX) { unsigned int text_shndx = this->adjust_shndx(shdr.get_sh_link()); - if (text_shndx >= this->shnum()) - gold_error(_("EXIDX section %u linked to invalid section %u"), - i, text_shndx); - else if (text_shndx == elfcpp::SHN_UNDEF) + if (text_shndx == elfcpp::SHN_UNDEF) deferred_exidx_sections.push_back(i); else - this->make_exidx_input_section(i, shdr, text_shndx); + { + elfcpp::Shdr<32, big_endian> text_shdr(pshdrs + + text_shndx * shdr_size); + this->make_exidx_input_section(i, shdr, text_shndx, text_shdr); + } } } // This is rare. if (!must_merge_flags_and_attributes) { + gold_assert(deferred_exidx_sections.empty()); this->merge_flags_and_attributes_ = false; return; } @@ -6572,15 +6682,14 @@ Arm_relobj::do_read_symbols(Read_symbols_data* sd) { unsigned int shndx = deferred_exidx_sections[i]; elfcpp::Shdr<32, big_endian> shdr(pshdrs + shndx * shdr_size); - unsigned int text_shndx; + unsigned int text_shndx = elfcpp::SHN_UNDEF; Reloc_map::const_iterator it = reloc_map.find(shndx); - if (it != reloc_map.end() - && find_linked_text_section(pshdrs + it->second * shdr_size, - psyms, &text_shndx)) - this->make_exidx_input_section(shndx, shdr, text_shndx); - else - gold_error(_("EXIDX section %u has no linked text section."), - shndx); + if (it != reloc_map.end()) + find_linked_text_section(pshdrs + it->second * shdr_size, + psyms, &text_shndx); + elfcpp::Shdr<32, big_endian> text_shdr(pshdrs + + text_shndx * shdr_size); + this->make_exidx_input_section(shndx, shdr, text_shndx, text_shdr); } } } @@ -7672,6 +7781,72 @@ Target_arm::Scan::unsupported_reloc_global( object->name().c_str(), r_type, gsym->demangled_name().c_str()); } +template +inline bool +Target_arm::Scan::possible_function_pointer_reloc( + unsigned int r_type) +{ + switch (r_type) + { + case elfcpp::R_ARM_PC24: + case elfcpp::R_ARM_THM_CALL: + case elfcpp::R_ARM_PLT32: + case elfcpp::R_ARM_CALL: + case elfcpp::R_ARM_JUMP24: + case elfcpp::R_ARM_THM_JUMP24: + case elfcpp::R_ARM_SBREL31: + case elfcpp::R_ARM_PREL31: + case elfcpp::R_ARM_THM_JUMP19: + case elfcpp::R_ARM_THM_JUMP6: + case elfcpp::R_ARM_THM_JUMP11: + case elfcpp::R_ARM_THM_JUMP8: + // All the relocations above are branches except SBREL31 and PREL31. + return false; + + default: + // Be conservative and assume this is a function pointer. + return true; + } +} + +template +inline bool +Target_arm::Scan::local_reloc_may_be_function_pointer( + Symbol_table*, + Layout*, + Target_arm* target, + Sized_relobj<32, big_endian>*, + unsigned int, + Output_section*, + const elfcpp::Rel<32, big_endian>&, + unsigned int r_type, + const elfcpp::Sym<32, big_endian>&) +{ + r_type = target->get_real_reloc_type(r_type); + return possible_function_pointer_reloc(r_type); +} + +template +inline bool +Target_arm::Scan::global_reloc_may_be_function_pointer( + Symbol_table*, + Layout*, + Target_arm* target, + Sized_relobj<32, big_endian>*, + unsigned int, + Output_section*, + const elfcpp::Rel<32, big_endian>&, + unsigned int r_type, + Symbol* gsym) +{ + // GOT is not a function. + if (strcmp(gsym->name(), "_GLOBAL_OFFSET_TABLE_") == 0) + return false; + + r_type = target->get_real_reloc_type(r_type); + return possible_function_pointer_reloc(r_type); +} + // Scan a relocation for a global symbol. template @@ -8090,6 +8265,7 @@ Target_arm::do_finalize_sections( if (this->attributes_section_data_ == NULL) this->attributes_section_data_ = new Attributes_section_data(NULL, 0); + bool merged_any_attributes = false; // Merge processor-specific flags. for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); p != input_objects->relobj_end(); @@ -8104,6 +8280,7 @@ Target_arm::do_finalize_sections( arm_relobj->processor_specific_flags()); this->merge_object_attributes(arm_relobj->name().c_str(), arm_relobj->attributes_section_data()); + merged_any_attributes = true; } } @@ -8118,6 +8295,7 @@ Target_arm::do_finalize_sections( arm_dynobj->processor_specific_flags()); this->merge_object_attributes(arm_dynobj->name().c_str(), arm_dynobj->attributes_section_data()); + merged_any_attributes = true; } // Check BLX use. @@ -8193,9 +8371,9 @@ Target_arm::do_finalize_sections( } } - // Create an .ARM.attributes section unless we have no regular input - // object. In that case the output will be empty. - if (input_objects->number_of_relobjs() != 0) + // Create an .ARM.attributes section if we have merged any attributes + // from inputs. + if (merged_any_attributes) { Output_attributes_section_data* attributes_section = new Output_attributes_section_data(*this->attributes_section_data_); @@ -8204,6 +8382,17 @@ Target_arm::do_finalize_sections( attributes_section, false, false, false, false); } + + // Fix up links in section EXIDX headers. + for (Layout::Section_list::const_iterator p = layout->section_list().begin(); + p != layout->section_list().end(); + ++p) + if ((*p)->type() == elfcpp::SHT_ARM_EXIDX) + { + Arm_output_section* os = + Arm_output_section::as_arm_output_section(*p); + os->set_exidx_section_link(); + } } // Return whether a direct absolute static relocation needs to be applied. @@ -8306,6 +8495,13 @@ Target_arm::Relocate::relocate( // be converted into an NOP. is_weakly_undefined_without_plt = true; } + else if (gsym->is_undefined() && reloc_property->uses_symbol()) + { + // This relocation uses the symbol value but the symbol is + // undefined. Exit early and have the caller reporting an + // error. + return true; + } else { // Set thumb bit if symbol: @@ -10760,12 +10956,6 @@ Target_arm::do_relax( bool stubs_always_after_branch = stub_group_size_param < 0; section_size_type stub_group_size = abs(stub_group_size_param); - // The Cortex-A8 erratum fix depends on stubs not being in the same 4K - // page as the first half of a 32-bit branch straddling two 4K pages. - // This is a crude way of enforcing that. - if (this->fix_cortex_a8_) - stubs_always_after_branch = true; - if (stub_group_size == 1) { // Default value. @@ -10775,25 +10965,51 @@ Target_arm::do_relax( // fixing cortex-a8 errata, the branch range has to be even smaller, // since wide conditional branch has a range of +-1MB only. // - // This value is 24K less than that, which allows for 2025 + // This value is 48K less than that, which allows for 4096 // 12-byte stubs. If we exceed that, then we will fail to link. // The user will have to relink with an explicit group size // option. - if (this->fix_cortex_a8_) - stub_group_size = 1024276; - else - stub_group_size = 4170000; + stub_group_size = 4145152; + } + + // The Cortex-A8 erratum fix depends on stubs not being in the same 4K + // page as the first half of a 32-bit branch straddling two 4K pages. + // This is a crude way of enforcing that. In addition, long conditional + // branches of THUMB-2 have a range of +-1M. If we are fixing cortex-A8 + // erratum, limit the group size to (1M - 12k) to avoid unreachable + // cortex-A8 stubs from long conditional branches. + if (this->fix_cortex_a8_) + { + stubs_always_after_branch = true; + const section_size_type cortex_a8_group_size = 1024 * (1024 - 12); + stub_group_size = std::max(stub_group_size, cortex_a8_group_size); } group_sections(layout, stub_group_size, stubs_always_after_branch); // Also fix .ARM.exidx section coverage. - Output_section* os = layout->find_output_section(".ARM.exidx"); - if (os != NULL && os->type() == elfcpp::SHT_ARM_EXIDX) + Arm_output_section* exidx_output_section = NULL; + for (Layout::Section_list::const_iterator p = + layout->section_list().begin(); + p != layout->section_list().end(); + ++p) + if ((*p)->type() == elfcpp::SHT_ARM_EXIDX) + { + if (exidx_output_section == NULL) + exidx_output_section = + Arm_output_section::as_arm_output_section(*p); + else + // We cannot handle this now. + gold_error(_("multiple SHT_ARM_EXIDX sections %s and %s in a " + "non-relocatable link"), + exidx_output_section->name(), + (*p)->name()); + } + + if (exidx_output_section != NULL) { - Arm_output_section* exidx_output_section = - Arm_output_section::as_arm_output_section(os); - this->fix_exidx_coverage(layout, exidx_output_section, symtab); + this->fix_exidx_coverage(layout, input_objects, exidx_output_section, + symtab); done_exidx_fixup = true; } } @@ -11244,6 +11460,7 @@ template void Target_arm::fix_exidx_coverage( Layout* layout, + const Input_objects* input_objects, Arm_output_section* exidx_section, Symbol_table* symtab) { @@ -11256,15 +11473,30 @@ Target_arm::fix_exidx_coverage( typedef std::set Sorted_output_section_list; Sorted_output_section_list sorted_output_sections; - Layout::Section_list section_list; - layout->get_allocated_sections(§ion_list); - for (Layout::Section_list::const_iterator p = section_list.begin(); - p != section_list.end(); + + // Find out all the output sections of input sections pointed by + // EXIDX input sections. + for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); + p != input_objects->relobj_end(); ++p) { - // We only care about output sections that contain executable code. - if (((*p)->flags() & elfcpp::SHF_EXECINSTR) != 0) - sorted_output_sections.insert(*p); + Arm_relobj* arm_relobj = + Arm_relobj::as_arm_relobj(*p); + std::vector shndx_list; + arm_relobj->get_exidx_shndx_list(&shndx_list); + for (size_t i = 0; i < shndx_list.size(); ++i) + { + const Arm_exidx_input_section* exidx_input_section = + arm_relobj->exidx_input_section_by_shndx(shndx_list[i]); + gold_assert(exidx_input_section != NULL); + if (!exidx_input_section->has_errors()) + { + unsigned int text_shndx = exidx_input_section->link(); + Output_section *os = arm_relobj->output_section(text_shndx); + if (os != NULL && (os->flags() & elfcpp::SHF_ALLOC) != 0) + sorted_output_sections.insert(os); + } + } } // Go over the output sections in ascending order of output addresses. diff --git a/binutils-2.19/gold/gc.h b/binutils-2.19/gold/gc.h index b79bd77..77ac6da 100644 --- a/binutils-2.19/gold/gc.h +++ b/binutils-2.19/gold/gc.h @@ -228,14 +228,14 @@ gc_process_relocs( unsigned int shndx = lsym.get_st_shndx(); bool is_ordinary; shndx = src_obj->adjust_sym_shndx(r_sym, shndx, &is_ordinary); - if (!is_ordinary) - continue; dst_obj = src_obj; dst_indx = shndx; - Section_id dst_id(dst_obj, dst_indx); if (is_icf_tracked) { - (*secvec).push_back(dst_id); + if (is_ordinary) + (*secvec).push_back(Section_id(dst_obj, dst_indx)); + else + (*secvec).push_back(Section_id(NULL, 0)); (*symvec).push_back(NULL); long long symvalue = static_cast(lsym.get_st_value()); (*addendvec).push_back(std::make_pair(symvalue, @@ -247,7 +247,8 @@ gc_process_relocs( // When doing safe folding, check to see if this relocation is that // of a function pointer being taken. - if (check_section_for_function_pointers + if (is_ordinary + && check_section_for_function_pointers && lsym.get_st_type() != elfcpp::STT_OBJECT && scan.local_reloc_may_be_function_pointer(symtab, NULL, NULL, src_obj, src_indx, @@ -256,7 +257,7 @@ gc_process_relocs( symtab->icf()->set_section_has_function_pointers( src_obj, lsym.get_st_shndx()); - if (shndx == src_indx) + if (!is_ordinary || shndx == src_indx) continue; } else @@ -265,16 +266,20 @@ gc_process_relocs( gold_assert(gsym != NULL); if (gsym->is_forwarder()) gsym = symtab->resolve_forwards(gsym); - if (gsym->source() != Symbol::FROM_OBJECT) - continue; - bool is_ordinary; - dst_obj = gsym->object(); - dst_indx = gsym->shndx(&is_ordinary); - Section_id dst_id(dst_obj, dst_indx); + + dst_obj = NULL; + dst_indx = 0; + bool is_ordinary = false; + if (gsym->source() == Symbol::FROM_OBJECT) + { + dst_obj = gsym->object(); + dst_indx = gsym->shndx(&is_ordinary); + } // When doing safe folding, check to see if this relocation is that // of a function pointer being taken. - if (check_section_for_function_pointers + if (gsym->source() == Symbol::FROM_OBJECT + && check_section_for_function_pointers && gsym->type() != elfcpp::STT_OBJECT && (!is_ordinary || scan.global_reloc_may_be_function_pointer( @@ -282,9 +287,6 @@ gc_process_relocs( r_type, gsym))) symtab->icf()->set_section_has_function_pointers(dst_obj, dst_indx); - if (!is_ordinary) - continue; - // If the symbol name matches '__start_XXX' then the section with // the C identifier like name 'XXX' should not be garbage collected. // A similar treatment to symbols with the name '__stop_XXX'. @@ -300,7 +302,10 @@ gc_process_relocs( } if (is_icf_tracked) { - (*secvec).push_back(dst_id); + if (is_ordinary && gsym->source() == Symbol::FROM_OBJECT) + (*secvec).push_back(Section_id(dst_obj, dst_indx)); + else + (*secvec).push_back(Section_id(NULL, 0)); (*symvec).push_back(gsym); Sized_symbol* sized_gsym = static_cast* >(gsym); @@ -312,6 +317,11 @@ gc_process_relocs( convert_to_section_size_type(reloc.get_r_offset()); (*offsetvec).push_back(reloc_offset); } + + if (gsym->source() != Symbol::FROM_OBJECT) + continue; + if (!is_ordinary) + continue; } if (parameters->options().gc_sections()) { diff --git a/binutils-2.19/gold/i386.cc b/binutils-2.19/gold/i386.cc index eb4ef0a..e7b700c 100644 --- a/binutils-2.19/gold/i386.cc +++ b/binutils-2.19/gold/i386.cc @@ -64,6 +64,10 @@ class Target_i386 : public Target_freebsd<32, false> got_mod_index_offset_(-1U), tls_base_symbol_defined_(false) { } + inline bool + can_check_for_function_pointers() const + { return true; } + // Process the relocations to determine unreferenced sections for // garbage collection. void @@ -203,24 +207,27 @@ class Target_i386 : public Target_freebsd<32, false> Symbol* gsym); inline bool - local_reloc_may_be_function_pointer(Symbol_table* , Layout* , Target_i386* , - Sized_relobj<32, false>* , - unsigned int , - Output_section* , - const elfcpp::Rel<32, false>& , - unsigned int , - const elfcpp::Sym<32, false>&) - { return false; } + local_reloc_may_be_function_pointer(Symbol_table* symtab, Layout* layout, + Target_i386* target, + Sized_relobj<32, false>* object, + unsigned int data_shndx, + Output_section* output_section, + const elfcpp::Rel<32, false>& reloc, + unsigned int r_type, + const elfcpp::Sym<32, false>& lsym); + + inline bool + global_reloc_may_be_function_pointer(Symbol_table* symtab, Layout* layout, + Target_i386* target, + Sized_relobj<32, false>* object, + unsigned int data_shndx, + Output_section* output_section, + const elfcpp::Rel<32, false>& reloc, + unsigned int r_type, + Symbol* gsym); inline bool - global_reloc_may_be_function_pointer(Symbol_table* , Layout* , - Target_i386* , - Sized_relobj<32, false>* , - unsigned int , - Output_section* , - const elfcpp::Rel<32, false>& , - unsigned int , Symbol*) - { return false; } + possible_function_pointer_reloc(unsigned int r_type); static void unsupported_reloc_local(Sized_relobj<32, false>*, unsigned int r_type); @@ -1234,6 +1241,55 @@ Target_i386::Scan::unsupported_reloc_global(Sized_relobj<32, false>* object, object->name().c_str(), r_type, gsym->demangled_name().c_str()); } +inline bool +Target_i386::Scan::possible_function_pointer_reloc(unsigned int r_type) +{ + switch (r_type) + { + case elfcpp::R_386_32: + case elfcpp::R_386_16: + case elfcpp::R_386_8: + case elfcpp::R_386_GOTOFF: + case elfcpp::R_386_GOT32: + { + return true; + } + default: + return false; + } + return false; +} + +inline bool +Target_i386::Scan::local_reloc_may_be_function_pointer( + Symbol_table* , + Layout* , + Target_i386* , + Sized_relobj<32, false>* , + unsigned int , + Output_section* , + const elfcpp::Rel<32, false>& , + unsigned int r_type, + const elfcpp::Sym<32, false>&) +{ + return possible_function_pointer_reloc(r_type); +} + +inline bool +Target_i386::Scan::global_reloc_may_be_function_pointer( + Symbol_table* , + Layout* , + Target_i386* , + Sized_relobj<32, false>* , + unsigned int , + Output_section* , + const elfcpp::Rel<32, false>& , + unsigned int r_type, + Symbol*) +{ + return possible_function_pointer_reloc(r_type); +} + // Scan a relocation for a global symbol. inline void diff --git a/binutils-2.19/gold/icf.cc b/binutils-2.19/gold/icf.cc index ff2058c..47b6c60 100644 --- a/binutils-2.19/gold/icf.cc +++ b/binutils-2.19/gold/icf.cc @@ -263,8 +263,11 @@ get_section_contents(bool first_iteration, { Icf::Sections_reachable_info v = (it_reloc_info_list->second).section_info; + // Stores the information of the symbol pointed to by the reloc. Icf::Symbol_info s = (it_reloc_info_list->second).symbol_info; + // Stores the addend and the symbol value. Icf::Addend_info a = (it_reloc_info_list->second).addend_info; + // Stores the offset of the reloc. Icf::Offset_info o = (it_reloc_info_list->second).offset_info; Icf::Sections_reachable_info::iterator it_v = v.begin(); Icf::Symbol_info::iterator it_s = s.begin(); @@ -285,6 +288,24 @@ get_section_contents(bool first_iteration, static_cast((*it_a).first), static_cast((*it_a).second), static_cast(*it_o)); + + // If the symbol pointed to by the reloc is not in an ordinary + // section or if the symbol type is not FROM_OBJECT, then the + // object is NULL. + if (it_v->first == NULL) + { + if (first_iteration) + { + // If the symbol name is available, use it. + if ((*it_s) != NULL) + buffer.append((*it_s)->name()); + // Append the addend. + buffer.append(addend_str); + buffer.append("@"); + } + continue; + } + Section_id reloc_secn(it_v->first, it_v->second); // If this reloc turns back and points to the same section, @@ -304,7 +325,12 @@ get_section_contents(bool first_iteration, symtab->icf()->section_to_int_map(); Icf::Uniq_secn_id_map::iterator section_id_map_it = section_id_map.find(reloc_secn); - if (section_id_map_it != section_id_map.end()) + bool is_sym_preemptible = (*it_s != NULL + && !(*it_s)->is_from_dynobj() + && !(*it_s)->is_undefined() + && (*it_s)->is_preemptible()); + if (!is_sym_preemptible + && section_id_map_it != section_id_map.end()) { // This is a reloc to a section that might be folded. if (num_tracked_relocs) @@ -338,7 +364,14 @@ get_section_contents(bool first_iteration, { uint64_t entsize = (it_v->first)->section_entsize(it_v->second); - long long offset = it_a->first + it_a->second; + long long offset = it_a->first; + + unsigned long long addend = it_a->second; + // Ignoring the addend when it is a negative value. See the + // comments in Merged_symbol_value::Value in object.h. + if (addend < 0xffffff00) + offset = offset + addend; + section_size_type secn_len; const unsigned char* str_contents = (it_v->first)->section_contents(it_v->second, @@ -389,12 +422,12 @@ get_section_contents(bool first_iteration, char*>(str_contents), entsize); } + buffer.append("@"); } else if ((*it_s) != NULL) { // If symbol name is available use that. - const char *sym_name = (*it_s)->name(); - buffer.append(sym_name); + buffer.append((*it_s)->name()); // Append the addend. buffer.append(addend_str); buffer.append("@"); diff --git a/binutils-2.19/gold/icf.h b/binutils-2.19/gold/icf.h index c1db8e5..c968c9d 100644 --- a/binutils-2.19/gold/icf.h +++ b/binutils-2.19/gold/icf.h @@ -121,13 +121,13 @@ class Icf // corresponding to taken function pointers. Ignores eh_frame // and vtable sections. inline bool - check_section_for_function_pointers(std::string section_name, + check_section_for_function_pointers(const std::string& section_name, Target* target) { return (parameters->options().icf_safe_folding() && target->can_check_for_function_pointers() - && !is_prefix_of(".rodata._ZTV", section_name.c_str()) - && !is_prefix_of(".eh_frame", section_name.c_str())); + && target->section_may_have_icf_unsafe_pointers( + section_name.c_str())); } // Returns a map of a section to info (Reloc_info) about its relocations. diff --git a/binutils-2.19/gold/output.cc b/binutils-2.19/gold/output.cc index dbdad78..280b125 100644 --- a/binutils-2.19/gold/output.cc +++ b/binutils-2.19/gold/output.cc @@ -1944,6 +1944,7 @@ Output_section::Output_section(const char* name, elfcpp::Elf_Word type, is_entsize_zero_(false), section_offsets_need_adjustment_(false), is_noload_(false), + always_keeps_input_sections_(false), tls_offset_(0), checkpoint_(NULL), lookup_maps_(new Output_section_lookup_maps) @@ -2032,8 +2033,10 @@ Output_section::add_input_section(Sized_relobj* object, { // Keep information about merged input sections for rebuilding fast // lookup maps if we have sections-script or we do relaxation. - bool keeps_input_sections = - have_sections_script || parameters->target().may_relax(); + bool keeps_input_sections = (this->always_keeps_input_sections_ + || have_sections_script + || parameters->target().may_relax()); + if (this->add_merge_input_section(object, shndx, sh_flags, entsize, addralign, keeps_input_sections)) { @@ -2087,7 +2090,8 @@ Output_section::add_input_section(Sized_relobj* object, // track of sections, or if we are relaxing. Also, if this is a // section which requires sorting, or which may require sorting in // the future, we keep track of the sections. - if (have_sections_script + if (this->always_keeps_input_sections_ + || have_sections_script || !this->input_sections_.empty() || this->may_sort_attached_input_sections() || this->must_sort_attached_input_sections() diff --git a/binutils-2.19/gold/output.h b/binutils-2.19/gold/output.h index da321b6..28bcb65 100644 --- a/binutils-2.19/gold/output.h +++ b/binutils-2.19/gold/output.h @@ -3437,6 +3437,19 @@ class Output_section : public Output_data input_sections() const { return this->input_sections_; } + // Whether this always keeps an input section list + bool + always_keeps_input_sections() const + { return this->always_keeps_input_sections_; } + + // Always keep an input section list. + void + set_always_keeps_input_sections() + { + gold_assert(this->current_data_size_for_child() == 0); + this->always_keeps_input_sections_ = true; + } + private: // We only save enough information to undo the effects of section layout. class Checkpoint_output_section @@ -3741,6 +3754,8 @@ class Output_section : public Output_data bool section_offsets_need_adjustment_ : 1; // Whether this is a NOLOAD section. bool is_noload_ : 1; + // Whether this always keeps input section. + bool always_keeps_input_sections_ : 1; // For SHT_TLS sections, the offset of this section relative to the base // of the TLS segment. uint64_t tls_offset_; diff --git a/binutils-2.19/gold/symtab.cc b/binutils-2.19/gold/symtab.cc index c2a811f..416a07c 100644 --- a/binutils-2.19/gold/symtab.cc +++ b/binutils-2.19/gold/symtab.cc @@ -306,7 +306,7 @@ Sized_symbol::allocate_common(Output_data* od, Value_type value) // table. inline bool -Symbol::should_add_dynsym_entry() const +Symbol::should_add_dynsym_entry(Symbol_table* symtab) const { // If the symbol is used by a dynamic relocation, we need to add it. if (this->needs_dynsym_entry()) @@ -324,7 +324,8 @@ Symbol::should_add_dynsym_entry() const bool is_ordinary; unsigned int shndx = this->shndx(&is_ordinary); if (is_ordinary && shndx != elfcpp::SHN_UNDEF - && !relobj->is_section_included(shndx)) + && !relobj->is_section_included(shndx) + && !symtab->is_section_folded(relobj, shndx)) return false; } @@ -1072,7 +1073,8 @@ Symbol_table::add_from_relobj( bool is_defined_in_discarded_section = false; if (st_shndx != elfcpp::SHN_UNDEF && is_ordinary - && !relobj->is_section_included(st_shndx)) + && !relobj->is_section_included(st_shndx) + && !this->is_section_folded(relobj, st_shndx)) { st_shndx = elfcpp::SHN_UNDEF; is_defined_in_discarded_section = true; @@ -2253,7 +2255,7 @@ Symbol_table::set_dynsym_indexes(unsigned int index, // some symbols appear more than once in the symbol table, with // and without a version. - if (!sym->should_add_dynsym_entry()) + if (!sym->should_add_dynsym_entry(this)) sym->set_dynsym_index(-1U); else if (!sym->has_dynsym_index()) { diff --git a/binutils-2.19/gold/symtab.h b/binutils-2.19/gold/symtab.h index 1a81fd1..4a97461 100644 --- a/binutils-2.19/gold/symtab.h +++ b/binutils-2.19/gold/symtab.h @@ -274,7 +274,7 @@ class Symbol // Return whether this symbol should be added to the dynamic symbol // table. bool - should_add_dynsym_entry() const; + should_add_dynsym_entry(Symbol_table*) const; // Return whether this symbol has been seen in a regular object. bool diff --git a/binutils-2.19/gold/target-reloc.h b/binutils-2.19/gold/target-reloc.h index 0bd060b..34c13e8 100644 --- a/binutils-2.19/gold/target-reloc.h +++ b/binutils-2.19/gold/target-reloc.h @@ -83,7 +83,8 @@ scan_relocs( shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary); if (is_ordinary && shndx != elfcpp::SHN_UNDEF - && !object->is_section_included(shndx)) + && !object->is_section_included(shndx) + && !symtab->is_section_folded(object, shndx)) { // RELOC is a relocation against a local symbol in a // section we are discarding. We can ignore this @@ -102,7 +103,6 @@ scan_relocs( continue; } - scan.local(symtab, layout, target, object, data_shndx, output_section, reloc, r_type, lsym); } diff --git a/binutils-2.19/gold/target.h b/binutils-2.19/gold/target.h index 02cbee2..563a365 100644 --- a/binutils-2.19/gold/target.h +++ b/binutils-2.19/gold/target.h @@ -71,6 +71,20 @@ class Target can_check_for_function_pointers() const { return false; } + // Whether a section called SECTION_NAME may have function pointers to + // sections not eligible for safe ICF folding. + virtual bool + section_may_have_icf_unsafe_pointers(const char* section_name) const + { + // We recognize sections for normal vtables, construction vtables and + // EH frames. + return (!is_prefix_of(".rodata._ZTV", section_name) + && !is_prefix_of(".data.rel.ro._ZTV", section_name) + && !is_prefix_of(".rodata._ZTC", section_name) + && !is_prefix_of(".data.rel.ro._ZTC", section_name) + && !is_prefix_of(".eh_frame", section_name)); + } + // Return the bit size that this target implements. This should // return 32 or 64. int diff --git a/binutils-2.19/gold/testsuite/Makefile.am b/binutils-2.19/gold/testsuite/Makefile.am index 34abf89..764ec26 100644 --- a/binutils-2.19/gold/testsuite/Makefile.am +++ b/binutils-2.19/gold/testsuite/Makefile.am @@ -193,6 +193,33 @@ icf_safe_so_test_1.stdout: icf_safe_so_test icf_safe_so_test_2.stdout: icf_safe_so_test $(TEST_READELF) -h icf_safe_so_test > icf_safe_so_test_2.stdout +check_PROGRAMS += icf_virtual_function_folding_test +MOSTLYCLEANFILES += icf_virtual_function_folding_test +icf_virtual_function_folding_test.o: icf_virtual_function_folding_test.cc + $(CXXCOMPILE) -O0 -c -ffunction-sections -fPIE -g -o $@ $< +icf_virtual_function_folding_test: icf_virtual_function_folding_test.o gcctestdir/ld + $(CXXLINK) -Bgcctestdir/ -Wl,--icf=all icf_virtual_function_folding_test.o -pie + +check_SCRIPTS += icf_preemptible_functions_test.sh +check_DATA += icf_preemptible_functions_test.stdout +MOSTLYCLEANFILES += icf_preemptible_functions_test +icf_preemptible_functions_test.o: icf_preemptible_functions_test.cc + $(CXXCOMPILE) -O0 -c -ffunction-sections -fPIC -g -o $@ $< +icf_preemptible_functions_test: icf_preemptible_functions_test.o gcctestdir/ld + $(CXXLINK) -Bgcctestdir/ -Wl,--icf=all icf_preemptible_functions_test.o -fPIC -shared +icf_preemptible_functions_test.stdout: icf_preemptible_functions_test + $(TEST_NM) icf_preemptible_functions_test > icf_preemptible_functions_test.stdout + +check_SCRIPTS += icf_string_merge_test.sh +check_DATA += icf_string_merge_test.stdout +MOSTLYCLEANFILES += icf_string_merge_test +icf_string_merge_test.o: icf_string_merge_test.cc + $(CXXCOMPILE) -O0 -c -ffunction-sections -fPIC -g -o $@ $< +icf_string_merge_test: icf_string_merge_test.o gcctestdir/ld + $(CXXLINK) -Bgcctestdir/ -Wl,--icf=all icf_string_merge_test.o +icf_string_merge_test.stdout: icf_string_merge_test + $(TEST_NM) icf_string_merge_test > icf_string_merge_test.stdout + check_PROGRAMS += basic_test check_PROGRAMS += basic_static_test check_PROGRAMS += basic_pic_test diff --git a/binutils-2.19/gold/testsuite/Makefile.in b/binutils-2.19/gold/testsuite/Makefile.in index 8815bc3..bc92bb4 100644 --- a/binutils-2.19/gold/testsuite/Makefile.in +++ b/binutils-2.19/gold/testsuite/Makefile.in @@ -62,6 +62,8 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_keep_unique_test.sh \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_test.sh \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_so_test.sh \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_preemptible_functions_test.sh \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_string_merge_test.sh \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared.sh weak_plt.sh \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg.sh undef_symbol.sh \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ ver_test_1.sh ver_test_2.sh \ @@ -91,6 +93,8 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_test_2.stdout \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_so_test_1.stdout \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_so_test_2.stdout \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_preemptible_functions_test.stdout \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_string_merge_test.stdout \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared.dbg \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ weak_plt_shared.so debug_msg.err \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ debug_msg_so.err \ @@ -112,10 +116,14 @@ check_PROGRAMS = object_unittest$(EXEEXT) binary_unittest$(EXEEXT) \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ gc_orphan_section_test icf_test \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_keep_unique_test \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_safe_test icf_safe_so_test \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_virtual_function_folding_test \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_preemptible_functions_test \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ icf_string_merge_test \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ two_file_shared.dbg \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ alt/weak_undef_lib.so -@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_4 = basic_test \ -@GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_static_test basic_pic_test \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@am__append_4 = icf_virtual_function_folding_test \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_test basic_static_test \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_pic_test \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_static_pic_test \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_pie_test constructor_test \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ constructor_static_test \ @@ -381,7 +389,8 @@ libgoldtest_a_LIBADD = am_libgoldtest_a_OBJECTS = test.$(OBJEXT) testmain.$(OBJEXT) \ testfile.$(OBJEXT) libgoldtest_a_OBJECTS = $(am_libgoldtest_a_OBJECTS) -@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_1 = basic_test$(EXEEXT) \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@am__EXEEXT_1 = icf_virtual_function_folding_test$(EXEEXT) \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_test$(EXEEXT) \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_static_test$(EXEEXT) \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_pic_test$(EXEEXT) \ @GCC_TRUE@@NATIVE_LINKER_TRUE@ basic_static_pic_test$(EXEEXT) \ @@ -653,6 +662,14 @@ flagstest_o_specialfile_and_compress_debug_sections_DEPENDENCIES = \ libgoldtest.a ../libgold.a ../../libiberty/libiberty.a \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) +icf_virtual_function_folding_test_SOURCES = \ + icf_virtual_function_folding_test.c +icf_virtual_function_folding_test_OBJECTS = \ + icf_virtual_function_folding_test.$(OBJEXT) +icf_virtual_function_folding_test_LDADD = $(LDADD) +icf_virtual_function_folding_test_DEPENDENCIES = libgoldtest.a \ + ../libgold.a ../../libiberty/libiberty.a $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am__initpri1_SOURCES_DIST = initpri1.c @CONSTRUCTOR_PRIORITY_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@am_initpri1_OBJECTS = initpri1.$(OBJEXT) initpri1_OBJECTS = $(am_initpri1_OBJECTS) @@ -1142,12 +1159,12 @@ SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c basic_pie_test.c \ $(exclude_libs_test_SOURCES) \ flagstest_compress_debug_sections.c flagstest_o_specialfile.c \ flagstest_o_specialfile_and_compress_debug_sections.c \ - $(initpri1_SOURCES) $(justsyms_SOURCES) $(large_SOURCES) \ - local_labels_test.c many_sections_r_test.c \ - $(many_sections_test_SOURCES) $(object_unittest_SOURCES) \ - permission_test.c plugin_test_1.c plugin_test_2.c \ - plugin_test_3.c plugin_test_4.c plugin_test_5.c \ - $(protected_1_SOURCES) $(protected_2_SOURCES) \ + icf_virtual_function_folding_test.c $(initpri1_SOURCES) \ + $(justsyms_SOURCES) $(large_SOURCES) local_labels_test.c \ + many_sections_r_test.c $(many_sections_test_SOURCES) \ + $(object_unittest_SOURCES) permission_test.c plugin_test_1.c \ + plugin_test_2.c plugin_test_3.c plugin_test_4.c \ + plugin_test_5.c $(protected_1_SOURCES) $(protected_2_SOURCES) \ $(relro_script_test_SOURCES) $(relro_test_SOURCES) \ $(script_test_1_SOURCES) $(script_test_2_SOURCES) \ script_test_3.c $(searched_file_test_SOURCES) \ @@ -1201,6 +1218,7 @@ DIST_SOURCES = $(libgoldtest_a_SOURCES) basic_pic_test.c \ $(am__exclude_libs_test_SOURCES_DIST) \ flagstest_compress_debug_sections.c flagstest_o_specialfile.c \ flagstest_o_specialfile_and_compress_debug_sections.c \ + icf_virtual_function_folding_test.c \ $(am__initpri1_SOURCES_DIST) $(am__justsyms_SOURCES_DIST) \ $(am__large_SOURCES_DIST) local_labels_test.c \ many_sections_r_test.c $(am__many_sections_test_SOURCES_DIST) \ @@ -1361,7 +1379,9 @@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ +install_as_default = @install_as_default@ install_sh = @install_sh@ +installed_linker = @installed_linker@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ @@ -1942,6 +1962,12 @@ exclude_libs_test$(EXEEXT): $(exclude_libs_test_OBJECTS) $(exclude_libs_test_DEP @NATIVE_LINKER_FALSE@flagstest_o_specialfile_and_compress_debug_sections$(EXEEXT): $(flagstest_o_specialfile_and_compress_debug_sections_OBJECTS) $(flagstest_o_specialfile_and_compress_debug_sections_DEPENDENCIES) @NATIVE_LINKER_FALSE@ @rm -f flagstest_o_specialfile_and_compress_debug_sections$(EXEEXT) @NATIVE_LINKER_FALSE@ $(LINK) $(flagstest_o_specialfile_and_compress_debug_sections_OBJECTS) $(flagstest_o_specialfile_and_compress_debug_sections_LDADD) $(LIBS) +@GCC_FALSE@icf_virtual_function_folding_test$(EXEEXT): $(icf_virtual_function_folding_test_OBJECTS) $(icf_virtual_function_folding_test_DEPENDENCIES) +@GCC_FALSE@ @rm -f icf_virtual_function_folding_test$(EXEEXT) +@GCC_FALSE@ $(LINK) $(icf_virtual_function_folding_test_OBJECTS) $(icf_virtual_function_folding_test_LDADD) $(LIBS) +@NATIVE_LINKER_FALSE@icf_virtual_function_folding_test$(EXEEXT): $(icf_virtual_function_folding_test_OBJECTS) $(icf_virtual_function_folding_test_DEPENDENCIES) +@NATIVE_LINKER_FALSE@ @rm -f icf_virtual_function_folding_test$(EXEEXT) +@NATIVE_LINKER_FALSE@ $(LINK) $(icf_virtual_function_folding_test_OBJECTS) $(icf_virtual_function_folding_test_LDADD) $(LIBS) initpri1$(EXEEXT): $(initpri1_OBJECTS) $(initpri1_DEPENDENCIES) @rm -f initpri1$(EXEEXT) $(initpri1_LINK) $(initpri1_OBJECTS) $(initpri1_LDADD) $(LIBS) @@ -2231,6 +2257,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flagstest_compress_debug_sections.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flagstest_o_specialfile.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flagstest_o_specialfile_and_compress_debug_sections.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/icf_virtual_function_folding_test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/initpri1.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/justsyms_1.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/large-large.Po@am__quote@ @@ -2696,6 +2723,22 @@ uninstall-am: @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) icf_safe_so_test > icf_safe_so_test_1.stdout @GCC_TRUE@@NATIVE_LINKER_TRUE@icf_safe_so_test_2.stdout: icf_safe_so_test @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_READELF) -h icf_safe_so_test > icf_safe_so_test_2.stdout +@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_virtual_function_folding_test.o: icf_virtual_function_folding_test.cc +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -fPIE -g -o $@ $< +@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_virtual_function_folding_test: icf_virtual_function_folding_test.o gcctestdir/ld +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--icf=all icf_virtual_function_folding_test.o -pie +@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_preemptible_functions_test.o: icf_preemptible_functions_test.cc +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -fPIC -g -o $@ $< +@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_preemptible_functions_test: icf_preemptible_functions_test.o gcctestdir/ld +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--icf=all icf_preemptible_functions_test.o -fPIC -shared +@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_preemptible_functions_test.stdout: icf_preemptible_functions_test +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) icf_preemptible_functions_test > icf_preemptible_functions_test.stdout +@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_string_merge_test.o: icf_string_merge_test.cc +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -ffunction-sections -fPIC -g -o $@ $< +@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_string_merge_test: icf_string_merge_test.o gcctestdir/ld +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXLINK) -Bgcctestdir/ -Wl,--icf=all icf_string_merge_test.o +@GCC_TRUE@@NATIVE_LINKER_TRUE@icf_string_merge_test.stdout: icf_string_merge_test +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(TEST_NM) icf_string_merge_test > icf_string_merge_test.stdout @GCC_TRUE@@NATIVE_LINKER_TRUE@basic_test.o: basic_test.cc @GCC_TRUE@@NATIVE_LINKER_TRUE@ $(CXXCOMPILE) -O0 -c -o $@ $< @GCC_TRUE@@NATIVE_LINKER_TRUE@basic_test: basic_test.o gcctestdir/ld diff --git a/binutils-2.19/gold/testsuite/icf_preemptible_functions_test.cc b/binutils-2.19/gold/testsuite/icf_preemptible_functions_test.cc new file mode 100644 index 0000000..35a96bc --- /dev/null +++ b/binutils-2.19/gold/testsuite/icf_preemptible_functions_test.cc @@ -0,0 +1,47 @@ +// icf_preemptible_functions_test.cc -- a test case for gold + +// Copyright 2010 Free Software Foundation, Inc. +// Written by Sriraman Tallam . + +// This file is part of gold. + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +// MA 02110-1301, USA. + +// The goal of this program is to verify that preemptible functions are +// correctly handled by ICF. In this program, foo and bar should not +// be folded although they are identical as zap or zip could be preempted. + +int zap() +{ + return 0; +} + +int zip() +{ + return 0; +} + +int foo() +{ + zap(); + return 0; +} + +int bar() +{ + zip(); + return 0; +} diff --git a/binutils-2.19/gold/testsuite/icf_preemptible_functions_test.sh b/binutils-2.19/gold/testsuite/icf_preemptible_functions_test.sh new file mode 100755 index 0000000..27cf459 --- /dev/null +++ b/binutils-2.19/gold/testsuite/icf_preemptible_functions_test.sh @@ -0,0 +1,35 @@ +# icf_preemptible_functions_test.sh -- test --icf=all + +# Copyright 2010 Free Software Foundation, Inc. +# Written by Sriraman Tallam . + +# This file is part of gold. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +# MA 02110-1301, USA. + + +check() +{ + func_addr_1=`grep $2 $1 | awk '{print $1}'` + func_addr_2=`grep $3 $1 | awk '{print $1}'` + if [ $func_addr_1 = $func_addr_2 ] + then + echo "Identical Code Folding should not fold" $2 "and" $3 + exit 1 + fi +} + +check icf_preemptible_functions_test.stdout "_Z3foov" "_Z3barv" diff --git a/binutils-2.19/gold/testsuite/icf_safe_so_test.cc b/binutils-2.19/gold/testsuite/icf_safe_so_test.cc index 5e4453b..0f50ad6 100644 --- a/binutils-2.19/gold/testsuite/icf_safe_so_test.cc +++ b/binutils-2.19/gold/testsuite/icf_safe_so_test.cc @@ -24,7 +24,8 @@ // in safe mode correctly folds functions in a shared object. The // foo_* functions below should not be folded. For x86-64, // foo_glob and bar_glob should be folded as their function pointers -// are addresses of PLT entries in shared objects. +// are addresses of PLT entries in shared objects. For 32-bit X86, +// the hidden protected and internal symbols can be folded. int __attribute__ ((visibility ("protected"))) foo_prot() diff --git a/binutils-2.19/gold/testsuite/icf_safe_so_test.sh b/binutils-2.19/gold/testsuite/icf_safe_so_test.sh index db2e73e..47ad390 100755 --- a/binutils-2.19/gold/testsuite/icf_safe_so_test.sh +++ b/binutils-2.19/gold/testsuite/icf_safe_so_test.sh @@ -25,8 +25,25 @@ # to verify if identical code folding in safe mode correctly folds # functions in a shared object. +error_if_symbol_absent() +{ + if ! is_symbol_present $1 $2; + then + echo "Symbol" $2 "not present, possibly folded." + exit 1 + fi +} + +is_symbol_present() +{ + grep $2 $1 > /dev/null 2>&1 + return $? +} + check_nofold() { + error_if_symbol_absent $1 $2 + error_if_symbol_absent $1 $3 func_addr_1=`grep $2 $1 | awk '{print $1}'` func_addr_2=`grep $3 $1 | awk '{print $1}'` if [ $func_addr_1 = $func_addr_2 ]; @@ -38,6 +55,16 @@ check_nofold() check_fold() { + if ! is_symbol_present $1 $2 + then + return 0 + fi + + if ! is_symbol_present $1 $3 + then + return 0 + fi + func_addr_1=`grep $2 $1 | awk '{print $1}'` func_addr_2=`grep $3 $1 | awk '{print $1}'` if [ $func_addr_1 != $func_addr_2 ]; @@ -49,21 +76,30 @@ check_fold() arch_specific_safe_fold() { - grep_x86_64=`grep -q "Advanced Micro Devices X86-64" $2` - if [ $? == 0 ]; + if [ $1 == 0 ]; then - check_fold $1 $3 $4 + check_fold $2 $3 $4 else - check_nofold $1 $3 $4 + check_nofold $2 $3 $4 fi } -check_nofold icf_safe_so_test_1.stdout "foo_prot" "foo_hidden" -check_nofold icf_safe_so_test_1.stdout "foo_prot" "foo_internal" -check_nofold icf_safe_so_test_1.stdout "foo_prot" "foo_static" -check_nofold icf_safe_so_test_1.stdout "foo_hidden" "foo_internal" -check_nofold icf_safe_so_test_1.stdout "foo_hidden" "foo_static" -check_nofold icf_safe_so_test_1.stdout "foo_internal" "foo_static" -arch_specific_safe_fold icf_safe_so_test_1.stdout icf_safe_so_test_2.stdout \ - "foo_glob" "bar_glob" +X86_32_specific_safe_fold() +{ + grep -e "Intel 80386" $1 > /dev/null 2>&1 + arch_specific_safe_fold $? $2 $3 $4 +} + +X86_64_specific_safe_fold() +{ + grep -e "Advanced Micro Devices X86-64" $1 > /dev/null 2>&1 + arch_specific_safe_fold $? $2 $3 $4 +} +X86_32_specific_safe_fold icf_safe_so_test_2.stdout icf_safe_so_test_1.stdout "foo_prot" "foo_hidden" +X86_32_specific_safe_fold icf_safe_so_test_2.stdout icf_safe_so_test_1.stdout "foo_prot" "foo_internal" +X86_32_specific_safe_fold icf_safe_so_test_2.stdout icf_safe_so_test_1.stdout "foo_prot" "foo_static" +X86_32_specific_safe_fold icf_safe_so_test_2.stdout icf_safe_so_test_1.stdout "foo_hidden" "foo_internal" +X86_32_specific_safe_fold icf_safe_so_test_2.stdout icf_safe_so_test_1.stdout "foo_hidden" "foo_static" +X86_32_specific_safe_fold icf_safe_so_test_2.stdout icf_safe_so_test_1.stdout "foo_internal" "foo_static" +check_nofold icf_safe_so_test_1.stdout "foo_glob" "bar_glob" diff --git a/binutils-2.19/gold/testsuite/icf_safe_test.cc b/binutils-2.19/gold/testsuite/icf_safe_test.cc index 3edb865..87294dc 100644 --- a/binutils-2.19/gold/testsuite/icf_safe_test.cc +++ b/binutils-2.19/gold/testsuite/icf_safe_test.cc @@ -22,10 +22,10 @@ // The goal of this program is to verify if identical code folding // in safe mode correctly folds only ctors and dtors. kept_func_1 must -// not be folded into kept_func_2 other than for X86-64 which can -// use relocation types to determine if function pointers are taken. -// kept_func_3 should never be folded as its pointer is taken. The ctor -// and dtor of class A must be folded. +// not be folded into kept_func_2 other than for X86 (32 and 64 bit) +// which can use relocation types to determine if function pointers are +// taken. kept_func_3 should never be folded as its pointer is taken. +// The ctor and dtor of class A must be folded. class A { diff --git a/binutils-2.19/gold/testsuite/icf_safe_test.sh b/binutils-2.19/gold/testsuite/icf_safe_test.sh index 540dcc2..23e4e29 100755 --- a/binutils-2.19/gold/testsuite/icf_safe_test.sh +++ b/binutils-2.19/gold/testsuite/icf_safe_test.sh @@ -22,8 +22,8 @@ # The goal of this program is to verify if --icf=safe works as expected. # File icf_safe_test.cc is in this test. This program checks if only -# ctors and dtors are folded, except for x86-64, which uses relocation -# types to detect if function pointers are taken. +# ctors and dtors are folded, except for x86 (32 and 64 bit), which +# uses relocation types to detect if function pointers are taken. check_nofold() { @@ -49,7 +49,7 @@ check_fold() arch_specific_safe_fold() { - grep_x86_64=`grep -q "Advanced Micro Devices X86-64" $2` + grep_x86=`grep -q -e "Advanced Micro Devices X86-64" -e "Intel 80386" $2` if [ $? == 0 ]; then check_fold $1 $3 $4 diff --git a/binutils-2.19/gold/testsuite/icf_string_merge_test.cc b/binutils-2.19/gold/testsuite/icf_string_merge_test.cc new file mode 100644 index 0000000..b1e1191 --- /dev/null +++ b/binutils-2.19/gold/testsuite/icf_string_merge_test.cc @@ -0,0 +1,50 @@ +// icf_string_merge_test.cc -- a test case for gold + +// Copyright 2010 Free Software Foundation, Inc. +// Written by Sriraman Tallam . + +// This file is part of gold. + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +// MA 02110-1301, USA. + +// The goal of this program is to verify is strings are handled correctly +// by ICF. ICF inlines strings that can be merged. In some cases, the +// addend of the relocation pointing to a string merge section must be +// ignored. This program has no pair of identical functions that can be +// folded. However, if the addend is not ignored then get2 and get3 will +// become identical. + +const char* const str1 = "aaaaaaaaaastr1"; +const char* const str2 = "bbbbaaaaaastr1"; +const char* const str3 = "cccccaaaaastr1"; + +const char* get1() +{ + return str1; +} +const char* get2() +{ + return str2; +} + +const char* get3() +{ + return str3; +} +int main() +{ + return 0; +} diff --git a/binutils-2.19/gold/testsuite/icf_string_merge_test.sh b/binutils-2.19/gold/testsuite/icf_string_merge_test.sh new file mode 100755 index 0000000..f22f212 --- /dev/null +++ b/binutils-2.19/gold/testsuite/icf_string_merge_test.sh @@ -0,0 +1,37 @@ +# icf_string_merge_test.sh -- test --icf=all + +# Copyright 2010 Free Software Foundation, Inc. +# Written by Sriraman Tallam . + +# This file is part of gold. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +# MA 02110-1301, USA. + + +check() +{ + func_addr_1=`grep $2 $1 | awk '{print $1}'` + func_addr_2=`grep $3 $1 | awk '{print $1}'` + if [ $func_addr_1 = $func_addr_2 ] + then + echo "Identical Code Folding should not fold" $2 "and" $3 + exit 1 + fi +} + +check icf_string_merge_test.stdout "get1" "get2" +check icf_string_merge_test.stdout "get1" "get3" +check icf_string_merge_test.stdout "get2" "get3" diff --git a/binutils-2.19/gold/testsuite/icf_virtual_function_folding_test.cc b/binutils-2.19/gold/testsuite/icf_virtual_function_folding_test.cc new file mode 100644 index 0000000..1ba3e73 --- /dev/null +++ b/binutils-2.19/gold/testsuite/icf_virtual_function_folding_test.cc @@ -0,0 +1,70 @@ +// icf_virtual_function_folding_test.cc -- a test case for gold + +// Copyright 2010 Free Software Foundation, Inc. +// Written by Sriraman Tallam . + +// This file is part of gold. + +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +// MA 02110-1301, USA. + +// Foo::fn1 is folded into fn2 with ICF. Since this file is linked as a +// position independent executable, a dynamic reloc is needed +// for the virtual call fn1 entry in the vtable. This test makes sure +// the call to Foo::fn1 works correctly after the folding. + +int fn2(void *) +{ + return 0xA; +} + +namespace +{ + +class Bar +{ + public: + virtual int fn1(); +}; + +int Bar::fn1() +{ + return 123; +} + +class Foo : public Bar +{ + virtual int fn1(); +}; + +int Foo::fn1() +{ + return 0xA; +} + +Bar* get() +{ + Bar *f = new Foo(); + return f; +} + +} // end of anonymous namespace. + +int main() +{ + Bar *f = get(); + f->fn1(); + return 0; +} diff --git a/binutils-2.19/gold/x86_64.cc b/binutils-2.19/gold/x86_64.cc index e9dd5ae..9110278 100644 --- a/binutils-2.19/gold/x86_64.cc +++ b/binutils-2.19/gold/x86_64.cc @@ -1398,14 +1398,10 @@ Target_x86_64::Scan::unsupported_reloc_global(Sized_relobj<64, false>* object, object->name().c_str(), r_type, gsym->demangled_name().c_str()); } -// Returns true if this relocation type could be that of a function pointer -// only if the target is not position-independent code. +// Returns true if this relocation type could be that of a function pointer. inline bool Target_x86_64::Scan::possible_function_pointer_reloc(unsigned int r_type) { - if (parameters->options().shared()) - return false; - switch (r_type) { case elfcpp::R_X86_64_64: @@ -1413,6 +1409,11 @@ Target_x86_64::Scan::possible_function_pointer_reloc(unsigned int r_type) case elfcpp::R_X86_64_32S: case elfcpp::R_X86_64_16: case elfcpp::R_X86_64_8: + case elfcpp::R_X86_64_GOT64: + case elfcpp::R_X86_64_GOT32: + case elfcpp::R_X86_64_GOTPCREL64: + case elfcpp::R_X86_64_GOTPCREL: + case elfcpp::R_X86_64_GOTPLT64: { return true; } diff --git a/binutils-2.19/ld/emultempl/armelf.em b/binutils-2.19/ld/emultempl/armelf.em index 4340a48..0fd9ab6 100644 --- a/binutils-2.19/ld/emultempl/armelf.em +++ b/binutils-2.19/ld/emultempl/armelf.em @@ -458,6 +458,7 @@ PARSE_AND_LIST_PROLOGUE=' #define OPTION_NO_WCHAR_SIZE_WARNING 313 #define OPTION_FIX_CORTEX_A8 314 #define OPTION_NO_FIX_CORTEX_A8 315 +#define OPTION_ICF 399 ' PARSE_AND_LIST_SHORTOPTS=p @@ -479,6 +480,7 @@ PARSE_AND_LIST_LONGOPTS=' { "no-wchar-size-warning", no_argument, NULL, OPTION_NO_WCHAR_SIZE_WARNING}, { "fix-cortex-a8", no_argument, NULL, OPTION_FIX_CORTEX_A8 }, { "no-fix-cortex-a8", no_argument, NULL, OPTION_NO_FIX_CORTEX_A8 }, + { "icf", required_argument, NULL, OPTION_ICF }, ' PARSE_AND_LIST_OPTIONS=' @@ -506,6 +508,7 @@ PARSE_AND_LIST_OPTIONS=' the linker should choose suitable defaults.\n" )); fprintf (file, _(" --[no-]fix-cortex-a8 Disable/enable Cortex-A8 Thumb-2 branch erratum fix\n")); + fprintf (file, _(" --icf= Ignored for compatibility with gold.\n")); ' PARSE_AND_LIST_ARGS_CASES=' @@ -585,6 +588,10 @@ PARSE_AND_LIST_ARGS_CASES=' case OPTION_NO_FIX_CORTEX_A8: fix_cortex_a8 = 0; break; + + case OPTION_ICF: + /* For compatibility with gold. */ + break; ' # We have our own before_allocation etc. functions, but they call -- cgit v1.1