Перевести код с помощью указателя, в сборку в Pascal - Delphi

StackOverflow https://stackoverflow.com/questions/2173570

Вопрос

У меня есть этот код ниже, и я хочу перевести его на 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 размер смещения между целочисленными значениями в массиве отличается от C ++?

Я уже пробовал много смещений, как 1, 2, 4, 6, 8 и т. Д. И множество типов массива (массив указателя; единственный указатель; массив целого числа и т. Д.), И я пробовал много конвенций, И CDECL был единственным, что работал с версией Non-ASM, но с ASM, все тесты не работали.

Спасибо.

Это было полезно?

Решение

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

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;

Адрес бар определяется правильно, но проблема в том, что компилятор 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

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

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

Другие советы

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top