Hello everyone,


Both stdcall and cdecl calling convention could support variable input
parameters? Is that correct?

(I think stdcall is using RET N and cdecl is using ESP - N, so both are
capable to handle variable number of input parameter, like printf?)

BTW: I have this question because I have something in mind that only one of
them supports variable number of parameters, but after reading assembly
language code, I think both of them are able to support this feature?


thanks in advance,
George

Re: calling convention stdcalll and cdecl call by Alf

Alf
Thu Jul 17 05:36:46 CDT 2008

* George:
>
> Both stdcall and cdecl calling convention could support variable input
> parameters? Is that correct?
>
> (I think stdcall is using RET N and cdecl is using ESP - N, so both are
> capable to handle variable number of input parameter, like printf?)
>
> BTW: I have this question because I have something in mind that only one of
> them supports variable number of parameters, but after reading assembly
> language code, I think both of them are able to support this feature?

both are based on passing arguments on stack.

cdecl pushes right to left, and caller cleans up.

stdcall, as far as i recall, pushes left to right, and called func cleans up.

thus with cdecl you can have an argument list descriptor as first argument (a la
printf), whereas with stdcall you can have it as last argument, but as far as i
know there's no library support for the latter.

anyway the only reason to dabble in this would be to interface to existing
braindead code that uses variable argument list.


cheer, & hth.,

- alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

Re: calling convention stdcalll and cdecl call by Igor

Igor
Thu Jul 17 07:03:40 CDT 2008

"George" <George@discussions.microsoft.com> wrote in message
news:2CC27965-06FB-4E77-B4A9-D73B1D8D1942@microsoft.com
> Both stdcall and cdecl calling convention could support variable input
> parameters? Is that correct?

No. Variadic functions must use cdecl calling convention.

> (I think stdcall is using RET N and cdecl is using ESP - N, so both
> are capable to handle variable number of input parameter, like
> printf?)

I have no idea what "RET N" or "ESP - N" is supposed to mean.

With stdcall, the function is responsible for removing its parameters
from the stack. To do this, it must know how many parameters there are,
and thus cannot take variable number of parameters.

With cdecl, the caller is responsible for removing parameters after the
called function returns. The caller of course knows how many parameters
it has just pushed on the stack, so there's no problem removing them.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925



Re: calling convention stdcalll and cdecl call by George

George
Fri Jul 18 00:44:07 CDT 2008

Thanks Alf,


1.

> thus with cdecl you can have an argument list descriptor as first argument (a la
> printf), whereas with stdcall you can have it as last argument, but as far as i
> know there's no library support for the latter.

The argument list descriptor you mean the string "My name is: %s, and my ID
is %d" in function call printf ("My name is: %s, and my ID is %d", "George",
123)?

2.

What is the root cause why stdcall does not support variable number of input
parameter? Maybe from generated assembly, we could find out?

(I think both caller and callee could get # of input parameters from stack
in theory?)


regards,
George

Re: calling convention stdcalll and cdecl call by George

George
Fri Jul 18 00:45:00 CDT 2008

Thanks Igor,


What is the root cause why stdcall does not support variable number of input
parameter? Maybe from generated assembly, we could find out?

(I think both caller and callee could get # of input parameters from stack
in theory?)


regard,
George

Re: calling convention stdcalll and cdecl call by Hendrik

Hendrik
Fri Jul 18 02:39:31 CDT 2008

George wrote:
> Thanks Igor,
>
>
> What is the root cause why stdcall does not support variable number of input
> parameter? Maybe from generated assembly, we could find out?

Igor wrote:
> With stdcall, the function is responsible for removing its parameters
> from the stack. To do this, it must know how many parameters there are,
> and thus cannot take variable number of parameters.

> (I think both caller and callee could get # of input parameters from stack
> in theory?)

In practice, however, that would be yet another parameter to push,
which is unnecessary for 99% of all functions. I wouldn't want to
pay for that.

> George

Schobi

Re: calling convention stdcalll and cdecl call by Alf

Alf
Fri Jul 18 03:14:01 CDT 2008

* Igor Tandetnik:
> "George" <George@discussions.microsoft.com> wrote in message
> news:2CC27965-06FB-4E77-B4A9-D73B1D8D1942@microsoft.com
>> Both stdcall and cdecl calling convention could support variable input
>> parameters? Is that correct?
>
> No. Variadic functions must use cdecl calling convention.
>
>> (I think stdcall is using RET N and cdecl is using ESP - N, so both
>> are capable to handle variable number of input parameter, like
>> printf?)
>
> I have no idea what "RET N" or "ESP - N" is supposed to mean.
>
> With stdcall, the function is responsible for removing its parameters
> from the stack. To do this, it must know how many parameters there are,
> and thus cannot take variable number of parameters.

I'm sorry, that's incorrect (counter-example below).

It's only a tool and library limitation.


> With cdecl, the caller is responsible for removing parameters after the
> called function returns. The caller of course knows how many parameters
> it has just pushed on the stack, so there's no problem removing them.

I now see that I remembered incorrectly about pushing order in my reply earlier
in this thread. Happily, as I recall I wrote a disclaimer "as I recall". ;-)


<code file="x.cpp">
#include <iostream>
#include <stdarg.h>

