2013-08-25 18 views
5

Muszę wywołać funkcję w C, po prostu znając jej adres i brak informacji na jej prototypie (nie mogę przesłać go do wskaźnika funkcji C).Wywołanie adresu C jako funkcji bez prototypu

Informacje jakie mam na temat tej funkcji to adres.

Wiem również parametry, które chcę przekazać (dzięki pustej wskazówce) i wielkość tablicy argumentów (dostęp za pomocą pustego wskaźnika).

Pragnę również uszanować konwencję telefonowania C. W przypadku wersji x86, w zasadzie wiem, jak to zrobić (przydzielić przestrzeń na stosie, skopiuj parametry do tej przestrzeni i w końcu wywołaj funkcję).

Problem dotyczy konwencji x64 (na razie Linux), gdzie parametry przechodzą przez rejestry . Nie mam pojęcia o wielkości każdego parametru, aby odpowiednio wypełnić rejestry, znam tylko rozmiar tablicy parametrów.

Poza tym nie chcę polegać na gcc, więc nie mogę użyć __builtin_apply, która wydaje się być nietypowa, a także być całkiem ciemną.

Chcę napisać własny fragment kodu, aby obsługiwać wiele kompilatorów, a także dowiedzieć się ciekawych rzeczy.

Więc w zasadzie, funkcja Chcę napisać jako ten sam prototyp jako __builtin_apply która jest:

void *call_ptr(void (*fun)(), void *params, size_t size); 

Chcę również kod napisać w C (dzięki asm inline) lub czystego x64 asm .

Czy istnieje sposób, aby zrobić to właściwie i zgodnie z konwencją wywołującą ? Czy jest to niemożliwe w konwencji x64 bez znajomości dokładnie prototypu funkcji o nazwie?

+4

Zobacz [libffi] (http://sourceware.org/libffi/). – tangrs

+0

To może być świetna alternatywa, ale problemem z libffi jest to, że musi znać typ każdego parametru i typ zwracanej funkcji. Chcę uniknąć gromadzenia tych informacji, aby w miarę możliwości uniknąć straty czasu. Czy to możliwe z architekturą x64? – Zerkan

+1

@Zerkan nie, nie, potrzebujesz typów parametrów, nie ma magii, która umieściłaby parametry w odpowiednich rejestrach lub przestrzeni stosu podczas wywoływania funkcji bez znajomości argumentów. – nos

Odpowiedz

0

myślę, wszystkich swoich decyzji nie będą obsługiwane multi-kompilatora, ponieważ mechanizm mijających argumentów do funkcji (rejestry, ich kolejność, stos, pamięć) - jest to cecha zależność kompilator ...

+3

_ "to funkcja zależności kompilatora" _. Na szczęście tak nie jest. Przynajmniej nie, jeśli kompilator jest zgodny z [ABI] (http://en.wikipedia.org/wiki/Application_binary_interface) docelowego systemu operacyjnego. – Michael

+0

Tak, oczywiście, obsługuje on niektóre zewnętrzne interfejsy niskopoziomowe. Ale obsługa ABI jest także zależna od kompilatora =) Tylko jedna rzecz, którą każdy kompilator powinien dokładnie obsługiwać - Standard językowy –

2

Szczególnie dla konwencji wywoływania x64 w systemie Linux to w ogóle nie działa.

Powodem jest bardzo skomplikowana konwencja wywoływania.

Przykłady:

void funcA(float64 x); 
void funcB(int64 x); 

W tych dwóch przypadkach wartości „x” jest przekazywane do funkcji inaczej, ponieważ zmiennoprzecinkowych oraz całkowitą są przekazywane do funkcji w różnych rejestrach.

void funcC(float64 x,int64 y); 
void funcD(int64 y,float64 x); 

W tych dwóch przypadkach argumenty "x" i "y" są w różnej kolejności. Jednak są one przekazywane do funkcji w ten sam sposób (obie funkcje używają tego samego rejestru dla "x" i tego samego rejestru dla "y").

Wniosek: Aby utworzyć funkcję, która robi to, co chcesz, musisz przekazać ciąg znaków zawierający typy argumentów każdego argumentu do funkcji asemblera. Liczba/rozmiar argumentów zdecydowanie nie wystarcza.Jednak na pewno byłoby to możliwe - o ile musi działać tylko na Linuksie.

Powiązane problemy