diff options
-rw-r--r-- | gold/ChangeLog | 15 | ||||
-rw-r--r-- | gold/arm.cc | 92 | ||||
-rw-r--r-- | gold/icf.h | 7 | ||||
-rw-r--r-- | gold/target.h | 14 |
4 files changed, 120 insertions, 8 deletions
diff --git a/gold/ChangeLog b/gold/ChangeLog index 304a4ae..50c1aff 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,18 @@ +2010-06-25 Doug Kwan <dougkwan@google.com> + + * arm.cc (Target_arm::can_check_for_functions_pointers): Return true. + (Target_arm::section_may_have_icf_unsafe_pointers): New method + definition. + (Target_arm::Scan::local_reloc_may_be_function_pointer, + Target_arm::Scan::global_reloc_may_be_function_pointer): Implement + target hook to detect function points. + (Target_arm::Scan::possible_function_pointer_reloc): New method. + * icf.h (Icf::check_section_for_function_pointers): Change type of + parameter SECTION_NAME to const reference to std::string. Use + target hook to determine if section may have unsafe pointers. + * target.h (Target::section_may_have_icf_unsafe_pointers): New + method definition. + 2010-06-21 Rafael Espindola <espindola@google.com> * fileread.cc (Input_file::find_fie): New diff --git a/gold/arm.cc b/gold/arm.cc index d9aa767..d19d04c 100644 --- a/gold/arm.cc +++ b/gold/arm.cc @@ -2109,6 +2109,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 @@ -2474,8 +2491,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* , @@ -2483,8 +2499,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 @@ -2515,6 +2530,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_; }; @@ -7688,6 +7706,72 @@ Target_arm<big_endian>::Scan::unsupported_reloc_global( object->name().c_str(), r_type, gsym->demangled_name().c_str()); } +template<bool big_endian> +inline bool +Target_arm<big_endian>::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<bool big_endian> +inline bool +Target_arm<big_endian>::Scan::local_reloc_may_be_function_pointer( + Symbol_table*, + Layout*, + Target_arm<big_endian>* 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<bool big_endian> +inline bool +Target_arm<big_endian>::Scan::global_reloc_may_be_function_pointer( + Symbol_table*, + Layout*, + Target_arm<big_endian>* 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<bool big_endian> @@ -121,14 +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(".data.rel.ro._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/gold/target.h b/gold/target.h index a0ec0b3..9f9c4f9 100644 --- a/gold/target.h +++ b/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 |