Re:GCC: the impressive and the disappointing
by kragen on Saturday March 05, 2011 @12:18PM
(#2291811)
For those who are wondering what the issue could possibly be, if you use the Pascal calling convention in which you push the parameters on the stack and the callee pops them off, then you'll crash when you try to return from a function that was passed the wrong number of parameters. It's perfectly valid for a C compiler to use that calling convention, at least for some functions. It's not traditional, and you need another calling convention for variadic functions, and ANSI C prototypes are a really good idea in that case, but it's certainly valid.
I'm so sure it's valid not because I've actually read the C standard, but because the whole Win16 API was called this way, and Win32 uses a slight variation that passes more things in registers.
Re:GCC: the impressive and the disappointing
by jckarter on Saturday March 05, 2011 @01:33PM
(#2291985)
This is incorrect. It's not possible to implicitly use an incompatible ABI for prototyped and vararg functions, since a foo f(bar, bas) function needs to be callable via an unprototyped foo (* )() pointer. Thus, even prototyped C functions need to use a caller-cleanup convention. To use the callee-cleanup convention, the entire Win16 and Win32 apis are annotated with explicit __stdcall attributes and are addressed by distinctly-typed (__stdcall * ) function pointers, of which no vararg variation is allowed.
Re:GCC: the impressive and the disappointing
by haberman on Saturday March 05, 2011 @04:11PM
(#2292442)
I really wish this were true since it would solve my original problem, but after reading the standard I don't think this is true. From c99, 6.5.2.2 p6:
"If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions. If the number of arguments does not equal the number of parameters, the behavior is undefined."
I take the last sentence to mean that an unprototyped function pointer may only be used to call a function that takes zero parameters.
Re:GCC: the impressive and the disappointing
by ajross on Saturday March 05, 2011 @04:56PM
(#2292577)
That's not what it says. The last statement is talking about what happens at runtime (i.e. the number of values on the stack vs. the number expected, not the number of values passed vs. declared).
Obviously if you don't pass the right number of parameters, the function behavior is undefined (i.e. a pascal function will of course muck up the stack)
Re:GCC: the impressive and the disappointing
by jckarter on Saturday March 05, 2011 @06:26PM
(#2292809)
The language in the standard may have changed in C99 due to unprototyped functions being deprecated. In C89, however, I'm pretty sure that unprototyped and prototyped functions need to have compatible calling conventions. In practice, there's no platform I know of where a prototyped function cannot be called as a variadic or unprototyped function (barring special platform-specific ABIs like stdcall that weren't designed for C). Some RISC-style ABIs with pass-by-register and shadow space will fail in the reverse case (a variadic function called as a fully prototyped function) since the shadow space doesn't get populated by the caller for a fully prototyped function, but for a variadic call site, both the shadow space and parameter registers will be populated, specifically to allow prototyped functions to be called as unprototyped.
Re:GCC: the impressive and the disappointing
by haberman on Saturday March 05, 2011 @03:01PM
(#2292210)
Author here. I was compiling on x86-64 which passes arguments in registers, so the fact that other calling conventions pass on the stack is not relevant for the case I posted about.
Re:GCC: the impressive and the disappointing
by ajg1977 on Saturday March 05, 2011 @01:06PM
(#2291927)
unions are well known for scaring compilers away from many types of optimizations when encountered. For example, if you're writing a SIMD vector class then pretty much the worst thing you can do is put the SIMD data type in a union with a float array.
Re:GCC: the impressive and the disappointing
by haberman on Saturday March 05, 2011 @03:05PM
(#2292222)
The union is irrelevant, even with a union the compiler eliminated the branch in another test I ran where both functions had the same prototype. I'm on an iPad at the moment so can't verify, but I'd be willing to bet that exactly the same code would be generated if the two function pointers were passed as separate parameters (ie not in a union)
I'm so sure it's valid not because I've actually read the C standard, but because the whole Win16 API was called this way, and Win32 uses a slight variation that passes more things in registers.
Further reading:
http://blogs.msdn.com/b/oldnewthing/archive/2004/01/02/47184... http://en.wikipedia.org/wiki/X86_calling_conventions http://unixwiz.net/techtips/win32-callconv.html http://webster.cs.ucr.edu/Page_win32/IczelionTuts/tut1.html
"If the expression that denotes the called function has a type that does not include a prototype, the integer promotions are performed on each argument, and arguments that have type float are promoted to double. These are called the default argument promotions. If the number of arguments does not equal the number of parameters, the behavior is undefined."
I take the last sentence to mean that an unprototyped function pointer may only be used to call a function that takes zero parameters.
Obviously if you don't pass the right number of parameters, the function behavior is undefined (i.e. a pascal function will of course muck up the stack)