bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Gnulib 64-bit ABI bug with OSX, generic patch proposed


From: Jarno Rajahalme
Subject: Gnulib 64-bit ABI bug with OSX, generic patch proposed
Date: Fri, 16 Apr 2010 15:12:20 -0700

Sorry for posting this same issue multiple times, but I have a possibly better 
proposal for fixing this this time.

I faced the following linking error trying to link octave on OSX with the stock 
Apple GCC 4.2 (Xcode 3.2.2) -m64:

dyld: Symbol not found: 
__ZNSt15basic_stringbufIcSt11char_traitsIcESaIcEE7seekoffElSt12_Ios_SeekdirSt13_Ios_Openmode
Referenced from: 
/Users/rajahalm/testing/octave/src/.libs/liboctinterp-3.3.51+.dylib
Expected in: flat namespace

unmangled:
std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> 
>::seekoff(long, std::_Ios_Seekdir, std::_Ios_Openmode)

/usr/lib/libstdc++.6.dylib has an _almost_ matching entry:
__ZNSt15basic_stringbufIcSt11char_traitsIcESaIcEE7seekoffExSt12_Ios_SeekdirSt13_Ios_Openmode

unmangled:
std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> 
>::seekoff(long long, std::_Ios_Seekdir, std::_Ios_Openmode)

The difference is that the first parameter to seekoff() should be "long long", 
but with gnulib it is "long", as it is of type std::streamoff, which is defined 
to be int64_t.

OSX /usr/include/stdint.h typedefs int64_t as "long long". As long as gnulib 
stdint.h (re)defines this as "long int" there is going to be this 
ABI/mangling/linking problem, even though both definitions result in the same 
size of the std::streamoff.

It seems the tests in stdint.in.h are insufficient. Testing for the size of 
"long" is not enough, as the name mangling rules are different for "long" and 
"long long", even if they are of the same size. stdint.in.h defines int64_t as 
"long long int" when @HAVE_LONG_LONG_INT@, provided that "long" is NOT 64 bit. 
I propose the following patch (see below) that allows defining int64_t as "long 
long int" (same mangling as for "long long"), when defined, even if "long" is 
64 bit. With this patch the ABI compatibility is maintained, and linking 
succeeds.

However, it is possible that some other platforms need int64_t to be defined as 
"long int", when long is 64 bit, causing this change to break the ABI 
compatibility on those platforms. So, maybe int64_t should NOT be defined, if 
already typedef'ed? But this may be hard to detect with the preprocessor 
macros, so maybe a configure time check for int64_t is needed.

Regards,

   Jarno


diff --git a/lib/stdint.in.h b/lib/stdint.in.h
index a861c07..25719ac 100644
--- a/lib/stdint.in.h
+++ b/lib/stdint.in.h
@@ -135,7 +135,7 @@ typedef unsigned int gl_uint32_t;
 
 /* Do not undefine int64_t if gnulib is not being used with 64-bit
    types, since otherwise it breaks platforms like Tandem/NSK.  */
-#if LONG_MAX >> 31 >> 31 == 1
+#if LONG_MAX >> 31 >> 31 == 1 && address@hidden@
 # undef int64_t
 typedef long int gl_int64_t;
 # define int64_t gl_int64_t



>> I faced the following linking error trying to compile octave on OSX with GCC 
>> 4.3 -m64:
>> 
>> dyld: Symbol not found: 
>> __ZNSt15basic_stringbufIcSt11char_traitsIcESaIcEE7seekoffElSt12_Ios_SeekdirSt13_Ios_Openmode
>> Referenced from: 
>> /Users/rajahalm/testing/octave/src/.libs/liboctinterp-3.3.51+.dylib
>> Expected in: flat namespace
>> in /Users/rajahalm/testing/octave/src/.libs/liboctinterp-3.3.51+.dylib
>> 
>> unmangled:
>> 
>> std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> 
>> >::seekoff(long, std::_Ios_Seekdir, std::_Ios_Openmode)
>> 
>> /opt/local/lib/gcc43/libstdc++.6.dylib has an _almost_ matching entry:
>> 
>> __ZNSt15basic_stringbufIcSt11char_traitsIcESaIcEE7seekoffExSt12_Ios_SeekdirSt13_Ios_Openmode
>> 
>> unmangled:
>> 
>> std::basic_stringbuf<char, std::char_traits<char>, std::allocator<char> 
>> >::seekoff(long long, std::_Ios_Seekdir, std::_Ios_Openmode)
>> 
>> The difference is that the first parameter to seekoff() should be "long 
>> long", but it is "long", as it is of type std::streamoff, which is defined 
>> to be int64_t, if _GLIBCXX_HAVE_INT64_T is defined. This definition is 
>> handled differently in GCC 4.4, which does not exhibit this linking problem.
>> 
>> GCC 4.0 and 4.2 seem to have the same definition of std::streamoff as GCC 
>> 4.3, so this problem exists with those versions as well.
>> 
>> OSX /usr/include/stdint.h defines int64_t as "long long". As long as gnulib 
>> stdint.h redefines this as "long int" there is going to be this linking 
>> problem with GCC 4.3, even though both definitions result in the same size 
>> of the std::streamoff :-)
>> 
>> I tested this with the following change:
>> 
>> *** lib/stdint.in.h~ Fri Apr  2 17:38:10 2010
>> --- lib/stdint.in.h  Thu Apr  8 19:29:39 2010
>> ***************
>> *** 135,141 ****
>> 
>> /* Do not undefine int64_t if gnulib is not being used with 64-bit
>>    types, since otherwise it breaks platforms like Tandem/NSK.  */
>> ! #if LONG_MAX >> 31 >> 31 == 1
>> # undef int64_t
>> typedef long int gl_int64_t;
>> # define int64_t gl_int64_t
>> --- 135,141 ----
>> 
>> /* Do not undefine int64_t if gnulib is not being used with 64-bit
>>    types, since otherwise it breaks platforms like Tandem/NSK.  */
>> ! #if LONG_MAX >> 31 >> 31 == 1 && !(defined (__APPLE__) && defined 
>> (__MACH__))
>> # undef int64_t
>> typedef long int gl_int64_t;
>> # define int64_t gl_int64_t
>> # define GL_INT64_T
>> #elif defined _MSC_VER
>> # undef int64_t
>> typedef __int64 gl_int64_t;
>> # define int64_t gl_int64_t
>> # define GL_INT64_T
>> #elif @HAVE_LONG_LONG_INT@
>> # undef int64_t
>> typedef long long int gl_int64_t;
>> # define int64_t gl_int64_t
>> # define GL_INT64_T
>> #endif
>> 
>> (added lines above for reference)
>> 
>> This change causes int64_t to be defined as "long long int", which seems to 
>> be equivalent to "long long" for name mangling pusposes.
>> 
>> With this change this linking error disappears. However, more fundamentally, 
>> it seems that definition of int64_t based on a matching LONG_MAX is not 
>> enough in any 64 bit C++ system, due to the name mangling difference between 
>> long and long long. The proper thing would be to not redefine int64_t at all 
>> if it is already defined as any type that is 64 bits long.
>> 
>> Jarno
>> 
>> 
>> 
>> 
>> 
> 





reply via email to

[Prev in Thread] Current Thread [Next in Thread]