public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* AMD64 ABI and comparison of structures
@ 2006-05-25 10:42 José Bollo
  2006-05-25 10:53 ` Andrew Haley
  0 siblings, 1 reply; 2+ messages in thread
From: José Bollo @ 2006-05-25 10:42 UTC (permalink / raw)
  To: gcc-help

hi all,

I repost here a problem that I met using GCC 3.4.4 and ABI for AMD64 
(-march=athlon64).

the following C code 

typedef struct {
    int32_t a;
    void *b;
} S;
void fs() {
    char t[255];
    int i;
    for(i=0;i<255;i++)
        t[i]=(char)(i+1);
}
int cmp1(S a1, S a2) {
    return !memcmp(&a1,&a2,sizeof(S));
}
int cmp2(S a1, S a2) {
    return a1.a==a2.a && a1.b==a2.b;
}
void put(S y) {
    int a,b;
    S x;
    x=y;
    a=cmp1(x,y);
    b=cmp2(x,y);
    printf("a=%d b=%d\n",a,b);
}
int main() {
    S a;
    a.a=1;
    a.b=&a;
    fs();
    put(a);
    return 0;
}

compiled for my linux x86_64 using the amd64 ABI (-march=athlon64) with gcc 
3.4.4 prints "a=0 b=1"!

i have seen why and it is clear to me how a such result is produced.
I add below a commented assembly listing of the incriminated part.

i think that it is not a bug and that the structure can not be compared using 
'memcmp'.

do you agree or it a bug ?

is it a bug or is it normal?

if it is a bug, must i open a bug track?

please comment.

regards
josé

First, the "put" function. After the obligatory initialisation code...

> .globl put
>         .type   put, @function
> put:
> .LFB8:
>         pushq   %rbp
> .LCFI8:
>         movq    %rsp, %rbp
> .LCFI9:
>         subq    $48, %rsp
> .LCFI10:

The parameter (y) was passed in edi:rsi. Here it is saved on the stack.
Presumably this is done to make debugging easier. 96 bits are copied.

>         movl    %edi, -16(%rbp)
>         movq    %rsi, -8(%rbp)

This makes a copy of the parameter on the stack. This is the translation
of the 'x=y' instruction. This time 128 bits are copied (why?) which
means that, if we called memcmp(&x,&y,sizeof(S)) right now, it would
return 0 (i.e. they are the same). But...

>         movq    -16(%rbp), %rax
>         movq    %rax, -48(%rbp)
>         movq    -8(%rbp), %rax
>         movq    %rax, -40(%rbp)

Here, cmp1 is called. As we already saw, only the meaningful part of the
structure is passed, in register (edx:rcx for one parameter, edi:rsi for
the other one). The result is saved on the stack (local var a)

>         movl    -16(%rbp), %edx
>         movq    -8(%rbp), %rcx
>         movl    -48(%rbp), %edi
>         movq    -40(%rbp), %rsi
>         call    cmp1
>         movl    %eax, -20(%rbp)

This time, cmp2 is called and the result is saved in b

>         movl    -16(%rbp), %edx
>         movq    -8(%rbp), %rcx
>         movl    -48(%rbp), %edi
>         movq    -40(%rbp), %rsi
>         call    cmp2
>         movl    %eax, -24(%rbp)

>         movl    -24(%rbp), %edx
>         movl    -20(%rbp), %esi
>         movl    $.LC0, %edi
>         movl    $0, %eax
>         call    printf
>         leave
>         ret
> .LFE8:
>         .size   put, .-put

Now it should be clear why cmp1 isn't working. Let's have a look

Entry code
> .globl cmp1
>         .type   cmp1, @function
> cmp1:
> .LFB6:
>         pushq   %rbp
> .LCFI3:
>         movq    %rsp, %rbp
> .LCFI4:
>         subq    $48, %rsp

save the parameters on the stack (one structure = 96 bits of data + 32
bits of junk)
> .LCFI5:
>         movl    %edi, -16(%rbp)
>         movq    %rsi, -8(%rbp)
>         movl    %edx, -32(%rbp)
>         movq    %rcx, -24(%rbp)

compare 128 bits of "data" on the stack. Obviously this won't work.
(I'll presume a call to memcmp was generated rather than rep cmpsq
because optimisations were turned off)

>         leaq    -32(%rbp), %rsi
>         leaq    -16(%rbp), %rdi
>         movl    $16, %edx
>         call    memcmp
>         movl    %eax, -36(%rbp)
>         cmpl    $0, -36(%rbp)
>         sete    %al
>         movzbl  %al, %eax
>         movl    %eax, -36(%rbp)
>         movl    -36(%rbp), %eax
>         leave
>         ret
> .LFE6:
>         .size   cmp1, .-cmp1
> .globl cmp2
>         .type   cmp2, @function

Obviously, cmp2 works because it only compares 96 bits of data

> cmp2:
> .LFB7:
>         pushq   %rbp
> .LCFI6:
>         movq    %rsp, %rbp
> .LCFI7:
>         movl    %edi, -16(%rbp)
>         movq    %rsi, -8(%rbp)
>         movl    %edx, -32(%rbp)
>         movq    %rcx, -24(%rbp)
>         movl    $0, -36(%rbp)
>         movl    -16(%rbp), %eax
>         cmpl    -32(%rbp), %eax
>         jne     .L7
>         movq    -8(%rbp), %rax
>         cmpq    -24(%rbp), %rax
>         jne     .L7
>         movl    $1, -36(%rbp)
> .L7:
>         movl    -36(%rbp), %eax
>         leave
>         ret
> .LFE7:
>         .size   cmp2, .-cmp2











^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: AMD64 ABI and comparison of structures
  2006-05-25 10:42 AMD64 ABI and comparison of structures José Bollo
@ 2006-05-25 10:53 ` Andrew Haley
  0 siblings, 0 replies; 2+ messages in thread
