[forwarded from http://bugs.debian.org/202016] seen in 3.2, 3,3 and current HEAD, "regression" from 2.95 #include <sys/socket.h> int main(void) { struct sockaddr_storage from; struct sockaddr *const fromp = (void *)&from; socklen_t fromlen; fromlen = sizeof(from); if (getpeername(0, fromp, &fromlen) < 0) { return 1; } return 0; } If you compile it with gcc -D_GNU_SOURCE -S -O2 you will get .file "bug-202016.c" .text .p2align 2,,3 .globl main .type main, @function main: pushl %ebp movl %esp, %ebp leal -144(%ebp), %eax subl $156, %esp leal -136(%ebp), %edx pushl %eax pushl %edx pushl $0 movl $128, -144(%ebp) movl %edx, -140(%ebp) call getpeername shrl $31, %eax addl $16, %esp leave ret .size main, .-main .section .note.GNU-stack,"",@progbits .ident "GCC: (GNU) 3.4 20030722 (experimental)" The store into -140(%ebp) is useless. This does not occur if you remove the -D_GNU_SOURCE, so this is related to the __SOCKADDR_ARG magic in sys/socket.h. I can reproduce this with gcc 3.2. gcc 2.95 does not have this problem.
Created attachment 4454 [details] preprocessed source
I can confirm this on 3.0.4, 3.2.3 (those both which produces worse code than 3.3.1 and the mainline), and 3.3.1 (20030707) and the mainline (20030719). gcc 3.3.1 and the mainline produces better code for after the call to getpeername. Also before the call, there are the same number of instructions. Note the store also happens when -march=i686. It also happens on powerpc. Looks like the ABI changed!!
I forgot to attach the reduced sources: typedef unsigned int __uint32_t; typedef unsigned int __socklen_t; typedef __socklen_t socklen_t; typedef unsigned short int sa_family_t; struct sockaddr { sa_family_t sa_family; char sa_data[14]; }; struct sockaddr_storage { sa_family_t ss_family; __uint32_t __ss_align; char __ss_padding[(128 - (2 * sizeof (__uint32_t)))]; }; typedef union { struct sockaddr *__restrict __sockaddr__; struct sockaddr_at *__restrict __sockaddr_a t__; struct sockaddr_ax25 *__restrict __sockaddr_ax25__; struct sockaddr_dl *__restrict __sockaddr_dl __; struct sockaddr_eon *__restrict __sockaddr_eon__; struct sockaddr_in *__restrict __sockaddr_in__; struct sockaddr_in6 *__restrict __sockaddr_in6__; struct sockaddr_inarp *__restrict __sockaddr_inarp __; struct sockaddr_ipx *__restrict __sockaddr_ipx__; struct sockaddr_iso *__restrict __sockaddr_iso_ _; struct sockaddr_ns *__restrict __sockaddr_ns__; struct sockaddr_un *__restrict __sockaddr_un__; st ruct sockaddr_x25 *__restrict __sockaddr_x25__; } __SOCKADDR_ARG __attribute__ ((__transparent_union__)); extern int getpeername (int __fd, __SOCKADDR_ARG __addr, socklen_t *__restrict __len) ; int main(void) { struct sockaddr_storage from; struct sockaddr *const fromp = (void *)&from; socklen_t fromlen; fromlen = sizeof(from); if (getpeername(0, fromp, &fromlen) < 0) { return 1; } return 0; }
Not really ABI change. GCC just overactively assign stack to cast into union. I am testing fix for this.
Fixed for 3.4 by: 2004-01-10 Jan Hubicka <jh@suse.cz> PR opt/11635 * expr.c (expand_expr_real): More curefully expand union casts.