2011-03-27 13 views
7

Estoy usando Delphi 2010. ¿Es posible decirle a Delphi que no genere un prólogo para una función? Estoy escribiendo algunas funciones de montaje puros como esto:Eliminar el prólogo de una función escrita en ensamblaje puro

procedure SomeAssembly; stdcall; 
begin 
    asm 
     ... 
    end; 
end; 

y me gustaría decirle a Delphi no generar un prólogo y un epílogo para esta función, como característica de C++ 's __declspec(naked).

Y así nadie pierde su tiempo, no necesito ayuda para que estas funciones funcionen con el prólogo; Ya puedo hacer eso. Es solo un gran inconveniente y hará que el mantenimiento sea una gran molestia. Tendré que inspeccionar manualmente los prólogos generados por el compilador para ver su longitud, y si eso cambia, mi programa fallará.

También sé que puedo escribir la función como una serie de bytes en una matriz de bytes, pero eso sería incluso peor que tener que buscar la longitud del prólogo de Delphi.

Respuesta

19

Delphi no genera prólogos o epílogos para las funciones que tienen sin argumentos y declaró con la convención de llamada registro. Si quiere funciones sin prólogos, declarelas como funciones de argumento cero, registro-convocatoria-convención. Además, omita el bloque begin - end y vaya directamente al ensamblaje.

procedure SomeAssembly; // register; (implied) 
asm 
    // ... 
end; 

Dado que efectivamente está mintiendo sobre la naturaleza de las funciones, llamarlas puede ser complicado. Si ha implementado una función como si hubiera recibido parámetros y hubiera usado una convención de llamadas diferente, entonces deberá asegurarse de que el compilador lo sepa en el sitio de llamadas. Para hacerlo, declare un puntero de función que refleje el tipo "real" de su función en lugar del tipo declarado. Por ejemplo, si su función es realmente una función stdcall de dos argumentos, declarar algo como esto:

type 
    TSomeAssemblyFunc = function (Arg1: Integer; Arg2: PAnsiChar): Boolean; stdcall; 
var 
    SomeAssemblyProc: TSomeAssemblyProc; 

Ahora, asignar dicha variable para que apunte a su función:

SomeAssemblyProc := TSomeAssemblyProc(@SomeAssembly); 
if SomeAssembly(2, 'foo') then ... 

Además de saltar el prólogo y el epílogo, el compilador generará la instrucción incorrecta RET para esta función (debido a las diferentes convenciones de llamadas), por lo que deberá asegurarse de decir ret 8 en su código en lugar de dejar que aparezca la instrucción ret predeterminada del compilador.


Encontrar la longitud del prólogo de Delphi es trivial, si usted tiene un depurador de trabajo:

  1. Establecer un punto de interrupción en el inicio de la función.
  2. Llamar a la función.
  3. Cuando el depurador se detiene en el punto de interrupción, cambie a la vista de CPU.
  4. Mire las instrucciones que componen el prólogo.
  5. Cuente los bytes que se muestran junto a esas instrucciones.
+0

¿Por qué no todos en SO pueden responder así? Extremadamente útil, gracias Rob. –

+0

@K. Charles: ¿diferente nivel de experiencia? Sin embargo, era una suposición descabellada, sin ofender a nadie. –

+0

¿No hay un nivel extra de indirección cuando tienes un puntero de función? Personalmente, hubiera pensado que tasm sería más adecuado. –

0

Does not

procedure SomeAssembly; stdcall; 
asm 
    ... 
end; 

hacer el truco?

+0

Si recuerdo correctamente, 'stdcall' hace que el compilador incluya un prólogo y un epílogo para guardar y restaurar el puntero de marco, incluso si no hay parámetros. –

1

De acuerdo con la this embarcadero docwiki puede omitir la rodea begin y end y el compilador omitirá algunas de sus cosas. Pero si realmente quieres ensamblador puro, por qué no poner tu función en un archivo de ensamblador separado, ensamblarlo con tasm (el exe se llama tasm32) y vincularlo. Luego usará la directiva assembler en el código delphi.

+0

@downvoters, por favor explique. TASM es parte de Delphi y es la forma natural de trabajar con ensamblador 100% puro. ¿Esta votación estratégica fue? –

Cuestiones relacionadas