Dlaczego pliki wykonywalne zależą od systemu operacyjnego, ale nie od procesora?

16

Jeśli napiszę program w języku C i skompiluję go do .exepliku, .exeplik zawiera nieprzetworzone instrukcje maszynowe dla procesora. (Myślę).

Jeśli tak, to w jaki sposób mogę uruchomić skompilowany plik na dowolnym komputerze z nowoczesną wersją systemu Windows? Każda rodzina procesorów ma inny zestaw instrukcji. Dlaczego więc każdy komputer z odpowiednim systemem operacyjnym może zrozumieć instrukcje w moim .exepliku, niezależnie od fizycznego procesora?

Ponadto często w witrynach internetowych na stronie „pobierania” niektórych aplikacji masz pliki do pobrania dla systemu Windows, Linux i Mac (często dwa pliki do pobrania dla każdego systemu operacyjnego, dla komputerów 86 i 64-bitowych). Dlaczego nie ma o wiele więcej plików do pobrania dla każdej rodziny procesorów?

Aviv Cohn
źródło
4
Procesory mają standardowe standardy, takie jak x86, 64b itp. Pliki wykonywalne zależą od procesora. Nie możesz uruchomić swojego exe, o którym wspomniałeś na jakimś specjalnym procesorze, takim jak RISC, jest też mnóstwo procesorów specjalnego przeznaczenia
InformedA
Systemy operacyjne składają się z plików wykonywalnych i zależą od procesora, a nie systemów operacyjnych, ponieważ są one systemem operacyjnym.
Tulains Córdova
Ze względu na kompatybilność wsteczną.
MiKL,
2
często dwa pliki do pobrania dla każdego systemu operacyjnego, dla komputerów 86 i 64-bitowych : interpretuję to jako zależność plików wykonywalnych od procesorów.
mouviciel

Odpowiedzi:

37

Pliki wykonywalne zależą zarówno od systemu operacyjnego, jak i procesora:

  • Zestaw instrukcji: instrukcje binarne w pliku wykonywalnym są dekodowane przez CPU zgodnie z niektórymi zestawami instrukcji. Większość procesorów konsumenckich obsługuje zestawy instrukcji x86 („32bit”) i / lub AMD64 („64bit”). Program można skompilować dla każdego z tych zestawów instrukcji, ale nie dla obu. Istnieją rozszerzenia tych zestawów instrukcji; wsparcie dla tych można zapytać w czasie wykonywania. Takie rozszerzenia oferują na przykład obsługę SIMD. Optymalizujące kompilatory mogą próbować skorzystać z tych rozszerzeń, jeśli są one obecne, ale zwykle oferują również ścieżkę kodu, która działa bez żadnych rozszerzeń.

  • Format binarny: Plik wykonywalny musi być zgodny z określonym formatem binarnym, który pozwala systemowi operacyjnemu poprawnie załadować, zainicjować i uruchomić program. Windows używa głównie przenośnego formatu wykonywalnego, podczas gdy Linux używa ELF.

  • Systemowe interfejsy API: Program może używać bibliotek, które muszą być obecne w systemie wykonawczym. Jeśli program używa funkcji z interfejsów API systemu Windows, nie można go uruchomić w systemie Linux. W świecie Uniksa interfejsy API centralnego systemu operacyjnego zostały znormalizowane do POSIX: program wykorzystujący tylko funkcje POSIX będzie mógł działać na dowolnym zgodnym systemie Unix, takim jak Mac OS X i Solaris.

Więc jeśli dwa systemy oferują te same systemowe interfejsy API i biblioteki, działają na tym samym zestawie instrukcji i używają tego samego formatu binarnego, wówczas program skompilowany dla jednego systemu będzie również działał w drugim.

