|
|
| Посл.отвђт | Сообщенiе |
|
|
Дата: Июн 29, 2004 14:59:30 · Поправил: Безпощадный даос Привет всем! Рассмотрим этот код: //--------------------------{cut here}------------------------- #include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
typedef void (*entry)(void *, ...);
int ParametersChecker(int args, entry fn, ...)
{
int ind = 0;
va_list marker;
void *iter_arg;
void **arguments = NULL;
/* Initialize variable arguments. */
va_start(marker, fn);
arguments = malloc(sizeof(void *) * args);
ind = 0;
for(;ind < args; ind ++)
arguments[ind] = va_arg(marker, void*);
va_end(marker);
ind = args - 1;
for(;ind != -1; ind --)
{
iter_arg = arguments[ind];
__asm {
push iter_arg
}
}
args *= 4;
__asm {
call fn
add esp, args
}
free(arguments);
return 0;
}
void fn(char *str, int len)
{
int i = 0;
i = 0;
for(;i < len; i ++)
{
printf("%c", str[i]);
}
}
void main()
{
// 1
char buf[] = "testtesttest\n";
fn(buf, strlen(buf));
// 2
ParametersChecker(2, fn, buf, strlen(buf));
}//--------------------------{cut here}-------------------------
Этот код просто вызывает функцию, переданную ей в качестве параметров, слегка в извращенной форме. По сути //1 делает то же самое что и //2, в чем можно убедиться, откомпилив это в VC++ 6.0. Внимание вопрос, как переделать этот код, чтобы он работал на железе отличного от x86, и не зависел от компилятора. Проблема в том, что, допустим, на других процах, регистра ESP нету. На gcc компилиться не хочет. И вообще, возможно ли это все сделать на уровне языка С, в этом случае, я полагаю, он будет переносим и скомпилиться на любом компиляторе! :) Заранее Б0ЛьШ0Е спасибо... 500174814__ |
|
|
Дата: Июн 29, 2004 15:35:45 liss Использовать соглашение вызова подпрограмм отличное от Си, например, pascal? |
|
|
Дата: Июн 29, 2004 15:39:38 q_q А как параметры в стек пихать? Все что имеется в ParameterChecker это массив параметров и указатель на функцию! ps тут соглашение ни на что не влияет... |
|
|
Дата: Июн 29, 2004 18:22:16 liss А почему ты это делаешь через такую, хм, это, ну... Как бы так повежливее сказать... хитрую позицию, во! Смысл-то этих извратов какой? |
|
|
Дата: Июн 29, 2004 18:51:35 У меня есть куча функций с различными параметрами, некоторые(каких достаточно много) из которых работают по одному принципу(например возвращают массив байтов). fn1(..., unsigned char* pBlob, int lenBlob, int *pResultSize, ...); Так вот, при помощи этой хрени, я хотел написать тестер, которому буду передавать функции подобного типа и делать перебор на всевозможные варианты (типа там НУЛЛ, -1 и т.п. допустим для этих трех параметров, нежели составлять список вызываемых функций у которых будут лишь разные параметры) для передаваемой функции. Под x86 это пройдет, под другие платформы - сомневаюсь. 2 volodya Что скажешь? |
|
|
Дата: Июн 29, 2004 19:13:15 Напоминает параметризацию ODBC :) Эта проблема у меня решалась достаточно просто. Передавалась строка спецификаторов (как для printf) наряду с параметрами. Для твоего случая это выглядело бы так: fn1("%s%i%x", unsigned char* pBlob, int lenBlob, int *pResultSize) Ты разбираешь строку спецификаторов в цикле и ожидаешь получить на вход параметр точно такого же типа. Если стандартных спецификаторов покажется мало - заведи свои. Например, мне с потолка ничего в голову не пришло по поводу int *. Для этого случая и пригодится свой спецификатор. |
|
|
Дата: Июн 29, 2004 19:49:04 Хмм.. А почему перегрузка функций не подходит? Функции с разными параметрами и разным кодом, но с одинаковым именем (ведь именно это хочется, насколько я понимаю?). Или я как всегда все перепутал? |
|
|
Дата: Июн 29, 2004 19:56:54 Или я как всегда все перепутал? А причем тут вообще С++? И перегрузка? |
|
|
Дата: Июн 29, 2004 20:11:39 liss тут соглашение ни на что не влияет... Ещё как влияет :-) Пусть вызываемая функция сама чистит стек (stdcall) и "add esp,args" можно будет убрать, но это справедливо только для фиксированного количества параметров, т.е. конкретно для fn() фокус пройдёт. |
|
|
Дата: Июн 30, 2004 04:04:32 · Поправил: q_q liss Про соглашение ни на что не влияет Quantum уже ответил. А как параметры в стек пихать? Согласно выбранному соглашению по передаче параметров. Afaik в твоем случае (все сделать на уровне языка С) подойдут три варианта __cdecl, pascal и stdcall. Что касается восстановления стека, то второй и третий варианты предполагают, что вызываемая подпрограмма сама зачистит стек, а в случае с __cdecl можно добавить цикл с pop'ами - аналогичный циклу помещающему параметры в стек. Итого: если к адресу функции и параметрам добавить информацию о calling conventions, то вполне можно написать универсальную подпрограмму. |
|
|
Дата: Июн 30, 2004 08:45:42 q_q Забыл сказать, что сорцов нету к этим ф-циям, объявлены они как __cdecl. Поэтому вариант с __stdcall и т.п. отпадает. Но все-таки, не вижу ответа на вопрос: Как без push'ов всунуть в стек локальной функции параметры, да чтобы было переносимо. По-моему - никак :( Можно, конечно создать переменную(буфер) под максимальное еоличество параметров, и передвинуть при помощи alloca... Но что-то уж слишком сложно да и не переносимо... |
|
|
Дата: Июн 30, 2004 16:11:47 если придумаешь что-нибудь, выкладывай исходники, могу протестить на sparc и motorolla процессорах |
|
Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.068 |