Вызов метода по указателю с переменным числом параметров

Тема в разделе "LANGS.C", создана пользователем _220, 11 окт 2010.

  1. W4FhLF

    W4FhLF New Member

    Публикаций:
    0
    Регистрация:
    3 дек 2006
    Сообщения:
    1.050
    А вообще это паттерн Command, только непонятно как его в такой постановке реализовать без хаков. :)
     
  2. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    W4FhLF
    Нечто подобное есть в .Net, только там инфа о типах лежит не отдельно, а вшита в сборку. И вызывать динамически, не зная на этапе компиляции ничего тоже можно.
     
  3. W4FhLF

    W4FhLF New Member

    Публикаций:
    0
    Регистрация:
    3 дек 2006
    Сообщения:
    1.050
    Booster, с .NET всё понятно, у шарпа в 4ой версии даже dynamic есть.
     
  4. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    W4FhLF
    Хорошая плюшка, но применение довольно узкое, да и скорее всего тормоз ещё тот.
     
  5. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Могу предложить решение. Заполняем в рантайме значениями некий плоский массив, затем передаём его нужной функции как значение, всё. Есть только одна проблема это размер передаваемого значения, тут можно сгенерировать множество функций, или типов аргументов.
     
  6. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.323
    можно попробовать руками на стек положить все параметры функции... что-то типа этого:
    Код (Text):
    1. LPVOID __stdcall CallByBuffer(LPVOID FuncAddress, PDWORD StackBuffer, DWORD nDwords)
    2. {
    3.  PDWORD RetAdr = _AddressOfReturnAddress();
    4.  RetAdr = RetAdr - nDwords - 1;
    5.  memcpy(RetAdr, StachBuffer, nDwords * 4);
    6.  typedef LPVOID (__stdcall* MyFunc)();
    7.  MyFunc func = (MyFunc)FuncAddress;
    8.  return func();
    9. }
    но это только для __stdcall и надо проверить, что стек вернулся в исходное состояние после вызова... может канеш и не будет работать, сам не проверял, просто идея...
     
  7. W4FhLF

    W4FhLF New Member

    Публикаций:
    0
    Регистрация:
    3 дек 2006
    Сообщения:
    1.050
    Это для Windows x32 stdcall. Проще уж тогда asm заюзать.
     
  8. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.323
    замени DWORD на ULONG_PTR и будет тебе поддержка x64 stdcall... asm надо прописывать отдельным файлом, чтобы была поддержка x64... тем более по условию задачаи asm не юзать, но и в том и в другом случае надо точно знать, как аргументы должны лечь на стек или попасть в регистры...
     
  9. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Rel
    Не понял, а где там опускается esp? По-моему func(); перезапишет наши данные и будет труляля. Да и "MyFunc func" тоже перезапишет.
     
  10. qqwe

    qqwe New Member

    Публикаций:
    0
    Регистрация:
    2 янв 2009
    Сообщения:
    2.914
    используйте собственный формат с разложением в поток байтов и указанием типов. медленно и неуниверсально не будет. как доп + вы сможете сохранять лог обмена в файл или передавать по сетке без дополнительных усилий.
     
  11. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.323
    а... кстати да... я же говорю, что не проверял сам))))
     
  12. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Rel
    По-моему единственный вариант изменить esp без ассеблера, это объявить массив, но проблема в том что у них нельзя задать размер в рантайме. Если только объявить большой фиксированный массив и записать значения снизу, но по-моему это тоже не слишком надёжно.
     
  13. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.323
    не, ну почему ненадежно... я чет забыл, что локальные статические массивы на стеке... можно попробовать переписать пример таким образом:
    Код (Text):
    1. LPVOID __stdcall CallByBuffer(LPVOID FuncAddress, PBYTE StackBuffer, DWORD Size)
    2. {
    3.  ULONG_PTR Params[64];
    4.  memcpy(Params, StackBuffer, Size);
    5.  typedef LPVOID (__stdcall* MyFunc)();
    6.  MyFunc func = (MyFunc)FuncAddress;
    7.  return func();
    8. }
    тут как бы можно предположить, что не будет функции с более чем 64 аргументами))) стек сдвинется на 64 параметра, снизу запишутся заранее подготовленные параметры, произойдет колл, на стек снизу допишется адрес возврата, функция заберет аргументы, вернется обратно, к esp приплюсуется размер 64 параметров... вроде все ок на первый взгляд... но как быть, если функция не stdcall?
     
  14. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Rel
    А откуда увереность, что это сработает в stdcall? Ведь вызываемая функции освободит часть стека, а вызывающая может тупо прибавить размер своих стековых данных. И что тогда? И не забывам про отимизацию.
     
  15. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.323
    блин, тут вообще говоря нетривиальная задача... надо посидеть отладчиком, что-то покрутить в этой теме... обычно значение esp перед использованием компилятор переносит в ebp, этим можно как-то попробовать воспользоваться... еще buffer security check перед каждым вызовом сохраняет значение esp в своей переменной, можно отключить в настройках проекта проверку и явно ее вызвать в коде... но от этого всего канеш костыль получится существенный, но все же)))
     
  16. qqwe

    qqwe New Member

    Публикаций:
    0
    Регистрация:
    2 янв 2009
    Сообщения:
    2.914
    а почему данные не передавать через нестековый буфер ссылкой? и скажем, первым параметром этого буфера - калбэк на его освобождение.
    или использовать С-калл конвенцию? wsprintf использует С конвенцию, хотя и из вин-апи
     
  17. _220

    _220 New Member

    Публикаций:
    0
    Регистрация:
    23 мар 2006
    Сообщения:
    111
    Вот это буча поднялась!
    Появилась небольшая вероятность, что получится обойтись без извратов.
    В любом случае, задача интересная. Разруливают ведь подобное как-то системы типа COM...
     
  18. W4FhLF

    W4FhLF New Member

    Публикаций:
    0
    Регистрация:
    3 дек 2006
    Сообщения:
    1.050
    Не как-то, а через динамический полиморфизм. Но это лишь один из способов. Существует далеко не один такой способ, который позволяет решить эту задачу без хаков. Просто ваша система неудачно спроектирована.

    Это, кстати, не с плагинами случайно связано?
     
  19. Partner

    Partner Павел

    Публикаций:
    0
    Регистрация:
    28 фев 2008
    Сообщения:
    917
    Адрес:
    Los Angeles
    динамический полиморфизм - это немного из другой оперы.
    В COM для передачи переменного числа параметров используют SafeArray. Другими словами, это массив VARIANT'ов.
     
  20. _220

    _220 New Member

    Публикаций:
    0
    Регистрация:
    23 мар 2006
    Сообщения:
    111
    Похоже на плагины.,только в данном случае я имею функционально децентрализованную систему из модулей.
    Ядро загружает модули и начинается сущщая вакханалия