extern "C" void __stdcall display( int x )
{
std::cout << x << std::endl;
}

void _stdcall knurre( int );
void _stdcall knurre( int, int );
void _stdcall knurre( int, int, int );
void _stdcall knurre( int, int, int, int );

int main()
{
knurre( 1, 101 );
knurre( 2, 201, 202 );
knurre( 3, 301, 302, 303 );
}
</code>


<code file="hackity.asm">
.386P
.model FLAT

_TEXT SEGMENT
EXTRN _display@4:NEAR
display EQU _display@4

PUBLIC ?knurre@@YGXH@Z ; (int)
PUBLIC ?knurre@@YGXHH@Z ; (int, int)
PUBLIC ?knurre@@YGXHHH@Z ; (int, int, int)
PUBLIC ?knurre@@YGXHHHH@Z ; (int, int, int, int)

?knurre@@YGXH@Z:
?knurre@@YGXHH@Z:
?knurre@@YGXHHH@Z:
?knurre@@YGXHHHH@Z:
_knurre PROC NEAR
push ebp
mov ebp, esp

mov ecx, [esp+8]
and ecx, ecx
jz finito

displayLoop:
mov eax, [esp+4*ecx+8]
push ecx
push eax
call _display@4
pop ecx
dec ecx
jnz displayLoop

finito:
mov eax, 1234
mov esp, ebp
pop ebp
pop ebx ; Return address
pop ecx
shl ecx, 2
add esp, ecx
jmp ebx
_knurre ENDP

_TEXT ENDS
END
</code>

<output>
101
202
201
303
302
301
</output>

As you can see at the assembly language level (apologies for novice style code,
it's been a long time!) there's no problem. The main problem with the above was
to get Visual C++ to accept the stdcall vararg routine, not changing the calling
convention to cdecl, which it does when it sees "...". For that, had to declare
the function with all actually used signatures -- so it's just a tool problem,
and for that matter, also library problem, that there's no support.


Cheers, & hth.,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

Re: calling convention stdcalll and cdecl call by Igor

Igor
Fri Jul 18 07:55:47 CDT 2008

"George" <George@discussions.microsoft.com> wrote in message
news:22A8AAA7-3D03-474F-AFB9-15177EC3C738@microsoft.com
> What is the root cause why stdcall does not support variable number
> of input parameter? Maybe from generated assembly, we could find out?
>
> (I think both caller and callee could get # of input parameters from
> stack in theory?)

I'm curious about this theory of yours. Show me how a callee can
determine the size of a variable list of parameters.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925



Re: calling convention stdcalll and cdecl call by Igor

Igor
Fri Jul 18 08:12:43 CDT 2008

"Alf P. Steinbach" <alfps@start.no> wrote in message
news:XMudnXxazN5UzR3VnZ2dnUVZ_oWdnZ2d@posted.comnet
> * Igor Tandetnik:
>> With stdcall, the function is responsible for removing its parameters
>> from the stack. To do this, it must know how many parameters there
>> are, and thus cannot take variable number of parameters.
>
> I'm sorry, that's incorrect (counter-example below).

Your example uses additional domain-specific information that the
compiler doesn't have, in general: that the first parameter specifies
the total number of remaining parameters, and that all parameters are
the same size.

Or are you suggesting that the caller should pass the total size of all
parameters as a hidden first parameter? That defeats the whole point of
__stdcall convention, which is to shave one machine instruction off the
call site. If you are willing to push the size of parameters onto the
stack before the call, you can just as well update ESP after the call
instead - at which point you are happily back in __cdecl land.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925



Re: calling convention stdcalll and cdecl call by Alex

Alex
Fri Jul 18 08:19:50 CDT 2008

"Alf P. Steinbach" wrote:
> As you can see at the assembly language level [...] there's no
> problem. [...] so it's just a tool problem, and for that matter,
> also library problem, that there's no support.

I think there is a problem at the assembly language level.
Actually, it is the __stdcall calling convention itself is a
problem.

You have to pass a number of actual parameters to the collee.
Otherwise there is no way to clean the stack from within a
function. This is inherent limitation of __stdcall calling
convention no matter what tool or library you may use. __cdecl
delegates this problem to the caller, so there is nothing to wory
about for the function itself.

Alex



Re: calling convention stdcalll and cdecl call by Alf

Alf
Fri Jul 18 12:02:59 CDT 2008

* Igor Tandetnik:
> "Alf P. Steinbach" <alfps@start.no> wrote in message
> news:XMudnXxazN5UzR3VnZ2dnUVZ_oWdnZ2d@posted.comnet
>> * Igor Tandetnik:
>>> With stdcall, the function is responsible for removing its parameters
>>> from the stack. To do this, it must know how many parameters there
>>> are, and thus cannot take variable number of parameters.
>> I'm sorry, that's incorrect (counter-example below).
>
> Your example uses additional domain-specific information that the
> compiler doesn't have, in general: that the first parameter specifies
> the total number of remaining parameters,

Are you of the impression that a vararg routine can access its arguments without
some information about them?


> and that all parameters are
> the same size.

I'm sorry, but that's incorrect.


> Or are you suggesting that the caller should pass the total size of all
> parameters as a hidden first parameter?

That is how it has worked on at least one OS, so it's not a bad idea, but
neither it is a required way to do it.


> That defeats the whole point of
> __stdcall convention, which is to shave one machine instruction off the
> call site. If you are willing to push the size of parameters onto the
> stack before the call, you can just as well update ESP after the call
> instead - at which point you are happily back in __cdecl land.

I'm sorry, but there's no connection between premise and conclusion, and the
conclusion is wrong (e.g. printf is a counter-example).

It would be nice if you'd care to think before posting, but I'm sure this all
babble comes from a wish to not have to admit being wrong.


Cheers,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

Re: calling convention stdcalll and cdecl call by Igor

Igor
Fri Jul 18 13:11:10 CDT 2008

Alf P. Steinbach <alfps@start.no> wrote:
> * Igor Tandetnik:
>> "Alf P. Steinbach" <alfps@start.no> wrote in message
>> news:XMudnXxazN5UzR3VnZ2dnUVZ_oWdnZ2d@posted.comnet
>>> * Igor Tandetnik:
>>>> With stdcall, the function is responsible for removing its
>>>> parameters from the stack. To do this, it must know how many
>>>> parameters there are, and thus cannot take variable number of
>>>> parameters.
>>> I'm sorry, that's incorrect (counter-example below).
>>
>> Your example uses additional domain-specific information that the
>> compiler doesn't have, in general: that the first parameter specifies
>> the total number of remaining parameters,
>
> Are you of the impression that a vararg routine can access its
> arguments without some information about them?

No, but the precise way the routine acheives that is not known to the
compiler.

>> Or are you suggesting that the caller should pass the total size of
>> all parameters as a hidden first parameter?
>
> That is how it has worked on at least one OS, so it's not a bad idea,
> but neither it is a required way to do it.

What other ways would you suggest to allow the callee to clean up the
stack space occupied by a variable number of parameters? Preferably ways
that a compiler could apply mechanically, without having to understand
the meaning of individual parameters (like having to parse printf-like
format string).

>> That defeats the whole point of
>> __stdcall convention, which is to shave one machine instruction off
>> the call site. If you are willing to push the size of parameters
>> onto the stack before the call, you can just as well update ESP
>> after the call instead - at which point you are happily back in
>> __cdecl land.
>
> I'm sorry, but there's no connection between premise and conclusion,
> and the conclusion is wrong (e.g. printf is a counter-example).

printf is a counterexample of what? It uses cdecl convention, where the
caller is responsible for clearing up the stack. Consider also:

printf("%d", 1, 2);

How would your hypothetical stdcall printf know to remove 12 bytes worth
of parameters, rather than 8?


Let's put it this way. Yes, it is possible to design a calling
convention that a) allows for variable number of arguments, and b)
requires the callee to clean the stack. All you have to do is to have
the caller set up and pass sufficient additional information to the
callee (e.g. total size of all arguments).

