Małe zadanie #1¶
Napisać prosty generator trampolin.
Trampoliny¶
Trampolinami nazywamy małe kawałki kodu, których jedynym zadaniem jest przakazać sterowanie w inne miejsce, być może modyfikując w jakiś sposób kontekst procesu, bądź przekazując dodatkowe parametry.
Interesującym przykładem użycia trampolin są biblioteki FFI (foreign function interface - umożliwiające wywoływanie funkcji między różnymi językami) dla języków skryptowych. Załóżmy, że API napisane w C, którego chcemy użyć z Pythona/Lua/itp wymaga podania wskaźnika na funkcję, którą potem wykona w określonej sytuacji (tzw. callback). Ponieważ nasz program jest napisany w interpretowanym języku dynamicznym, biblioteka FFI obsługująca wywołania zwrotne musi obsługiwać dynamiczne generowanie funkcji wywoływalnych z C. W tym celu, biblioteka generuje trampolinę, która zapamięta odpowiednie rejestry zawierające parametry, zapisze identyfikator trampoliny (aby wybrać odpowiednią funkcję wysokiego poziomu do wywołania), po czym wywoła funkcję biblioteki FFI uruchamiającą interpreter języka dynamicznego z odpowiednimi parametrami. Dzięki takiemu rozwiązaniu, możemy w czasie wykonania wygenerować dowolnie dużo funkcji do wywołań zwrotnych i przekazywać wskaźniki na nie do funkcji w C.
Zadanie¶
Napisać implementację funkcji make_formatter
:
typedef void (*formatter) (int);
formatter make_formatter (const char *format);
Funkcja make_formatter
powinna zwracać wskaźnik na funkcję formatującą
w zadanym formacie - format
ma składnię jak do printf
i powinien
zawierać dokładnie 1 specyfikację formatu pasującą do typu int
.
Funkcja formatująca powinna wypisywać odpowiednio sformatowany parametr
na standardowe wyjście. Na przykład:
formatter x08_format = make_formatter ("%08x\n");
formatter xalt_format = make_formatter ("%#x\n");
formatter d_format = make_formatter ("%d\n");
formatter verbose_format = make_formatter ("Liczba: %9d!\n");
x08_format (0x1234);
xalt_format (0x5678);
d_format (0x9abc);
verbose_format (0xdef0);
powinno być równoważne:
printf ("%08x\n", 0x1234);
printf ("%#x\n", 0x5678);
printf ("%d\n", 0x9abc);
printf ("Liczba: %9d!\n", 0xdef0);
Podpowiedzi¶
Skompilować następujący kod (z opcją -no-pie -mcmodel=large -fno-pie
) i zdisasemblować wynikowy plik .o
:
void formatter (int param) {
printf ("%08x\n", param);
}
Ze zrzuconego kodu maszynowego zrobić szablon, który będzie wypełniany
wskaźnikiem na odpowiedni format przez make_formatter
. Należy
pamiętać o zapewnieniu praw do wykonania obszaru pamięci, w którym będą
znajdować sie gotowe trampoliny.