powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Ассемблерный код
4 сообщений из 4, страница 1 из 1
Ассемблерный код
    #39634438
Гирлионайльдо
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Нашёл единственный в мире динамический обработчик евентов Можно ли делегировать эвент?

Исправил его на такой, выкинув много лишнего
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
unit ObjAutoMyy;

interface

uses System.Rtti, System.SysUtils, System.TypInfo, vcl.dialogs, Winapi.Windows,
  TEngineStruct;

const
  paEAX = Word(0);
  paEDX = Word(1);
  paECX = Word(2);
  paStack = Word(3);

type
  TEventBeforeNotify = reference to procedure(_Function: pzval;
    o: TRttiProperty; const Args: TArray<TValue>);

  PParameters = ^TParameters;

  TParameters = packed record
    Registers: array [paEDX .. paECX] of Cardinal;
    EAXRegister: Cardinal;
    ReturnAddress: Pointer;
    Stack: array [0 .. 1023] of Byte;
  end;

function CreateMethodPointer(__PropType: TRttiProperty; FuncPHP: pzval;
  OnBefore: TEventBeforeNotify): TMethod; overload;

procedure ReleaseMethodPointer(MethodPointer: TMethod);

implementation

uses
  System.Variants, System.VarUtils, System.RTLConsts;

function GetTypeSize(TypeInfo: PTypeInfo): Integer;
var
  TypeData: PTypeData;
begin
  case TypeInfo^.Kind of
    tkChar:
      Result := 1;
    tkWChar:
      Result := 2;
    tkInteger, tkEnumeration:
      begin
        TypeData := GetTypeData(TypeInfo);
        if TypeData^.MinValue >= 0 then
          if Cardinal(TypeData^.MaxValue) > $FFFF then
            Result := 4
          else if TypeData^.MaxValue > $FF then
            Result := 2
          else
            Result := 1
        else if (TypeData^.MaxValue > $7FFF) or (TypeData^.MinValue < -$7FFF - 1)
        then
          Result := 4
        else if (TypeData^.MaxValue > $7F) or (TypeData^.MinValue < -$7F - 1)
        then
          Result := 2
        else
          Result := 1;
      end;
    tkFloat:
      begin
        TypeData := GetTypeData(TypeInfo);
        case TypeData^.FloatType of
          ftSingle:
            Result := 4;
          ftComp, ftCurr, ftDouble:
            Result := 8;
        else
          Result := -1;
        end;
      end;
    tkString, tkLString, tkUString, tkWString, tkInterface, tkClass:
      Result := SizeOf(Pointer);
    tkMethod:
      Result := SizeOf(TMethod);
    tkInt64:
      Result := 8;
    tkVariant:
      Result := 16;
    tkSet:
      Result := 4;
  else
    Result := -1;
  end;
end;

type
  PParameterInfos = ^TParameterInfos;
  TParameterInfos = array [0 .. 255] of ^PTypeInfo;

  TBaseMethodHandlerInstance = class
  protected
    PHPFunc: pzval;
    TypeData: PTypeData;
    _PropertyType: TRttiProperty;
    ParamInfos: PParameterInfos;
    ParamOffsets: array of Word;
    StackSize: Integer;
    FOnBefore: TEventBeforeNotify;
    procedure Handler(Params: Pointer);
    procedure RegisterStub;
  public
    constructor Create(__PropType: TRttiProperty; FuncPHP: pzval;
      OnBefore: TEventBeforeNotify);
  end;

function AdditionalInfoOf(TypeData: PTypeData): Pointer;
var
  P: PByte;
  I: Integer;
begin
  P := @TypeData^.ParamList;
  for I := 1 to TypeData^.ParamCount do
  begin
    Inc(P, 1 + P[1] + 1);
    Inc(P, P[0] + 1);
  end;
  if TypeData^.MethodKind = mkFunction then
    Inc(P, P[0] + 1 + 4);
  Result := P;
end;

function CreateMethodPointer(__PropType: TRttiProperty; FuncPHP: pzval;
  OnBefore: TEventBeforeNotify): TMethod;
begin
  TObject(Result.Data) := TBaseMethodHandlerInstance.Create(__PropType, FuncPHP,
    OnBefore);
  Result.Code := @TBaseMethodHandlerInstance.RegisterStub;
end;

procedure ReleaseMethodPointer(MethodPointer: TMethod);
begin
  TObject(MethodPointer.Data).Free;
end;

{ TBaseMethodHandlerInstance }