However, it's not clear _why_ you would want such a thing. It has no
advantage over __cdecl - you still need an extra machine instruction or
two at every call site to set up this additional information (which is
the problem __stdcall was designed to solve). And, it complicates the
callee, too - witness the dance you had to perform in your assembly code
to simulate RET instruction (where __cdecl function would just have
plain RET, and __stdcall one would have RET n for some constant n).

You complained that tools and libraries don't support such a calling
convention. This is the reason why - this convention doesn't make much
sense. It doesn't improve in any way on those already supported, and in
fact makes things (slightly) worse. Just because something is, in
principle, possible, doesn't necessarily mean it's a good idea.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925



Re: calling convention stdcalll and cdecl call by Alf

Alf
Fri Jul 18 13:54:01 CDT 2008

* Igor Tandetnik:
>
> printf is a counterexample of what? It uses cdecl convention, where the
> caller is responsible for clearing up the stack. Consider also:
>
> printf("%d", 1, 2);
>
> How would your hypothetical stdcall printf know to remove 12 bytes worth
> of parameters, rather than 8?

I think you're stupid.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

Re: calling convention stdcalll and cdecl call by Igor

Igor
Fri Jul 18 14:12:04 CDT 2008

Alf P. Steinbach <alfps@start.no> wrote:
> * Igor Tandetnik:
>>
>> printf is a counterexample of what? It uses cdecl convention, where
>> the caller is responsible for clearing up the stack. Consider also:
>>
>> printf("%d", 1, 2);
>>
>> How would your hypothetical stdcall printf know to remove 12 bytes
>> worth of parameters, rather than 8?
>
> I think you're stupid.

That's what kids on the playground say when they don't have any
arguments. Have a nice day.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925



Re: calling convention stdcalll and cdecl call by Alf

Alf
Fri Jul 18 14:30:32 CDT 2008

* Igor Tandetnik:
> Alf P. Steinbach <alfps@start.no> wrote:
>> * Igor Tandetnik:
>>> printf is a counterexample of what? It uses cdecl convention, where
>>> the caller is responsible for clearing up the stack. Consider also:
>>>
>>> printf("%d", 1, 2);
>>>
>>> How would your hypothetical stdcall printf know to remove 12 bytes
>>> worth of parameters, rather than 8?
>> I think you're stupid.
>
> That's what kids on the playground say when they don't have any
> arguments. Have a nice day.