Istnieją jednak sposoby osiągnięcia większej zgodności:

  • Systemy działające na zestawie instrukcji AMD64 zwykle będą również uruchamiały pliki wykonywalne x86. Format binarny wskazuje, który tryb należy uruchomić. Obsługa programów 32-bitowych i 64-bitowych wymaga dodatkowego wysiłku ze strony systemu operacyjnego.

  • Niektóre formaty binarne pozwalają plikowi zawierać wiele wersji programu skompilowanych dla różnych zestawów instrukcji. Takie „grube pliki binarne” były wspierane przez Apple podczas przechodzenia z architektury PowerPC na x86.

  • Niektóre programy nie są kompilowane do kodu maszynowego, ale do niektórych reprezentacji pośrednich. To jest następnie tłumaczone w locie na rzeczywiste instrukcje lub może być interpretowane. To uniezależnia program od konkretnej architektury. Taką strategię zastosowano w systemie p UCSD.

  • Jeden system operacyjny może obsługiwać wiele formatów binarnych. Windows jest dość wstecznie kompatybilny i nadal obsługuje formaty z epoki DOS. W systemie Linux Wine umożliwia ładowanie formatów Windows.

  • Interfejsy API jednego systemu operacyjnego można ponownie zaimplementować w innym systemie operacyjnym hosta. W systemie Windows Cygwin i podsystem POSIX można wykorzystać do uzyskania (głównie) środowiska zgodnego z POSIX. W systemie Linux Wine reimplementuje wiele interfejsów API Windows.

  • Biblioteki wieloplatformowe pozwalają programowi być niezależnym od interfejsów API systemu operacyjnego. Wiele języków programowania ma standardowe biblioteki, które próbują to osiągnąć, np. Java i C.

  • Emulator symuluje inny system przez parsowania zagranicznego formatu binarnego, interpretacji instrukcje i oferując powtórną implementację wszystkich wymaganych interfejsów API. Emulatory są powszechnie używane do uruchamiania starych gier Nitendo na nowoczesnym komputerze.

amon
źródło
10
Należy wspomnieć, że zarówno java, jak i .net są przykładami użycia formatu pośredniego - formaty pośrednie są dziś bardzo popularne, a nie tylko relikt systemu z lat 70., w którym zabrakło 5 1/4 dyskietek.
jmoreno
@AKosciański dziękuję za sugerowaną edycję . Myślę jednak, że projekt bezpieczeństwa nie jest powodem, dla którego pliki wykonywalne są zależne od systemu operacyjnego, ale przede wszystkim powodem podziału systemu operacyjnego na obszar użytkownika. Różne interfejsy API dla takiej chronionej funkcjonalności systemu operacyjnego zostały już omówione w części „Interfejsy API systemu” tej odpowiedzi.
amon
2

99% obecnych komputerów z systemem Windows ma procesor 64-bitowy, który jest również zdolny do uruchamiania oprogramowania 32-bitowego. Drugi procent ma procesory 32-bitowe. Oprogramowanie zbudowane dla 32-bitowych procesorów działa wszędzie. Oprogramowanie zbudowane dla procesorów 64-bitowych działa na każdym komputerze, na którym zależy twórcy oprogramowania.

MacOS X i iOS obsługują „duże pliki binarne” - tak naprawdę to, co pobierasz, może zawierać wersje dla różnych procesorów. Nikt już nie buduje aplikacji dla procesorów PowerPC, ale w pewnym momencie kilka lat temu plik wykonywalny mógł zawierać PowerPC, 32-bitowy Intel i 64-bitową wersję Intela, a właściwy zostałby wykonany. W dzisiejszych czasach na iOS, gdy pobierzesz aplikację, otrzymasz wersję odpowiednią dla procesora na twoim urządzeniu. Pobierz na inne urządzenie, a otrzymasz inną wersję. Całkowicie niewidoczny dla użytkownika.

gnasher729
źródło
-1

Plik exe zawiera więcej informacji niż tylko surowy kod maszynowy. System operacyjny czyta to podczas ładowania i może dowiedzieć się, jak powinien działać.

Podczas kompilacji zazwyczaj ustawiasz docelowy procesor, jeśli tego nie zrobisz, kompilator wybierze bieżący procesor i ograniczy się do wybrania tylko instrukcji wspólnych dla twojego procesora i jego starszych wersji. Jeśli chcesz użyć nowej, wymyślnej instrukcji, która jest specyficzna dla określonej wersji docelowego procesora, możesz powiedzieć kompilatorowi lub ręcznie go zakodować za pomocą wewnętrznego lub wbudowanego kodu asemblera. Jednak program ulegnie awarii, jeśli zostanie uruchomiony na procesorze, który nie obsługuje tej instrukcji.

James
źródło