Re: calling convention stdcalll and cdecl call

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance



* Igor Tandetnik:
"Alf P. Steinbach" <alfps@xxxxxxxx> wrote in message
news:s76dnfnYGKVeUR3VnZ2dnUVZ_h3inZ2d@xxxxxxxxxxxxx
* Igor Tandetnik:
"Alf P. Steinbach" <alfps@xxxxxxxx> wrote in message
news:XMudnXxazN5UzR3VnZ2dnUVZ_oWdnZ2d@xxxxxxxxxxxxx
* 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?

I think I finally understand what you are trying to say. Please correct me if I'm wrong.

OK.


It goes like this.

A variadic function needs some way to know which parameters it is given. It could be a printf-like format string, a counter passed as the first parameter, or perhaps some sentinel value terminating the sequence.

OK.


If the compiler can somehow figure out how the function accesses its parameters (presumably by semantic analysis of its source code), it can figure out how many there are, and pop the stack correctly without any additional information from the caller.

Far-fetched.


This is not going to fly for two reasons. First, in general, the problem of figuring out from source code how many arguments the function is going to access is equivalent to the halting problem. Which, as we all know, is undecidable. Even for a moderately complicated code, I don't think modern compilers are that smart. And you probably won't find too many programmers willing to hand-craft assembly code.

OK.


A more realistic approach would be perhaps to instrument va_start, va_arg and va_end. The implementation could work some housekeeping into them to keep track of how deep up the stack they reached. Supporting things like vprintf would be tricky, but probably solvable.

Or a complete redesign of that library support.


None of this adresses the second problem though: a variadic function doesn't have to use, or even known about, all the parameters it is given. We have already discussed the fact that printf may be legitimately called with more parameters than there are format specifiers in its format string. Consider this example:

int find(int what, ...) {
va_list vl;
va_start(vl, what);
int ret;
for (ret = 0; what != va_arg(vl, int); ++ret) ;
va_end(vl);
return ret;
}

The function looks for a given value in a variadic sequence. The caller is responsible for terminating with a searched-for value, but the value may also appear in the middle. Once the function finds the value, there's no way to know whether or not this is the last argument. It can't correctly pop the stack, unless it's somehow passed additional information.

Right.

Essentially then upon seeing

int __stdcall find( int what, ... );

all the compiler needs to remember is to, in its own way, pass the number of argument bytes, and remember to not adjust stack pointer at call site. This is similar to how it must take some action for a __stdcall member function (COM), or for an RVO optimization. That makes the compiled form compiler-specific.

It could be elaborated on with additional notation like

__declspec( nfrs_rgssz ) int __stdcall find( int what, ... );

(darned if I can remember ordinary syntax for __declspec but something like that), and here the compiler would know that it doesn't need to pass the number of argument bytes because the function infers that from the arguments.

If one wishes such functions to be exportable from DLLs in language-independent manner, then a global convention would have to be pushed by e.g. MS and made part of __stdcall. I see no need for that (the only good thing would slightly improved possibility of dynamic error checking for "..." functions, but "..." functions are to be avoided anyway, so, would mostly be a net cost). But the point is that there's nothing in the __stdcall convention that prevents it.


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?
.



Relevant Pages

  • Re: made it to page 4 of gforth tutorial
    ... the stack space anyway. ... And there are clearly going to be some platform ... came with an embedded C compiler once. ... like I've written before, if one *really* needs recursion (as I have, ...
    (comp.lang.forth)
  • Re: Direction in which the process stack grows
    ... >> int main ... > would force the compiler to create local variables in the same ... > sequence on the stack as you define them in the source code. ... > with gcc and either without optimization or inlining explicitely ...
    (comp.unix.programmer)
  • Re: Issue with printing a string
    ... in the absense of a declaration, the compiler ... and that it returns int. ... off of the stack. ... i and j and str point to the wrong place because your ...
    (comp.lang.c)
  • Re: where do the automatic variables go ?
    ... and bss segments etc...but there is notthing like stack and heap ... Stack variables are implied by the compiler (the compiler generates code ... int foo ...
    (comp.os.linux.misc)
  • Re: Do buffers always start with the lowest memory address being the first element?
    ... > The C standard does not assume a downward-growing stack, ... > an upward-growing stack. ... C allows but does not require that the array produced ... > machine depends on both the C compiler and the machine. ...
    (comp.lang.c)