Or perhaps you're just weaseling, who knows.

For what it's worth the above example (1) has undefined behavior, (2) states
that I somehow have ownership of an addressing convention, which is incorrect
and misleading and just idiotic, but typical weaseling rhetoric, and (3) asks a
question you already got complete demonstration code for, and based on that
example you yourself pointed out one possible answer to that question.

It shouldn't be that hard to admit a technical mistake.

But instead you start (1) misrepresenting me, (2) accusing me of "complaining"
etc, and now (3) accusing me of lacking arguments when I refuse to address all
your inane babble, as if such accusations could correct your mistake.

But I think you're simply stupid.


- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

Re: calling convention stdcalll and cdecl call by Alex

Alex
Fri Jul 18 14:58:56 CDT 2008

"Alf P. Steinbach" wrote:
> It shouldn't be that hard to admit a technical mistake.

I think it is you who should admit a technical mistake, besides
the fact that you owe an apology to Igor for being plain rude.
Igor's answer is to the point and you failed to address the issue.

Your example proves the very point that Igor and I tried to
convey, but you refused to see. In order to enable __stdcall
function to accept a variable number of parameters you have to
pass this information to the function. This is exactly what you
did. At this point __stdcall is not much different from existing
__cdecl.

Alex



Re: calling convention stdcalll and cdecl call by Alf

Alf
Fri Jul 18 15:15:53 CDT 2008

* Alex Blekhman:
> "Alf P. Steinbach" wrote:
>> It shouldn't be that hard to admit a technical mistake.
>
> I think it is you who should admit a technical mistake, besides
> the fact that you owe an apology to Igor for being plain rude.

Igor owes me apology for misrepresenting me, calling me a complainer etc. And
I'm doing him honors by assuming he's stupid rather than weaseling person
employing deception. So he should properly also thank me, after apologizing.


> Igor's answer is to the point and you failed to address the issue.

Igor made a mistake (i.e. not answer and not to the point), I posted working
code that completely addressed the issue (i.e. not failed to address issue but
the complete opposite, I addressed the issue, fully), and what is the point of
posting two such blatantly false assertions in one sentence?


> Your example proves the very point that Igor and I tried to
> convey, but you refused to see.

Igor write "thus cannot take variable number of parameters", which as
demonstrated is *incorrect*, and it is a self-contradiction that I should have
refused to see what I demonstrated. Given the lack of coherence and meaning in
Igor's successive articles I don't know what he originally tried to convey, so
you may be right that he may have meant to convey something wildly different
from what he wrote. But unless he has explained that via some other physical
channel to you, you don't know that either, other than via telepathy.

So, telepathy + self-contradiction in one sentence => a bit overheated, perhaps?

No matter, 'tis OK. :-)


> In order to enable __stdcall
> function to accept a variable number of parameters you have to
> pass this information to the function. This is exactly what you
> did.

That's correct.


> At this point __stdcall is not much different from existing
> __cdecl.

The "not much" means that it's a matter of personal opinion, not something we
can resolve if we should turn out to be of different minds about that. So, not
meaningful. I gather you do agree that there is a difference, no matter size.

Cheers, & hth.

- Alf


--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

Re: calling convention stdcalll and cdecl call by Hendrik

Hendrik
Fri Jul 18 15:13:47 CDT 2008

Alf P. Steinbach wrote:
> [...]
> It would be nice if you'd care to think before posting, but I'm sure this all
> babble comes from a wish to not have to admit being wrong.

I have no idea where this came from and your following answers
convey exactly what above you try to pin on Igor.
So far this had been a very interesting discussion, but now you
stopped arguing and instead resorted to being rude, so that I
can't help but think you ran out of arguments.

> - Alf

Schobi

Re: calling convention stdcalll and cdecl call by Igor

Igor
Fri Jul 18 15:34:51 CDT 2008

Alf P. Steinbach <alfps@start.no> wrote:
> * Igor Tandetnik:
>>>> printf("%d", 1, 2);
>
> For what it's worth the above example (1) has undefined behavior

Not true. C99 standard explicitly covers this case:

7.19.6.1/2 The fprintf function writes output to the stream pointed to
by stream, under control of the string pointed to by format that
specifies how subsequent arguments are converted for output. If there
are insufficient arguments for the format, the behavior is undefined.
*If the format is exhausted while arguments remain, the excess arguments
are evaluated (as always) but are otherwise ignored.* (emphasis mine).

In 7.19.6.3, printf is defined in terms of fprintf.

I don't have C89 standard handy at the moment, but I'm pretty sure it
contains the same wording.

> (2) states that I somehow have ownership of an addressing convention,
> which is incorrect and misleading and just idiotic, but typical
> weaseling rhetoric

What do you mean by "addressing convention"? I'm not familiar with the
term. Since I don't know what it is, I don't make any statements about
its ownership.

All I state is this. The above call is perfectly valid according to the
standard, so a conforming C compiler has to support it. To execute this
call, three arguments have to be pushed onto the stack, and then later
three arguments have to be popped off. Under cdecl calling convention,
both operations are done by the caller, who of course knows how many
arguments there are.