From: Andrew Haley @ 2006-05-25 10:53 UTC (permalink / raw)
  To: José Bollo; +Cc: gcc-help

José Bollo writes:
 > hi all,
 > 
 > I repost here a problem that I met using GCC 3.4.4 and ABI for AMD64 
 > (-march=athlon64).
 > 
 > the following C code 
 > 
 > typedef struct {
 >     int32_t a;
 >     void *b;
 > } S;
 > void fs() {
 >     char t[255];
 >     int i;
 >     for(i=0;i<255;i++)
 >         t[i]=(char)(i+1);
 > }
 > int cmp1(S a1, S a2) {
 >     return !memcmp(&a1,&a2,sizeof(S));
 > }
 > int cmp2(S a1, S a2) {
 >     return a1.a==a2.a && a1.b==a2.b;
 > }
 > void put(S y) {
 >     int a,b;
 >     S x;
 >     x=y;
 >     a=cmp1(x,y);
 >     b=cmp2(x,y);
 >     printf("a=%d b=%d\n",a,b);
 > }
 > int main() {
 >     S a;
 >     a.a=1;
 >     a.b=&a;
 >     fs();
 >     put(a);
 >     return 0;
 > }
 > 
 > compiled for my linux x86_64 using the amd64 ABI (-march=athlon64) with gcc 
 > 3.4.4 prints "a=0 b=1"!
 > 
 > i have seen why and it is clear to me how a such result is produced.
 > I add below a commented assembly listing of the incriminated part.
 > 
 > i think that it is not a bug and that the structure can not be compared using 
 > 'memcmp'.

That's right.  It's a consequence of 6.7.2.1 Para 13: "There may be
unnamed padding within a structure object, but not at its beginning".

Andrew.

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2006-05-25 10:53 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-05-25 10:42 AMD64 ABI and comparison of structures José Bollo
2006-05-25 10:53 ` Andrew Haley

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).