Hmm actually you are right on the writable part:
5.1.2.2.1 Program Startup: "The parameters argc and argv and the strings pointed to by the argv array shall be modifiable by the program, and retain their last-stored values between program startup and program termination."
However, nothing says they must be on the stack.
I ran the following program to test this:
int main(int argc, const char * argv[])
{
char buff1[0x1000];
char buff2[0x1000];
printf("buff1 = %p\n", buff1);
printf("buff2 = %p\n", buff2);
printf("argv = %p\n", argv);
for(int i = 0; i < argc; i++)
{
printf("arg %d = %p\n", i, argv[i]);
}
return 0;
}
I passed it the params "1 2 3" and got the following:
buff1 = 0x7fff5fbfe7b0
buff2 = 0x7fff5fbfd7b0
argv = 0x7fff5fbff7f8
arg 0 = 0x7fff5fbff970
arg 1 = 0x7fff5fbff9e9
arg 2 = 0x7fff5fbff9eb
arg 3 = 0x7fff5fbff9ed
It seems odd that there's a 376 byte gap between what's clearly the stack and what addresses the arguments reside at. They also appear in ascending order despite the fact that the stack is descending (a required convention, maybe?). It's still pretty damn close to the stack so it might very well be the stack with a bunch of process-specific stuff in it, or it could just be that the OS put the start of the stack close to the startup parameters.
Either way, this is very esoteric stuff that has no place in an interview. I've read through the complete spec a number of times and I STILL get stuff wrong!