You seem to suggest that it is perfectly reasonable to require the
callee to clean up the stack instead. I'd like to see what mechanism you
propose to make this possible, other than having the caller pass
additional information to the callee, above and beyond the three
arguments (e.g. the total size of all arguments).

If the mechanism you'd like to propose does involve passing additional
information to the function, then I agree with you in that such a
calling convention would indeed be possible. However, I don't see how it
would be an improvement over cdecl. And since cdecl is already happily
supported by existing tools, it is hard to expect compiler authors to
begin supporting something that is worse. What would be the point?

On the other hand, stdcall is an improvement over cdecl, however minor.
It shifts one machine instruction from the call site (where it has to be
repeated for each call) to the callee (where it exists only once per
function, not once per every place in the program where the function is
called). In exchange for this slight efficiency gain, it loses the
ability to support variadic functions.

> and (3) asks a question you already got complete
> demonstration code for, and based on that example you yourself
> pointed out one possible answer to that question.

Right. My point is _not_ that the technique your sample demonstrates is
impossible. Just that it's unnecessarily complicated and pointless, and
so it's not at all surprising that it's not supported by mainstream
tools.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925



Re: calling convention stdcalll and cdecl call by Ben

Ben
Fri Jul 18 15:57:05 CDT 2008

Igor Tandetnik wrote:
> "George" <George@discussions.microsoft.com> wrote in message
> news:22A8AAA7-3D03-474F-AFB9-15177EC3C738@microsoft.com
>> What is the root cause why stdcall does not support variable number
>> of input parameter? Maybe from generated assembly, we could find out?
>>
>> (I think both caller and callee could get # of input parameters from
>> stack in theory?)
>
> I'm curious about this theory of yours. Show me how a callee can
> determine the size of a variable list of parameters.

By parsing the format string...

Of course, this would cause even more terrible things to happen when the
format string mismatches the parameters than currently happens.

non-printf style functions still need to process all the parameters to do
their work, so they too need some way of identifying how many parameters
will be used.



Re: calling convention stdcalll and cdecl call by Liviu

Liviu
Fri Jul 18 16:01:39 CDT 2008

"Alf P. Steinbach" <alfps@start.no> wrote
>* Igor Tandetnik:
>> Alf P. Steinbach <alfps@start.no> wrote:
>>> * Igor Tandetnik:
>>>>
>>>> printf("%d", 1, 2);
>
> For what it's worth the above example (1) has undefined behavior

Nope, behavior is both defined and expected (prints 1, excess arguments
are evaluated but ignored).

You might be thinking at "printf("%d");" but even in that case the
"undefinededness" is particular to printf, and has nothing to do with
calling conventions for variadic functions in general. Didn't follow the
thread in all its glorious detail. but if you are trying to make the
point that a callee can "magically guess" the number of arguments pushed
on the stack by the caller (without hidden parameters or additional
overhead like standard stack "frames"), then that's so obviously wrong.







Re: calling convention stdcalll and cdecl call by Alex

Alex
Fri Jul 18 16:23:01 CDT 2008

"Alf P. Steinbach" wrote
>> Your example proves the very point that Igor and I tried to
>> convey, but you refused to see.
>
> Igor write "thus cannot take variable number of parameters",
> which as demonstrated is *incorrect*, and it is a
> self-contradiction that I should have refused to see what I
> demonstrated.

Oh, come on. What you have demonstrated that a developer can pull
a trick and fool the compiler. You could have written
__declspec(naked) for that matter. What you have written is not
__stdcall anymore, but your own calling convention that supports a
variable number of arguments.

>> At this point __stdcall is not much different from existing
>> __cdecl.
>
> The "not much" means that it's a matter of personal opinion, not
> something we can resolve if we should turn out to be of
> different minds about that.

The "not much" means the following:

1. __stdcall, as it is implemeted today, cannot accept a variable
number of arguments because a function must know a number of
actual arguments at compile time.

2. In order to enable __stdcall to accept a variable number of
arguments we need to change it. This change envolves
a) passing an additional hidden argument to a function,
b) changing a way that a function uses to clean the stack.

3. Making the above changes we eventually have invented a new
calling convention, which does the same job that __cdecl designed
to do and uses the same amount of CPU instructions to make things
work.

So, the question is why do we need to invent this new calling
convention when we have perfectly working __cdecl already?

Let me return to your asm example to demonstrate the point.
Imagine that you need to make a DLL that exports

void __stdcall knurre(...);

function. All you know is that compiler pushes parameters right to
left and you are responsible to clean the stack. It is simply
impossible to do *without changing* the way how the compiler
generates __stdcall calling code.

Alex



Re: calling convention stdcalll and cdecl call by Alf

Alf
Fri Jul 18 16:27:55 CDT 2008

* Liviu:
> "Alf P. Steinbach" <alfps@start.no> wrote
>> * Igor Tandetnik:
>>> Alf P. Steinbach <alfps@start.no> wrote:
>>>> * Igor Tandetnik:
>>>>> printf("%d", 1, 2);
>> For what it's worth the above example (1) has undefined behavior
>
> Nope, behavior is both defined and expected (prints 1, excess arguments
> are evaluated but ignored).

In C99. Thanks, I didn't know. Do you have C89 standard?


