E
Elmar
Hi everyone,
I just switched to GCC 4.4 (gcc44 (GCC) 4.4.0 20090514 (Red Hat
4.4.0-6)) and noted that quite a lot of my functions with variable
arguments are not compiled correctly anymore at -O2 (things are OK at -
O).
Since the problem could well be my knowledge of the C standard, I'd
like to ask about it here before I file a bug report.
Here is the minimum example:
/* PRINT A LIST OF INTEGER VALUES
==============================
list[0] is the number of values in list */
void lst_print(int *list)
{ int i;
for (i=0;i<*list;i++) printf("Value %d: %d\n",i,list[1+i]); }
/* PRINT INTEGER VALUES
====================
The values are specified directly as function parameters */
void val_print(int values,...)
{ /* The list has been put on the stack by the caller... */
lst_print(&values); }
/* TEST PROGRAM
============ */
int main(int argc,char **argv)
{ /* Print 5 integer values from 10 to 50 */
val_print(5,10,20,30,40,50);
return(0); }
Now, at optimization level -O, the result is as expected:
Value 0: 10
Value 1: 20
Value 2: 30
Value 3: 40
Value 4: 50
But at optimization level -O2, the result is garbage:
Value 0: 241472600
Value 1: 0
Value 2: 1
Value 3: 12652532
Value 4: 11273664
Analysis of the assembler code shows that at -O2, GCC entirely
bypasses the function val_print and calls lst_print directly from
main(), but forgets to also put the variable arguments on the stack:
0x08167820 <main+0>: push %ebp
0x08167821 <main+1>: mov %esp,%ebp
0x08167823 <main+3>: sub $0x28,%esp
0x08167826 <main+6>: lea -0xc(%ebp),%eax
0x08167829 <main+9>: mov %eax,(%esp)
0x0816782c <main+12>: movl $0x5,-0xc(%ebp)
0x08167833 <main+19>: call 0x81677c0 <lst_print>
0x08167838 <main+24>: xor %eax,%eax
0x0816783a <main+26>: leave
0x0816783b <main+27>: ret
What do you think about this? I would say that since variable
arguments can only be accessed via a pointer to the last non-variable
argument, GCC is wrong to ignore the variable arguments here: Function
val_print takes the address of the last non-variable argument and
passes it on, so GCC must expect that the variable arguments will
still be accessed later, no..?
In case GCC is right and my functions are not allowed by the C
standard: does anyone have a hint how to fix my program?
An ugly hack that works is to move function val_print or lst_print to
another source code file.
Maybe there is an __attribute__ I can add to the function?
Many thanks for your time and help,
Elmar
I just switched to GCC 4.4 (gcc44 (GCC) 4.4.0 20090514 (Red Hat
4.4.0-6)) and noted that quite a lot of my functions with variable
arguments are not compiled correctly anymore at -O2 (things are OK at -
O).
Since the problem could well be my knowledge of the C standard, I'd
like to ask about it here before I file a bug report.
Here is the minimum example:
/* PRINT A LIST OF INTEGER VALUES
==============================
list[0] is the number of values in list */
void lst_print(int *list)
{ int i;
for (i=0;i<*list;i++) printf("Value %d: %d\n",i,list[1+i]); }
/* PRINT INTEGER VALUES
====================
The values are specified directly as function parameters */
void val_print(int values,...)
{ /* The list has been put on the stack by the caller... */
lst_print(&values); }
/* TEST PROGRAM
============ */
int main(int argc,char **argv)
{ /* Print 5 integer values from 10 to 50 */
val_print(5,10,20,30,40,50);
return(0); }
Now, at optimization level -O, the result is as expected:
Value 0: 10
Value 1: 20
Value 2: 30
Value 3: 40
Value 4: 50
But at optimization level -O2, the result is garbage:
Value 0: 241472600
Value 1: 0
Value 2: 1
Value 3: 12652532
Value 4: 11273664
Analysis of the assembler code shows that at -O2, GCC entirely
bypasses the function val_print and calls lst_print directly from
main(), but forgets to also put the variable arguments on the stack:
0x08167820 <main+0>: push %ebp
0x08167821 <main+1>: mov %esp,%ebp
0x08167823 <main+3>: sub $0x28,%esp
0x08167826 <main+6>: lea -0xc(%ebp),%eax
0x08167829 <main+9>: mov %eax,(%esp)
0x0816782c <main+12>: movl $0x5,-0xc(%ebp)
0x08167833 <main+19>: call 0x81677c0 <lst_print>
0x08167838 <main+24>: xor %eax,%eax
0x0816783a <main+26>: leave
0x0816783b <main+27>: ret
What do you think about this? I would say that since variable
arguments can only be accessed via a pointer to the last non-variable
argument, GCC is wrong to ignore the variable arguments here: Function
val_print takes the address of the last non-variable argument and
passes it on, so GCC must expect that the variable arguments will
still be accessed later, no..?
In case GCC is right and my functions are not allowed by the C
standard: does anyone have a hint how to fix my program?
An ugly hack that works is to move function val_print or lst_print to
another source code file.
Maybe there is an __attribute__ I can add to the function?
Many thanks for your time and help,
Elmar