Перевести код с помощью указателя, в сборку в Pascal - Delphi
Вопрос
У меня есть этот код ниже, и я хочу перевести его на 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;
- Обратите внимание, однако, что вам придется делать ручное распределение и освобождение.