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.

Foi útil?

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top