Traduza um código usando ponteiro, para montagem em Pascal - Delphi
Pergunta
Eu tenho esse código abaixo e quero traduzi -lo para o ASM, para usar em Delphi também.
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;
Funciona normalmente, mas quando eu tento sua versão de montagem:
function Function(parameter: Integer): Integer; cdecl;
asm
mov eax, FunctionAddressList
jmp dword ptr [eax + 5 * 4]
end;
Deve funcionar, porque, em C ++, funciona nos dois lados:
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);
}
Mas não funciona em Delphi.
Na versão de montagem, ele multiplica a matriz para 4, porque é o tamanho do deslocamento entre cada elemento da matriz; portanto, ambas as versões são equivalentes.
Então, quero saber por que não funciona com Delphi. Em Delphi, o tamanho do deslocamento entre os valores inteiros em uma matriz é diferente de C ++?
Eu já tentei muitas compensações, como 1, 2, 4, 6, 8, etc. e muitos tipos de matriz (matriz de ponteiro; apenas ponteiro; matriz de inteiro, etc), e tentei muitas convenções de chamadas, E o CDECL foi o único que funcionou com a versão não-ASS, mas com o ASM, todos os testes não funcionaram.
Obrigado.
Solução
Primeiro aplicativo de teste para reproduzir o erro:
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;
O endereço da barra é definido corretamente, mas o problema é que o compilador Delphi gera prólogo e epilog para foo, então o código FOO real é
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
Como resultado, a pilha está corrompida, o parâmetro está errado e o endereço de retorno da barra está errado. Se você ainda quiser fazer o truque, use
function Foo(parameter: Integer): Integer; cdecl;
asm
pop ebp
mov eax, FunctionAddressList
jmp dword ptr [eax + 5 * 4]
end;
Outras dicas
Array of Integer
não é o que você acha que é. É uma matriz dinâmica gerenciada automaticamente.
Você deve tentar o mesmo usando FunctionAddressList: ^Pointer;
- Observe, no entanto, que você terá que fazer alocação e desalocação manual.