· Начало · Отвђтить · Статистика · Поиск · FAQ · Правила · Установки · Язык · Выход · WASM.RU · Noir.Ru ·

 WASM Phorum —› WASM.ZEN —› переносимые параметры...

Посл.отвђт Сообщен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