> You might be thinking at "printf("%d");" but even in that case the
> "undefinededness" is particular to printf, and has nothing to do with
> calling conventions for variadic functions in general.

It had to do with a minor point that Igor may or may not have been trying to
make, who knows since evidently he doesn't mean what he writes.

But just to address what you say, although unrelated to original context: I'm
sorry, but that's incorrect, i.e. contrary to your claim the behavior of printf
has to do with calling conventions for variadic functions in general.

C99 printf directly supports a functionally limited and generally inefficient
calling convention (C-style) and for printf, makes the case that that convention
doesn't handle, undefined behavior.


> Didn't follow the
> thread in all its glorious detail. but if you are trying to make the
> point that a callee can "magically guess" the number of arguments pushed
> on the stack by the caller (without hidden parameters or additional
> overhead like standard stack "frames"), then that's so obviously wrong.

Yeah, it's clear that you haven't followed the thread. I replied originally to
Igor by posting complete C++ plus assembly language code for an example of
__stdcall variadic arguments. Showing that his claim that it was impossible, was
simply incorrect.

Since then a number of idiotic claims and positions, such as the one you
describe, have been argued against, /as if/ they had been claims I made, plus
that evidently I have been complaining, plus thinking my ways are "better", +++.

I made only one claim, and proved it, that Igor's claim was 100% incorrect. Any
other claims attributed to me are just deception, weaseling. I don't understand
how it can be so hard for some to admit they made an error, but evidently it is.


Cheers,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

Re: calling convention stdcalll and cdecl call by Alf

Alf
Fri Jul 18 16:48:52 CDT 2008

* Alex Blekhman:
> "Alf P. Steinbach" wrote
>>> Your example proves the very point that Igor and I tried to
>>> convey, but you refused to see.
>> Igor write "thus cannot take variable number of parameters",
>> which as demonstrated is *incorrect*, and it is a
>> self-contradiction that I should have refused to see what I
>> demonstrated.
>
> Oh, come on. What you have demonstrated that a developer can pull
> a trick and fool the compiler. You could have written
> __declspec(naked) for that matter. What you have written is not
> __stdcall anymore, but your own calling convention that supports a
> variable number of arguments.

It's pure __stdcall, as you can see from the C++ interface.

The C++ compiler only sees a set of __stdcall functions.

Hence those functions, by virtue of walking, waddling and quacking and in any
other way behaving just like __stdcall functions, are __stdcall functions.

And since each of them is identically, same address, the same as a single
variadic function, that one is also __stdcall.

If that was too complex an explanation, then think about what property of
__stdcall is violated: there is no such property.



>>> At this point __stdcall is not much different from existing
>>> __cdecl.
>> The "not much" means that it's a matter of personal opinion, not
>> something we can resolve if we should turn out to be of
>> different minds about that.
>
> The "not much" means the following:
>
> 1. __stdcall, as it is implemeted today, cannot accept a variable
> number of arguments because a function must know a number of
> actual arguments at compile time.
>
> 2. In order to enable __stdcall to accept a variable number of
> arguments we need to change it. This change envolves
> a) passing an additional hidden argument to a function,
> b) changing a way that a function uses to clean the stack.

There are more alternatives here.

In particular, one practical one would be where the function calls some library
function that reports the stack usage, based on e.g. printf-style first argument.


> 3. Making the above changes we eventually have invented a new
> calling convention, which does the same job that __cdecl designed
> to do

No it isn't a new calling convention, no it isn't invented by "us" (whoever that
is), and no it doesn't do just the same job as __cdecl, it does a little more.


> and uses the same amount of [executed] CPU instructions to make things
> work.

Actually may uses fewer or more (I'd guess one or two more), but in the case
where a function fits in a cache but calling code doesn't, may be more efficient.


> So, the question is why do we need to invent this new calling
> convention when we have perfectly working __cdecl already?

Whoever the plural "you" are, probably don't need to invent anything.

I just showed that the claim that it was impossible, was totally incorrect.

Your inference that there is a need for this may be correct or not, I dunno.


> Let me return to your asm example to demonstrate the point.
> Imagine that you need to make a DLL that exports
>
> void __stdcall knurre(...);
>
> function. All you know is that compiler pushes parameters right to
> left and you are responsible to clean the stack. It is simply
> impossible to do *without changing* the way how the compiler
> generates __stdcall calling code.

Is the point that if you insist on using a way that doesn't work, it won't work?

Seems a little silly to me. ;-)


Cheers, & hth.,

- Alf


--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

Re: calling convention stdcalll and cdecl call by Liviu

Liviu
Fri Jul 18 17:22:40 CDT 2008

"Alf P. Steinbach" <alfps@start.no> wrote
>* Liviu:
>> "Alf P. Steinbach" <alfps@start.no> wrote
>>> * Igor Tandetnik:
>>>> Alf P. Steinbach <alfps@start.no> wrote:
>>>>> * Igor Tandetnik:
>>>>>> printf("%d", 1, 2);
>>> For what it's worth the above example (1) has undefined behavior
>>
>> Nope, behavior is both defined and expected (prints 1, excess
>> arguments
>> are evaluated but ignored).
>
> In C99. Thanks, I didn't know. Do you have C89 standard?

