bug-gnulib
[Top][All Lists]
Advanced

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

Unexpected frexpf implementation used by MSVC9 in C++ mode


From: Michael Goffioul
Subject: Unexpected frexpf implementation used by MSVC9 in C++ mode
Date: Sun, 11 Mar 2012 18:30:19 +0000

Hi,

I'm trying to clarify a potential issue when using gnulib float math
functions like frexpf (and possibly others) with MSVC9. It all started
when compiling octave and getting link error because of duplicate
symbols like frexpf in libgnulib.la and octave code like Cell.cc. I
don't fully unserstand why I have duplicate symbol, but I think it's
related to the fact that frexpf is defined inline in MSVC math.h and
this is not well detected by the frexpf.m4.

To analyze further, I disassembled the 2 versions of frexpf and
compared them. In libgnulib.la, the code is as follows:

_frexpf:
  00000000: 55                 push        ebp
  00000001: 8B EC              mov         ebp,esp
  00000003: 51                 push        ecx
  00000004: 8B 45 0C           mov         eax,dword ptr [ebp+0Ch]
  00000007: 50                 push        eax
  00000008: D9 45 08           fld         dword ptr [ebp+8]
  0000000B: 83 EC 08           sub         esp,8
  0000000E: DD 1C 24           fstp        qword ptr [esp]
  00000011: E8 00 00 00 00     call        _rpl_frexp
  00000016: 83 C4 0C           add         esp,0Ch
  00000019: D9 5D FC           fstp        dword ptr [ebp-4]
  0000001C: D9 45 FC           fld         dword ptr [ebp-4]
  0000001F: 8B E5              mov         esp,ebp
  00000021: 5D                 pop         ebp
  00000022: C3                 ret

In octave code (like Cell.cc), the frexpf code is as follows:

_frexpf:
  00000000: 55                 push        ebp
  00000001: 8B EC              mov         ebp,esp
  00000003: 51                 push        ecx
  00000004: 8B 45 0C           mov         eax,dword ptr [ebp+0Ch]
  00000007: 50                 push        eax
  00000008: D9 45 08           fld         dword ptr [ebp+8]
  0000000B: 83 EC 08           sub         esp,8
  0000000E: DD 1C 24           fstp        qword ptr [esp]
  00000011: FF 15 00 00 00 00  call        dword ptr [__imp__frexp]
  00000017: 83 C4 0C           add         esp,0Ch
  0000001A: D9 5D FC           fstp        dword ptr [ebp-4]
  0000001D: D9 45 FC           fld         dword ptr [ebp-4]
  00000020: 8B E5              mov         esp,ebp
  00000022: 5D                 pop         ebp
  00000023: C3                 ret

As you can see, one version uses the frexp gnulib replacement, while
the other does not. The link error can be avoided by forcing MSVC to
accept duplicate symbols, but the problem is that there's a high
probability that the wrong version will be used.

For completeness, I've pasted below the pre-processed code of Cell.cc,
only the parts containing the string "frexp":


extern "C" {
...
__declspec(dllimport) double  __cdecl frexp([SA_Pre(Null=SA_No)]
[SA_Pre(Deref=1,Valid=SA_Yes,Access=SA_Read)] double _X,
[SA_Pre(Null=SA_No,WritableElementsConst=1)]
[SA_Pre(Deref=1,Valid=SA_No)] int * _Y);
...
inline long double frexpl([SA_Pre(Null=SA_No)]
[SA_Pre(Deref=1,Valid=SA_Yes,Access=SA_Read)] long double _X,
[SA_Pre(Null=SA_No,WritableElementsConst=1)]
[SA_Pre(Deref=1,Valid=SA_No)] int *_Y)
        {return (frexp((double)_X, _Y)); }
...
inline float frexpf([SA_Pre(Null=SA_No)]
[SA_Pre(Deref=1,Valid=SA_Yes,Access=SA_Read)] float _X,
[SA_Pre(Null=SA_No,WritableElementsConst=1)]
[SA_Pre(Deref=1,Valid=SA_No)] int *_Y)
        {return ((float)frexp((double)_X, _Y)); }
...
}
...
extern "C++" {
...
inline float __cdecl frexp([SA_Pre(Null=SA_No)]
[SA_Pre(Deref=1,Valid=SA_Yes,Access=SA_Read)] float _X,
[SA_Pre(Null=SA_No,WritableElementsConst=1)]
[SA_Pre(Deref=1,Valid=SA_No)] int * _Y)
        {return (frexpf(_X, _Y)); }
...
inline long double __cdecl frexp([SA_Pre(Null=SA_No)]
[SA_Pre(Deref=1,Valid=SA_Yes,Access=SA_Read)] long double _X,
[SA_Pre(Null=SA_No,WritableElementsConst=1)]
[SA_Pre(Deref=1,Valid=SA_No)] int * _Y)
        {return (frexpl(_X, _Y)); }
...
}
...
extern "C" float frexpf (float x, int *expptr) ;
namespace gnulib { static float (*frexpf) (float x, int *expptr) =
::frexpf; } extern "C" int _gl_cxxalias_dummy;
...
extern "C" double rpl_frexp (double x, int *expptr);
namespace gnulib { double (*const frexp) (double x, int *expptr) =
::rpl_frexp; } extern "C" int _gl_cxxalias_dummy;


I think the problem is at least partially due to the inlined version
of frexpf provided by MSVC. This is not properly detected by
frexpf.m4, so gnulib provides a replacement. But then C++ code using
gnulib math.h will end up using the original inlined version from MSVC
when trying to use gnulib::frexpf, instead of the gnulib replacement.
I think MSVC copies the inlined frexpf in the object code and uses it
to assign gnulib::frexpf. This leads to the duplicate symbol
definition.

I'm not 100% sure of all this, but I have the impression this is
what's happening. Any comment?

Michael.



reply via email to

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