I'm programming for Windows in assembly in NASM, and i found this in the code:
extern _ExitProcess#4
;Rest of code...
; ...
call _ExitProcess#4
What does the #4 mean in the declaration and call of a winapi library function?
The winapi uses the __stdcall calling convention. The caller pushes all the arguments on the stack from right to left, the callee pops them again to cleanup the stack, typically with a RET n instruction.
It is the antipode of the __cdecl calling convention, the common default in C and C++ code where the caller cleans up the stack, typically with an ADD ESP,n instruction after the CALL. The advantage of __stdcall is that it is generates more compact code, just one cleanup instruction in the called function instead of many for each call to the function. But one big disadvantage: it is dangerous.
The danger lurks in the code that calls the function having been compiled with an out-dated declaration of the function. Typical when the function was changed by adding an argument for example. This ends very poorly, beyond the function trying to use an argument that is not available, the new function pops too many arguments off the stack. This imbalances the stack, causing not just the callee to fail but the caller as well. Extremely hard to diagnose.
So they did something about that, they decorated the name of the function. First with a leading _underscore, as is done for __cdecl functions. And appended #n, the value of n is the operand of the RET instruction at the end of the function. Or in other words, the number of bytes taken by the arguments on the stack.
This provides a linker diagnostic when there's a mismatch, a change in a foo(int) function to foo(int, int) for example generates the name _foo#8. The calling code not yet recompiled will look for a _foo#4 function. The linker fails, it cannot find that symbol. Disaster avoided.
The name decoration scheme for C is documented at Format of a C Decorated Name. A decorated name containing a # character is used for the __stdcall calling convention:
__stdcall: Leading underscore (_) and a trailing at sign (#) followed by a number representing the number of bytes in the parameter list
Tools like Dependency Walker are capable of displaying both decorated and undecorated names.
Unofficial documentation can be found here: Name Decoration
It's a name decoration specifying the total size of the function's arguments:
The name is followed by the at sign (#) followed by the number of bytes (in decimal) in the argument list.
(source)
Related
My understanding is that for the cdecl calling convention, the caller is responsible for cleaning the stack and therefore can pass any number of arguments.
On the other hand, stdcall callees clean the stack and therefore cannot receive varying amounts of arguments.
My question is twofold:
Couldn't stdcall functions also get a parameter about how many variables there are and do the same?
How do cdecl functions know how many arguments they've received?
Couldn't stdcall functions also get a parameter of how many variables are there and do the same?
Yes, sure. You could invent any calling convention. But then that wouldn't be stdcall anymore.
How do cdecl functions know how many arguments they've received?
They don't. They assume to find the required number of arguments in the locations specified by the calling convention. If they are missing, then that's a bug which the code cannot observe. The following code compiles:
printf("%s");
even though it is missing an argument. The result is undefined. For printf-style functions compilers generally issue warnings (if they can) due to knowledge of the functions' internals, but that's not a solution that can be generically applied.
If a caller provides the wrong number or types of arguments, then the behavior is undefined.
Couldn't stdcall functions also get a parameter of how many variables are there and do the same?
If the caller has to pass a separate arg with the number of bytes to be popped, that's more work than just doing add esp, 16 or whatever after the call (cdecl style caller-pops). It would totally defeat the purpose of stdcall, which is to save a few bytes of space at each call site, especially for naive code-gen that wouldn't defer popping args across a couple calls, or reuse the space allocated by a push with mov stores. (There are often multiple call-sites for each function, so the extra 2 bytes for ret imm16 vs. ret is amortized over that.)
Even worse, the callee can't use a variable number efficiently on x86 / x86-64. ret imm16 only works with an immediate (constant embedded in the machine code), so to pop a variable number of bytes above the return address, a function would have to copy the return address high up in the stack and do a plain ret from there. (Or defeat branch return-address branch prediction by popping the return address into a register.)
See also:
Stack cleanup in stdcall (callee-pops) for variable arguments (x86 asm)
What calling convention does printf() in C use? (why stdcall is unusable)
How do cdecl functions know how many arguments they've received?
They don't.
C is designed around the assumption that variadic functions don't know how many args they received, so functions need something like a format string or sentinel to know how many to iterate. For example, the POSIX execl(3) (wrapper for the execve(2) system call) takes a NULL-terminated list of char* args.
Thus calling conventions in general don't waste code-size and cycles on providing a count as a side-channel; whatever info the function needs will be part of the real C-level args.
Fun fact: printf("%d", 1, 2, 3) is well-defined behaviour in C, and is required to safely ignore args beyond the ones referenced by the format string.
So using stdcall and calculating based on the format-string can't work. You're right, if you wanted to make a callee-pops convention that worked for variadic functions, you would need to pass a size somewhere, e.g. in a register. But like I said earlier, the caller knows the right number, so it would be vastly easier to let the caller manage the stack, instead of making the callee dig up this extra arg later. That's why no real-world calling conventions work this way, AFAIK.
Passing the number of arguments in a callee cleans the stack convention would be possible but the additional overhead of the extra parameter outweighs its usefulness. It wastes stack space with the extra parameter and complicates the callees stack handling.
The reason stdcall was invented is because it makes the code smaller. One adjustment in the callee vs adjusting every place it is called (on x86 or on another architecture when there are more parameters than you can pass in registers). The x86 even has a retn # instruction where # is the number of bytes to adjust. Windows NT switched from cdecl to stdcall early in its development and it supposedly reduced the size and improved speed (I believe Larry Osterman blogged about this (mini answer here)).
cdecl functions do not know how many parameters there are. You are allowed (on the ABI level) to pass more arguments than the function will actually use. A printf style function will use the format parameter as a "guide" to access the parameters one by one. When this is done the callee also has to be informed of the type of each parameter (so it knows the size which in turn, in an implementation defined manner, allows it to walk the list of parameters. On Windows x86 the parameters are on the stack, all you need is the parameter size to calculate their offset as you walk the stack). The va_list and its macros in stdarg.h provides the helping glue for C functions to access these parameters.
My summary, based on #IInspectable's answer.
stdcall functions could also get a parameter of how many variables there are, but then that wouldn't be stdcall anymore.
cdecl don't know how many arguments to read. It is assumed that the function will be able to derive the number of arguments based on a pre-determined amount of arguments, like a format string for printf.
If a caller provides the less arguments than could be derived, or of an unexpected type, then the behavior is undefined. (Thanks for the correction #Peter Cordes)
_Generic became available with C11, and before that in C99, tgmath.h included similar functionality using compiler specific hacks.
but how did main have multiple signatures back in K&R C, or C89/C90?
there's at least 2 function signatures for main() that I'm aware of:
1: int main(int argc, const char *argv[]);
2: int main(void);
but how did main have multiple signatures back in K&R C, or C89/C90?
main did not have multiple signatures per se in K&R C. That version had no sense of "signature" as you mean it. Although functions did have expectations about the number and types of their arguments, and their behavior was defined only if those expectations were satisfied, function arguments did not constitute a part of function declarations.
The following quotation from section 5.11 of the first edition of The C Programming Language (Kernighan & Ritchie, 1978) may be illuminating:
When main is called to begin execution, it is called with two arguments.
The statement is unconditional: main is (always) called with two arguments in C as described by K&R. Compilers could do whatever they wanted or needed to deal with cases where those parameters were not declared.
The case is not really different in C90 or any later version of C (all of which still support K&R-style functions definitions). Even when main is declared with a prototype, implementations do whatever they want or need to do. For example, maybe they generate code for a standard signature, and perform any necessary patch-up of recursive calls to main() during linking. Or maybe they generate code for whatever (supported) declaration of main() is provided, and deal with it in some kind of OS-specific wrapper. Maybe nothing special is even needed in some implementations.
The C Standard only requires the implementation to support the two signatures given in the question,
1: int main(int argc, const char *argv[]);
2: int main(void);
For calling conventions where the caller pops the arguments off the calling stack, the calling sequence for (1) works fine for (2) -- the caller pushes the arguments onto the stack, the callee (main) never uses them, and the caller removes them from the stack.
For calling conventions where the callee pops the arguments off the calling stack, main would have to be compiled differently depending on which signature is used. This would be a problem in implementations with a fixed piece of startup code in the C runtime, since it doesn't know how main was declared. The easiest way to deal with that is to always use a "caller pops" calling convention for main, and this is in fact how Microsoft's C compiler works -- see, e.g., https://learn.microsoft.com/en-us/cpp/build/reference/gd-gr-gv-gz-calling-convention, which states that other calling conventions are ignored when applied to main.
P.S.
_Generic and tgmath.h had no effect on any of this.
There were no signatures in K&R C, only the names of the arguments and optional type declarations for them, so there was only one possible calling convention for main.
So, none of these language changes over the decades has had any effect on how main is called.
C had and has no munged function signatures. Certainly nothing parameter-specific. Most compilers prepended (and some appended) an underscore ("_") to create a poor-man's linker namespace which made it easy to prevent symbol name collisions.
So the C runtime startup would always have one unambiguous symbol to startup. Most often _main.
start:
;# set up registers
;# set up runtime environment:
;# set up stack, initialize heap, connect stdin, stdout, stderr, etc.
;# obtain environment and format for use with "envp"
;# obtain command line arguments and set up for access with "argv"
push envp
push argv
push argc ; number of arguments in argv
call _main
push r0
call exit
.end start
The __stdcall and __cdecl calling conventions states that the functions names must be preceded by an underscore:
C (__cdecl)
The same constraints apply to the 32-bit world as in the 16-bit world.
The parameters are pushed from right to left (so that the first
parameter is nearest to top-of-stack), and the caller cleans the
parameters. Function names are decorated by a leading underscore.
__stdcall
This is the calling convention used for Win32, with exceptions for
variadic functions (which necessarily use __cdecl) and a very few
functions that use __fastcall. Parameters are pushed from right to
left [corrected 10:18am] and the callee cleans the stack. Function
names are decorated by a leading underscore and a trailing #-sign
followed by the number of bytes of parameters taken by the function.
I have compiled the following code in Visual C++ (The source file had a .c extension, so I guess the source file was compiled as a C file):
void __stdcall stdcallFunction(int i)
{
int j = 12345;
}
void __cdecl cdeclFunction(int i)
{
int j = 12345;
}
int main()
{
stdcallFunction(123);
cdeclFunction(123);
return 0;
}
I have noticed that the function names inside the compiled object file did not have a leading underscore:
Is the leading underscore for the function names for the __stdcall and __cdecl calling conventions optional?
Name decoration isn't directly related to the calling convention. For the calling convention, it's only important that caller and callee use this same convention, and the compiler can make sure they do if you provide the correct attributes in declarations.
So the name decoration is just conventional. It's sometimes useful being able to deduce how to call a function from its decorated name. Therefore, it's good practice to follow the convention when exposing functions from a library. I assume you would end up with decorated names if you dllexport these functions and link your code into a DLL.
The function decorations are not part of the C standard.
It is something defined in the ABI (Abstract Binary Interface) defined by the development environment used.
Specifically the rules reported in the question are those used by MS.
MS compiler doesn't use by default the C decoration (mangling) unless the function(s) are enclosed in EXTERN 'C' { ... } block, or a specific compiler switch is used (typically -TC).
And, as already mentioned in another answer, the MS ABI for 64bits code use a different C mangling that doesn't include the underscore prefix.
I am working on some legacy C code. The original code was written in the mid-90s, targeting Solaris and Sun's C compiler of that era. The current version compiles under GCC 4 (albeit with many warnings), and it seems to work, but I'm trying to tidy it up -- I want to squeeze out as many latent bugs as possible as I determine what may be necessary to adapt it to 64-bit platforms, and to compilers other than the one it was built for.
One of my main activities in this regard has been to ensure that all functions have full prototypes (which many did not have), and in that context I discovered some code that calls a function (previously un-prototyped) with fewer arguments than the function definition declares. The function implementation does use the value of the missing argument.
Example:
impl.c:
int foo(int one, int two) {
if (two) {
return one;
} else {
return one + 1;
}
}
client1.c:
extern foo();
int bar() {
/* only one argument(!): */
return foo(42);
}
client2.c:
extern int foo();
int (*foop)() = foo;
int baz() {
/* calls the same function as does bar(), but with two arguments: */
return (*foop)(17, 23);
}
Questions: is the result of a function call with missing arguments defined? If so, what value will the function receive for the unspecified argument? Otherwise, would the Sun C compiler of ca. 1996 (for Solaris, not VMS) have exhibited a predictable implementation-specific behavior that I can emulate by adding a particular argument value to the affected calls?
EDIT: I found a stack thread C function with no parameters behavior which gives a very succinct and specific, accurate answer. PMG's comment at the end of the answer taks about UB. Below were my original thoughts, which I think are along the same lines and explain why the behaviour is UB..
Questions: is the result of a function call with missing arguments defined?
I would say no... The reason being is that I think the function will operate as-if it had the second parameter, but as explained below, that second parameter could just be junk.
If so, what value will the function receive for the unspecified argument?
I think the values received are undefined. This is why you could have UB.
There are two general ways of parameter passing that I'm aware of... (Wikipedia has a good page on calling conventions)
Pass by register. I.e., the ABI (Application Binary Interface) for the plat form will say that registers x & y for example are for passing in parameters, and any more above that get passed via stack...
Everything gets passed via stack...
Thus when you give one module a definition of the function with "...unspecified (but not variable) number of parameters..." (the extern def), it will not place as many parameters as you give it (in this case 1) in either the registers or stack location that the real function will look in to get the parameter values. Therefore the second area for the second parameter, which is missed out, essentially contains random junk.
EDIT: Based on the other stack thread I found, I would ammended the above to say that the extern declared a function with no parameters to a declared a function with "unspecified (but not variable) number of parameters".
When the program jumps to the function, that function assumes the parameter passing mechanism has been correctly obeyed, so either looks in registers or the stack and uses whatever values it finds... asumming them to be correct.
Otherwise, would the Sun C compiler of ca. 1996 (for Solaris, not VMS) have exhibited a >> predictable implementation-specific behavior
You'd have to check your compiler documentation. I doubt it... the extern definition would be trusted completely so I doubt the registers or stack, depending on parameter passing mechanism, would get correctly initialised...
If the number or the types of arguments (after default argument promotions) do not match the ones used in the actual function definition, the behavior is undefined.
What will happen in practice depends on the implementation. The values of missing parameters will not be meaningfully defined (assuming the attempt to access missing arguments will not segfault), i.e. they will hold unpredictable and possibly unstable values.
Whether the program will survive such incorrect calls will also depend on the calling convention. A "classic" C calling convention, in which the caller is responsible for placing the parameters into the stack and removing them from there, will be less crash-prone in presence of such errors. The same can be said about calls that use CPU registers to pass arguments. Meanwhile, a calling convention in which the function itself is responsible for cleaning the stack will crash almost immediately.
It is very unlikely the bar function ever in the past would give consistent results. The only thing I can imagine is that it is always called on fresh stack space and the stack space was cleared upon startup of the process, in which case the second parameter would be 0. Or the difference between between returning one and one+1 didn't make a big difference in the bigger scope of the application.
If it really is like you depict in your example, then you are looking at a big fat bug. In the distant past there was a coding style where vararg functions were implemented by specifying more parameters than passed, but just as with modern varargs you should not access any parameters not actually passed.
I assume that this code was compiled and run on the Sun SPARC architecture. According to this ancient SPARC web page: "registers %o0-%o5 are used for the first six parameters passed to a procedure."
In your example with a function expecting two parameters, with the second parameter not specified at the call site, it is likely that register %01 always happened to have a sensible value when the call was made.
If you have access to the original executable and can disassemble the code around the incorrect call site, you might be able to deduce what value %o1 had when the call was made. Or you might try running the original executable on a SPARC emulator, like QEMU. In any case this won't be a trivial task!
I am currently changing the function signatures of a class of functions in an application. These functions are being stored in a function table, so I was expecting to change this function table as well. I have just realised that in certain instances, we already use the new function signature. But because everything is casted to the correct function type as it is put into the function table, no warnings are being raised.
When the function is called, it will be passed extra parameters that are not really part of the function declaration, but they are on the end of the parameter list.
I can't determine if this is guaranteed by the way function parameters are passed in C. I guess to do variadic functions like sprintf, it has to be the case that earlier arguments can be resolved correctly whatever is on the end of the parameter list?
It evidently works just fine across multiple platforms but out of curiosity I'd like to know how and why it works.
But because everything is casted to the correct function type as it is put into the function table, no warnings are being raised.
So the compiler gets to be no help to speak of. C programmers cast too much. >_<
I can't determine if this is guaranteed by the way function parameters are passed in C. I guess to do variadic functions like sprintf, it has to be the case that earlier arguments can be resolved correctly whatever is on the end of the parameter list?
Technically, you've got undefined behavior. But it's defined for your platform to use the standard C calling conventions (see Scott's answer), or something that maps directly to them (usually by mapping the first N parameters to a certain set of processor registers).
This comes up a lot with variable argument lists, too. For example, printf is declared something like:
int printf(const char* format, ...);
And its definition usually uses the stdarg system to handle the extra arguments, which looks like:
#include <stdarg.h>
int printf(const char* format, ...)
{
va_list ap;
int result;
va_start(ap, format);
result = vprintf(format, ap);
va_end(ap);
return result;
}
If you're on a platform with standard C calling conventions, that va_end(ap) macro usually turns into a do-nothing. In this case, you can get away with passing extra arguments to a function. But on some platforms, the va_end() call is required to restore the stack to a predictable state (i.e. where it was before the call to va_start); in those cases, your functions will not leave the stack the way it found it (it won't pop enough arguments back off the stack) so your calling function could, for example, crash on exit when it fetches a bogus value for a return address.
Your functions must certainly be using the cdecl calling convention (http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl). This pushes arguments on the stack in reverse order, from right to left, ensuring that the last argument can be easily located (top of the stack) and used to interpret the remainder, such as a printf format string. It is also the responsibility of the caller to clean up the stack, which is a bit less compact than the function itself doing so (as in pascal/stdcall convention), but ensures that variable argument lists can be used, and implies that trailing arguments can be ignored.