bug-gnulib
[Top][All Lists]
Advanced

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

Re: Unexpected frexpf implementation used by MSVC9 in C++ mode


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

On Sun, Mar 11, 2012 at 6:30 PM, Michael Goffioul
<address@hidden> wrote:
> 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.

To confirm my suspicion, I tested the following sample:

#include "config.h"
#include <math.h>
#include <stdio.h>

int main (int argc, char** argv)
{
        volatile float x;
        float zero = 0.0f;

        x = 1.0f / zero;
        {
                int exp;
#ifdef __cplusplus
                float y = gnulib::frexpf (x, &exp);
#else
                float y = frexpf (x, &exp);
#endif
                if (y != x)
                        printf ("failed\n");
        }

        return 0;
}

This code will print "failed" when the MSVC implementation is used
instead of the gnulib replacement. The files config.h and math.h are
taken from the compiled octave sources. When compiling in C mode, it
works fine, nothing is printed. When compiled in C++ mode, it fails.
In C++ mode, I can even compile and link it without including gnulib
sources like frexp.c, which indicates gnulib replacement is not used.

Michael.



reply via email to

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