Есть адрес виртуальной функции. Как вызвать функцию?

Тема в разделе "LANGS.C", создана пользователем Ezrah, 28 сен 2011.

  1. Ezrah

    Ezrah Member

    Публикаций:
    0
    Регистрация:
    22 мар 2011
    Сообщения:
    411
    Ну вроде как стандартно, указатель на void вмещает любой указатель.
    А это да, это проблема.

    Booster
    Если вы имеете в виду переписать весь класс, то это, во-первых, слишком сложно, а во-вторых, реализация может быть изменена с сохранением, тогда мне придётся переписывать всё заново (однако, интерфейс 100% не изменится). Иначе я не вникся.
     
  2. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Ezrah
    Он самое. Пишите абстрактный класс с чисто виртуальными функциями, без всякой реализации, объявляете указатель на одну из них. А если у вас нет объекта, то сами себе... И при чём здесь detour? В чём ваша проблема, для меня так и не ясно.
    Ещё можно объявить указатель на обычную функцию с первым параметром - объект. Я так dx хукал.
     
  3. Ezrah

    Ezrah Member

    Публикаций:
    0
    Регистрация:
    22 мар 2011
    Сообщения:
    411
    Booster
    Забудьте про всё, что выше написано. Мне нужно из своего кода вызвать виртуальную функцию класса, когда есть только реальный её адрес в памяти. Чтобы это правильно сделать, нужно определить указатель на виртуальную функцию и присвоить ему известный адрес. Проблема в том, что нельзя число присваивать указателям на методы класса. Так как же можно вызвать виртуальную функцию класса, имея только её объявление и физ. адрес?
     
  4. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Ezrah
    Всё забыть? Имея реальный адрес виртуальной функции, вам нужно объявить обычную функцию и добавить первый параметр - this, повторять больше не буду.

    Да?
    Код (Text):
    1. class T
    2. {
    3. };
    4.  
    5. typedef void (T::*p)();
    6. int main()
    7. {
    8.     int a = 9;
    9.     p p1 = (p&)a;
    10. }
     
  5. Ezrah

    Ezrah Member

    Публикаций:
    0
    Регистрация:
    22 мар 2011
    Сообщения:
    411
    Добавив первый параметр this, я не получу __thiscall с передачей this в ecx, что мне хотелось бы сделать.
    Я не силён в плюсах особо. Попробую приведённый код, отпишусь.
     
  6. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    C thiscall безусловно, но методы ком объектов к примеру stdcall.
     
  7. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Ezrah
    Попробуй конечно, наверняка получится. Только не понятно, чем этот совершенно не документированный метод лучше асм-вставки, реализующей хоть как-то документированный вызов __thiscall. Тебя не смущает, что размер указателя на функцию-член может составлять от 4 до 12-16 байт в зависимости от опций компилятора и типа наследования класса? Поэтому можно только "догадываться", что именно первый дворд этой структуры содержит нужный тебе указатель на функцию.

    Аналогично и внутренняя кухня реализации vtbl толком не документирована, но из того, что известно следует, что вариант с подменой vtbl типа #14 by Squash не будет работать, если вызываемая функция обращается к самому объекту или вызывает другие виртуальные функции
     
  8. Ezrah

    Ezrah Member

    Публикаций:
    0
    Регистрация:
    22 мар 2011
    Сообщения:
    411
    Как-то я думал на 32-хбитной машине указатели не превосходят 4х байт.
    Этого я тоже не понял. Какой структуры?
     
  9. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    leo
    Чем это он недокументированный? Если по адресу лежит нормальная область памяти, то всё будет ок.

    Если бы такое было, то и к ком объекту нельзя было обращаться, неизвестно какими опциями собрано.
     
  10. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Ezrah, Booster
    Указатель на функцию-член (типа T::*p), это не обычный указатель, т.к. он должен учитывать такие фишки, как виртуальное и множественное наследование. Поэтому и внутрення структура такого "указателя" не документирована, и допустимые операции присваивания\кастинга для него "официально" урезаны по самый "нусталуйсь". Разумеется, что он должен содержать в себе обычный указатель на функцию и "скорее всего" этот указатель идет первым в структуре - для популярных компилеров типа msvc, intel, g++, borland так оно и есть, хотя в статье "Member Function Pointers and ..." приводятся примеры компилеров, где этот указатель не является первым.
    Что касается размера этого "указателя", то все определяется типом наследования и опциями компилятора - в частности в msvc по умолчанию юзается /vmb (=best) и соотв-но для простого класса имеем всего 4 байта (т.е. только сам ук-ль на функцию), но если включить /vmg (=general), то получится 16 байт

    PS: В COM юзаются обычные указатели из vtbl - по сути ком-интерфейс это и есть указатель на vtbl, т.е. тоже самое, что и абстрактный класс, содержащий только одни виртуальные функции

    Вот еще ссылка на простой примерчик с определением размеров этого с позволения сказать "указателя" для разных типов наследования (по ссылке для msvc при /vmb, а на последней странице для борланда)
     
  11. Dmitry_Milk

    Dmitry_Milk Member

    Публикаций:
    0
    Регистрация:
    20 ноя 2007
    Сообщения:
    540
    Еще раз прочитал самое первое сообщение топика - у топикстартера ведь уже есть непосредственно сам raw адрес точки входа в процедуру! Зачем заморачиываться со всей этой кухней vtbl, если уже имеется тот конечный результат, что должен быть получен в результате обработки кухни? Почему нелья просто в ассемблере просто запихнуть обычные параметры в стек, заполнить ecx адресом объекта (если точно известно, что это __thiscall) и просто сделать вызов по имеющемуся RAW-адресу процедуры?
     
  12. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    leo
    По-вашей логике нельзя использовать ком, так как внутренняя структура класса недокументирована. Или вы противоречите сами себе?

    Указатель не учитывает, учитывает компилятор знающий о классе.

    Не надо пугать. Один и то же компилятор работает одинаково. Есть сгенерированный компилятором указатель, который приведён к void*, затем он снова приводится к первоначальному указателю. Всё нормально.

    Dmitry_Milk
    Не хочет человек использовать асм и я его прекрасно понимаю.

    З.Ы. Если следовать вашей дотошности, то приводить лучше dynamic_cast-ом, но это всё мелочи.
     
  13. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Booster
    Чистые сишники, помешанные на стандартах, так и считают :)
    А я бы сказал наоборот - из того, что структура КОМ документирована, и чисто абстракный класс с одними виртуальными методами совместим с КОМ, можно сделать вывод о том, что этот класс содержит в качестве первого мембера указатель на vtbl, а сама vtbl представляет собой таблицу указателей на вирт.методы в порядке их объявления. А по какому смещению будет расположен указатель на vtbl, если базовый класс не содержит вирт.методов, а его наследник содержит? Будет ли наследник совместим с КОМ? Если ответишь, то желательно не на уровне догадок\исследований, а на уровне ссылочки на некий докУмент от M$, али еще кого ;)

    Учитывет не компилятор, а разработчики компиляторов, которые знают, что для виртуального и множественного наследования одного 4-х байтного ук-ля на функцию не достаточно. Они же и решают, делать ли размер такого квазиуказателя на мембер-функцию одного макс.размера для любых типов наследования (/vmg), или разного (/vmb), или предоставить какие-то опции. Одним словом, см. статью по ссылке - там все расписано (на рсдн есть руский перевод)

    Я не пугаю, а просто намекаю, что в данном случае вариант с эмуляцией __thiscall на асме, является наиболее "законным" = документированным, по сравнению со всеми другими "грязными хаками" ;)
     
  14. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    leo
    Помешательство не есть хорошо. ^)


    В Ком есть ряд требований и одно из них это наследовние от IUnknown. Надеюсь я ответил?

    То что явное указание будет не хуже - согласен, но минус в том что тут ассемблер. Ну а насчёт законности опять могу поспорить, человеку не нужно портировать это на все платформы и компиляторы. К тому же ассемблер и здесь не является какой-то понацеей.
     
  15. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Booster
    Грешно смеяться над больными людьми :) Но дело-то не в самих людях, а в недостаточности инфы, если не в стандартах, то хотя бы в заметках типа Microsoft specific.

    Нет, т.к. я не о КОМ, а о не- или недостаточно-документрованной структуре сишных классов
     
  16. Ezrah

    Ezrah Member

    Публикаций:
    0
    Регистрация:
    22 мар 2011
    Сообщения:
    411
    Дабы разрешить споры, исследуемый класс унаследован только от одного абстрактного класса, являющегося интерфейсом.
    Кстати я так и не понял первого поста leo.
    Код (Text):
    1. class T
    2. {
    3. };
    4.  
    5. typedef void (T::*p)();
    6. int main()
    7. {
    8.     int a = 9;
    9.     p p1 = (p&)a;
    10. }
    меня есть адрес функции,а не какой-то структуры данных со всевозможными vftbl/vbtbl. Не пойму, где тут множественное или виртуальное наследование?
     
  17. _Juicy

    _Juicy Active Member

    Публикаций:
    0
    Регистрация:
    12 авг 2003
    Сообщения:
    1.159
    Адрес:
    SPb
    В моем посте #14 вроде проблема решена, не?
     
  18. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    leo
    А какая им нужна инфа?

    Чёт я не понял. Вы спрашивали о совместимости с ком, по моему я ответил. А насчёт того где будет расположен vtbl, то это уже не столь важно(если класс не соответствует требованиям).

    Squash
    Прикольно, но есть одна неувязочка. Данные где?
     
  19. _Juicy

    _Juicy Active Member

    Публикаций:
    0
    Регистрация:
    12 авг 2003
    Сообщения:
    1.159
    Адрес:
    SPb
    Данные - это что?
     
  20. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Данные!