2011-08-09 12 views
12

estoy tratando de establecer SEH sin utilizar try except
(Esto es para mi propio conocimiento personal para tener una mejor idea de cómo funciona SEH)estructurado manejador de excepción y Delphi

El código siguiente no funciona

type 
    TSeh = packed record 
    OldSeh:DWORD; 
    NewSeh:DWORD; 
    end; 


procedure test; 
begin 
WriteLn('Hello from seh'); 
end; 


var 
    eu:TSeh; 
    old_seh:DWORD; 
begin 
    asm 
    mov eax,fs:[0] 
    mov old_seh,eax 
    end; 
    eu.OldSeh := old_seh; 
    eu.NewSeh := DWORD(@test); 
    asm 
     mov eax,offset eu 
     mov fs:[0],eax 
     ret //This will cause an exception because jumps on an invalid memory address 
    end; 
end. 

Pero esto hace

procedure test; 
begin 
WriteLn('Hello from seh'); 
end; 



begin 
    asm 
    push offset test 
    push fs:[0] 
    mov fs:[0],esp 
    ret //This will cause an exception because jumps on an invalid memory address 
    end; 
end. 

¿Qué estoy haciendo mal? ¿Cuál es la diferencia entre el primer código y el segundo?

+6

+1 por intentar algo raro. –

+1

+1 también para intentar algo raro en Delphi y con asm – EMBarbosa

Respuesta

6

Windows requiere que todos los marcos de pila estén dentro de la pila asignada por el sistema. También requiere que los marcos de pila estén en orden secuencial en la pila. Además, para el manejo de excepciones, requiere que todos los "registros de excepción" estén en la pila, y para que se encadenen en un orden secuencial a través de la memoria de la pila.

Me di cuenta de esto/leí esto en algún lugar hace años mientras escribía una biblioteca de microhilos (http://www.eternallines.com/microthreads).

+0

Gracias por su respuesta que arroja luz sobre lo que me molestaba. Muchísimas gracias – opc0de

4

No se puede usar el procedimiento test como función de devolución de llamada de excepción porque la función de devolución de llamada de excepción tiene un prototipo diferente. Lea Matt Pietrek article, IMO, la mejor fuente de información acerca de Win32 SEH.


actualización

Para las nuevas investigaciones que recomendaría los siguientes cambios en el código para hacer que el problema un poco más limpia:

function test: Integer; 
begin 
    WriteLn('Hello from seh'); 
    Result:= 0; 
end; 

(a causa de devolución de llamada excepción debe devolver número entero valor en EAX)

Y para el primer fragmento de código

begin 
    asm 
     mov eax,fs:[0] 
     mov old_seh,eax 
    end; 
    eu.OldSeh := old_seh; 
    eu.NewSeh := Cardinal(@test); 
    asm 
     lea eax, eu 
     mov fs:[0],eax 
     mov ds:[0],eax //This will cause an AV exception 
    end; 
end. 

Ahora aparece que la excepción se maneja correctamente como:

--------------------------- 
Debugger Fault Notification 
--------------------------- 
Project C:\Users\Serg\Documents\RAD Studio\Projects\Project13.exe faulted with 
message: 'access violation at 0x004050f5: write of address 0x00000000'. Process 
Stopped. Use Step or Run to continue. 
--------------------------- 

pero no por su manejador de excepciones. Probablemente el sistema operativo ignora los registros de registro de excepción que no están basados ​​en la pila (el sistema operativo puede hacerlo fácilmente porque conoce los valores mínimo y máximo de la pila)

+0

Sé que lo he leído, pero lo que me confunde es ¿por qué funciona el segundo fragmento de código? – opc0de

+0

la función de excepción está definida de manera estándar, por lo que funcionará con un procedimiento definido sin ningún parámetro, como la prueba –

+0

@ opc0de. Es interesante que el primer fragmento de código no maneje la excepción. Parece que al sistema operativo no le gusta el registro de registro de excepción que no está basado en la pila. – kludg

2

Para el primer código, TSeh se encuentra en la sección global del ejecutable, mientras que El segundo código lo almacena en la pila.

Esto es en mi humilde opinión, donde la diferencia es. La estructura _EXCEPTION_REGISTRATION_RECORD probablemente debería estar en la pila. No sé por qué, sinceramente (¿algún truco de registro SS de bajo nivel?).

Para elevar una excepción, usted debe tratar mejor algo así como una división por cero o un acceso a una dirección absoluta nula:

PInteger(nil)^ := 0; // will always raise an exception 

asm 
    xor eax,eax 
    mov [eax],eax // will always raise an exception 
end; 

sobre cómo interceptar excepciones en Delphi, echar un vistazo at this article. De hecho, Delphi agrega un poco de capa personalizada sobre SEH sobre Windows.

Y tenga en cuenta también que el exception handling changes in Win64 mode. Vale la pena leer cuando se avance para venir Delphi XE2.

+0

El ret causa una excepción porque no puedo verlo en un depurador;) intenté desencadenar la excepción de la forma en que dijiste que aún obtengo el mismo resultado ... Así que ese no es el problema, gracias por tu respuesta, – opc0de

+0

. prueba tu código en un sub-procedimiento? La instancia de TSeh estaría en la pila, al igual que para el segundo código. AFAIK la única diferencia es que _EXCEPTION_REGISTRATION_RECORD está en el bloque DATA del programa para el primer código, mientras que está en la pila para el segundo ... –

Cuestiones relacionadas