Czy plik wykonywalny potrzebuje jądra systemu operacyjnego do uruchomienia?

53

Wiem, że po skompilowaniu kodu źródłowego, powiedzmy C ++, wyjściem kompilatora jest kod maszynowy (wykonywalny), który moim zdaniem był instrukcją bezpośrednio do procesora. Ostatnio czytałem o jądrach i dowiedziałem się, że programy nie mogą uzyskać bezpośredniego dostępu do sprzętu, ale muszą przejść przez jądro.

Kiedy więc skompilujemy jakiś prosty kod źródłowy, powiedzmy za pomocą tylko jednej printf()funkcji, a kompilacja wygeneruje wykonywalny kod maszynowy, czy każda instrukcja w tym kodzie maszynowym zostanie wykonana bezpośrednio z pamięci (po załadowaniu kodu do pamięci przez system operacyjny) lub każde polecenie w kodzie maszynowym musi jeszcze przejść przez system operacyjny (jądro), aby zostać wykonane?

Przeczytałem podobne pytanie . Nie wyjaśnił, czy kod maszynowy generowany po kompilacji jest instrukcją bezpośrednio do procesora, czy też będzie musiał ponownie przejść przez jądro, aby utworzyć poprawną instrukcję dla procesora. To znaczy, co dzieje się po załadowaniu kodu maszynowego do pamięci? Czy przejdzie przez jądro, czy bezpośrednio porozmawia z procesorem?

GRANZER
źródło
29
Jeśli piszesz kod dla Arduino, nie potrzebujesz systemu operacyjnego.
stib
12
printfnie jest świetnym przykładem. Jest to wyraźnie zdefiniowane przez specyfikację C jako funkcja, która jest dostępna tylko w implementacjach „hostowanych” (co oznacza, że ​​działa na jądrze, w przeciwieństwie do „wolnostojącego”, który może go nie wymagać). I na większości platform, printfjest to po prostu funkcja zapewniana przez twoją, libcktóra robi wiele rzeczy w twoim imieniu (która ostatecznie obejmuje połączenie systemowe do wydrukowania na standardowe wyjście). Naprawdę nie różni się niczym od dzwonienia libvlc_media_list_add_medialub PyObject_GetAttr, z tym wyjątkiem, że pewna printfimplementacja jest gwarantowana do połączenia bez dodawania dodatkowych niestandardowych -l.
abarnert
1
To istnieje! (nie związany, tylko myślałem, że to było fajne) erikyyy.de/invaders
Nonny Moose
9
To naprawdę zależy od dokładnej definicji terminów „plik wykonywalny”, „jądro”, „uruchamianie”, „potrzeba”, „rozmowa z” i „przejście”. Bez precyzyjnej definicji tych terminów na pytanie nie można odpowiedzieć.
Jörg W Mittag
3
@ JörgWMittag - Jeśli zamierzasz być pedantyczny, to dlaczego analizujesz tylko te warunki i tylko to pytanie? Naprawdę istotnym terminem, który wymaga zdefiniowania, jest „system operacyjny”, który jest wątpliwie stosowany w MS-DOS (i podobnych środowiskach wykonawczych z jednym zadaniem). Jeśli jest kilka (źle poinformowanych) osób, które myślą, że BIOS komputera to system operacyjny , czy wszystko jest w porządku? Myślę, że nie. OP używa tych słów w kontekście, który wydaje się albo rozsądny (szczególnie jeśli nie mówi po angielsku), albo nietechniczny.
trociny

Odpowiedzi:

86

Jako ktoś, kto napisał programy, które działają bez systemu operacyjnego, oferuję ostateczną odpowiedź.

Czy plik wykonywalny potrzebuje jądra systemu operacyjnego do uruchomienia?

To zależy od tego, jak ten program został napisany i zbudowany.
Możesz napisać program (zakładając, że masz wiedzę), który wcale nie wymaga systemu operacyjnego.
Taki program jest opisany jako samodzielny .
Programy ładujące i programy diagnostyczne są typowymi zastosowaniami dla samodzielnych programów.

Jednak typowy program napisany i wbudowany w niektóre środowisko systemu operacyjnego hosta domyślnie działałby w tym samym środowisku systemu operacyjnego hosta.
Aby napisać i zbudować samodzielny program, konieczne są bardzo wyraźne decyzje i działania.


... wyjściem kompilatora jest kod maszynowy (wykonywalny), który moim zdaniem był instrukcją bezpośrednio do procesora.

Poprawny.

Ostatnio czytałem o jądrach i dowiedziałem się, że programy nie mogą uzyskać bezpośredniego dostępu do sprzętu, ale muszą przejść przez jądro.

Jest to ograniczenie narzucone przez tryb procesora używany przez system operacyjny do uruchamiania programów i ułatwione przez niektóre narzędzia do budowania, takie jak kompilatory i biblioteki.
Nie jest to wewnętrzne ograniczenie każdego napisanego programu.


