Как получить указатель на аргументы функции в C? - PullRequest
0 голосов
/ 20 января 2011

Существует ли универсальный метод для получения указателя на каждый аргумент в C, как если бы вы использовали функцию vararg?

Специальный синтаксис, такой как $ 1, $ 2, $ 3

И если нет, тоесть некоторый макрос препроцессора, который определяет это?

Если это невозможно в C, я также заинтересован в решении Objective C.Я знаю, что могу получить селектор для текущего метода с помощью специального скрытого параметра _cmd.Есть ли какой-то _arg1, _arg2 ??Также возможно ли указывать непосредственно на память после _cmd?Безопасно ли считать указатели параметров рядом друг с другом?

ОБНОВЛЕНИЕ МОЕГО СОБСТВЕННОГО ВОПРОСА

Если я получу доступ к стеку фреймов с помощью некоторого кода на ассемблере, я смогу удержатьуказатель на функцию с ebp, верно?Так возможно ли получить доступ к аргументам таким же образом?Извините, если это очевидно, я не очень разбираюсь в ассемблере.

Ответы [ 5 ]

2 голосов
/ 21 января 2011

Что возможно, но, возможно, не совсем полезно в вашем случае, это извлечь текущие и предыдущие указатели фреймов стека (т. Е. Регистр bp) и, используя стандартную структуру фрейма стека, определить, сколько 4 байта (для 32-битного)Прикладные) параметры блоков были переданы в вызов текущей процедуры.Вы не сможете определить, какие единицы являются char, short или long, и если два из них вместе могут быть параметром long long / __ int64.


Я подумал об этом еще немного.Рассмотрим типичный вызов функции «func (a, b)».Вызывающий код, если у вас нет параметров в регистрах (некоторые опции компилятора x86-32 и рекомендуемые intel для x86-64), код будет выглядеть так:

               ; 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

Затем вы переходите к обработке в 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 ...)

Теперь, когда вы находитесь в func и вам нужен доступ к параметрам, вы обращаетесь к ним с помощью ebp + 2 и ebp + 3 (* ebp содержит предыдущий ebp, ebp + 1 обратный адрес. Когда вам нужен доступ к локальномуПеременные, к которым вы обращаетесь с помощью ebp-4 до ebp-1 (могут быть чрезмерно упрощены, если они не все длинные, и у вас есть набор опций упаковки).

Через некоторое время func сделал свое дело, и вам нужнодля возврата:

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

Из первого фрагмента вы также увидите, как освобождается первое выделение стека (для передачи параметров) сразу после возврата.

Несколько советов:

  • Сделайте математику для себя, пошагово (инструкция за инструкцией) через последовательность вызовов / возвратов, и вы получите идеи о том, как решить исходную проблему.dling, который выглядит более или менее одинаково на всех архитектурах и реализациях, поэтому полезно знать
  • Представьте неправильно рассчитанный memset / memcpy для локального буфера и как он уничтожит данные в стеке, включая адреса возвратапредыдущие кадры стека и т. д.
  • Обратите внимание на значения в ds и ss (селекторы данных и стека), и, если они содержат одно и то же значение, ваше решение может использовать memcpy для копирования параметров из стека в данныепамять для проверки или что-то еще, если это поможет
  • Если ds = ss, вы можете использовать &, чтобы найти адрес переданных параметров изнутри func (¶m1, ¶m2)
  • Если ds и ssили не равно (как они могут быть в многопоточном приложении) вам понадобится вариант memcpy, который использует «дальнюю адресацию», которая будет обрабатывать ситуацию, когда ds и ss отличаются
2 голосов
/ 20 января 2011

Нет, единственный способ сделать это - использовать макросы va_list, предоставленные в stdarg.h

0 голосов
/ 20 января 2011

Если все аргументы функции с переменным числом имеют одинаковый тип (например, void *), вы можете сделать что-то вроде этого:

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);
}

Заменить type фактическим типом.

0 голосов
/ 20 января 2011

Нет, особого способа сделать это или каких-либо специальных обозначений нет.

Полагаю, вы могли бы определить макрос для каждого аргумента и сгенерировать на него указатель (найдите библиотеку препроцессора Boost);Я уверен, что не хотел бы.

int somefunc(int arg1, char *arg2)
{
    int *p_arg1 = &arg1;
    char **p_arg2 = &arg2;
    ...
}
0 голосов
/ 20 января 2011

См. stdarg(3) и учебник .

...