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.