Kiedy więc skompilujemy jakiś prosty kod źródłowy, powiedzmy za pomocą funkcji printf (), a kompilacja wygeneruje wykonywalny kod maszynowy, każda instrukcja w tym kodzie maszynowym zostanie wykonana bezpośrednio z pamięci (po załadowaniu kodu do pamięci przez system operacyjny ) lub czy każde polecenie w kodzie maszynowym nadal musi przejść przez system operacyjny (jądro), aby zostać wykonane?

Każda instrukcja wykonywana jest przez CPU.
Instrukcja nieobsługiwana lub nielegalna (np. Proces ma niewystarczające uprawnienia) spowoduje natychmiastowy wyjątek, a procesor zamiast tego wykona procedurę obsługującą ten nietypowy warunek.

Funkcja printf () nie powinna być używana jako przykład „prostego kodu źródłowego” .
Tłumaczenie z obiektowego języka programowania wysokiego poziomu na kod maszynowy może nie być tak proste, jak sugerujesz.
Następnie wybierasz jedną z najbardziej złożonych funkcji z biblioteki wykonawczej, która wykonuje konwersje danych i operacje we / wy.

Pamiętaj, że twoje pytanie określa środowisko z systemem operacyjnym (i biblioteką wykonawczą).
Po uruchomieniu systemu i przejęciu kontroli nad komputerem przez system operacyjny nakładane są ograniczenia na to, co program może zrobić (np. Operacje we / wy muszą być wykonywane przez system operacyjny).
Jeśli spodziewasz się uruchomić samodzielny program (tj. Bez systemu operacyjnego), nie możesz uruchamiać komputera, aby uruchomić system operacyjny.


... co dzieje się po załadowaniu kodu maszynowego do pamięci?

To zależy od środowiska.

W przypadku samodzielnego programu można go wykonać, tzn. Sterowanie jest przekazywane przez przeskakiwanie do adresu początkowego programu.

W przypadku programu ładowanego przez system operacyjny program musi być dynamicznie powiązany z bibliotekami współdzielonymi, od których jest zależny. System operacyjny musi utworzyć przestrzeń wykonywania dla procesu, który uruchomi program.

Czy przejdzie przez jądro, czy bezpośrednio porozmawia z procesorem?

Kod maszynowy jest wykonywany przez CPU.
Nie „przechodzą przez jądro” , ale nie „rozmawiają z procesorem” .
Kod maszynowy (składający się z kodu operacyjnego i operandów) jest instrukcją dla procesora, która jest dekodowana i wykonywana jest operacja.

Być może następnym tematem, który powinieneś zbadać, są tryby procesora .

trociny
źródło
2
„Jeśli spodziewasz się uruchomić samodzielny program (tj. Bez systemu operacyjnego), nie możesz uruchamiać komputera, aby uruchomić system operacyjny.” nie jest całkowicie poprawne. Wiele programów DOS zostało załadowanych po DOS, a następnie całkowicie zignorowało usługi DOS (bezpośrednio bit-banging lub może bezpośrednio wywołać BIOS). Win3.x jest doskonałym przykładem, który (z wyjątkiem niektórych interesujących przypadków narożnych) zignorował obecność DOS. Win95 / 98 / Me również to zrobił. Istnieje wiele przykładów systemów operacyjnych obsługujących samodzielne programy, wiele z ery 8- / 16-bitowej.
Eric Towers
8
@EricTowers - Przez „DOS” przypuszczalnie masz na myśli MS-DOS (skoro używałem DOS niezwiązanych z MS ani Intelem)? Przytaczasz „system operacyjny”, który nawet nie spełnia kryteriów moich podręczników z lat 70. ubiegłego wieku na temat koncepcji i projektu systemu operacyjnego. Początki MS-DOS sięgają wstecz (za pośrednictwem Seattle Computer Products) do CP / M, którego autor wyraźnie nie nazwał systemem operacyjnym Gary Kildall. FWIW system operacyjny, który pozwala programowi przejąć system, zawiódł w swojej podstawowej funkcji zarządzania zasobami systemowymi. „Istnieje wiele przykładów systemów operacyjnych obsługujących samodzielne programy” - „Wsparcie” lub nie można temu zapobiec?
trociny
5
... lub ProDOS lub PC-DOS lub DR-DOS lub CBM DOS lub TRS DOS lub FLEX ...
Eric Towers
3
Lubię terminologię „wolnostojącą” GCC. Angielskie słowo ma wszystkie odpowiednie konotacje dla kodu działającego bez systemu operacyjnego, może nawet lepiej niż „samodzielny”. np. możesz skompilować, gcc -O2 -ffreestanding my_kernel.c special_sauce.Saby plik wykonywalny nie zakładał, że będzie w nim normalna biblioteka lub system operacyjny. (Oczywiście można by się normalnie trzeba skrypt linkera, aby zmusić go do użytecznie połączyć w formacie pliku, który bootloader będzie chciał załadować!)
Peter Cordes
4
@PeterCordes „samodzielny” to termin używany w standardzie C, który IMO można uznać za nieco autorytatywny. Alternatywnie dobrym terminem jest również „nie hostowany” (jak w hostowanym przez system operacyjny)
Jan Dorniak
38

