Mam dziwny kod modyfikujący, ale w jego głównym katalogu jest całkiem prosty problem: chcę móc wykonać jmp
(lub call
), a następnie od ten punkt arbitralny rzuca wyjątek i przechwytuje go blok próbny/przechwytujący, który zawierał jmp
/call
.Rzucanie wyjątku C++ po skoku inline-asm
Ale kiedy to zrobię (w gcc 4.4.1 x86_64) wyjątek spowoduje, że terminate()
będzie tak, jakby wyjątek został wyrzucony spoza try/catch. Naprawdę nie widzę, jak to jest inne niż wyrzucenie wyjątku z wnętrza jakiejś odległej biblioteki, ale to oczywiście dlatego, że po prostu nie działa.
Jak mogę wykonać jmp
lub call
, ale nadal mogę podać wyjątek z powrotem do oryginalnego try/catch? Dlaczego ta próba/catch nadal nie obsługuje tych wyjątków, tak jak gdyby funkcja była wywoływana normalnie?
Kod:
#include <iostream>
#include <stdexcept>
using namespace std;
void thrower()
{
cout << "Inside thrower" << endl;
throw runtime_error("some exception");
}
int main()
{
cout << "Top of main" << endl;
try {
asm volatile (
"jmp *%0" // same thing happens with a call instead of a jmp
:
: "r"((long)thrower)
:
);
} catch (exception &e) {
cout << "Caught : " << e.what() << endl;
}
cout << "Bottom of main" << endl << endl;
}
oczekiwany wynik:
Top of main
Inside thrower
Caught : some exception
Bottom of main
Rzeczywista moc:
Top of main
Inside thrower
terminate called after throwing an instance of 'std::runtime_error'
what(): some exception
Aborted
Pierwotnie zadałem podobne pytanie w kontekście programów obsługi sygnałów w systemie Linux. To naprawdę tylko przesłaniało problem, więc usunąłem ten i poprosiłem o znacznie bardziej uproszczoną wersję. Cała obsługa sygnału po prostu maskowała mój prawdziwy problem. – SoapBox
Istnieją dwa różne sposoby implementacji wyjątków. Jedną z nich jest udekorowanie kodu i stron wywoływania w celu przepchnięcia kontekstu dookoła, drugim jest zindeksowanie wywołań i punktów zwracanych, aby program obsługi wyjątków mógł sprawdzić, dokąd się udać. Tak czy inaczej, inline asm czegoś nie ma. – spraff