2015-07-23 14 views
5

Chcę podnieść wyjątek w bloku ASM X64.Jak zgłosić wyjątek w bloku ASM?

Załóżmy Mam funkcję tak:

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

wiem, że mogę po prostu czytać wskaźnika, a także uzyskać AV, jednak Chcę podnieść błąd bardziej opisową.

mogłem zrobić dodatkową funkcję i zadzwonić że jeden:

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); 

jednak błąd będzie występować wtedy poza funkcją, w której było spowodowane. Jak uzyskać wyjątek (wydaje się) pochodzić z wewnątrz funkcji Example.

Należy pamiętać, że to jest X64, więc wszystkie odpowiedzi SEH które odnoszą się do X86 nie są dobre, bo X64 wykorzystuje poj.

+2

Myślę, że nadal jest SEH na x64. Po prostu napisz trochę Pascala i zobacz, co kompilator wyemituje, aby to przetworzyć. –

+1

Ponieważ nikt nie zapyta, jeśli kod jest na tyle wysoki, że chcesz, aby zgłaszał wyjątki, dlaczego najpierw piszesz je w zespole? – alcalde

+0

Ponieważ potrzebuje instrukcji SSE, a ja nie mam wewnętrznej samoistności SSE. – Johan

Odpowiedz

4

Pełna składnia podbiciem jest:

raise Exception at address 

Wszystko, co musisz zrobić, to przekazać aktualny adres IP jako parametr i proc błędu może przekazać, że się do wyjątku.

Możesz uzyskać RIP używając lea rax, [rip].

Zatem kod staje:

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; 

Oczywiście w tym przypadku jest to łatwiejsze w użyciu

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

Uwaga
W tym przypadku, jeśli trzymać JMP błąd może wydawać się pochodzą z procedury wywołującej, w tym przypadku jest to poprawne. Jeśli chcesz, aby wyjątek wskazywał winnego palca na twój kod asm, użyj połączenia.

+3

W Delphi XE2 +, możesz (i powinieneś) używać wewnętrznego kompilatora 'System.ReturnAddress', który działa zarówno w wersji 32-bitowej, jak i 64-bitowej:' procedure RaiseError (code: integer; const Msg: string); rozpocznij ... podniesienie EEmptyArrayError.Create (Msg) na ReturnAddress; ... end; ' –

+0

Myślę, że musisz użyć' call RaiseError' zamiast 'jmp RaiseError' kiedy używasz' RaiseError' wersji z 'ReturnAddress'. – JRL

+0

@JRL Brak jmp jest poprawny. W tym przypadku błąd nie znajduje się w moim kodzie asm, błąd jest w procedurze, która wywołuje ten kod z parametrem zero. wyjątek powinien to pokazywać. w przeciwnym razie użytkownik będzie debugował niewłaściwą procedurę. – Johan