2012-06-26 9 views
5

Rozumiem, co robi emulator, zmieniając jeden język maszyny na inny, często "Just-in-time". Czy taki program może być zbudowany w ten sposób, że czyta w binarnym zapisanym dla jednej architektury i zapisuje nowy plik binarny dla innej architektury. Po zakończeniu procesu pozostawiłby użytkownika binarnie gotowego do natywnego wykonania na danej architekturze. Byłoby to szczególnie przydatne dla tych, którzy mają drogie zastrzeżone aplikacje dla starszej architektury.Dlaczego emulacja musi być wykonywana w czasie rzeczywistym?

Czy można złożyć taki wniosek? Rekompilacja binarna nie jest nową koncepcją, ale nie znalazłem jeszcze żadnych użytecznych jej implementacji.

Przy pomocy innych osób byłbym zachwycony, gdyby zaczął programować kodowanie na otwartym oprogramowaniu, jeśli istnieje możliwość takiego zaprogramowania.

+1

Zrobiono to kilka razy. Na przykład DEC FX! 32 zrekompilował binaria x86, aby działać na DEC Alpha, często szybciej niż jakikolwiek x86 tego czasu. Nie wystarczyło to jednak do nadrobienia zaległości w zarządzaniu DEC, a Compaq/HP nie przejmował się tym zbytnio. –

+0

Dlaczego emulatory istnieją, jeśli tak jest? Czy to NAPRAWDĘ * to * znacznie trudniejsze niż pisanie emulatora? – user1483857

Odpowiedz

0

Trzeba zacząć od upewnienia się, że wszystkie biblioteki referencyjne są ponownie kompilowane przy użyciu tego również.

Jest to możliwe, ale ogromne przedsięwzięcie.

Weź również pod uwagę, że mogą pojawić się problemy z licencjonowaniem; tworzysz prace pochodne w oparciu o oryginalne oprogramowanie. Większość licencji, które pozwolą ci to zrobić, pozwoli ci również uzyskać źródło, więc będziesz mógł po prostu ponownie skompilować lub przesłać źródło, co jest o wiele łatwiejsze.

+0

Czyli nie byłoby to dokładnie zaliczone do inżynierii wstecznej, prawda? Chciałbym zrobić taką bestię, żeby był precedens w sądach. Przydatną aplikacją byłyby binarne pliki PPC o zamkniętym kodzie źródłowym w systemie OS X Mountain Lion, gdzie wiele wymaganych bibliotek znajduje się w systemie operacyjnym lub można je przenieść z systemu Snow Leopard lub Lion. Innym rozwiązaniem byłaby emulacja konsolowa, w której większość lib jest w grze. – user1483857

+1

Niezupełnie, twój re-kompilator będzie: "read-> translate-> write new version". Brzmi to bardziej jak pochodna-praca niż inżynieria odwrotna. Inżynieria odwrotna to ** zrozumienie **, co robi i pisanie nowego kodu, który robi to samo. – WhyNotHugo

+0

Przydatną aplikacją byłyby binarne pliki PPC o zamkniętym kodzie źródłowym w systemie OS X Mountain Lion, gdzie wiele wymaganych bibliotek znajduje się w systemie operacyjnym lub można je przenieść z systemu Snow Leopard lub Lion. Innym rozwiązaniem byłaby emulacja konsolowa, w której większość lib jest w grze. Czy pojawią się problemy prawne? – user1483857

3

Uważam, że szukasz rekompilacji statycznej vs dynamicznej. Dynamiczna rekompilacja to to, co opisujesz jako emulację "czasu rzeczywistego" lub rekompilację. Kod jest rekompilowany w bloki, co pozwala emulatorowi dokładnie odzwierciedlić środowisko wykonawcze oryginalnego kodu.

Ponowna kompilacja statyczna jest tym, o co pytasz, jeśli jest to możliwe. Jest to możliwe w wielu różnych sytuacjach, jak niektórzy zwracają uwagę, jednak kod, który oczekuje bardzo konkretnych ograniczeń czasu wykonania, może nie działać poprawnie po statycznej rekompilacji. Właśnie dlatego Corn, N64 Emulator, który używał statycznej rekompilacji, może uruchomić tylko kilka wysoce zoptymalizowanych gier, podczas gdy inne emulatory N64, które wykorzystują dynamiczną rekompilację, uruchamiają znacznie szerszą gamę gier.

Rekompilacja statyczna jest rzeczywiście możliwa dla jeszcze bardziej złożonego i tradycyjnego kodu (np. X86 dla PowerPC), jednak takie przedsięwzięcie okazałoby się niezwykle żmudne, ponieważ rekompilator musiałby użyć wielu sztuczek, aby uzyskać wygenerowany kod statyczny do uruchomienia niezawodnie na maszynie docelowej. Dynamiczne rekompilatory mogą to robić w locie w czasie wykonywania przy ułamku wysiłku programistycznego i przy znikomych kosztach wydajności.

+0