Jądro to „tylko” więcej kodu. Po prostu ten kod jest warstwą, która żyje między najniższymi częściami systemu a rzeczywistym sprzętem.

Wszystko działa bezpośrednio na procesorze, wystarczy przejść przez kolejne warstwy, aby cokolwiek zrobić.

Twój program „potrzebuje” jądra w taki sam sposób, jak potrzebuje standardowych bibliotek C, aby móc korzystać z printfpolecenia w pierwszej kolejności.

Rzeczywisty kod twojego programu działa na CPU, ale gałęzie, które kod tworzy, aby wydrukować coś na ekranie, przechodzą przez kod printffunkcji C , przez różne inne systemy i interpretery, z których każdy wykonuje własne przetwarzanie, aby dowiedzieć się, jak to zrobić hello world!faktycznie drukuje się na ekranie.

Załóżmy, że masz program terminalowy uruchomiony na pulpicie menedżera okien, działający na twoim jądrze, które z kolei działa na twoim sprzęcie.

Dzieje się o wiele więcej, ale niech to będzie proste ...

  1. W swoim programie terminalowym uruchamiasz swój program do drukowania hello world!
  2. Terminal widzi, że program napisał (za pomocą procedur wyjściowych C) hello world!na konsoli
  3. Program terminala podchodzi do menedżera okien pulpitu powiedzenie „mam hello world!napisane na mnie, można umieścić go w pozycji x, yproszę?”
  4. Menedżer okien pulpitu podchodzi do jądra z „jednym z moich programów chce, aby twoje urządzenie graficzne umieściło tekst w tym miejscu, przejdź do niego, koleś!”
  5. Jądro przekazuje żądanie do sterownika urządzenia graficznego, które formatuje je w sposób zrozumiały dla karty graficznej
  6. W zależności od sposobu podłączenia karty graficznej należy wywołać inne sterowniki urządzeń jądra w celu wypchnięcia danych na magistrale urządzeń fizycznych, takich jak PCIe, obsługując takie rzeczy, jak upewnienie się, że wybrane jest właściwe urządzenie i że dane mogą przejść przez odpowiedni mostek lub konwertery
  7. Sprzęt wyświetla rzeczy.

Jest to ogromne uproszczenie wyłącznie w celu opisu. Oto smoki.

W rzeczywistości wszystko, co robisz, wymaga dostępu do sprzętu, czy to wyświetlania, bloków pamięci, bitów plików itp., Musi przejść przez jakiś sterownik urządzenia w jądrze, aby dokładnie ustalić , jak rozmawiać z odpowiednim urządzeniem. Czy to sterownik systemu plików na sterowniku kontrolera dysku twardego SATA, który sam siedzi na urządzeniu mostkowym PCIe.

Jądro wie, jak powiązać ze sobą wszystkie te urządzenia i oferuje stosunkowo prosty interfejs dla programów do robienia rzeczy bez konieczności posiadania wiedzy o tym, jak sami wszystkie te rzeczy robić.

Menedżery okien pulpitu zapewniają warstwę, która oznacza, że ​​programy nie muszą wiedzieć, jak rysować okna i dobrze się bawić z innymi programami próbującymi wyświetlać rzeczy w tym samym czasie.

Wreszcie, program terminalowy oznacza, że ​​twój program nie musi wiedzieć, jak narysować okno, ani jak rozmawiać ze sterownikiem karty graficznej jądra, ani całej złożoności związanej z obsługą buforów ekranu i timingu wyświetlania oraz faktycznym poruszaniem linie danych do wyświetlacza.

Wszystko jest obsługiwane przez warstwy po warstwach kodu.

Mokubai
źródło
Nie tylko dostęp do sprzętu , większość komunikacji między programami również przechodzi przez jądro; tym, co zwykle nie wymaga przynajmniej jądra, jest ustawienie bardziej bezpośredniego kanału. Jednak dla celów tego pytania możliwe jest i praktykowane w znacznie prostszych przypadkach zagęszczenie całego kodu w jednym programie.
Chris Stratton
Rzeczywiście, twój program terminalowy nie musi nawet działać na tym samym komputerze, co program, który zapisuje na nim różne rzeczy.
jamesqf
Ponieważ może to wymagać wyraźnego określenia w tym pytaniu - pamiętaj, że kiedy mówimy o programach „rozmawiających ze sobą”, jest to metaforyczne.
user253751,
21

