Aby lepiej zrozumieć przepływ sterowania programu zinstrumentowanego za pomocą podejścia trampoliny, wróćmy do prawej strony rysunku 9-2, przedstawiającego zinstrumentowany plik binarny i załóżmy, że oryginalna funkcja f1 została właśnie wywołana. Zaraz po wywołaniu f1, trampolina przeskakuje do f1_copy (1), zinstrumentowanej wersji f1. Po trampolinie (2) mogą znajdować się pewne niepotrzebne bajty, ale nie są one wykonywane. Silnik SBI wstawia kilka instrukcji nop w każdym możliwym punkcie instrumentacji w f1_copy (3). W ten sposób, aby zinstrumentować instrukcję, silnik SBI może po prostu nadpisać instrukcje nop w tym punkcie instrumentacji za pomocą jmp lub wywołania fragmentu kodu instrumentacji. Należy pamiętać, że zarówno wstawianie instrukcji nop, jak i instrumentacja są wykonywane statycznie, a nie w czasie wykonywania. Na rysunku 9-2 wszystkie regiony nop są nieużywane, z wyjątkiem ostatniego, tuż przed instrukcją ret, co wyjaśnię za chwilę. Aby zachować poprawność skoków względnych pomimo przesunięcia kodu spowodowanego nowo wstawionymi instrukcjami, silnik SBI poprawia przesunięcia wszystkich instrukcji względnych jmp. Dodatkowo silnik zastępuje wszystkie 2-bajtowe instrukcje względne jmp, które mają 8-bitowe przesunięcie, odpowiadającą im 5-bajtową wersją z 32-bitowym przesunięciem (4). Jest to konieczne, ponieważ podczas przesuwania kodu w funkcji f1_copy przesunięcie między instrukcjami jmp a ich obiektami docelowymi może stać się zbyt duże, aby zakodować je w 8 bitach. Podobnie silnik SBI przepisuje wywołania bezpośrednie, takie jak wywołanie f2, tak aby wskazywały one na funkcję zinstrumentowaną, a nie na oryginalną (5). Biorąc pod uwagę to przepisanie wywołań bezpośrednich, można się zastanawiać, dlaczego trampoliny na początku każdej oryginalnej funkcji są w ogóle potrzebne. Jak wyjaśnię za chwilę, są one niezbędne do obsługi wywołań pośrednich. Załóżmy teraz, że poleciłeś silnikowi SBI instrumentację każdej instrukcji ret. W tym celu silnik SBI nadpisuje instrukcje nop zarezerwowane do tego celu poleceniem jmp lub wywołaniem kodu instrumentacji (6). W przykładzie z rysunku kod instrumentacji to funkcja o nazwie hook_ret, umieszczona w bibliotece współdzielonej i dostępna poprzez wywołanie umieszczone przez silnik SBI w punkcie instrumentacji. Funkcja hook_ret najpierw zapisuje stan (7), taki jak zawartość rejestrów, a następnie uruchamia dowolny określony kod instrumentacji. Na koniec przywraca zapisany stan (8) i wznawia normalne wykonywanie, powracając do instrukcji następującej po punkcie instrumentacji. Teraz, gdy wiesz już, jak podejście trampoliny przepisuje instrukcje bezpośredniego przepływu sterowania, przyjrzyjmy się, jak obsługuje ono pośredni przepływ sterowania.

