3

While trying to make my own alternative to the stdarg.h macros for variable arguments functions, a.k.a. functions with an unknown number of arguments, i tried to understand the way the arguments are stored in memory.

Here is a MWE :

#include <stdio.h>

void    foo(int num, int bar1, int bar2)
{
  printf("%p %p %p %p\n", &foo, &num, &bar1, &bar2);
}

int main ()
{
  int     i, j;

  i = 3;
  j = -5;
  foo(2, i, j);
  return 0;
}

I understand without any problem that the function's address is not in the same place as the arguments' addresses. But the latter aren't always organized in the same way.

On a x86_32 architecture (mingw32), i get this kind of result :

004013B0 0028FEF0 0028FEF4 0028FEF8

which means that the adresses are in the same order as the arguments.

BUT when I run it on a x86_64 this time the output is :

0x400536 0x7fff53b5f03c 0x7fff53b5f038 0x7fff53b5f034

Where the addresses are obviously in reverse order w.r.t. the arguments.

Therefore my question is (tl;dr) :

Are the arguments' addresses architecture dependent, or also compiler dependent?

4
  • It's actually ABI dependent. Commented May 26, 2015 at 13:09
  • "Yes." How arguments are passed depends on the calling convention, the architecture and what types the the arguments are. You may want to look at en.wikipedia.org/wiki/X86_calling_conventions Commented May 26, 2015 at 13:10
  • I think that the parameters's location only depends of the architecture, but the compiler shouldn't change this, cause the assembly code generated must be readable regardless the compiler Commented May 26, 2015 at 13:11
  • about the linux ABI: eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64 Commented May 26, 2015 at 13:18

4 Answers 4

2

It is compiler dependent. Compiler vendors naturally have to obey by the rules of the CPU architecture. A compiler normally obey the platform ABI as well, at least for code that could potentially interoperate with code produced by another compiler. The platform ABI is a specification of calling convention, linking semantic and much more, for a given platform.

E.g. compilers on linux and other unix like operating system adhere to the System V Application Binary Interface, and you'll find in chapter 3.2.3 how parameters are passed to functions (arguments passed in registers are passed left to right and arguments passed in memory(on the stack) are passed from right to left). On Windows, the rules are documented here.

Sign up to request clarification or add additional context in comments.

3 Comments

Very clear indeed! Though I wonder why this fedora distribution (on x86_64) assigns the addresses obviously from right to left, and not left to right as specified. Am I missing something?
@Aulo Well, chapter 3.2.3(bottom of page 20) specifies that it should be right to left, not as you claim left to right.
My bad! I mixed up the register assignment and the arguments pushing. Thank you!
2

They're ABI dependent. In cases where it doesn't matter (functions that will only be called in a known way), it's entirely compiler dependent and that usually means using registers, which don't have an address (those arguments will have an address if you ask for that address, giving the appearance that everything has an address). Functions that get inlined don't even really have arguments anymore, so the question of what their addresses are is moot - though again they will appear to exist and have an address when you force that happen.

1 Comment

Like Schrödinger's Cat, the observed value of an arguments address may depend on whether or not you choose or observe it.
1

Arguments may not be stored in memory at all, but passed via registers; however the language requires an address to be returned for any symbol operand of &, so your observation may be a result of you actually attempting the observation and the compiler has simply copied the values to those addresses in order that they are addressable.

It might be interesting to see what happens if you request the addresses in a different order that they were passed for example:

printf("%p %p %p %p\n", &num, &bar1, &bar2, &foo) ;

You may or may not get the same result; the point is that teh addresses you observed may be an artefact of the observation rather than of the passing. Certainly in the ARM ABI, the first four arguments to a function are passed in registers R0, R1, R2, & R3, and thereafter are passed vis the stack.

2 Comments

When interverting bar1 and bar2 in the printf, the two corresponding addresses are simply swapped. i.e. it displays : 004013B0 0028FEF0 0028FEF8 0028FEF4 and 0x400536 0x7fff4ac19a4c 0x7fff4ac19a44 0x7fff4ac19a48 Thus it is so on both architectures.
@Aulo : Yes - in this case; but my point is you cannot rely on that across platform (or even possibly between compilers or with different compiler options), and the values may still be affected by the manner in which you have observed them. The point is that making the observation by writing code is unreliable; either use the ABI documentation for your platform/compiler or reverse engineer it by observing the compiler generated assembler code.
0

On x86_64 you get the arguments in a "weird" order because they are not actually passed to the function in any memory at all. They are passed in cpu registers. By taking their address you actually force the compiler to generate code that will store the arguments in memory (on the stack in your case) so that you can take the address of them.

You can't implement stdarg macros without interacting with the compiler. In gcc the stdarg macros just wrap a builtin construct because there is no way for you to know where the arguments might be by the time you need them (the compiler might have reused the registers for something). The builtin stdarg support in gcc can significantly change code generation for functions that use them so that the arguments are available at all. I presume the same goes for other compilers.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.