From e7dea20321d2eb2ab24293953a9914031b8c532a Mon Sep 17 00:00:00 2001 From: Andrew Hsieh Date: Tue, 18 Sep 2012 23:21:28 -0700 Subject: Fix GCC 4.4.3 GNU libstdc++ to NOT merge typeinfo names by default Back port r149964, r153734, r153742 and r153768, with later revision reverts previous one (some "partially", or nothing would have left :) This issue is fixed in GCC 4.6 (NDK r8b+). See the new gcc-4.4.3/libstdc++-v3/libsupc++/typeinfo for details. Related issue/discussion: http://code.google.com/p/android/issues/detail?id=22165 https://groups.google.com/forum/#!msg/android-ndk/FlnuAOIKHOo/kLEwaBso7KYJ%5B1-25%5D Change-Id: I0ef9d5001c82f2eb5472a1c4fd60b07d33e0ab1f --- gcc-4.4.3/gcc/cp/rtti.c | 28 +++++++++---- gcc-4.4.3/libstdc++-v3/libsupc++/tinfo.cc | 3 +- gcc-4.4.3/libstdc++-v3/libsupc++/tinfo2.cc | 3 +- gcc-4.4.3/libstdc++-v3/libsupc++/typeinfo | 66 +++++++++++++++++------------- 4 files changed, 63 insertions(+), 37 deletions(-) (limited to 'gcc-4.4.3') diff --git a/gcc-4.4.3/gcc/cp/rtti.c b/gcc-4.4.3/gcc/cp/rtti.c index 8861934df..7ae227c2a 100644 --- a/gcc-4.4.3/gcc/cp/rtti.c +++ b/gcc-4.4.3/gcc/cp/rtti.c @@ -103,7 +103,7 @@ VEC(tree,gc) *unemitted_tinfo_decls; static GTY (()) VEC(tinfo_s,gc) *tinfo_descs; static tree ifnonnull (tree, tree); -static tree tinfo_name (tree); +static tree tinfo_name (tree, bool); static tree build_dynamic_cast_1 (tree, tree, tsubst_flags_t); static tree throw_bad_cast (void); static tree throw_bad_typeid (void); @@ -350,16 +350,30 @@ build_typeid (tree exp) return exp; } -/* Generate the NTBS name of a type. */ +/* Generate the NTBS name of a type. If MARK_PRIVATE, put a '*' in front so that + comparisons will be done by pointer rather than string comparison. */ static tree -tinfo_name (tree type) +tinfo_name (tree type, bool mark_private) { const char *name; + int length; tree name_string; name = mangle_type_string (type); - name_string = fix_string_type (build_string (strlen (name) + 1, name)); - return name_string; + length = strlen (name); + + if (mark_private) + { + /* Inject '*' at beginning of name to force pointer comparison. */ + char* buf = (char*) XALLOCAVEC (char, length + 1); + buf[0] = '*'; + memcpy (buf + 1, name, length); + name_string = build_string (length + 1, buf); + } + else + name_string = build_string (length + 1, name); + + return fix_string_type (name_string); } /* Return a VAR_DECL for the internal ABI defined type_info object for @@ -841,13 +855,12 @@ tinfo_base_init (tinfo_s *ti, tree target) tree vtable_ptr; { - tree name_name; + tree name_name, name_string; /* Generate the NTBS array variable. */ tree name_type = build_cplus_array_type (build_qualified_type (char_type_node, TYPE_QUAL_CONST), NULL_TREE); - tree name_string = tinfo_name (target); /* Determine the name of the variable -- and remember with which type it is associated. */ @@ -864,6 +877,7 @@ tinfo_base_init (tinfo_s *ti, tree target) DECL_TINFO_P (name_decl) = 1; set_linkage_according_to_type (target, name_decl); import_export_decl (name_decl); + name_string = tinfo_name (target, !TREE_PUBLIC (name_decl)); DECL_INITIAL (name_decl) = name_string; mark_used (name_decl); pushdecl_top_level_and_finish (name_decl, name_string); diff --git a/gcc-4.4.3/libstdc++-v3/libsupc++/tinfo.cc b/gcc-4.4.3/libstdc++-v3/libsupc++/tinfo.cc index 1ce6f8f46..d939a3fda 100644 --- a/gcc-4.4.3/libstdc++-v3/libsupc++/tinfo.cc +++ b/gcc-4.4.3/libstdc++-v3/libsupc++/tinfo.cc @@ -41,7 +41,8 @@ operator== (const std::type_info& arg) const #if __GXX_MERGED_TYPEINFO_NAMES return name () == arg.name (); #else - return (&arg == this) || (__builtin_strcmp (name (), arg.name ()) == 0); + return (&arg == this) + || (name ()[0] != '*' && (__builtin_strcmp (name (), arg.name ()) == 0)); #endif } diff --git a/gcc-4.4.3/libstdc++-v3/libsupc++/tinfo2.cc b/gcc-4.4.3/libstdc++-v3/libsupc++/tinfo2.cc index 4b01037f3..0182c6cc0 100644 --- a/gcc-4.4.3/libstdc++-v3/libsupc++/tinfo2.cc +++ b/gcc-4.4.3/libstdc++-v3/libsupc++/tinfo2.cc @@ -37,7 +37,8 @@ type_info::before (const type_info &arg) const #if __GXX_MERGED_TYPEINFO_NAMES return name () < arg.name (); #else - return __builtin_strcmp (name (), arg.name ()) < 0; + return (name ()[0] == '*') ? name () < arg.name () + : __builtin_strcmp (name (), arg.name ()) < 0; #endif } diff --git a/gcc-4.4.3/libstdc++-v3/libsupc++/typeinfo b/gcc-4.4.3/libstdc++-v3/libsupc++/typeinfo index eea38e70e..f7f9d4e2c 100644 --- a/gcc-4.4.3/libstdc++-v3/libsupc++/typeinfo +++ b/gcc-4.4.3/libstdc++-v3/libsupc++/typeinfo @@ -43,32 +43,29 @@ namespace __cxxabiv1 } // namespace __cxxabiv1 // Determine whether typeinfo names for the same type are merged (in which -// case comparison can just compare pointers) or not (in which case -// strings must be compared and g++.dg/abi/local1.C will fail), and -// whether comparison is to be implemented inline or not. By default we -// use inline pointer comparison if weak symbols are available, and -// out-of-line strcmp if not. Out-of-line pointer comparison is used -// where the object files are to be portable to multiple systems, some of -// which may not be able to use pointer comparison, but the particular -// system for which libstdc++ is being built can use pointer comparison; -// in particular for most ARM EABI systems, where the ABI specifies -// out-of-line comparison. Inline strcmp is not currently supported. The -// compiler's target configuration can override the defaults by defining -// __GXX_TYPEINFO_EQUALITY_INLINE to 1 or 0 to indicate whether or not -// comparison is inline, and __GXX_MERGED_TYPEINFO_NAMES to 1 or 0 to -// indicate whether or not pointer comparison can be used. +// case comparison can just compare pointers) or not (in which case strings +// must be compared), and whether comparison is to be implemented inline or +// not. We used to do inline pointer comparison by default if weak symbols +// are available, but even with weak symbols sometimes names are not merged +// when objects are loaded with RTLD_LOCAL, so now we always use strcmp by +// default. For ABI compatibility, we do the strcmp inline if weak symbols +// are available, and out-of-line if not. Out-of-line pointer comparison +// is used where the object files are to be portable to multiple systems, +// some of which may not be able to use pointer comparison, but the +// particular system for which libstdc++ is being built can use pointer +// comparison; in particular for most ARM EABI systems, where the ABI +// specifies out-of-line comparison. The compiler's target configuration +// can override the defaults by defining __GXX_TYPEINFO_EQUALITY_INLINE to +// 1 or 0 to indicate whether or not comparison is inline, and +// __GXX_MERGED_TYPEINFO_NAMES to 1 or 0 to indicate whether or not pointer +// comparison can be used. #ifndef __GXX_MERGED_TYPEINFO_NAMES - #if !__GXX_WEAK__ - // If weak symbols are not supported, typeinfo names are not merged. - #define __GXX_MERGED_TYPEINFO_NAMES 0 - #else - // On platforms that support weak symbols, typeinfo names are merged. - #define __GXX_MERGED_TYPEINFO_NAMES 1 - #endif +// By default, typeinfo names are not merged. +#define __GXX_MERGED_TYPEINFO_NAMES 0 #endif -// By default follow the same rules as for __GXX_MERGED_TYPEINFO_NAMES. +// By default follow the old inline rules to avoid ABI changes. #ifndef __GXX_TYPEINFO_EQUALITY_INLINE #if !__GXX_WEAK__ #define __GXX_TYPEINFO_EQUALITY_INLINE 0 @@ -97,28 +94,41 @@ namespace std /** Returns an @e implementation-defined byte string; this is not * portable between compilers! */ const char* name() const - { return __name; } + { return __name[0] == '*' ? __name + 1 : __name; } #if !__GXX_TYPEINFO_EQUALITY_INLINE - bool before(const type_info& __arg) const; - // In old abi, or when weak symbols are not supported, there can // be multiple instances of a type_info object for one // type. Uniqueness must use the _name value, not object address. + bool before(const type_info& __arg) const; bool operator==(const type_info& __arg) const; #else #if !__GXX_MERGED_TYPEINFO_NAMES - #error "Inline implementation of type_info comparision requires merging of type_info objects" - #endif /** Returns true if @c *this precedes @c __arg in the implementation's * collation order. */ - // In new abi we can rely on type_info's NTBS being unique, + // Even with the new abi, on systems that support dlopen + // we can run into cases where type_info names aren't merged, + // so we still need to do string comparison. + bool before(const type_info& __arg) const + { return (__name[0] == '*' && __arg.__name[0] == '*') + ? __name < __arg.__name + : __builtin_strcmp (__name, __arg.__name) < 0; } + + bool operator==(const type_info& __arg) const + { + return ((__name == __arg.__name) + || (__name[0] != '*' && + __builtin_strcmp (__name, __arg.__name) == 0)); + } + #else + // On some targets we can rely on type_info's NTBS being unique, // and therefore address comparisons are sufficient. bool before(const type_info& __arg) const { return __name < __arg.__name; } bool operator==(const type_info& __arg) const { return __name == __arg.__name; } + #endif #endif bool operator!=(const type_info& __arg) const { return !operator==(__arg); } -- cgit v1.2.3