Sądzę, że istnieją różnice między implementacją zmiennoprzecinkowej w różnych architekturach, ale nie jestem pewien. –

4

Rekompilacja statyczna to obiecujący sposób tłumaczenia plików binarnych z obcej architektury na inną docelową architekturę. Byłby szybszy niż Just-In-Time (JIT), ponieważ nie musi kompilować kodu tuż przed uruchomieniem, a ponieważ dodatkowy czas kompilacji może zająć użyteczne jest zoptymalizowanie kodu generującego.

Jednak kompilacja JIT wykorzystuje dynamiczną analizę programu, podczas gdy rekompilacja statyczna opiera się na statycznej analizie programu (stąd nazwa).

W analizie statycznej nie ma informacji o czasie wykonywania.

Głównym problemem jest pośrednie skoki. Termin ten obejmuje kod, który może być generowany z pewnych instrukcji switch, z użycia wskaźników funkcji lub z polimorfizmu środowiska wykonawczego (think virtual table). To wszystko sprowadza się do instrukcji w postaci:

JMP reg_A 

Powiedzmy znasz adres początkowy programu, i postanowił zacząć skompilować instrukcji od tego momentu. Gdy natrafisz na bezpośredni skok, przejdziesz do jego adresu docelowego i będziesz kontynuował jego rekompilację. Kiedy jednak dojdziesz do pośredniego skoku, utkniesz. W niniejszej instrukcji montażu treść reg_A nie jest znana statycznie. Dlatego nie znamy adresu następnej instrukcji. Zauważ, że w rekompilacji dynamicznej nie mamy tego problemu, ponieważ emulujemy stan wirtualny rejestrów i znamy aktualną zawartość reg_A. Poza tym, w rekompilacji statycznej, jesteś zainteresowany znalezieniem w tym miejscu możliwych wartości dla , ponieważ chcesz skompilować wszystkie możliwe ścieżki. W analizie dynamicznej potrzebna jest tylko bieżąca wartość do wygenerowania ścieżki, którą aktualnie wykonujesz, jeśli zmienimy jej wartość na reg_A, nadal będziesz mógł wygenerować inne ścieżki. W niektórych przypadkach analiza statyczna może znaleźć listę kandydatów (jeśli jest to switch, gdzieś musi być tabela możliwego przesunięcia), ale w ogólnym przypadku po prostu nie wiemy.

Dobrze, mówisz, Ponownie skompilujmy wszystkie instrukcje w pliku binarnym!

Problem polega na tym, że w większości plików binarnych znajdują się zarówno kod, jak i dane. W zależności od architektury, możesz nie być w stanie stwierdzić, która jest która.

Co gorsza, w niektórych architekturach nie ma ograniczeń wyrównania i instrukcji o zmiennej szerokości, i możesz zacząć rozbierać się w pewnym momencie, tylko po to, aby odkryć, że uruchomiłeś swoją rekompilację z przesunięciem.

Weźmy uproszczony zestaw instrukcji zawierającej dwie instrukcje i jeden rejestr A:

41 xx (size 2): Add xx to `A`. 
42 (size 1): Increment `A` by one. 

Weźmy następujący binarny programu:

41 42 

Załóżmy, że punkt startowy to pierwszy bajt 41 . zrobić:

41 42 (size 2): Add 42 to `A`. 

Ale co, jeśli 41 to fragment danych? Następnie program będzie:

42 (size 1): Increment `A` by one. 

Problem ten jest powiększany w stare gry, które często były zoptymalizowane bezpośrednio w montażu, a gdzie programista może celowo expect some byte to be interpreted as both code and data, depending on the context!

Nawet gorzej The zrekompilowane program może generować sam kod! Wyobraź sobie rekompilację kompilatora JIT. Wynik nadal generuje kod dla architektury źródłowej i próbuje przeskoczyć do niego, najprawdopodobniej powodując, że program wkrótce umrze. Statyczna rekompilacja kodu, który jest dostępny tylko w środowisku wykonawczym, wymaga nieskończonej sztuczki!

Statyczna analiza binarna to bardzo żywa dziedzina badań (głównie w dziedzinie bezpieczeństwa, szukania luk w systemach, których źródła nie są dostępne), a tak naprawdę znam próbę wyprodukowania NES emulator that tries to statically recompile programs. Artykuł jest bardzo interesujący.

Kompromisem pomiędzy JIT a rekompilacją statyczną byłoby statyczna rekompilacja jak największej ilości kodu, zachowując tylko bity, których nie można przetłumaczyć statycznie.

+0

Świetne wyjaśnienie. Chciałbym wspomnieć o innym możliwym kompromisie pomiędzy rekompilacją statyczną/dynamiczną - buforowaniem (do pliku) dynamicznie rekompilowanych fragmentów kodu. Być może to podejście przyniosłoby dużą korzyść z rekompilacji statycznej, wzmocnionej przez zdolność wykrywania kodu źródłowego w analizie środowiska wykonawczego. – Cauterite

Powiązane problemy