2015-07-23 12 views
5

Voglio sollevare un'eccezione in un blocco asm X64.Come si genera un'eccezione in un blocco asm?

lascia supporre Ho una funzione in questo modo:

function Example(Values: array of integer): integer; 
asm 
    or rcx,rcx 
    jz @error 
    .... 

So che posso appena letto il puntatore e ottenere un AV, però vorrei sollevare un errore più descrittivo.

ho potuto fare una funzione aggiuntiva e chiamare quello:

asm 
    or rcx,rcx 
    jz @error 
    .... 
@error: 
    mov ecx, 1 
    mov rdx, ErrorString 
    jmp RaiseError 
    .... 

function RaiseError(code: integer; const Msg: string); 
begin 
    case code of 
    1: raise EEmptyArrayError.Create(Msg); 

Tuttavia l'errore sarà quindi avvenire al di fuori della funzione in cui è stato causato. Come faccio a ottenere l'eccezione (sembra) originata dalla funzione Example.

Si noti che questo è X64, quindi tutte le risposte SEH valide per X86 non vanno bene perché X64 utilizza VEH.

+2

Penso che sia ancora SEH in x64. E basta scrivere un po 'di Pascal e vedere cosa emette il compilatore per risolverlo. –

+1

Poiché nessun altro chiederà, se il codice è abbastanza alto da consentire di generare eccezioni, perché lo si scrive in assembly in primo luogo? – alcalde

+0

Perché ha bisogno di istruzioni SSE e non ho intrinseco SSE. – Johan

risposta

4

La sintassi completa di rilancio è:

raise Exception at address 

Tutto quello che dovete fare è far passare la corrente IP come parametro e il proc errore può passare che a l'eccezione.

È possibile ottenere il RIP utilizzando lea rax, [rip].

Così il codice diventa:

asm 
    or rcx,rcx 
    jz @error 
    .... 
@error: 
    mov ecx, 1 
    mov rdx, ErrorString 
    lea r8,[rip] 
    jmp RaiseError 
    .... 

function RaiseError(code: integer; const Msg: string; address: pointer); 
begin 
    case code of 
    1: raise EEmptyArrayError.Create(Msg) at address; 

Naturalmente, in questo caso è più facile da usare

function RaiseError(code: integer; const Msg: string); 
begin 
    case code of 
    1: raise EEmptyArrayError.Create(Msg) at ReturnAddress; 

Nota
In questo caso se si mantiene il JMP l'errore sembrerà provengono dalla routine di chiamata, in questo caso è effettivamente corretta. Se vuoi che l'eccezione indichi il colpevole al tuo codice asm, usa una chiamata.

+3

In Delphi XE2 +, puoi (e dovresti) usare il compilatore 'System.ReturnAddress' intrinseco, che funziona sia in 32bit sia in 64bit:' procedure RaiseError (code: integer; const Msg: string); begin ... raise EEmptyArrayError.Create (Msg) a ReturnAddress; ... end; ' –

+0

Penso che devi usare' call RaiseError' invece di 'jmp RaiseError' quando usi la versione' RaiseError' con 'ReturnAddress'. – JRL

+0

@ JRL No jmp è corretto. In questo caso l'errore non è nel mio codice asm l'errore è nella routine che chiama quel codice con un parametro nil. l'eccezione dovrebbe mostrarlo. altrimenti l'utente eseguirà il debug della routine sbagliata. – Johan