To zależy od środowiska. Na wielu starszych (i prostszych!) Komputerach, takich jak IBM 1401, odpowiedź brzmiałaby „nie”. Twój kompilator i linker emitowały autonomiczny „plik binarny”, który działał bez żadnego systemu operacyjnego. Gdy Twój program przestał działać, załadowałeś inny, który również działał bez systemu operacyjnego.

System operacyjny jest potrzebny w nowoczesnych środowiskach, ponieważ nie uruchamiasz tylko jednego programu na raz. Udostępnianie rdzenia (rdzeni) procesora, pamięci RAM, urządzenia pamięci masowej, klawiatury, myszy i wyświetlacza wielu programom jednocześnie wymaga koordynacji. System operacyjny to zapewnia. Więc w nowoczesnym środowisku twój program nie może po prostu czytać i zapisywać dysku lub dysku SSD, musi poprosić system operacyjny, aby zrobił to w jego imieniu. System operacyjny otrzymuje takie żądania od wszystkich programów, które chcą uzyskać dostęp do urządzenia pamięci masowej, implementuje takie rzeczy, jak kontrola dostępu (nie może pozwolić zwykłym użytkownikom na zapisywanie plików systemu operacyjnego), umieszcza je w kolejce na urządzeniu i sortuje zwrócone informacje do właściwych programów (procesów).

Ponadto współczesne komputery (w odróżnieniu od, powiedzmy, 1401) obsługują połączenie bardzo szerokiej gamy urządzeń I / O, nie tylko tych, które IBM sprzedawałby w dawnych czasach. Twój kompilator i linker nie mogą wiedzieć o wszystkich możliwościach. Na przykład klawiatura może być podłączona za pomocą PS / 2 lub USB. System operacyjny pozwala instalować „sterowniki urządzeń” specyficzne dla urządzenia, które wiedzą, jak rozmawiać z tymi urządzeniami, ale zapewniają wspólny interfejs dla klasy urządzeń w systemie operacyjnym. Więc twój program, a nawet system operacyjny, nie musi robić nic innego, aby uzyskać naciśnięcia klawiszy z USB w porównaniu z klawiaturą PS / 2, lub w celu uzyskania dostępu, powiedzmy, do lokalnego dysku SATA vs. na NAS lub SAN. Te dane są obsługiwane przez sterowniki urządzeń dla różnych kontrolerów urządzeń.

W przypadku urządzeń pamięci masowej system operacyjny zapewnia na wszystkich sterownikach systemu plików, który oferuje ten sam interfejs katalogom i plikom, niezależnie od tego, gdzie i jak pamięć jest implementowana. I znowu, OS martwi się o kontrolę dostępu i serializację. Zasadniczo, na przykład, ten sam plik nie powinien być otwierany do zapisu przez więcej niż jeden program na raz bez przeskakiwania niektórych obręczy (ale jednoczesne odczyty są ogólnie ok).

Tak więc w nowoczesnym środowisku ogólnego zastosowania tak - naprawdę potrzebujesz systemu operacyjnego. Ale nawet dzisiaj istnieją komputery, takie jak kontrolery czasu rzeczywistego, które nie są wystarczająco skomplikowane, aby ich potrzebować.

Na przykład w środowisku Arduino tak naprawdę nie ma systemu operacyjnego. Jasne, jest mnóstwo kodu bibliotecznego, który środowisko kompilacji zawiera w każdym kompilowanym pliku binarnym. Ale ponieważ nie ma trwałości tego kodu między programami, nie jest to system operacyjny.

Jamie Hanrahan
źródło
10

Myślę, że wiele odpowiedzi nie rozumie pytania, które sprowadza się do tego:

Kompilator generuje kod maszynowy. Czy ten kod maszynowy jest wykonywany bezpośrednio przez procesor, czy też jest „interpretowany” przez jądro?