constructor TBaseMethodHandlerInstance.Create(__PropType: TRttiProperty;
  FuncPHP: pzval; OnBefore: TEventBeforeNotify);
var
  P: PByte;
  Offset: Integer;
  CurReg: Integer;
  I: Integer;
  Size: Integer;
begin
  Self.PHPFunc := FuncPHP;
  Self._PropertyType := __PropType;
  Self.FOnBefore := OnBefore;

  Self.TypeData := __PropType.PropertyType.Handle.TypeData;

  P := AdditionalInfoOf(TypeData);
  ParamInfos := PParameterInfos(Cardinal(P) + 1);

  // Calculate stack size
  CurReg := paEDX;
  P := @TypeData^.ParamList;
  StackSize := 0;
  for I := 0 to TypeData^.ParamCount - 1 do
  begin
    if System.TypInfo.TParamFlags(P[0]) * [pfVar, pfConst, pfAddress,
      pfReference, pfOut] <> [] then
      Size := 4
    else
      Size := GetTypeSize(ParamInfos^[I]^);
    if (Size <= 4) and (CurReg <= paECX) then
      Inc(CurReg)
    else
    begin
      if Size < 4 then
        Size := 4;
      Inc(StackSize, Size);
    end;
    Inc(P, 1 + P[1] + 1);
    Inc(P, P[0] + 1);
  end;

  // Calculate parameter offsets
  SetLength(ParamOffsets, TypeData^.ParamCount);
  CurReg := paEDX;
  P := @TypeData^.ParamList;
  Offset := StackSize;
  for I := 0 to TypeData^.ParamCount - 1 do
  begin
    if System.TypInfo.TParamFlags(P[0]) * [pfVar, pfConst, pfAddress,
      pfReference, pfOut] <> [] then
      Size := 4
    else
      Size := GetTypeSize(ParamInfos^[I]^);
    if (Size <= 4) and (CurReg <= paECX) then
    begin
      ParamOffsets[I] := CurReg;
      Inc(CurReg);
    end
    else
    begin
      Dec(Offset, Size);
      ParamOffsets[I] := Offset;
    end;
    Inc(P, 1 + P[1] + 1);
    Inc(P, P[0] + 1);
  end;
end;

procedure TBaseMethodHandlerInstance.RegisterStub;
const
  PtrSize = SizeOf(Pointer);
  asm
    PUSH    EAX
    PUSH    ECX
    PUSH    EDX
    MOV     EDX,ESP
    CALL    Handler
    // Pop EDX and ECX off the stack while preserving all registers.
    MOV     [ESP+4],EAX
    POP     EAX
    POP     EAX
    POP     ECX             // Self
    MOV     ECX,[ECX].TBaseMethodHandlerInstance.StackSize

    TEST    ECX,ECX
    JZ      @@SimpleRet
    // Jump to the actual return instruction since it is most likely not just a RET
    // JMP     ECX    // Data Exec. Prevention: Jumping into a GetMem allocated memory block

    // stack address alignment
    ADD     ECX, PtrSize - 1
    AND     ECX, NOT (PtrSize - 1)
    AND     ECX, $FFFF

    // clean up the stack
    PUSH    EAX                         // we need this register, so save it
    MOV     EAX,[ESP + 4]               // Load the return address
    MOV     [ESP + ECX + 4], EAX        // Just blast it over the first param on the stack
    POP     EAX
    ADD     ESP,ECX                     // This will move the stack back to where the moved
    // return address is now located. The next RET
    // instruction will do the final stack cleanup
  @@SimpleRet:
end;

function GetCodePointer(Instance: TObject; P: Pointer): Pointer; inline;
begin
  if (IntPtr(P) and PROPSLOT_MASK) = PROPSLOT_VIRTUAL then // Virtual Method
    Result := PPointer(PNativeUInt(Instance)^ + (UIntPtr(P) and $FFFF))^
  else // Static method
    Result := P;
end;

procedure TBaseMethodHandlerInstance.Handler(Params: Pointer);
var
  P: PByte;
  Parameters: PParameters;
  I: Integer;
  Regs: array [paEAX .. paEDX] of Cardinal;
  Offset: Integer;
  Data: Pointer;
  MethodValues: TArray<TValue>;
  Zerk: Integer;
  tmp: TValue;
