Is _start() a function? - c

It stands to reason that, for executable code to be called a function, it should conform to the function calling convention of the platform it's running on.
However, _start() does not; for example in this reference implementation there is no return address on the stack:
.section .text
.global _start
_start:
# Set up end of the stack frame linked list.
movq $0, %rbp
pushq %rbp # rip=0
pushq %rbp # rbp=0
movq %rsp, %rbp
# We need those in a moment when we call main.
pushq %rsi
pushq %rdi
# Prepare signals, memory allocation, stdio and such.
call initialize_standard_library
# Run the global constructors.
call _init
# Restore argc and argv.
popq %rdi
popq %rsi
# Run main
call main
# Terminate the process with the exit code.
movl %eax, %edi
call exit
.size _start, . - _start
Yet it's called a function in a myriad of sources. A number of questions and answers on StackOverflow also refer to it as a function.
Is a function simply a group of instructions identified by the address to the entry point, or must it conform to the calling convention? The C standard does not seem to define the concept of a function, neither do the gcc and clang docs. What is the authoritative source that defines this concept?

About the lack of a return making a piece of code not a function, even a function written in C, does not have to have a return instruction in it:
int call_fn(int(*fn)()) {
return fn();
}
This function, with proper optimizations compiles down to a single jmp instruction: https://godbolt.org/z/nxT9qTvaf
call_fn(int (*)()): # #call_fn(int (*)())
jmp rdi # TAILCALL
In general, I don't think the C or the C++ standard would define anything about stuff written in assembly. A common calling convention helps for making direct calls into functions written in other languages, but you can still call functions using other calling conventions using a trampoline.

It stands to reason that, for executable code to be called a function, it should conform to the function calling convention of the platform it's running on.
"Function" is the primary idea here; "calling convention" is subsidiary to that. As such, I think a more supportable claim would be that for every function, there is a convention for calling it.
Interoperability considerations lead to standardization of calling conventions, but there is no One True calling convention, not even on a per-platform basis. Even subject to the influence of interoperability, there are platforms that support multiple standard calling conventions. In any case the existence of standard calling conventions does not necessarily relegate code with other conventions for entry and exit to non-function-hood.
Is a function simply a group of instructions identified by the address to the entry point, or must it conform to the calling convention?
This is a question of the definition of "function". There is room for variation on this, and in practice, different definitions apply in different contexts. For example, the question refers to the C language specification, but this speaks to the meaning of "function" in the context of C source code, not assembly or machine code.
In practice, in various languages and contexts, there are
functions with identifiers and functions without;
functions that return a value and functions that don't;
functions with a single entry point and functions with multiple entry points;
functions with a single exit point and functions with multiple exit points;
functions that always return to the caller, functions that usually return, functions that occasionally return, and functions that never return;
a wide variety of patterns for how functions receive data to operate on, how they return data to their caller (if they do so), and what invariants they do and do not ensure
other dimensions of variation, too
Thus, no, I do not accept in any universal sense that a piece of code needs to conform to a particular calling convention to be called a "function", and I also do not accept "a group of instructions identified by the address to the entry point" as a satisfactory universal definition.
Is _start() a function?
A _start() function such as is provided by GCC / Glibc satisfies some relevant definitions of the term. I have no problem with calling it a "function".

