Q:

How are variable length argument lists implemented?

What happens internally when a functions that uses varargs is called? Are the arguments themselves stored on the heap or on the stack like any other arguments. If on the stack, how does that work?

A:

It's implementation-dependent.  But most probably, the args are placed on the stack, one after the other (after default argument promotions have been performed).
va_start, va_arg etc. work by simply walking a pointer through the stack, and reinterpreting the bits as whatever type you ask for.

A:

Like was noted before, it's implementation dependent.
In the C calling convention (known as cdecl), arguments are pushed into the stack in reverse order, so:
void myfunc(int one, int two, int three)

will look like this on the stack after it's called (the stack grows upwards, towards 0): 
  .                .                0x00000000
  .                .
  .                .
  | current frame  |
  |----------------|
  | return address |
  |----------------|                   ^
  |    one         |                   | stack
  |----------------|                   | growth
  |    two         |                   | direction
  |----------------|                   |
  |    three       |
  |----------------|
  | previous frame |
         ...       
         ...                        0xFFFFFFFF

So, the first argument can be fetched first (because we know it's location, it's just before the return address), and hopefully it contains enough information on how many other arguments are present. For example, in printf(3) and related functions, all information about the other arguments is present in the format string, which is the first argument.

A:

In C, function arguments are both pushed onto and pulled from the stack by the caller function. The caller function knows how many items were pushed and so it is also able to pull them back after the call. The callee can only infer the number of the arguments from other parameters, like the format string of printf().
In Pascal, for example, the arguments on the stack are pulled by the callee. As the callee is not aware of the number of items pushed, it cannot restore the stack to its previous state either. That's why it's impossible to implement varargs in Pascal.

