Re: calling convention stdcalll and cdecl call
* Ben Voigt [C++ MVP]:
Alf P. Steinbach wrote:
* Ben Voigt [C++ MVP]:
Since stdcall defines no such mechanism and reserves no location
(hidden param, designated register, stack slot) to accommodate that
additional information, any place you'd choose to pass the info
would have been up for grabs under the existing stdcall convention,
No, not at all. There are only two cases to consider.
Either (1) the language implementation already supports variadic
stdcall routines, in which case it necessarily already does this.
:-)
And possibly in a way incompatible with yours.
First, I've posted in a follow-up to you elsewhere that I have no
ownership.
I see "a proposal for extending tool support for stdcall to permit variadic
functions". The calling convention stdcall is not yours, the proposal to
extend it is. Or no?
No to both and more.
The calling convention is not mine,
the way to implement it that I've demonstrated is not mine,
I have not made any proposal (on the contrary, I've cautioned against that, but
seemingly for very deaf ears),
and your quote, if it is meant as a quote, is certainly not quoting me -- I
think it's something you made up.
Please don't use such intentionally misleading rhetorical techniques
in future, especially after having been notified not to do so. This
paragraph is your second notification about that particular issue. I
must assume that you did understand the first notification, and are
therefore now doing it just as a manipulative technique. TIA for
stopping, if you can. I understand that this manipulative tendency is
perhaps ingrained in Microsoft corporate culture, at least as
displayed in this group, but it just takes some willpower to be
honest.
Now, re your comment.
In the case of having support for stdcall variadic function in the
language implementation, one would not change the language
implementation.
A definite article has no place here (i.e. "the").
The definite article refers to the hypothetical language implementation under
discussion.
English is not my native language, but you're really grasping at straws here.
As Liviu has pointed out
repeatedly, there's not just one implementation. Many compilers, for
multiple languages, have support for stdcall.
I fail to see the relevance to any aspect of the /technical/ matters discussed.
The Earth is round, the moon is there, one must assume the galaxy is still
hanging on. Those are all trivially true facts, but by mentioning particular
trivially true facts, in a context where it seems you're arguing against me, I'm
pretty sure you're trying to be manipulative again.
I.e., talking to an audience, trying to make readers believe I must, somewhere
earlier, have maintained the opposite of your mentioned trivially true facts.
Why not try to be honest for a change?
Your entire rebuttal hinges on there being only one existing implementation
which either includes or excludes variable argument lists, and thus is
faulty.
No, that's at best a misunderstanding on your part.
But since this doesn't even make sense as manipulative
make-readers-believe-some-silly-thing-about-Alf's-arguments, I think you're
perhaps sleep-deprived or something.
I mean, you have written meaningful things before, even insightful things, as I
recall.
So I'll go easy, I'm assuming sleep deprivation or tiredness or something on
your part.
Anyway, first, even if had made such an idiotic argument, which of course I
haven't (this is Usenet, with complete history available for those who want to
check), even if I had made such an idiotic argument it wouldn't affect reality.
And second, your article contained four individual fallacies which I pointed out
individually, no one individual pointing-out-of-fallacy relying on others.
I will present my argument in a simpler form to make it easier to respond
to.
Good, thank you.
Premise #1 -- An calling convention implements stdcall iff it in binary
compatible with every other conformant implementation.
This either places very strong constraints on "binary compatible", or is simply
wrong.
In general it's simply wrong -- but see comment at end of this section below.
Although I don't consider mangled names to be part of stdcall convention, first
example that binary compatibility doesn't hold for that. g++ produces mangled
name "__Z3food@8" for "void __stdcall foo( double ) {}", whereas MSVC produces
mangled name "?foo@@YGXN@Z". I'm sorry for addressing since you don't bring it
explicitly up, but the vagueness of "binary compatible" means it could mean just
about anything, so, if you need even more forceful arg about that, consider e.g.
not-mangled names of MessageBox routines in user32.dll.
Arguing against myself, it's not unreasonable to consider /C/ mangled names as
part of stdcall convention.
Arguing back against myself, hey, that's a neat notion, but only for a subset of
cases; e.g. it falls flat on its face when compared to the Windows API reality,
where names are not mangled that way, but are certainly stdcall.
Then, if hopefully that's a complete enough exposition of the mangling as part
of convention or not (yes in some cases, no in general, e.g. for Windows API),
example of different machine code for same __stdcall routine.
#include <iostream>
struct Blah { int x; Blah(): x(666) {} };
Blah __stdcall foo() { Blah x; return x; } // This routine.
int main()
{
Blah const b = foo();
std::cout << b.x << std::endl;
}
Here g++ (default options) returns the result in register EAX,
.def __Z3foov@0; .scl 2; .type 32; .endef
__Z3foov@0:
push ebp
mov ebp, esp
mov eax, 666
pop ebp
ret
while MSVC (default options) employs RVO where the caller must supply the
address where the result should be placed,
_x$ = -4 ; size = 4
___$ReturnUdt$ = 8 ; size = 4
?foo@@YG?AUBlah@@XZ PROC NEAR ; foo
push ebp
mov ebp, esp
push ecx
lea ecx, DWORD PTR _x$[ebp]
call ??0Blah@@QAE@XZ ; Blah::Blah
mov eax, DWORD PTR ___$ReturnUdt$[ebp]
mov ecx, DWORD PTR _x$[ebp]
mov DWORD PTR [eax], ecx
mov eax, DWORD PTR ___$ReturnUdt$[ebp]
mov esp, ebp
pop ebp
ret 4
I hope you understand this, that in the g++ case above the caller pushes
nothing, calls foo() and gets a result back in register eax, while in the MSVC
case the caller must push the caller's result storage address before calling
foo, i.e., that the generated machine code for the two tools *is not binary
compatible* in spite of both tools generating perfectly acceptable stdcall.
I can elaborate if you want, but the point is, evidenced by facts above, your
premise #1 is simply wrong in general -- although, I hasten the emphasise, it
*is* an important consideration for a large subset of cases.
It's quite natural to make such a mistaken generalization.
But now, perhaps you know better, yes? ;-)
Premise #2 -- If variadic functions are compatible with stdcall, then there
might exist a conformant implementation already (other than the released
versions of Microsoft Visual C++), which neither of us knows about.
Right.
Premise #3 -- You gave assembly code for an example of what you called a
variadic stdcall function.
Right, and not just "called" a variadic stdcall function: it was, conforming to
every stdcall requirement.
Postulate #1 -- The argument for stdcall-conformance of the example of point
#3 is valid.
Right.
Consequence #1 -- If the example you gave were modified to pass the number
of succeeding arguments in an integer twice as wide, none of your arguments
for it being stdcall-conformant are affected, so your logic decrees that
this also is a variadic stdcall function.
Right.
Consequence #2 -- Since the example in point #4 is stdcall conformant, then
it might be implemented in some tools already.
Right.
Consequence #3 -- The stdcall-compliant example in point #3 and the related
stdcall-compliant example in point #4 are not binary-compatible.
Right.
QED, by contradiction of consequence #3 with point #1.
Point #1 does not hold. :-)
[snip]
PS: In the follow-up to your eearlier article I wrote that it was
"good reasoning", which it was. I'm now speculating that perhaps,
given the manifest lack of reasoning powers you display above, you
may have misunderstood my comment to mean you had reached a correct
conclusion then. You had not, the conclusion there was just
meaningless, due to you having your facts wrong.
I understand perfectly well that a valid argument + incorrect premises do
not a correct conclusion make.
The argument given here is also valid, as you will see. So which of the
premises do you dispute?
See above.
You have a faulty premise #1.
Plus (although that's not necessary to discuss to invalidate the conclusion)
you have too abstract terminology, a term that can mean different things in
different contexts, "binary compatibility". It's like the term "something", as
used in "We must do something, this is something, ergo, we must do this".
So, there's an important addendum: even if point #1 held (which as demonstrated
by actual examples above it does not), then /breaking/ binary compatibility is
something very different from having two routines that are not binary
compatible. In order to break compatibility the compatibility must be used, and
something must be changed so that the existing usage doesn't work anymore. That
would not be the case anyway, unless done by design in order to achieve that.
Cheers, & rhth.,
- Alf
PS: Thanks very much for trying to make a clear case. Hopefully that's also made
my response, & reality!, more grokkable. If not, then I'll elaborate on request.
--
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?