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?