Don't have it handy, but if google's
http://rm-f.net/~orange/devel/specifications/c89-draft.html#4.9.6.1
is to be trusted, then it's the same:

| If there are insufficient arguments for the format, the behavior is
| undefined. If the format is exhausted while arguments remain, the
| excess arguments are evaluated (as always) but are otherwise ignored.

>> You might be thinking at "printf("%d");" but even in that case the
>> "undefinededness" is particular to printf, and has nothing to do with
>> calling conventions for variadic functions in general.
>
> It had to do with a minor point that Igor may or may not have been
> trying to make, who knows since evidently he doesn't mean what he
> writes.

I'll go on a limb here ;-) but I trust Igor meant exactly what he wrote:

| With stdcall, the function is responsible for removing its parameters
| from the stack. To do this, it must know how many parameters there
| are, and thus cannot take variable number of parameters.

> But just to address what you say, although unrelated to original
> context: I'm sorry, but that's incorrect, i.e. contrary to your claim
> the behavior of printf has to do with calling conventions for variadic
> functions in general.
>
> C99 printf directly supports a functionally limited and generally
> inefficient calling convention (C-style) and for printf, makes the
> case that that convention doesn't handle, undefined behavior.

Sorry, but I don't follow. The only undefined behavior mentioned there
is when the caller passes _fewer_ arguments than expected from the
format string, and that's because of printf internals. On the other
hand, the standard explicitly states that excess parameters are
ignored, so it's painfully obvious that printf couldn't possibly clear
the stack after itself based on what the format string says.

Imagine for a moment that you'd be writing the __stdcall printf(const
char *, ...) code. At the point your code would be entered, everything
would look _exactly_ the same when the function is called in either of
these ways:

printf("%d", 1);
printf("%d", 1, 2);

How would you code your printf so that it pops the right number of bytes
off the stack in each case?

> I replied originally to Igor by posting complete C++ plus assembly
> language code for an example of __stdcall variadic arguments.

No. You just provided several overloads of the 'knurre' function which
happened to internally share some assembly code.

If the point of the exercise was to show that passing an additional
"number of params" into a function can allow it to pop the stack itself,
then yes of course it's both possible and trivial. But it's not
__stdcall, since there is no presumption in __stdcall that such a
"number of params" argument must exist.

And, if you proposed a new calling convention which does that, it would
be highly fragile, and something like

knurre(1, 101, 102, 103);

would not only confuse the callee, but also corrupt the entire stack.

> Showing that his claim that it was impossible, was simply incorrect.

I requoted his claim above. What part exactly do you find incorrect?

Cheers,
Liviu











Re: calling convention stdcalll and cdecl call by Alf

Alf
Fri Jul 18 17:39:51 CDT 2008

* Liviu:
> "Alf P. Steinbach" <alfps@start.no> wrote
>> It had to do with a minor point that Igor may or may not have been
>> trying to make, who knows since evidently he doesn't mean what he
>> writes.
>
> I'll go on a limb here ;-) but I trust Igor meant exactly what he wrote:
>
> | With stdcall, the function is responsible for removing its parameters
> | from the stack. To do this, it must know how many parameters there
> | are, and thus cannot take variable number of parameters.

That was not it. But that was the start of that subthread, yes.


> I requoted his claim above. What part exactly do you find incorrect?

"and thus cannot take variable number of parameters" is incorrect.


Cheers,

- Aldf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

Re: calling convention stdcalll and cdecl call by Alf

Alf
Fri Jul 18 17:52:52 CDT 2008

* Liviu:
> "Alf P. Steinbach" <alfps@start.no> wrote
>> * Liviu:
>>> "Alf P. Steinbach" <alfps@start.no> wrote
>>>> * Igor Tandetnik:
>>>>> Alf P. Steinbach <alfps@start.no> wrote:
>>>>>> * Igor Tandetnik:
>>>>>>> printf("%d", 1, 2);
>>>> For what it's worth the above example (1) has undefined behavior
>>> Nope, behavior is both defined and expected (prints 1, excess
>>> arguments
>>> are evaluated but ignored).
>> In C99. Thanks, I didn't know. Do you have C89 standard?
>
> Don't have it handy, but if google's
> http://rm-f.net/~orange/devel/specifications/c89-draft.html#4.9.6.1
> is to be trusted, then it's the same:
>
> | If there are insufficient arguments for the format, the behavior is
> | undefined. If the format is exhausted while arguments remain, the
> | excess arguments are evaluated (as always) but are otherwise ignored.
>
>>> You might be thinking at "printf("%d");" but even in that case the
>>> "undefinededness" is particular to printf, and has nothing to do with
>>> calling conventions for variadic functions in general.
>> It had to do with a minor point that Igor may or may not have been
>> trying to make, who knows since evidently he doesn't mean what he
>> writes.
>
> I'll go on a limb here ;-) but I trust Igor meant exactly what he wrote:
>
> | With stdcall, the function is responsible for removing its parameters
> | from the stack. To do this, it must know how many parameters there
> | are, and thus cannot take variable number of parameters.
>
>> But just to address what you say, although unrelated to original
>> context: I'm sorry, but that's incorrect, i.e. contrary to your claim
>> the behavior of printf has to do with calling conventions for variadic
>> functions in general.
>>
>> C99 printf directly supports a functionally limited and generally
>> inefficient calling convention (C-style) and for printf, makes the
>> case that that convention doesn't handle, undefined behavior.
>
> Sorry, but I don't follow.