Zasadniczo CPU bezpośrednio wykonuje kod maszynowy . Byłoby znacznie wolniej, aby jądro wykonywało wszystkie aplikacje. Istnieje jednak kilka zastrzeżeń.

  1. Gdy obecny jest system operacyjny, aplikacje zwykle nie mogą wykonywać niektórych instrukcji ani uzyskiwać dostępu do niektórych zasobów. Na przykład, jeśli aplikacja wykona instrukcję, która modyfikuje tablicę przerwań systemowych, procesor zamiast tego przeskoczy do procedury obsługi wyjątków systemu operacyjnego, tak że szkodliwa aplikacja zostanie zakończona. Ponadto aplikacje zwykle nie mogą odczytywać / zapisywać w pamięci urządzenia. (Tj. „Rozmawia ze sprzętem”). Dostęp do tych specjalnych obszarów pamięci polega na tym, jak system operacyjny komunikuje się z urządzeniami takimi jak karta graficzna, interfejs sieciowy, zegar systemowy itp.

  2. Ograniczenia, jakie system operacyjny nakłada na aplikacje, są osiągane dzięki specjalnym funkcjom procesora, takim jak tryby uprawnień, ochrona pamięci i przerwania. Chociaż każdy procesor, który można znaleźć w smartfonie lub komputerze, ma te funkcje, niektóre procesory nie. Te procesory rzeczywiście potrzebują specjalnych jąder, które „interpretują” kod aplikacji, aby osiągnąć pożądane funkcje. Bardzo interesującym przykładem jest Gigatron , który jest komputerem z 8 instrukcjami, które można zbudować z układów, które emulują komputer z 34 instrukcjami.

  3. Niektóre języki, takie jak Java, „kompilują się” do czegoś o nazwie Bytecode, co tak naprawdę nie jest kodem maszynowym. Chociaż w przeszłości interpretowano je w celu uruchamiania programów, obecnie zwykle używa się czegoś zwanego kompilacją Just-in-Time, więc kończą one bezpośrednio na procesorze jako kod maszynowy.

  4. Uruchamianie oprogramowania na maszynie wirtualnej wymagało „interpretacji” kodu maszynowego przez program o nazwie Hypervisor . Ze względu na ogromne zapotrzebowanie branży na maszyny wirtualne producenci procesorów dodali do procesorów takie funkcje, jak VTx, aby umożliwić wykonywanie większości instrukcji systemu gościa bezpośrednio przez procesor. Jednak w przypadku uruchamiania oprogramowania zaprojektowanego dla niekompatybilnego procesora na maszynie wirtualnej (na przykład emulacji NES) kod maszynowy będzie wymagał interpretacji.

Artelius
źródło
1
Chociaż kod bajtowy Java zwykle nie jest kodem maszynowym, nadal istnieją procesory Java .
Ruslan
Hiperwizorzy nigdy nie byli tłumaczami. Interpretacja jest oczywiście konieczna, jeśli maszyna wirtualna jako zestaw instrukcji, który jest niezgodny z jej hostem, ale w celu wykonania tej samej architektury, nawet wczesne hiperwizory wykonują kod bezpośrednio na procesorze (możesz być zdezorientowany potrzebą parawirtualizowanych jąder, dla procesorów bez niezbędne wsparcie hiperwizora).
Toby Speight
5

Podczas kompilowania kodu tworzony jest tak zwany kod „obiektowy”, który (w większości przypadków) zależy od bibliotek systemowych ( printfna przykład), a następnie kod jest zawijany przez linker, który doda rodzaj programu ładującego program, który może być używany przez dany system operacyjny rozpoznaj (dlatego nie możesz na przykład uruchomić programu skompilowanego dla systemu Windows w systemie Linux) i umieć rozpakować kod i wykonać go. Więc twój program jest jak mięso wewnątrz kanapki i może być spożywany tylko jako pakiet, w całości.

Ostatnio czytałem o jądrach i dowiedziałem się, że programy nie mogą uzyskać bezpośredniego dostępu do sprzętu, ale muszą przejść przez jądro.

Cóż, to w połowie prawda; jeśli twój program jest sterownikiem trybu jądra, to tak naprawdę możesz uzyskać bezpośredni dostęp do sprzętu, jeśli wiesz, jak „rozmawiać” ze sprzętem, ale zwykle (szczególnie w przypadku nieudokumentowanego lub skomplikowanego sprzętu) ludzie używają sterowników, które są bibliotekami jądra. W ten sposób możesz znaleźć funkcje API, które potrafią rozmawiać ze sprzętem w sposób prawie czytelny dla człowieka, bez potrzeby znajomości adresów, rejestrów, czasu i wielu innych rzeczy.

czy każda instrukcja w tym kodzie maszynowym zostanie wykonana bezpośrednio z pamięci (po załadowaniu kodu do pamięci przez system operacyjny), czy też każda komenda w kodzie maszynowym będzie musiała przejść przez system operacyjny (jądro), aby zostać wykonana

Cóż, jądro jest jak kelnerka, której obowiązkiem jest odprowadzenie cię do stołu i podanie. Jedyne, czego nie może zrobić - to dla ciebie jeść, powinieneś to zrobić sam. Podobnie z twoim kodem, jądro rozpakuje twój program do pamięci i uruchomi twój kod, który jest kodem maszynowym wykonywanym bezpośrednio przez CPU. Jądro musi tylko cię nadzorować - co możesz robić, a czego nie wolno robić.

nie wyjaśnia, czy kod maszynowy generowany po kompilacji jest instrukcją bezpośrednio do CPU, czy też będzie musiał ponownie przejść przez jądro, aby utworzyć poprawną instrukcję dla CPU?