begin
  Parameters := Params;

  Zerk := 0; // зеркальное отрожение!

  SetLength(MethodValues, TypeData^.ParamCount);

  // Fetch the parameters into ParamValues
  P := @TypeData^.ParamList;
  for I := 0 to TypeData^.ParamCount - 1 do
  begin
    Offset := ParamOffsets[I];
    if (Offset >= paEDX) and (Offset <= paECX) then
      Data := @Parameters^.Registers[Offset]
    else
      Data := @Parameters^.Stack[Offset];

    if ParamInfos^[I]^.Kind = tkClass then
      MethodValues[Zerk] := TObject(PPointer(Data)^)
    else if System.TypInfo.TParamFlags(P[0]) * [pfVar, pfOut] <> [] then
      TValue.Make(Pointer(PCardinal(Data)^), ParamInfos[I]^, MethodValues[Zerk])
    else
      TValue.Make(Data, ParamInfos[I]^, MethodValues[Zerk]);

    Inc(P, 1 + P[1] + 1);
    Inc(P, P[0] + 1);
    Inc(Zerk);
  end;
  // P is left pointing to the return type name if there is one.
  // Self.MethodHandler.
  Self.FOnBefore(Self.PHPFunc, Self._PropertyType, MethodValues);

  P := @TypeData^.ParamList;
  for I := 0 to TypeData^.ParamCount - 1 do
  begin
    Offset := ParamOffsets[I];
    if (Offset >= paEDX) and (Offset <= paECX) then
      Data := @Parameters^.Registers[Offset]
    else
      Data := @Parameters^.Stack[Offset];

    if System.TypInfo.TParamFlags(P[0]) * [pfVar, pfOut] <> [] then
    begin
      // ~ = AV
      TValue.Make(Pointer(PCardinal(Data)^), ParamInfos[I]^, tmp);
      if (tmp.ToString <> MethodValues[I].ToString) then
        PPointer(PCardinal(Data)^)^ :=
          PPointer(MethodValues[I].GetReferenceToRawData^)^;
    end;

    Inc(P, 1 + P[1] + 1);
    Inc(P, P[0] + 1);
  end;



  // Let Stub procedures know where the RET instruction is
  asm
    MOV     EAX,DWORD PTR Regs[paEAX*4]
    MOV     EDX,DWORD PTR Regs[paEDX*4]
  end;
end; // of X86ASM implementation

end.



Всё прекрасно работает, функции перехватываются в поставленный обработчик вместе со всеми аргументами.

Собственно вопрос, а зачем нужен стаб ??? Я его пробовал убрать, но ничего не выходит
Код: pascal
1.
2.
3.
4.
 asm
    PUSH    EAX
    PUSH    ECX
    PUSH    EDX



Увелечение трёх регистров
Код: pascal
1.
2.
    MOV     EDX,ESP
    CALL    Handler


Помещаем в 32 разрядный регистр EDX указатель стэка ESP (1699200) и вызываем Handler


Какую роль это играет на коде? Убрав этот стаб
Код: pascal
1.
  Result.Code := @TBaseMethodHandlerInstance.Handler;


, код перестаёт читать аргументы правильно. Я думал что EDX должен указывать на первый аргумент в коллбэке. То есть
Код: pascal
1.
2.
3.
  asm
     MOV     Parameters,ESP
  end;



В методе Handler вместо
Код: pascal
1.
Parameters := Params;



И адресс становится 1699120 а не 1699200 Что я не учёл?
...
Рейтинг: 0 / 0
Ассемблерный код
    #39634444
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Гирлионайльдо,

PUSH EAX
PUSH ECX
PUSH EDX
MOV EDX,ESP
CALL Handler
Это заполнение структуры TParameters на стеке

Result.Code := @TBaseMethodHandlerInstance.Handler;
Дельфийское событие - это пара: Self и указатель на код. Что тут не понятно?
...
Рейтинг: 0 / 0
Ассемблерный код
    #39634451
Гирлионайльдо
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
SOFT FOR YOUГирлионайльдо,

PUSH EAX
PUSH ECX
PUSH EDX
MOV EDX,ESP
CALL Handler
Это заполнение структуры TParameters на стеке



Магия какая то, не пойму как оно так работает, я пытался тоже самое реализовать в Handler но это не приводила к успеху


Result.Code := @TBaseMethodHandlerInstance.Handler;
Дельфийское событие - это пара: Self и указатель на код. Что тут не понятно?


Это я показал как именно переопределил в коде
...
Рейтинг: 0 / 0
Ассемблерный код
    #39634490
SOFT FOR YOU
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Гирлионайльдо,

А ты знаешь, как заполняются структуры на стеке, как работает PUSH?
...
Рейтинг: 0 / 0
4 сообщений из 4, страница 1 из 1
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Ассемблерный код
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]