There seems to be this idea going around in the newer programming models that all running code is inside functions; but in the beginning this was not so, and if we look at the old languages we can observe this.
Drawing from lisp:
(format t "Hello, World!")
This is hello world in common lisp, and is not a function in any normal sense. For comparison, here is it as a function:
(defun hello ()
(format t "Hello, World!"))
(hello)
And from near the other root of all programming languages; here is Fortran (source):
PROGRAM FUNDEM
C Declarations for main program
REAL A,B,C
REAL AV, AVSQ1, AVSQ2
REAL AVRAGE
C Enter the data
DATA A,B,C/5.0,2.0,3.0/
C Calculate the average of the numbers
AV = AVRAGE(A,B,C)
AVSQ1 = AVRAGE(A,B,C) **2
AVSQ2 = AVRAGE(A**2,B**2,C**2)
PRINT *,'Statistical Analysis'
PRINT *,'The average of the numbers is:',AV
PRINT *,'The average squared of the numbers: ',AVSQl
PRINT *,'The average of the squares is: ', AVSQ2
END
REAL FUNCTION AVRAGE(X,Y,Z)
REAL X,Y,Z,SUM
SUM = X + Y + Z
AVRAGE = SUM /3.0
RETURN
END
Yup that's top level statements and a function definition. Fortran has three things, the PROGRAM, SUBROUTINEs, and FUNCTIONs.
And again, we can do the same kind of example in QuickBasic:
CALL Hello
Sub Hello()
Print "Hello, World"
End Sub
QuickBasic was kind of funny; you never even tried to name the entry point and whatever .OBJ file was first in the build script was where the entry point was.
There's a general recurring theme here. In all of these, the top level isn't very function-like. The compiler would add stuff to the beginning of the entry point for you so that runtime initialization worked correctly.
Now what happened in C? C took a different path. The initialization routines were written in their own file that calls main() and the compiler just compiles main() as it would any other function and has no capacity for emitting code that runs at top level. Thus, the entry point (traditionally called _start but doesn't have to be) is not and cannot be written in C.
Don't get me wrong here, if you were to compile any of these on a Unix platform today and look at the resulting .o files you would see the modern compilers emit a main() function with the top level code in it. This is because of the preeminence of the C runtime and not because of any need for it to be a function. Had the other languages carried around in their runtimes the definitions of the system calls like they used to, this would not need to be.
Thus we have the process entry point is not a function.
We can take this argument one step farther; suppose (and I have seen news articles reference a thing kind of like this) we had a full native Java compiler that emitted .o files and linked against .so files providing the Java runtime; we could then ask Is _start a class method? The answer isn't no. The answer is the question makes no sense because you can't get a valid Java reference to the symbol. The same silly thing happens in C, we just need to pick a different platform. On DOS FAR model, _start is exported as PROC NEAR but void _start() expects a PROC FAR. The emitted link-time fixup is of the wrong size and trying to take the address of _start results in undefined behavior.

You are mixing fields. You can't apply "text specification" to oranges.
the C standard does not seem to define the concept of a function
C is a language. In the C language, the text like the following:
void func();
is a function declaration of a function func.
Is _start() a function?
The text you posted is not in C language. There are no functions declarations and definitions in it.
As you stated, the term function is not defined in the C standard. I would assume that the English language understanding of the term "function" applies here, as to any other word in the C standard.
I see in Merriam-Webster that a "function" is a computer subroutine, where a subroutine is a a sequence of computer instructions for performing a specified task that can be used repeatedly.
Clearly, _start is a function - it is a sequence of instructions to be executed repeatedly, it is executed on a computer, and it also operates on variables in the form of registers.
The text you posted represents the function _start in the form of a text using assembly language. It is not possible to represent the function _start in the C programming language.
(It is also not possible to express oranges, yet they exist in the real world. My point is, you can take any other word in the C standard, like, I don't know, "international", and ask "Are oranges international?". Applying C standard and "language-lawyer" tag to abstract contexts is not going to give you answers. Bottom line is that the C standard is a specification - it tells what happens when, it is not a dictionary.)
Is a function simply a group of instructions identified by the address to the entry point, or must it conform to the calling convention?
See Merriam-Webster function.
What is the authoritative source that defines this concept?
I googled and "There is no official agency that makes rules for English language".
The C standard is created by http://www.open-std.org/jtc1/sc22/wg14/ .

Related

Is there any practical use for a function that does nothing?

Would there be any use for a function that does nothing when run, i.e:
void Nothing() {}
Note, I am not talking about a function that waits for a certain amount of time, like sleep(), just something that takes as much time as the compiler / interpreter gives it.
Such a function could be necessary as a callback function.
Supposed you had a function that looked like this:
void do_something(int param1, char *param2, void (*callback)(void))
{
// do something with param1 and param2
callback();
}
This function receives a pointer to a function which it subsequently calls. If you don't particularly need to use this callback for anything, you would pass a function that does nothing:
do_something(3, "test", Nothing);
When I've created tables that contain function pointers, I do use empty functions.
For example:
typedef int(*EventHandler_Proc_t)(int a, int b); // A function-pointer to be called to handle an event
struct
{
Event_t event_id;
EventHandler_Proc_t proc;
} EventTable[] = { // An array of Events, and Functions to be called when the event occurs
{ EventInitialize, InitializeFunction },
{ EventIncrement, IncrementFunction },
{ EventNOP, NothingFunction }, // Empty function is used here.
};
In this example table, I could put NULL in place of the NothingFunction, and check if the .proc is NULL before calling it. But I think it keeps the code simpler to put a do-nothing function in the table.
Yes. Quite a lot of things want to be given a function to notify about a certain thing happening (callbacks). A function that does nothing is a good way to say "I don't care about this."
I am not aware of any examples in the standard library, but many libraries built on top have function pointers for events.
For an example, glib defines a callback "GLib.LogFunc(log_domain, log_level, message, *user_data)" for providing the logger. An empty function would be the callback you provide when logging is disabled.
One use case would be as a possibly temporary stub function midway through a program's development.
If I'm doing some amount of top-down development, it's common for me to design some function prototypes, write the main function, and at that point, want to run the compiler to see if I have any syntax errors so far. To make that compile happen I need to implement the functions in question, which I'll do by initially just creating empty "stubs" which do nothing. Once I pass that compile test, I can go on and flesh out the functions one at a time.
The Gaddis textbook Starting out with C++: From Control Structures Through Objects, which I teach out of, describes them this way (Sec. 6.16):
A stub is a dummy function that is called instead of the actual
function it represents. It usually displays a test message
acknowledging that it was called, and nothing more.
A function that takes arguments and does nothing with them can be used as a pair with a function that does something useful, such that the arguments are still evaluated even when the no-op function is used. This can be useful in logging scenarios, where the arguments must still be evaluated to verify the expressions are legal and to ensure any important side-effects occur, but the logging itself isn't necessary. The no-op function might be selected by the preprocessor when the compile-time logging level was set at a level that doesn't want output for that particular log statement.
As I recall, there were two empty functions in Lions' Commentary on UNIX 6th Edition, with Source Code, and the introduction to the re-issue early this century called Ritchie, Kernighan and Thompson out on it.
The function that gobbles its argument and returns nothing is actually ubiquitous in C, but not written out explicitly because it is implicitly called on nearly every line. The most common use of this empty function, in traditional C, was the invisible discard of the value of any statement. But, since C89, this can be explicitly spelled as (void). The lint tool used to complain whenever a function return value was ignored without explicitly passing it to this built-in function that returns nothing. The motivation behind this was to try to prevent programmers from silently ignoring error conditions, and you will still run into some old programs that use the coding style, (void)printf("hello, world!\n");.
Such a function might be used for:
Callbacks (which the other answers have mentioned)
An argument to higher-order functions
Benchmarking a framework, with no overhead for the no-op being performed
Having a unique value of the correct type to compare other function pointers to. (Particularly in a language like C, where all function pointers are convertible and comparable with each other, but conversion between function pointers and other kinds of pointers is not portable.)
The sole element of a singleton value type, in a functional language
If passed an argument that it strictly evaluates, this could be a way to discard a return value but execute side-effects and test for exceptions
A dummy placeholder
Proving certain theorems in the typed Lambda Calculus
Another temporary use for a do-nothing function could be to have a line exist to put a breakpoint on, for example when you need to check the run-time values being passed into a newly created function so that you can make better decisions about what the code you're going to put in there will need to access. Personally, I like to use self-assignments, i.e. i = i when I need this kind of breakpoint, but a no-op function would presumably work just as well.
void MyBrandNewSpiffyFunction(TypeImNotFamiliarWith whoKnowsWhatThisVariableHas)
{
DoNothing(); // Yay! Now I can put in a breakpoint so I can see what data I'm receiving!
int i = 0;
i = i; // Another way to do nothing so I can set a breakpoint
}
From a language lawyer perspective, an opaque function call inserts a barrier for optimizations.
For example:
int a = 0;
extern void e(void);
int b(void)
{
++a;
++a;
return a;
}
int c(void)
{
++a;
e();
++a;
return a;
}
int d(void)
{
++a;
asm(" ");
++a;
return a;
}
The ++a expressions in the b function can be merged to a += 2, while in the c function, a needs to be updated before the function call and reloaded from memory after, as the compiler cannot prove that e does not access a, similar to the (non-standard) asm(" ") in the d function.
In the embedded firmware world, it could be used to add a tiny delay, required for some hardware reason. Of course, this could be called as many times in a row, too, making this delay expandable by the programmer.
Empty functions are not uncommon in platform-specific abstraction layers. There are often functions that are only needed on certain platforms. For example, a function void native_to_big_endian(struct data* d) would contain byte-swapping code on a little-endian CPU but could be completely empty on a big-endian CPU. This helps keep the business logic platform-agnostic and readable. I've also seen this sort of thing done for tasks like converting native file paths to Unix/Windows style, hardware initialization functions (when some platforms can run with defaults and others must be actively reconfigured), etc.
At the risk of being considered off-topic, I'm going to argue from a Thomistic perspective that a function that does nothing, and the concept of NULL in computing, really has no place anywhere in computing.
Software is constituted in substance by state, behavior, and control flow which belongs to behavior. To have the absence of state is impossible; and to have the absence of behavior is impossible.
Absence of state is impossible because a value is always present in memory, regardless of initialization state for the memory that is available. Absence of behavior is impossible because non-behavior cannot be executed (even "nop" instructions do something).
Instead, we might better state that there is negative and positive existence defined subjectively by the context with an objective definition being that negative existence of state or behavior means no explicit value or implementation respectively, while the positive refers to explicit value or implementation respectively.
This changes the perspective concerning the design of an API.
Instead of:
void foo(void (*bar)()) {
if (bar) { bar(); }
}
we instead have:
void foo();
void foo_with_bar(void (*bar)()) {
if (!bar) { fatal(__func__, "bar is NULL; callback required\n"); }
bar();
}
or:
void foo(bool use_bar, void (*bar)());
or if you want even more information about the existence of bar:
void foo(bool use_bar, bool bar_exists, void (*bar)());
of which each of these is a better design that makes your code and intent well-expressed. The simple fact of the matter is that the existence of a thing or not concerns the operation of an algorithm, or the manner in which state is interpreted. Not only do you lose a whole value by reserving NULL with 0 (or any arbitrary value there), but you make your model of the algorithm less perfect and even error-prone in rare cases. What more is that on a system in which this reserved value is not reserved, the implementation might not work as expected.
If you need to detect for the existence of an input, let that be explicit in your API: have a parameter or two for that if it's that important. It will be more maintainable and portable as well since you're decoupling logic metadata from inputs.
In my opinion, therefore, a function that does nothing is not practical to use, but a design flaw if part of the API, and an implementation defect if part of the implementation. NULL obviously won't disappear that easily, and we just use it because that's what currently is used by necessity, but in the future, it doesn't have to be that way.
Besides all the reasons already given here, note that an "empty" function is never truly empty, so you can learn a lot about how function calls work on your architecture of choice by looking at the assembly output. Let's look at a few examples. Let's say I have the following C file, nothing.c:
void DoNothing(void) {}
Compile this on an x86_64 machine with clang -c -S nothing.c -o nothing.s and you'll get something that looks like this (stripped of metadata and other stuff irrelevant to this discussion):
nothing.s:
_Nothing: ## #Nothing
pushq %rbp
movq %rsp, %rbp
popq %rbp
retq
Hmm, that doesn't really look like nothing. Note the pushing and popping of %rbp (the frame pointer) onto the stack. Now let's change the compiler flags and add -fomit-frame-pointer, or more explicitly: clang -c -S nothing.c -o nothing.s -fomit-frame-pointer
nothing.s:
_Nothing: ## #Nothing
retq
That looks a lot more like "nothing", but you still have at least one x86_64 instruction being executed, namely retq.
Let's try one more. Clang supports the gcc gprof profiler option -pg so what if we try that: clang -c -S nothing.c -o nothing.s -pg
nothing.s:
_Nothing: ## #Nothing
pushq %rbp
movq %rsp, %rbp
callq mcount
popq %rbp
retq
Here we've added a mysterious additional call to a function mcount() that the compiler has inserted for us. This one looks like the least amount of nothing-ness.
And so you get the idea. Compiler options and architecture can have a profound impact on the meaning of "nothing" in a function. Armed with this knowledge you can make much more informed decisions about both how you write code, and how you compile it. Moreover, a function like this called millions of times and measured can give you a very accurate measure of what you might call "function call overhead", or the bare minimum amount of time required to make a call given your architecture and compiler options. In practice given modern superscalar instruction scheduling, this measurement isn't going to mean a whole lot or be particularly useful, but on certain older or "simpler" architectures, it might.
These functions have a great place in test driven development.
class Doer {
public:
int PerformComplexTask(int input) { return 0; } // just to make it compile
};
Everything compiles and the test cases says Fail until the function is properly implemented.

Register usage in ARM assembly function which is called by a C function

The C function call convention for ARM says:
Caller will pass the first 4 parameters in r0-r3.
Caller will pass any extra parameters on stack.
Caller will get the return value from r0.
I am handcrafting an assembly function called by C. The prototype is equivalent to this:
void s(void);
Suppose a C function c() calls s().
Since s() has no parameter nor return value. I believe r0-r3 will not be touched by the compiler to generate the calling sequence for c() to call s().
Suppose s() will use r0-r12 to complete its function. It is also possible that c() will use those registers.
I am not sure if I have to explicitly save and restore all the registers touched in s(), say r0-r12. Such memory operation will cost some time.
Or at least I don't have to do that for r0-r3?
From Procedure Call Standard for the Arm Architecture, section 6.1.1 (page 19):
A subroutine must preserve the contents of the registers r4-r8, r10, r11 and SP (and r9 in PCS variantsthat designate r9 as v6)
So yes, since r0-r3 are scratch registers, you do not need to save those before using them in s(), but you have to save and restore any other register.
Assuming that the compiler is compliant with the ARM ABI, then declaring s() like this:
extern void s(void);
should suffice, and the compiler should not emit code that relies on previous values of r0-r3 in the c() function after the call to s() (i.e. c() should save r0-r3 if needed before calling s() and restore them after), since that would break the ABI compliance.
Generally when mixing C and asm, you can never make any assumptions about what registers the C code uses, save for those guaranteed to get stacked by the calling convention. Stack all other registers before using them and then pop them later. All of this depends on what assumptions the compiler makes and doesn't make internally upon calling your assembler function.
Some good info here: Mixing C, C++, and Assembly Language

Do C compilers guarantee two eightbyte field structs will be passed as INTEGER on SysV x64?

Specifically in the context of the SysV x86-64 ABI
If I have a struct with only two fields, such as:
typedef struct {
void *foo;
void *bar;
} foobar_t;
And I pass it to a function with a definition like so:
foobar_t example_function(foobar_t example_param);
The ABI seems to say that each eightbyte field should be passed as INTEGER to the function, therefore rdi == foo and rsi == bar. Similarly, when returning we should be able to use rax and rdx, since we don't need a memory pointer in rdi. If example_function is trivially defined as:
foobar_t example_function(foobar_t example_param) {
return example_param;
}
A valid assembly implementation, ignoring prologue and epilogue, would be:
example_function:
mov rax, rdi
mov rdx, rsi
ret
Conceivably, a mentally-deficient compiler could fill the struct with NO_CLASS padding and make that assembly invalid somehow. I'm wondering if it's written down anywhere that a struct with only two eightbyte fields must be handled this way.
The larger context to my question is that I'm writing a simple C11 task switcher for my own edification. I'm basing it largely on boost.context and this is exactly how boost passes two-field structs around. I want to know if it's kosher under all circumstances or if boost is cheating a little.
The ABI seems to say that each eightbyte field should be passed as
INTEGER to the function, therefore rdi == foo and rsi == bar.
Agreed, for "global" functions accessible from multiple compilation units, the argument structure is broken up into to eightbyte pieces, the first completely filled by foo, and the second completely filled by bar. These are classified as INTEGER, and therefore passed in %rdi and %rsi, respectively.
Similarly, when returning we should be able to use rax and rdx, since we don't need a memory pointer in rdi.
I don't follow your point about %rdi, but I agree that the members of the return value are returned in %rax and %rdx.
A valid assembly implementation, ignoring prologue and epilogue, would be: [...]
Agreed.
Conceivably, a mentally-deficient compiler could fill the struct with NO_CLASS padding and make that assembly invalid somehow. I'm wondering if it's written down anywhere that a struct with only two eightbyte fields must be handled this way.
A compiler that produces code conforming to the SysV x86-64 ABI will use the registers already discussed for passing the argument and returning the return value. Such a compiler is of course not obligated to implement the function body exactly as you describe, but I'm not seeing your concern. Yes, these details are written down. Although the specific case you present is not explicitly described in the ABI specification you linked, all of the behavior discussed above follows from that specification. That's the point of it.
A compiler that produces code (for a global function) that behaves differently is not mentally-deficient, it is non-conforming.
The larger context to my question is that I'm writing a simple C11
task switcher for my own edification. I'm basing it largely on
boost.context and this is exactly how boost passes two-field structs
around. I want to know if it's kosher under all circumstances or if
boost is cheating a little.
It would take me more analysis than I'm prepared to expend to determine exactly what Boost is doing in the code you point to. Note that it is not what you present in your example_function. But it is reasonable to suppose that Boost is at least attempting to implement its function calls according to the ABI.
Compilers agreeing on struct layout and how they're passed by value as function args are key parts of an ABI. Otherwise they couldn't call each other's functions.
Hand-written asm is not different from compiler-generated asm; it doesn't have to have to come from the same version of the same compiler to interoperate properly. This is why stable and correct ABIs are such a big deal.
Compatibility with hand-written asm is fairly similar to compatibility with machine code that was compiled a long time ago and has been sitting in a binary shared library for years. If it was correct then, it's correct now. Unless the structs have changed in the source newly compiled code can call and be called by the existing instructions.
If a compiler doesn't match the standard as-written, it's broken.
Or maybe more accurately, if it doesn't match gcc, it's broken. And if the standard wording doesn't describe what gcc/clang/ICC do, then the standard document is broken.
If you had a compiler for x86-64 System V that passes a 2x void* struct any way other than in 2 registers, that compiler is broken, not your hand-written asm.
(Assuming there aren't a lot of earlier args that use up the arg-passing registers before we get to the struct arg.)

How were C's different signatures for main supported before _Generic?

_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

Call MASM function in StdCall convention [duplicate]

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)

Resources