Kod maszynowy generowany po kompilacji jest instrukcją bezpośrednio do procesora. Bez wątpienia. Jedyną rzeczą, o której musisz pamiętać, nie cały kod w skompilowanym pliku to rzeczywisty kod komputera / procesora. Linker zawarł twój program w metadane, które tylko jądro może interpretować, jako wskazówkę - co zrobić z twoim programem.

Co dzieje się po załadowaniu kodu maszynowego do pamięci? Czy przejdzie przez jądro, czy bezpośrednio porozmawia z procesorem?

Jeśli twój kod jest po prostu prostymi opcodes, takimi jak dodanie dwóch rejestrów, to zostanie on wykonany bezpośrednio przez CPU bez pomocy jądra, ale jeśli twój kod używa funkcji z bibliotek, wówczas takie połączenia będą wspomagane przez jądro, jak na przykład z kelnerką, jeśli chcesz do jedzenia w restauracji dadzą ci narzędzia - widelec, łyżkę (i to wciąż ich atuty), ale co z tym zrobisz, - to zależy od twojego „kodu”.

Cóż, tylko po to, by nie dopuścić do pojawienia się płomienia w komentarzach - mam nadzieję, że jest to model bardzo uproszczony, który pomógłby OP zrozumieć podstawowe rzeczy, ale mile widziane są dobre sugestie dotyczące poprawy tej odpowiedzi.

Alex
źródło
3

Kiedy więc skompilujemy prosty kod źródłowy, powiedzmy za pomocą funkcji printf (), a kompilacja wygeneruje wykonywalny kod maszynowy, czy każda instrukcja w tym kodzie maszynowym zostanie wykonana bezpośrednio z pamięci (po załadowaniu kodu do pamięci przez system operacyjny) lub czy każde polecenie w kodzie maszynowym nadal musi przejść przez system operacyjny (jądro), aby zostać wykonane?

Zasadniczo tylko wywołania systemowe trafiają do jądra. Cokolwiek wspólnego z We / Wy lub alokacją / dezalokacją pamięci zazwyczaj kończy się wywołaniem systemowym. Niektóre instrukcje można wykonać tylko w trybie jądra i spowoduje to, że procesor uruchomi wyjątek. Wyjątki powodują przejście do trybu jądra i przejście do kodu jądra.

Jądro nie przetwarza wszystkich instrukcji w programie. Po prostu wykonuje wywołania systemowe i przełącza się między uruchomionymi programami w celu współużytkowania procesora.

Wykonanie alokacji pamięci w trybie użytkownika (bez jądra) nie jest możliwe, jeśli uzyskujesz dostęp do pamięci, nie masz uprawnień dostępu, MMU, wcześniej zaprogramowane przez jądro, zauważa i powoduje wyjątek „błąd segmentacji” na poziomie procesora , który uruchamia jądro, a jądro zabija program.

Wykonanie operacji we / wy w trybie użytkownika (bez jądra) nie jest możliwe, jeśli uzyskujesz dostęp do portów we / wy lub rejestrów urządzeń lub adresów podłączonych do urządzeń (jeden lub oba są potrzebne do wykonania dowolnego we / wy), wyzwalają one wyjątek w ten sam sposób.


Czy plik wykonywalny potrzebuje jądra systemu operacyjnego do uruchomienia?

Zależy od typu pliku wykonywalnego.

Jądra, oprócz pośredniczenia w dzielonym dostępie do pamięci RAM i sprzętu, pełnią również funkcję modułu ładującego.

Wiele „formatów plików wykonywalnych”, takich jak ELF lub PE, oprócz kodu zawiera metadane w pliku wykonywalnym i zadanie modułu ładującego do przetworzenia tego. Przeczytaj krwawe szczegóły dotyczące formatu PE Microsoft, aby uzyskać więcej informacji.

Te pliki wykonywalne również odwołują się do bibliotek ( pliki .dllobiektów współużytkowanych w systemie Windows lub Linux .so) - należy podać ich kod.

Jeśli Twój kompilator utworzy plik, który ma zostać przetworzony przez moduł ładujący systemu operacyjnego, a tego modułu ładującego nie ma, nie będzie działać.

  • Czy możesz dołączyć kod, który wykonuje zadanie modułu ładującego?

Pewnie. Musisz przekonać system operacyjny, aby jakoś uruchomił surowy kod bez przetwarzania jakichkolwiek metadanych. Jeśli Twój kod wywołuje interfejsy API jądra, nadal nie będzie działać.

  • Co jeśli nie wywoła interfejsów API jądra?

Jeśli w jakiś sposób załadujesz ten plik wykonywalny z systemu operacyjnego (tj. Jeśli pozwala on na załadowanie i wykonanie surowego kodu), nadal będzie w trybie użytkownika. Jeśli twój kod uzyskuje dostęp do rzeczy, które są zabronione w trybie użytkownika, w przeciwieństwie do trybu jądra, takich jak nieprzydzielona pamięć lub adresy / rejestry urządzeń I / O, zawiesi się z naruszeniem uprawnień lub segmentów (ponownie wyjątki przechodzą w tryb jądra i są obsługiwane tam) i nadal nie będzie działać.

  • Co jeśli uruchomisz go z trybu jądra.

