Перевести код, используя указатель, на ассемблер в Pascal - Delphi - PullRequest
3 голосов
/ 01 февраля 2010

У меня есть этот код ниже, и я хочу перевести его на ASM, чтобы использовать и в Delphi.

var
    FunctionAddressList: Array of Integer;

type TFunction = function(parameter: Integer): Integer; cdecl;

function Function(parameter: Integer): Integer;
var
    ExternFunction: TFunction;
begin
    ExternFunction := TFunction(FunctionAddressList[5]);
    Result := ExternFunction(parameter);
end;

Он работает нормально, но когда я пробую его версию сборки:

function Function(parameter: Integer): Integer; cdecl;
asm
  mov eax, FunctionAddressList
  jmp dword ptr [eax + 5 * 4]
end;

Предполагается, что он работает, потому что в C ++ он работает в обоих направлениях:

void *FunctionAddressList;

_declspec(naked) int Function(int parameter)
{
    _asm mov eax, FunctionAddressList;
    _asm jmp dword ptr [eax + 5 * 4];
}

typedef int (*TFunction)(int parameter);
int Function(int parameter)
{
    TFunction ExternFunction = ((TFunction *)FunctionAddressList)[5];
    return ExternFunction(parameter);
}

Но в Delphi это не работает.

В версии сборки он умножает массив на 4, потому что это размер смещения между каждым элементом массива, поэтому обе версии эквивалентны.

Итак, я хочу знать, почему это не работает с Delphi. В Delphi размер смещения между значениями Integer в массиве отличается от C ++?

Я уже пробовал много смещений, как 1, 2, 4, 6, 8 и т. Д. И много типов Array (Array of Pointer; только Pointer; Array of Integer и т. Д.), И я пробовал много соглашения о вызовах, и cdecl был единственным, кто работал с версией без asm, но с ASM все тесты не работали.

Спасибо.

Ответы [ 2 ]

3 голосов
/ 01 февраля 2010

Первое тестовое приложение для воспроизведения ошибки:

var
  FunctionAddressList: Array of Integer;

function Bar(parameter: Integer): Integer; cdecl;
begin
  ShowMessage('Bar '+IntToStr(parameter));
end;

function Foo(parameter: Integer): Integer; cdecl;
asm
  mov eax, FunctionAddressList
  jmp dword ptr [eax + 5 * 4]
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  SetLength(FunctionAddressList, 6);
  FunctionAddressList[5]:= Integer(@Bar);
  Foo(25);
end;

Адрес Bar определен правильно, но проблема в том, что компилятор Delphi генерирует пролог и эпилог для Foo, поэтому реальный код Foo равен

0046CD30 55               push ebp
0046CD31 8BEC             mov ebp,esp
Unit1.pas.46:             mov eax, FunctionAddressList
Unit1.pas.47:             jmp dword ptr [eax + 5 * 4]
0046CD3B 5D               pop ebp
0046CD3C C3               ret

В результате стек поврежден, неверный параметр и неправильный адрес возврата Bar. Если вы все еще хотите сделать трюк, используйте

function Foo(parameter: Integer): Integer; cdecl;
asm
  pop ebp
  mov eax, FunctionAddressList
  jmp dword ptr [eax + 5 * 4]
end;
1 голос
/ 01 февраля 2010

Array of Integer не то, что вы думаете.Это автоматически управляемый динамический массив.

Вы должны попробовать то же самое, используя FunctionAddressList: ^Pointer; - заметьте, однако, что вам придется делать ручное распределение и освобождение.

...