Конференция "Начинающим" » Вызов своей скомпилированной процедуры
 
  • dmk © (28.08.18 19:23) [0]
    Привет!
    Возникла необходимость сделать сборку нескольких процедур в одну.
    Вроде составной перегрузки. Proc1 + Proc2 + Proc3. И так по мере надобности.
    Есть такой код. Вызов процедуры происходит, но выполнять его ядро не дает. AV.
    Куда копать? Неужели в DOS?
    procedure DoCall;
    const
     D: array[0..3] of byte = ($90, $C3, $0, $0);

    asm
     .NOFRAME

     //nop
     //ret

     lea rax, D
     call rax
    end;

  • KilkennyCat © (28.08.18 21:33) [1]

    > lea rax, D
    >  call rax

    ну и чего в итоге в rax?
  • Игорь Шевченко © (28.08.18 22:42) [2]
    Нельзя выполнять код в указанном сегменте, DEP, видимо. Ну и полный текст надо приводить, у AV причин обычно бывает больше одной.
  • dmk © (29.08.18 00:50) [3]
    Оказывается в Delphi предусмотрен вариант исполнения кода.
    И мой вариант работает тоже. Главное странице памяти назначить права правильные.
    Собственно что мне и было нужно.

    const
      size = 128;

    type
      TFuncInt = function(param: Integer): Integer; // EAX -> EAX
      TByteArray = array[0..size-1] of Byte;
      PByteArray = ^TByteArray;

    var
      arr: PByteArray;
      FParam: Integer;
      FResult: Integer;

    procedure DoCall;
    asm
     .NOFRAME

     mov rax, arr
     call qword ptr rax
    end;

    procedure ExecCode;
    begin
     arr := VirtualAlloc(nil, size, (MEM_RESERVE or MEM_COMMIT), PAGE_EXECUTE_READWRITE);

     if (arr <> nil) then
     begin
       arr[0] := $FF;  // inc ECX
       arr[1] := $C1;
       arr[2] := $89;  // mov eax, ecx
       arr[3] := $C8;
       arr[4] := $C3;  // ret

       DoCall; //<- Мой вызов

       FParam := 77;
       FResult := TFuncInt(arr)(FParam);  // 78 <- Вызов через Delphi
     end;

     VirtualFree(arr, 0, MEM_RELEASE);
    end;
  • dmk © (29.08.18 00:54) [4]
    Можно сразу массив вызвать, без RAX.
    procedure DoCall;
    asm
     .NOFRAME

     call qword ptr arr
    end;
  • dmk © (29.08.18 00:56) [5]
    Еще бы инфу по отладчикам найти. Int 3.
  • KSergey © (30.08.18 07:00) [6]
    Какие описываются технические проблемы с вызовом кода, записанного в данных программы - я вроде понял.
    А вот исходного вопроса про "составные процедуры" - нет.
  • Leonid Troyanovsky © (30.08.18 10:53) [7]
  • dmk © (30.08.18 13:52) [8]
    >А вот исходного вопроса про "составные процедуры" - нет.

    Вот процедура состоящая из блоков. Ее сожно модифицировать и создавать другие варианты расчетов. В общем как шейдеры в OpenGL/DirectX. Собственно я и делаю расчетные шейдеры. Просто мне надо скомпилировать шейдер перед вызовом. Сложить в зависимости от условий куски кода в одну процедуру.

    function SpecularB(SpecColor, FaceNormal, LightDir: TVertex): TColorRef;
    const
     K: Single = 0.333333333;

    asm
     .NOFRAME

     movd xmm3, [K]
     shufps xmm3, xmm3, 01000000b

     movdqa xmm2, xmm10
     addps xmm2, xmm11
     addps xmm2, xmm12
     mulps xmm2, xmm3

     movdqa xmm5, xmm2
     movdqa xmm6, [FaceNormal]

     //№1 - Dot(I, N)
     mulps xmm5, xmm6
     haddps xmm5, xmm5
     haddps xmm5, xmm5

     //№2 - 2.0 * №1
     mulss xmm5, [SingleTwo]

     //№3 - VecMul(N, №2)
     shufps xmm5, xmm5, 01000000b
     mulps xmm5, xmm6

     //№4 - FaceCenter - №3
     subps xmm2, xmm5

     pxor xmm1, xmm1
     insertps xmm2, xmm1, 00110000b
     movdqa xmm0, xmm2

     //Len := VecLen(V);
     mulps xmm2, xmm2
     haddps xmm2, xmm2
     haddps xmm2, xmm2
     sqrtss xmm2, xmm2

     //if (Len <> 0.0)
     ptest xmm2, xmm2
     jz @Zero

     //F := (1.0 / Len);
     movd xmm1, [SingleOne]
     divss xmm1, xmm2

     //V * F
     shufps xmm1, xmm1, 01000000b
     mulps xmm0, xmm1

     movdqa xmm2, xmm0
     jmp @EndNormalize

    @Zero:
     movdqa xmm2, xmm1

    @EndNormalize:

     //№5 - Dot(LightDir, №4)
     movdqa xmm0, [LightDir]
     mulps xmm0, xmm2
     haddps xmm0, xmm0
     haddps xmm0, xmm0

     //№6 - Max(№5, minLightK)
     maxss xmm0, [minLightK]

     //№7 - Pow32(№6)
     call Pow

     //№8 VecMul(SpecColor, №7)
     shufps xmm0, xmm0, 01000000b
     mulps xmm0, [SpecColor]

     //№9 * 255.0
     movd xmm1, [M255]
     shufps xmm1, xmm1, 01000000b
     mulps xmm0, xmm1
     cvtps2dq xmm0, xmm0

     //№14 - VecToColor(№13)
     movd xmm2, [GatherColors]
     pshufb xmm0, xmm2
     movd eax, xmm0
    end;
  • dmk © (30.08.18 13:59) [9]
    Короче это что-то типа интерсинков получится. Просто комбинаций сложения процедур огромное кол-во, поэтому и занялся таким вопросом.
  • Leonid Troyanovsky © (30.08.18 14:58) [10]

    > dmk ©   (30.08.18 13:59) [9]

    > сложения процедур огромное кол-во, поэтому и занялся таким
    > вопросом.

    Позволю себе привести мой пример из [7] для компиляции "на лету".
    Оно работает в D6/win32 в коде, который вписывается в память,
    распределенную простым New (т.е., там уже есть r|w|e).

    type
     TProc = procedure;
     TEProc = procedure(E: Exception);

    procedure Agregate(p1: TProc; p2: TEProc);
    begin
     try
       p1;
     except
       on E: Exception do
         p2(E);
     end;
    end;

    type
     TModProcs = packed record
       proc1: TProc;
       proc2: TEProc;
       code: PByte;
     end;
     PModProcs=^TModProcs;

    const
     vagr: procedure(p1: TProc; p2: TEProc)= Agregate;

    procedure Template(m: PModProcs); register;
    begin
     with m^ do
       vagr(proc1, proc2);
    end;

    type
     TPrecode = packed record
       b8: Byte;
       m: Pointer;
     end;

    procedure AddModProc(const p1: TProc; p2: TEProc; var p3: TProc);
    var
     procsize: Longint;
     p0, pt: PByte;
     pc: TPrecode;
     pmp: PModProcs;
    begin
     New(pmp);
     procsize := Dword(@AddModProc)-Dword(@template)+1;
     pc.b8 := $B8;
     pc.m := pmp;   // mov eax, pmp = B8 00 00 00 00
     with pmp^ do
       begin
         proc1 := p1;
         proc2 := p2;
         GetMem(code, SizeOf(pc)+ procsize);
         pt := code;
         Move(pc.b8, pt^, SizeOf(pc));
         inc(pt, SizeOf(pc));
         p0 := @template;
         Move(p0^, pt^, procsize);
         p3 := @code^;
       end;
    end;

    procedure a;
    begin
     ShowMessage('a: '+IntToStr(GetTickCount));
     abort;
    end;

    procedure b(E: Exception);
    begin
     Application.ShowException(E);
    end;

    procedure d;
    begin
     ShowMessage('d: '+IntToStr(GetTickCount));
     raise Exception.Create('MyException');
    end;

    procedure TForm1.Button2Click(Sender: TObject);
    var
     c, e: TProc;
    begin
     AddModProc(a, b, c);
     AddModProc(d, b, e);
     c;
     e;
    end;

    --
    Regards, LVT.
  • dmk © (31.08.18 02:01) [11]
    >Leonid Troyanovsky ©   (30.08.18 14:58) [10]
    Пытался под 64 бита адаптировать - не вышло :)
    Переделал на mov rax, XXXXXXXXX с префиксом $48B8.
    Размеры естественно все на UInt64 перевел.
    Не помогло.
  • KSergey © (31.08.18 09:00) [12]
    Массив указателей на функции?
    Набил ячейки массива адресами в нужном порядке - и вызываем подряд поочерёдно.
    Будут, правда, накладные расходы на call / ret, но вроде это не так и страшно
  • dmk © (31.08.18 11:37) [13]
    А понял. Да не, я опкоды складываю или блоки опкодов.
    Типа компилятора нормального.
  • Leonid Troyanovsky © (31.08.18 19:45) [14]

    > dmk ©   (31.08.18 02:01) [11]

    > Пытался под 64 бита адаптировать - не вышло :)

    Ну, дык, ошибка у тебя, в 17 строке.

    Если б код был, кто-нибудь мог бы и подсказать.
    Не я, конечно, бо нет у мну 64 бит.

    --
    Regards, LVT.
  • dmk © (31.08.18 23:47) [15]
    >Ну, дык, ошибка у тебя, в 17 строке.
    Вот модификация. Под 64 бита не пашет.

    unit CompileProcs;

    interface

    uses
     Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
     Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

    type
     TForm1 = class(TForm)
       Button1: TButton;
       procedure Button1Click(Sender: TObject);
     private
       { Private declarations }
     public
       { Public declarations }
     end;

    var
     Form1: TForm1;

    implementation

    {$R *.dfm}

    procedure GetMem64(var Buf: Pointer; Size: Integer);
    begin
     buf := VirtualAlloc(nil, size, (MEM_RESERVE or MEM_COMMIT), PAGE_EXECUTE_READWRITE);
    end;

    procedure FreeMem64(var Buf: Pointer; Size: Integer);
    begin
     if VirtualFree(buf, 0, MEM_RELEASE) then buf := nil;
    end;

    type
     TProc = procedure;
     TEProc = procedure(E: Exception);
     QWord = UInt64;

    procedure Agregate(p1: TProc; p2: TEProc);
    begin
     try
       p1;
     except
       on E: Exception do
         p2(E);
     end;
    end;

    type
     TModProcs = packed record
       proc1: TProc;
       proc2: TEProc;
       code: PByte;
     end;
     PModProcs=^TModProcs;

    const
     vagr: procedure(p1: TProc; p2: TEProc)= Agregate;

    procedure Template(m: PModProcs); register;
    begin
     with m^ do vagr(proc1, proc2);
    end;

    {$IFDEF WIN32}
    type
     TPrecode = packed record
       b8: Byte;
       m: Pointer;
     end;
    {$ENDIF WIN32}
    {$IFDEF WIN64}
    type
     TPrecode = packed record
       w8: Word;
       m: Pointer;
     end;
    {$ENDIF WIN64}

    procedure AddModProc(const p1: TProc; p2: TEProc; var p3: TProc);
    var
     p0, pt: PByte;
     {$IFDEF WIN32}
     procsize: Longint;
     pc: TPrecode;
     {$ENDIF WIN32}
     {$IFDEF WIN64}
     procsize: QWord;
     pc: TPrecode;
     {$ENDIF WIN64}
     pmp: PModProcs;

    begin
     New(pmp);
     {$IFDEF WIN32}
     procsize := DWord(@AddModProc) - DWord(@template) + 1;
     pc.b8 := $B8; //$B8
     pc.m := pmp;  //mov eax, pmp = B8 00 00 00 00
     {$ENDIF WIN32}
     {$IFDEF WIN64}
     procsize := QWord(@AddModProc) - QWord(@template) + 1;
     pc.w8 := $48B8; //$48B8
     pc.m := pmp;   // mov rax, pmp = 48 B8 00 00 00 00 00 00
     {$ENDIF WIN64}

     with pmp^ do
     begin
       proc1 := p1;
       proc2 := p2;
       {$IFDEF WIN32}
       GetMem64(Pointer(code), SizeOf(pc) + procsize);
       pt := code;
       Move(pc.b8, pt^, SizeOf(pc));
       {$ENDIF WIN32}
       {$IFDEF WIN64}
       GetMem64(Pointer(code), SizeOf(pc) + procsize);
       pt := code;
       Move(pc.w8, pt^, SizeOf(pc));
       {$ENDIF WIN64}
       inc(pt, SizeOf(pc));
       p0 := @template;
       Move(p0^, pt^, procsize);
       p3 := @code^;
     end;
    end;

    procedure a;
    begin
     ShowMessage('a: '+IntToStr(GetTickCount));
     abort;
    end;

    procedure b(E: Exception);
    begin
     Application.ShowException(E);
    end;

    procedure d;
    begin
     ShowMessage('d: ' + IntToStr(GetTickCount));
     raise Exception.Create('MyException');
    end;

    procedure TForm1.Button1Click(Sender: TObject);
    var
     c, e: TProc;

    begin
     AddModProc(a, b, c);
     AddModProc(d, b, e);
     c;
     e;
    end;

    end.


    >Не я, конечно, бо нет у мну 64 бит.
    64 бита качается с сайта Embarcadero. Называется Delphi 10.2 Community edition.
    Абсолютно бесплатна на год. Уровень prof.
  • dmk © (31.08.18 23:49) [16]
  • имя (04.09.18 13:14) [17]
    Удалено модератором
  • SergeyPopov (13.09.18 02:05) [18]
    Удалено модератором
 
Конференция "Начинающим" » Вызов своей скомпилированной процедуры
Есть новые Нет новых   [134427   +35][b:0][p:0.001]