Wtedy to zadziała.


LawrenceC
źródło
To nie jest do końca poprawne. Wymóg, że dostęp do sprzętu przejść przez jądro, albo że tam nawet być jądro, jest decyzją konstrukcja wykonana twierdząco na wielu systemach dzisiaj, ale również w negatywie (nawet do dziś) na wielu prostych systemów.
Chris Stratton,
Wyjaśniam, jak się sprawy mają, jeśli A) jest jądro i B) jeśli uruchamiasz kod na procesorze w trybie użytkownika / nadzorcy i MMU, aby pomóc w egzekwowaniu tego. Tak, istnieją procesory i mikrokontrolery bez MMU lub trybu użytkownika / superwizora, i tak, niektóre systemy działają bez korzystania z całej infrastruktury użytkownika / superwizora. Pierwszy Xbox Microsoftu był taki - chociaż standardowy procesor x86 z trybem użytkownika / nadzorcy, z tego, co rozumiem, nigdy nie opuścił trybu jądra - załadowana gra mogła zrobić, co tylko zechce.
LawrenceC
1
System Macintosh, przed MacOS X, był systemem operacyjnym komputera ogólnego przeznaczenia , działającym na procesorze ogólnego przeznaczenia (rodzina 68000, PowerPC) z obsługą ochrony pamięci przez dziesięciolecia (z wyjątkiem pierwszych komputerów opartych na 68000), które nigdy nie używały ochrony pamięci : dowolny program może uzyskać dostęp do czegokolwiek w pamięci.
ciekawy
3

TL; DR nr

Rozwój Arduino przychodzi na myśl jako obecne środowisko, w którym nie ma systemu operacyjnego. Zaufaj mi, na jednym z tych dzieci nie masz miejsca na system operacyjny.

Podobnie, gry dla Sega Genesis nie miały systemu operacyjnego dostarczonego przez Sega do wywołania. Właśnie stworzyłeś swoją grę w asemblerze 68K, pisząc bezpośrednio na goły metal.

Lub tam, gdzie obciąłem zęby, wykonując pracę wbudowaną w Intel 8051. Ponownie, gdy wszystko, co masz, to 2716 eprom o powierzchni 2k * 8, nie masz miejsca na system operacyjny.

Oczywiście zakłada to bardzo szerokie użycie słowa. Jako pytanie retoryczne warto zadać sobie pytanie, czy szkic Arduino jest aplikacją.

dgnuff
źródło
3

Chociaż nie chcę sugerować, że inne odpowiedzi nie są właściwe same w sobie, zawierają one zbyt wiele szczegółów, które, obawiam się, są dla ciebie bardzo niejasne.

Podstawowa odpowiedź jest taka, że ​​kod zostanie wykonany bezpośrednio na procesorze. I nie, kod maszynowy nie będzie z nikim „rozmawiał”, jest na odwrót. Procesor jest aktywnym składnikiem i wszystko, co robisz na komputerze, zostanie wykonane przez ten procesor (nieco upraszczam, ale na razie jest OK). Procesor odczyta kod, wykona go i wypluje wyniki, kod maszynowy jest po prostu pokarmem dla procesora.

Twoje zamieszanie wynika z użycia słowa sprzęt. Chociaż podział nie jest tak wyraźny, jak kiedyś, lepiej jest myśleć o urządzeniach peryferyjnych niż po prostu nazywać wszystko sprzętem. Tak więc, jeśli na twoim komputerze jest system operacyjny lub podobny, twój program musi korzystać z jego usług w celu uzyskania dostępu do urządzeń peryferyjnych, ale sam procesor nie jest urządzeniem peryferyjnym, jest to główna jednostka przetwarzająca, na której program działa bezpośrednio.

Jądra, systemy operacyjne i podobne warstwy pośredniczące są zwykle używane tylko w większych systemach, w których oczekuje się, że uruchomi się kilka programów, i system musi zarządzać sposobem, w jaki te programy mogą korzystać z urządzeń peryferyjnych komputera (dość często na w tym samym czasie). W takich przypadkach uruchomione programy mogą uzyskiwać dostęp do tych urządzeń peryferyjnych tylko za pomocą systemu, który zdecyduje, jak je udostępnić i upewni się, że nie wystąpią konflikty. Małe systemy, w których nie ma potrzeby zarządzania między konkurującymi programami, ponieważ ich nie ma, często nie mają żadnego systemu bazowego, a pojedynczy program normalnie działający na tych systemach jest mniej lub bardziej wolny, aby robić wszystko, co chce z urządzeniami peryferyjnymi.

Gábor
źródło
2