See below.


> The only undefined behavior mentioned there
> is when the caller passes _fewer_ arguments than expected from the
> format string, and that's because of printf internals.

No, that's not because of printf internals, that's because with the C calling
convention printf has no way of checking that there are indeed enough arguments.



> On the other
> hand, the standard explicitly states that excess parameters are
> ignored, so it's painfully obvious that printf couldn't possibly clear
> the stack after itself based on what the format string says.

Unfortunately, yes.


> Imagine for a moment that you'd be writing the __stdcall printf(const
> char *, ...) code. At the point your code would be entered, everything
> would look _exactly_ the same when the function is called in either of
> these ways:
>
> printf("%d", 1);
> printf("%d", 1, 2);
>
> How would you code your printf so that it pops the right number of bytes
> off the stack in each case?

No problem. The number of bytes is passed in any way the compiler deems
suitable, since printf is declared with "...". This is the same as the compiler
is free to use e.g. RVO, and really whatever it wants; you'd not say that a
stdcall function that the compiler implements with RVO is not stdcall?


>> I replied originally to Igor by posting complete C++ plus assembly
>> language code for an example of __stdcall variadic arguments.
>
> No. You just provided several overloads of the 'knurre' function which
> happened to internally share some assembly code.

So? "You just provided a car-minus-wheels plus wheels attached". How is that the
reality different from a car, just by your description being different and
focused on irrelevant details?


> If the point of the exercise was to show that passing an additional
> "number of params" into a function can allow it to pop the stack itself,
> then yes of course it's both possible and trivial. But it's not
> __stdcall, since there is no presumption in __stdcall that such a
> "number of params" argument must exist.

The __stdcall convention does not address what arguments are used for.

It's meaningless to say that void foo(char ch), when compiled as stdcall, isn't
stdcall just because that argument is used for output or whatever, and that that
argument usage is not prescribed by stdcall.

And it's meaningless to say that an RVO-optimized function isn't stdcall (an
RVO-optimized function may have an extra hidden compiler-generated argument).
However by your reasoning it can't be. I don't really think you believe this
idiocy yourself, I think you're just putting it forward as rhetoric.


Cheers, & hth.,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

Re: calling convention stdcalll and cdecl call by Igor

Igor
Fri Jul 18 18:20:42 CDT 2008

Alf P. Steinbach <alfps@start.no> wrote:
> * Alex Blekhman:
>> "Alf P. Steinbach" wrote
>>>> Your example proves the very point that Igor and I tried to
>>>> convey, but you refused to see.
>>> Igor write "thus cannot take variable number of parameters",
>>> which as demonstrated is *incorrect*, and it is a
>>> self-contradiction that I should have refused to see what I
>>> demonstrated.
>>
>> Oh, come on. What you have demonstrated that a developer can pull
>> a trick and fool the compiler. You could have written
>> __declspec(naked) for that matter. What you have written is not
>> __stdcall anymore, but your own calling convention that supports a
>> variable number of arguments.
>
> It's pure __stdcall, as you can see from the C++ interface.

No it's not, really. You have effectively defined a new calling
convention - let's call it alfcall - where the caller passes the number
or size of the argument list to the callee, and the callee is
responsible for cleaning the stack. alfcall is different from both cdecl
and stdcall.

You then go to some lengths to simulate alfcall using existing
mechanisms. On the caller side, you have to define multiple function
signatures for what is supposed to be one variadic function, and you
have to explicitly supply an extra argument that contains the number of
remaining arguments. On the callee side, you can't use C or C++ at all,
but have to implement it in assembly.

Consider an example. Suppose I have a function

void f(int x, int y) {}

and I call it like this: f(1, 2). Let's see what the call site and the
function body would look like if the function were declared cdecl,
stdcall and alfcall.

1) cdecl
; call site
push 2
push 1
call f
add esp, 8 ; pop parameters

; function body
ret

2) stdcall
; call site
push 2
push 1
call f

; function body
ret 8 ; pop parameters

3) alfcall
; call site
push 2
push 1
push 8 ; total size of arguments
call f

; function body
pop ebx ; return address
pop ecx ; size of arguments
add esp, ecx; pop arguments
jmp ebx ; return


Compared to cdecl, call site for alfcall convention has the same number
of machine instructions, but the function epilogue is larger. Contrast
with stdcall, where the call site is one instruction smaller (which was
the goal of the exercise), and the function epilogue is slightly larger.

So, while it is possible to implement something like alfcall calling
convention, it's not clear why one should bother, given that it's
strictly worse than cdecl.

> The C++ compiler only sees a set of __stdcall functions.

But wasn't the goal of the exercise to have the C++ compiler see just
one variadic function with __stdcall convention? Defining a set of
__stdcall functions, each with a fixed signature, is not particularly
interesting. Requiring the developer to count parameters and pass the
count explicitly probably won't help adoption either. Neither would
having to write the function itself in assembly.

I assumed that your sample was intended to demonstrate that a compiler