RFC: Cygwin 64 bit?

Corinna Vinschen corinna-cygwin@cygwin.com
Wed Jan 18 09:56:00 GMT 2012


On Jan 18 17:25, JonY wrote:
> On 1/18/2012 17:02, Kai Tietz wrote:
> > Hi,
> > 
> > my 5 cents for this thread.
> > 
> > 2012/1/17 JonY <jon_y@users.sourceforge.net>:
> >> On 1/18/2012 04:26, Corinna Vinschen wrote:
> >>>>> Here's a question to warm up this age-old thread.
> >>>>>
> >>>>> Consider we would like to have Cygwin-64 being LP64, and consider we
> >>>>> would like to use the mingw64 headers and libs to build Cygwin.
> >>>>>
> >>>>> In that case, all mingw64 headers have a problem in conjunction with
> >>>>> a Cygwin 64 bit compiler:  All definitions in the headers which are
> >>>>> based on 'long' or 'unsigned long' are wrong.  All of them would have
> >>>>> to use 'int' or 'unsigned int' instead.
> >>>>>
> >>>>> So, here's my question:  Would it be acceptable upstream to add changes
> >>>>> along the lines of this one, for instance, in winnt.h:
> >>>>>
> >>>>>  #if defined (__CYGWIN__) && defined (__x86_64__)
> >>>>>    typedef int LONG;
> >>>>>  #else
> >>>>>    typedef long LONG;
> >>>>>  #endif
> >>>>>
> >>>>> ?
> >>>>
> >>>> I think it's very wrong to put understanding of __CYGWIN__ into w32api.
> >>>>
> >>>> I'm saying this without checking to see if it's already there because,
> >>>> if it is, that's not a justification, it's a bug.
> >>>
> >>> Windows headers in their current state as in Mingw32 and Mingw64 only
> >>> work for 32-bit compiler or LLP64 64-bit compilers.  How do you manage
> >>> it so that they still work in conjunction with an LP64 compiler as the
> >>> 64-bit Cygwin compiler is supposed to be?
> >>>
> >>> There are three ways AFAICS, but all of them require to change the
> >>> header files:
> >>>
> >>> - As above.
> >>>
> >>> - Start every header with a redefinition of "long":
> >>>
> >>>   #if defined (__CYGWIN__) && defined (__x86_64__)
> >>>   # define long int
> >>>   #endif
> >>>   [...]
> >>>   #if defined (__CYGWIN__) && defined (__x86_64__)
> >>>   # undef long
> >>>   #endif
> > 
> > To use here __CYGWIN__ as marker in platform-headers seems to me
> > wrong.  But compiler defines for LP64 IIRC already __LP64__ makro (or
> > if it doesn't we could teach it to do so along with __LLP64__).

Right, at least gcc 4.6.2 on Linux defines __LP64__ and _LP64.
x86_64-w64-mingw32-gcc 4.5.3 does not defined __LLP64__ or _LLP64,
though.  Maybe it has only been added in gcc 4.6?

> > Redefining long has some disadvantages here too.  It might make it
> > impossible to use 'long long' as type, and causes issues to describe
> > types like 'long double'.  Well, the latter shouldn't happen very
> > often, if there at all any 'long double' types in platform-headers.
> > Maybe in midl stuff.

It was just a desperate idea anyway.

> >>> - Add a new target-independent pragma to GCC and add this to the headers:
> >>>
> >>>     #pragma long_size (push, 4)
> >>>     [...]
> >>>     #pragma long_size (pop)
> >>>
> >>>   or
> >>>
> >>>     #pragma model64 (push, LLP64) // value one of LLP64, LP64, ILP64, SILP64
> >>>     [...]
> >>>     #pragma model64 (pop)
> >>>
> >>> I would prefer the latter.
> > 
> > Well, pragma approach looks more sane to me, but is of course for user
> > of platform-headers always challenging, as (s)he has to take care that
> > signature gets proper types on usage.  But normally - IIUC - usage of
> > platform-headers by end-users is discuraged anyway.

I don't quite understand what you mean.  The idea here is that these
#pragmas are at the start (push) and the end (pop) of the Windows header
files.  That would make sure that the Windows types and some of the
functions are defined with the right size for long and unsigned long.
Most Win32 functions are defined based on the Win32 types, which in turn
are defined using base types, like this:

Consider an artificial example like this:

  #include <windows.h>

  int
  main (int argc, char **argv)
  {
    DWORD type;
    GetBinaryTypeA (argv[1], &type);
  }

Part of windows.h and its subsequently called header files is:

  #pragma model64 (push, LLP64)

  typedef unsigned long DWORD, *LPDWORD;

  BOOL WINAPI GetBinaryTypeA (LPCSTR file, LPDWORD type);

  #pragma model64 (pop)

So DWORD is defined as unsigned long, which is 4 bytes in the LLP64
model.  The application using DWORD is using a 4 byte type throughout.

Now consider this application:

  #include <windows.h>

  int
  main (int argc, char **argv)
  {
    unsigned long type;
    GetBinaryTypeA (argv[1], &type);
  }

This would work in the LLP64 model, but it would and should result in a
type mismatch on a LP64 compiler.

> > About the pragma approach I see some interesting (and sadly not that
> > easy to abstract) issue about type-sanity.
> > 
> > Eg.
> > 
> > long foo (long *p)
> > {
> > #pragma long_size (push, 4)
> >   *p = 0;
> > #pragma long_size(pop)
> >   return *p;
> > }

I don't see a problem here.  The idea of the pragma is to influence
type definitions.  Since long *p in the argument list of foo is outside
of the pragma, it is defined as LP64 8 byte long.  The *p = 0 will do
the right thing.  The prgam should *never* change the size of types
in-flight.  Only definitions of types should be affected.

> > 
> > Regards,
> > Kai
> > 
> 
> Make it settable via GCC command line option only? -mlong-abi=4? At
> least the whole translation unit has the same "long".

But that's exactly not the idea.  Think of a standard Cygwin application
which usually uses Cygwin functions.  It must stick to LP64 since that's
the data model of the POSIX API.  The switch of type definitions to the
LLP64 model should happen in the affected Windows headers and then the
application can also call Windows functions without type size problems.
Think of something like mintty which is a Cygwin POSIX application with
additional Win32 GUI calls.


Corinna

-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Project Co-Leader          cygwin AT cygwin DOT com
Red Hat



More information about the Cygwin-developers mailing list