Is it not expected that argument 1 ( of test()) will be written in the function stack frame in a low address ex: 0000 0004 (since 0000 0000 will be reserved for return address) then followed by arg_a in the higher address following first arg?
This is how it used to work a long time ago, but essentially all ABIs for full-fat processors (as opposed to microcontrollers), defined since the mid-1990s, put the first several arguments in registers instead, to make function calls faster. They do this whether or not the callee is variadic. You can't access registers with pointer arithmetic, so the thing you're trying to do is flat-out impossible. Because of this change, if you look at the contents of the stdarg.h
provided by any current-generation compiler, you will see that va_start
, va_arg
, and va_end
are defined using compiler intrinsics, something like
#define va_start(ap, last_named_arg) __builtin_va_start(ap, last_named_arg)
// etc
You might have been confused into thinking that arguments still go on the stack because most of the 32-bit x86 ABIs were defined in the late 1980s (contemporary to the 80386 and 80486) and they do put all the arguments on the stack. The only exception I remember offhand is Win32 "fastcall". The 64-bit x86 ABIs, however, were defined in the early 2000s (contemporary to the AMD K8) and they put arguments in registers.
Your code will not work reliably even if you compile it for 32-bit x86 (or any other old ABI that does put all the arguments on the stack), because it breaks the rules in the C standard about offsetting pointers. The pointer arg_b
doesn't point to "whatever happens to be in memory next to a
", it points to nothing. (Formally, it points one element past the end of a one-element array, because all non-array objects are treated as the sole element of a one-element array for pointer arithmetic purposes. You are allowed to do the arithmetic that computes this pointer, but not to dereference it.) Dereferencing arg_b
gives the program undefined behavior, which means the compiler is allowed to arbitrarily "miscompile" it.