CodeFlakes
CodeFlakes

Reputation: 3711

How to get a pointer on a function's arguments in C?

Is there a generic method to get pointer on each argument in C like you would do with a vararg function ?

A special syntax like $1, $2, $3

And if not is there some preprocessor macro that define that ?

If not possible in C I'm also interested in a Objective C solution. I know I can get a selector on current method with _cmd special hidden parameter. Is there some kind of _arg1, _arg2 ?? Also would it be possible to directly point on memory after _cmd ? Is it "safe" to consider parameter pointers are next to each other ?

UPDATE TO MY OWN QUESTION

If I access the frame stack by using some assembler code I can get a hold on the function pointer with ebp right ? So is it possible to access arguments the same way ? Sorry if this is obvious, I don't know much about assembler.

Upvotes: 0

Views: 1502

Answers (5)

Olof Forshell
Olof Forshell

Reputation: 3264

What is possible but perhaps not entirely useful in your case would be to extract the current and previous stack frame pointers (i e bp register) and, using the standard stack frame structure, determine how many 4 byte (for a 32-bit application) parameter units have been passed in the call to the current routine. You won't be able to determine which units are char, short or long and if two of them together might be a long long/__int64 parameter.


I've thought about this some more. Consider a typical function call "func (a,b)". The calling code unless you have parameters in registers (some x86-32 compiler options and intel recommended for x86-64) the code would turn out like this

               ; long *esp,*ebp;
push b         ; *(--esp)=b;
push a         ; *(--esp)=a;
call func      ; *(--esp)=return_address_location;
return_address_location:
add esp,8      ; esp+=2;    // free memory allocated for passing parameters

Then you come to processing in func

func:
push ebp       ; *(--esp)=(long) ebp;    // save current ebp <=> current stack frame 
mov ebp,esp    ; ebp=esp;                // create new stack frame in ebp
sub esp,16     ; esp-=4;                 // reserve space for local variables <=> sizeof(long)*4

(func code ...)

Now when you're in func and you need access to parameters you address them with ebp+2 and ebp+3 (*ebp contains previous ebp, ebp+1 the return address. When you need access to local variables you address them with ebp-4 to ebp-1 (may be over-simplified if they are not all longs and you have some packing option set).

After a while func has done its thing and you need to return:

mov esp,ebp    ; esp=ebp;         // unreserve space for local variables
pop ebp        ; ebp=*(esp++);    // restore previous ebp <=> previous stack frame
ret            ; eip=*(esp++);    // pop return address into instruction pointer

From the first snippet you will also see how the first stack allocation (for passing parameters) is freed right after returning.

A few tips:

  • Do the math for yourself while single-stepping (instruction by instruction) through a call/return sequence and you'll get ideas on how to solve the original problem. This is basic stack handling which looks more or less the same on all architectures and implementations so it's a good thing to know
  • Imagine an incorrectly calculated memset/memcpy to a local buffer and how it will destroy the data on the stack including return addresses, previous stack frames etc
  • Take note of the values in ds and ss (data and stack selectors) and if they contain the exact same value a solution of yours could use memcpy to copy the parameters from the stack to data memory for examination or whatever if that helps
  • If ds=ss you can use & to find the address of the passed parameters from inside func (&param1, &param2)
  • If ds and ss or not equal (as they might be in a multi-threaded application) you will need a memcpy variant that uses "far addressing" which will handle the situation where ds and ss differ

Upvotes: 3

Nikolai Fetissov
Nikolai Fetissov

Reputation: 84159

See stdarg(3) and a tutorial.

Upvotes: 0

R.. GitHub STOP HELPING ICE
R.. GitHub STOP HELPING ICE

Reputation: 215261

If all arguments to a variadic function have the same type (e.g. void *), you can do something like this:

type nth_arg(va_list ap, size_t n)
{
    va_list ap2;
    va_copy(ap2, ap);
    while (n--) va_arg(ap2, type);
    return va_arg(ap2, type);
}

Replace type with the actual type.

Upvotes: 0

Jonathan Leffler
Jonathan Leffler

Reputation: 753695

No, there isn't a special way to do that, or any special notation.

I suppose you could define a macro to take each argument and generate a pointer to it (find the Boost preprocessor library); I'm sure I wouldn't want to.

int somefunc(int arg1, char *arg2)
{
    int *p_arg1 = &arg1;
    char **p_arg2 = &arg2;
    ...
}

Upvotes: 0

Jacob Relkin
Jacob Relkin

Reputation: 163238

No, the only way you could do this is with the va_list macros provided in stdarg.h

Upvotes: 2

Related Questions