Traducir un código de uso de un apuntador, a la Asamblea en Pascal - Delphi
Pregunta
Tengo este código de abajo, y quiero traducirlo a ASM, para su uso en Delphi también.
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 normaly, pero cuando trato de su versión Asamblea:
function Function(parameter: Integer): Integer; cdecl;
asm
mov eax, FunctionAddressList
jmp dword ptr [eax + 5 * 4]
end;
Se supone que es el trabajo, ya que, en C ++ funciona en ambos sentidos:
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);
}
Sin embargo, no funciona en Delphi.
En la versión Asamblea, se multiplica la matriz a 4, porque es el tamaño de desplazamiento entre cada elemento de la matriz, por lo que ambas versiones son equivalentes.
Por lo tanto, me gustaría saber por qué no funciona con Delphi. En Delphi, el tamaño de desplazamiento entre los valores de número entero en una matriz es diferente de C ++?
He intentado ya muchas compensaciones, como 1, 2, 4, 6, 8, etc, y muchos tipos de matriz (matriz de puntero, sólo Pointer; matriz de enteros, etc.), y he probado muchos convenciones de llamada, y cdecl fue el único que trabajó con la versión no asm, pero con ASM, todas las pruebas no funcionaba.
Gracias.
Solución
En primer aplicación de prueba para reproducir el error:
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;
La barra de direcciones se define correctamente, pero el problema es que Delphi compilador genera prólogo y epílogo de Foo, por lo que el código real es 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
Como resultado se corrompe la pila, el parámetro es incorrecta y la dirección de retorno Bar está mal. Si todavía quiere hacer el truco, el uso
function Foo(parameter: Integer): Integer; cdecl;
asm
pop ebp
mov eax, FunctionAddressList
jmp dword ptr [eax + 5 * 4]
end;
Otros consejos
Array of Integer
no es lo que piensa que es. Es una matriz dinámica gestionada automáticamente.
Se debe tratar de la misma utilizando FunctionAddressList: ^Pointer;
- Nota sin embargo que va a tener que hacer la asignación manual y cancelación de asignación