System BIOS, który działa na komputerze podczas uruchamiania, to kod wykonywalny przechowywany w pamięci ROM. Składa się z instrukcji maszyny i danych. Istnieje kompilator (lub asembler), który składa ten BIOS z kodu źródłowego. To jest szczególny przypadek.

Inne specjalne przypadki obejmują program ładujący ładujący jądro i samo jądro. Te specjalne przypadki są na ogół kodowane w języku innym niż C ++.

W ogólnym przypadku znacznie bardziej praktyczne jest, aby kompilator generował instrukcje wywołujące usługi systemowe dostarczane przez jądro lub procedury biblioteczne. Dzięki temu kompilator jest znacznie lżejszy. Sprawia również, że skompilowany kod jest mniejszy.

Na drugim końcu spektrum jest Java. W Javie kompilator nie tłumaczy kodu źródłowego na instrukcje maszynowe, jak zwykle rozumie się ten termin. Zamiast tego kod źródłowy jest tłumaczony na „instrukcje maszyny” dla wyobrażonej maszyny, zwanej Java Virtual Machine. Przed uruchomieniem programu Java należy go połączyć z środowiskiem wykonawczym Java, który zawiera interpreter wirtualnej maszyny Java.

Walter Mitty
źródło
2

W dawnych dobrych czasach twój program był odpowiedzialny za robienie wszystkiego, co trzeba było zrobić podczas wykonywania programu, albo robiąc to sam, albo dodając kod biblioteki napisany przez innych do twojego programu. Jedyną rzeczą, która działała obok tego na komputerze, był kod do odczytania w skompilowanym programie - jeśli miałeś szczęście. Niektóre komputery musiały mieć kod wprowadzony za pomocą przełączników, aby móc wykonać więcej (oryginalny proces „bootstrap”), lub nawet cały program wszedł w ten sposób.

Szybko okazało się, że miło jest mieć działający kod zdolny do ładowania i wykonywania programu. Później ustalono, że komputery były wystarczająco mocne, aby obsługiwać uruchamianie kilku programów jednocześnie, przełączając procesor między nimi, szczególnie jeśli sprzęt mógł pomóc, ale z dodatkową złożonością programów, które nie przyspieszały sobie nawzajem palców (na przykład , jak obsługiwać wiele programów próbujących jednocześnie wysłać dane do drukarki?).

Wszystko to spowodowało, że duża część kodu pomocnika została przeniesiona z poszczególnych programów do „systemu operacyjnego”, ze znormalizowanym sposobem wywoływania kodu pomocnika z programów użytkownika.

I tu jesteśmy dzisiaj. Twoje programy działają na pełnych obrotach, ale ilekroć potrzebują czegoś zarządzanego przez system operacyjny, wywołują procedury pomocnicze dostarczone przez system operacyjny, a ten kod nie jest potrzebny i nie jest obecny w samych programach użytkownika. Obejmowało to pisanie na wyświetlaczu, zapisywanie plików, dostęp do sieci itp.

Napisano mikrojądra, które zapewniają dokładnie to, co jest potrzebne do uruchomienia danego programu bez pełnego systemu operacyjnego. Ma to pewne zalety dla doświadczonych użytkowników, jednocześnie rozdając większość innych. Możesz przeczytać na ten temat stronę w Wikipedii - https://en.wikipedia.org/wiki/Microkernel - jeśli chcesz dowiedzieć się więcej.

Eksperymentowałem z Microkernelem zdolnym do uruchamiania wirtualnej maszyny Java, ale później odkryłem, że najlepszym miejscem do tego jest Docker.

Thorbjørn Ravn Andersen
źródło
1

W typowych systemach operacyjnych sam jądro jest plikiem wykonywalnym. (Windows ma ntoskrnl.exe; Linux ma vmlinuxitp.) Jeśli potrzebujesz jądra, aby uruchomić plik wykonywalny, te systemy operacyjne nie mogą istnieć.

Jądro potrzebujesz do robienia rzeczy, które robi jądro. Zezwalaj na uruchamianie wielu plików wykonywalnych jednocześnie, ocenianie między nimi, wyodrębnianie sprzętu itp. Większość programów nie jest w stanie samodzielnie wykonywać tych czynności w sposób kompetentny, a nie chciałbyś, aby to robiły, nawet gdyby mogły. W czasach DOS-a, który ledwo można nazwać samym systemem operacyjnym, gry często używały systemu operacyjnego jako niewiele więcej niż modułu ładującego i bezpośrednio uzyskiwały dostęp do sprzętu, podobnie jak jądro. Ale często musiałeś wiedzieć, jakie marki i modele sprzętu były w twojej maszynie, zanim kupiłeś grę. Wiele gier obsługiwało tylko niektóre rodziny kart wideo i dźwiękowych i działało bardzo źle na konkurencyjnych markach, jeśli w ogóle działały. Że'

cHao
źródło