изучаем sysutils.pas например или просто окно cpu открываем и смотрим как же на асме вызываются методы
Подсказка: в любой метод неявным образом передается self, т.е. указатель на объект, который этот метод вызывает. В остальном - используется соглашение fastcall, насколько я помню. Однако проще всего не пытаться решить задачу умозрительно, а просто вызвать нужный метод в тестовой программе на Delphi и срисовать соответствующий код из встроенного отладчика.
Срисовать один к одному для виртуальных методов не получится, т.к. кроме компилятора никто смещений методов в VMT не знает Поэтому на асме можно вызывать методы объектов только статически без использования VMT и соответсвенно без всякого полиморфизма (т.е. действительный тип объекта должен быть известен заранее). В дельфях рулит соглашение о вызовах register: при вызове метода в eax передается указатель на объект, затем первые два параметра размеров до 4 байт в регистры edx и ecx, остальное через стек в порядке слева-направо (в противоположном stdcall). Примерчик: Код (Text): type TFoo = class(..) ... function SomeFunc(x,y,z:integer); ... end; var foo:TFoo; x,y,z:integer; begin foo:=TFoo.Create; ... asm mov eax,foo mov edx,x mov ecx,y push z call TFoo.SomeFunc end; ...
leo т.к. кроме компилятора никто смещений методов в VMT не знает не факт еще помогает курить мануалы - ниже кусок делфевского хелпа. Two additional directives allow assembly code to access dynamic and virtual method: VMTOFFSET and DMTINDEX. VMTOFFSET retrives the offset in bytes of the virtual method pointer table entry of the virtual method argument from the beginning of the virtual method table (VMT). This directive needs a fully specified class name with a method name as a parameter, for example,TExample.VirtualMethod. DMTINDEX retrieves the dynamic method table index of the passed dynamic method. This directive also needs a fully specified class name with a method name as a parameter, for example,TExample.DynamicMethod. To invoke the dynamic method, call System.@CallDynaInst with the (E)SI register containing the value obtained from DMTINDEX. Note: Methods with the "message" directive, are implemented as dynamic methods and can also be called using the DMTINDEX technique. For example: Код (Text): TMyClass = class procedure x; message MYMESSAGE; end; Код (Text): program Project2; type TExample = class procedure DynamicMethod; dynamic; procedure VirtualMethod; virtual; end; procedure TExample.DynamicMethod; begin end; procedure TExample.VirtualMethod; begin end; procedure CallDynamicMethod(e: TExample); asm // Save ESI register PUSH ESI // Instance pointer needs to be in EAX MOV EAX, e // DMT entry index needs to be in (E)SI MOV ESI, DMTINDEX TExample.DynamicMethod // Now call the method CALL System.@CallDynaInst // Restore ESI register POP ESI end; procedure CallVirtualMethod(e: TExample); asm // Instance pointer needs to be in EAX MOV EAX, e // Retrieve VMT table entry MOV EDX, [EAX] // Now call the method at offset VMTOFFSET CALL DWORD PTR [EDX + VMTOFFSET TExample.VirtualMethod] end; var e: TExample; begin e := TExample.Create; try CallDynamicMethod(e); CallVirtualMethod(e); finally e.Free; end; end.
вот еще до кучи... кусок кода неизвестного автора Код (Text): // функция служит для получения указателя на байт, cледующий за адресом // последнего метода в VMT класса // возвращает nil в случае, если у класса нет VMT function GetVMTEnd(Cls: TClass): Pointer; asm // Вход: Cls --> EAX // Выход: Result --> EAX PUSH EBX MOV ECX, 8 MOV EBX, -1 MOV EDX, vmtSelfPtr @@cycle: ADD EDX, 4 CMP [EAX + EDX], EAX JE @@vmt_not_found JB @@continue CMP [EAX + EDX], EBX JAE @@continue MOV EBX, [EAX + EDX] @@continue: DEC ECX JNZ @@cycle MOV EAX, EBX JMP @@exit @@vmt_not_found: XOR EAX, EAX @@exit: POP EBX end;
Max Спасибо за подсказку. Отстаю от жизни, однако ) Фичи конечно полезные, но вот интересно как их использовать в наследуемых классах со сложной иерархией. Берем к примеру стандартный TEdit и понятия не имеем какие у него методы виртуальные, какие динамические, а какие статические. Лазить по хэлпам и сорцам или действовать методом тыка ?
Просто лазим по сорцам (vcl) или берем код на Delphi, компилируем и смотрим по ctrl+C какие методы виртуальные, а какие нет.