Es que no se pone un puntero a funcion ahi sino un puntero a una estructura que apunta a la estructura que estaba ahi anteriormente en su primer campo y tiene otro campo mas que es el puntero al manejador. Y asi es como se construye la cadena de manejadores.
Mas informacion en el archivo:
https://web.archive.org/web/20041011152640fw_/http://www.spiff.tripnet.se/~iczelion/Exceptionhandling.htmlY si depuramos con el WinDbg el siguiente ejemplo:
.386
.model flat, stdcall
includelib kernel32.lib
ExitProcess PROTO stdcall :DWORD
.code
main:
int 3
assume fs:nothing
MOV ESI, OFFSET handler
PUSH ESI
PUSH DWORD PTR FS:[0]
MOV DWORD PTR FS:[0], ESP
xor eax, eax
mov eax, dword ptr [eax]
ret
handler:
invoke ExitProcess, 1
ret
end main
Podemos ver que al principio:
dd fs:0 l1
0053:00000000
006ff930dd 006ff930 l2
006ff930 006ff948 77a788c0
u 77a788c0 l1
ntdll!_except_handler4:
77a788c0 8bff mov edi,edi
dd 006ff948 l2
006ff948 ffffffff 77a853d2
u 77a853d2 l1
ntdll!FinalExceptionHandlerPad50:
77a853d2 90 nop
Y no seguimos que ffffffff debe ser el señalador de fin de cadena.
Ahora ejecutamos nuestro programa hasta MOV DWORD PTR FS:[0], ESP
dd fs:0 l1
0053:00000000 006ff8d0
dd 006ff8d0 l2
006ff8d0
006ff930 008d101a ;en rojo la ultima estructura que existia hasta entonces
u 008d101a
seh+0x101a:
008d101a 6a01 push 1
008d101c e801000000 call seh+0x1022 (008d1022)
008d1021 c3 ret
u 008d1022
seh+0x1022:
008d1022 ff2500208d00 jmp dword ptr [seh+0x2000 (008d2000)]
dps 008d2000 l1
008d2000 754a4f20 KERNEL32!ExitProcessImplementation