This is the mail archive of the
mailing list for the Cygwin project.
- From: Ken Brown <kbrown at cornell dot edu>
- To: cygwin at cygwin dot com
- Date: Tue, 21 Oct 2014 08:27:13 -0400
- Subject: Re: Threads
- Authentication-results: sourceware.org; auth=none
- References: <54450835 dot 3050602 at cornell dot edu> <20141020164324 dot GA32374 at calimero dot vinschen dot de> <20141020190350 dot GB32374 at calimero dot vinschen dot de> <54456964 dot 4090007 at cornell dot edu> <20141021111724 dot GA12476 at calimero dot vinschen dot de>
On 10/21/2014 7:17 AM, Corinna Vinschen wrote:
On Oct 20 15:58, Ken Brown wrote:
On 10/20/2014 3:03 PM, Corinna Vinschen wrote:
One of the headaches when porting is sometimes the ABI. While on Linux
the first 6 arguments to a function are given in registers, on Windows
only 4 args are in registers. This can result in bugs when calling
functions with more than 4 parameters, which are invisible on Linux, due
to the way 32 bit parameter are stored in registers on x86_64. This
happened to us already for at least one package.
Am I right in thinking this can only be an issue if the source includes
No. This can be easily trigger by a bug in C code. What happens is
The 64 bit ABI is defined so that the first function args are passed
to the called functions via CPU registers. On Windows the ABI uses 4
such registers(*), on Linux 6(**). All following arguments are passed
on the stack.
The AMD64 CPUs introduced the following behaviour: If a 32 bit value
(for instance, an int in C) is written to a register, the CPU
automatically clears the upper 32 bits of the register. For instance:
%rdx == 0x0123456789abcdef
mov.l $0x42,%edx <- This is a 32 bit mov!
==> %rdx == 0x0000000000000042
No sign extension:
==> %rdx == 0x00000000ffffffff
Now consider what happens if, for instance, the 5th argument to a
stdargs function is expecting a pointer value. The caller calls the
function like this:
foo (a, b, c, d, 0);
The 0 is int, it's not extendend to 64 bit. On Linux, nothing bad
happens, because the 0 will be passed over to foo via register R8,
so the upper 32 bits are cleared. On Cygwin, the 5th parameter is
passed via the stack, 64 bit aligned. The upper 32 bits will not
be explicitely written. They will contain random bytes. foo doesn't
get a NULL pointer, but something like 0xdeadbeef00000000. Here's
$ cat > p.c <<EOF
printf ("prepare stack:\n%p\n%p\n%p\n%p\n%p\n%p\n",
0x1111111111111111UL, 0x2222222222222222UL, 0x3333333333333333UL,
0x4444444444444444UL, 0x5555555555555555UL, 0x6666666666666666UL);
printf ("\nprint null ptr:\n%p\n%p\n%p\n%p\n%p\n%p\n", 0, 0, 0, 0, 0, 0);
$ gcc -g -o p p.c
The same problem might occur if some code uses a function unprototyped.
My favorite example:
/* Don't include string,h */
printf ("Error message is: %s\n", strerror (errno));
Long story short, I have no idea if that's your problem at all, but I
thought I should at least mention it.
Thanks for the explanation!
Problem reports: http://cygwin.com/problems.html
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple