win64. как вызвать виртуальный метод? (Решено)

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Ответить
zub
долгожитель
Сообщения: 2890
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

win64. как вызвать виртуальный метод? (Решено)

Сообщение zub »

Знаю адрес VMT и смещение в нем нужного метода object`а. Нужно его вызвать, под вин32, лин32, лин64 работала следующая конструкция:

Код: Выделить всё

SimpleProcOfObj=procedure of object;
tm:tmethod;
....
tm.Data:=obj{указатель на нужный object};
tm.Code:=ppointer(GDBPlatformint(PVMT{указатель на VMT})+GDBPlatformint(MetodAddr{смещение метода в VMT}))^;
SimpleProcOfObj(tm);

Метод без параметров. Нужно для реализации паскалеподобного скрипта, поэтому напрямую вызывать не катит

update:

возможно дело в неправильном вызове конструктора, он тоже вызывается из скрипта:
под вин64 насколько понял надо так:

Код: Выделить всё

mov rcx,[obj]{указатель на выделенную под object память}]
mov rdx,[p]{указатель на VMT}]
call tm.Code{в tm.Code лежит адрес конструктора} 

под лин64 работало так:

Код: Выделить всё

mov rdi,[obj]
mov rsi,[p]
call tm.Code
Последний раз редактировалось zub 21.11.2011 21:12:14, всего редактировалось 3 раза.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
Сообщения: 1409
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение Sergei I. Gorelkin »

Если считать ассемблерный код для Linux правильным, то в виндовом коде rcx и rdx перепутаны местами.
zub
долгожитель
Сообщения: 2890
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

вроде заработало если адрес метода считать со смещением 12

Код: Выделить всё

tm.Code:=ppointer(GDBPlatformint(self.PVMT)+GDBPlatformint(pmd^.MetodAddr)+12)^;

что это за смещение? и почему не кратно 8?

Если считать ассемблерный код для Linux правильным, то в виндовом коде rcx и rdx перепутаны местами.

в линуксе всё работало нормально. вроде не перепутал, ориентируюсь на тестовый код генерируемый FPC приведеный на скрине (a.init - конструктор, a.a - виртуальный метод)
строка callq *0x18(%rax) как будет выглядеть в интеловском синтаксисе?

надо было тему назвать "как вызвать виртуальный метод через задний проход?" :lol:
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
Сообщения: 1409
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение Sergei I. Gorelkin »

zub писал(а):что это за смещение? и почему не кратно 8?

Вообще в теории TObject.ClassType указывает на структуру TVmt (из rtl/inc/objpash.inc), после которой находятся указатели на виртуальные методы. А уж как вы у себя вычисляете MethodAddr, это не ко мне вопрос :)

upd: А, тут вообще речь не о классах, а об object'ах...

zub писал(а):в линуксе всё работало нормально. вроде не перепутал, ориентируюсь на тестовый код генерируемый FPC приведеный на скрине

Да, в Linux первый параметр таки в rdi. Это я ступил, каюсь.
zub
долгожитель
Сообщения: 2890
Зарегистрирован: 14.11.2005 22:51:26
Контактная информация:

Сообщение zub »

указатель на VMT получаю

Код: Выделить всё

pvmt:=TypeOf(ТипОбъекта)

Номер виртуального метода в VMT получаю парсеньем исходников

Добавлено спустя 10 часов 10 минут 11 секунд:
Re: win64. как вызвать виртуальный метод? (Решено)
Дошло откуда взялось это 12
Вообще в теории TObject.ClassType указывает на структуру TVmt

у обжектов есть свой аналог TVmt, состоящий из 3х указателей (почемуто не нашел где он описан). на 32 разрядах методы начинались с смещения 12, на 64 соответственно с 24. вот это тридцатидвух разрядное смещение было учтено в дебрях исходников, а на 64 работало только еще добавив 12. Зато осталось загадкой как это работало на лин64))

Где описано TVmt для обжектов?
Можно ли какнибудь изловчиться вызвать конструктор без асм вставок?
Ответить