Dec 05, 2013 02:25
Эта тема волнует меня достаточно давно. Как вызвать функцию не напрямую, имея имя и параметры, а в обход, получая информацию перед самым вызовом. С вызовом через прототип я разобрался довольно быстро и тема имени отпала. Остались параметры и начались поиски решений.
В прошлый раз исследования привели к решению вызывать функции через ассемблер. Передавая параметры в стеи и делая вызов. Тогда это решение устроило. Но вот проблема встала снова и захотелось чего-то нового.
Помощь пришла с совершенно неожиданной стороны. Те, кто пользовался функциями типа int func(...) и va_list знают, насколько оно чувствительно к параметрам и как любит падать. В общем адская штука и пользоваться ей категорически не советую. Но, как оказалось, при вызове такой функции компилятор кладет параметры с тек так же как при вызове любой другой. И это внезапно открыло новые перспективы.
#include
#include
// Берем функцию:
int test(int a, char *b, double c){
printf("%d %s %f", a, b, c);
return 0;
}
// Делаем прототип:
typedef int (*callfunc)(...);
// И пишем код:
int main(int args, char* arg[]){
// параметры функции, которые хотим передать.
double d=11; int str[4]={15, (unsigned int)"text"}; memcpy(str+2, &d, 8);
// структура, которая будет полностью скопирована в стек. Если передавать str, то будет передан указатель, а нам нужно передать именно данные.
struct efunc_s{ unsigned int a[4]; };
// получаем адрес функции.
callfunc cf=(callfunc)test;
// Приводим в вид, который будет скопирован в стек.
efunc_s &s=*(efunc_s*)&str;
// вызываем функцию
(*cf)(s);
return 0;
}
Код прекрасно работает в MSVS 2010. К сожалению под g++ этот код работать не захотел, но думаю это не надолго. Естественно, при сборке под 64 бита. В g++ -m32 отлично работает, под 64 бита надо принять во внимание размер char*.
struct efunc_s{ unsigned int a[4]; }; может быть больше без ущерба для работы программы. Лишние данные никак не повлияют.
Наконец-то достигнут именно тот результат, который я искал.
typedef,
c++