Braucht eine ausführbare Datei einen Betriebssystemkern, um ausgeführt zu werden?

8667
GRANZER

Ich weiß, dass der Compiler beim Kompilieren des Quellcodes, etwa in C ++, den Maschinencode (ausführbar) ist, von dem ich dachte, dass er Anweisungen an die CPU direkt waren. Vor kurzem las ich über Kernel nach und fand heraus, dass Programme nicht direkt auf die Hardware zugreifen können, sondern den Kernel durchlaufen müssen.

Wenn wir also einfachen Quellcode kompilieren, beispielsweise mit einer printf()Funktion, und die Kompilierung den ausführbaren Maschinencode erzeugt, wird jeder Befehl in diesem Maschinencode direkt aus dem Speicher ausgeführt (sobald der Code vom Betriebssystem in den Speicher geladen wird) oder werden muss jeder Befehl im Maschinencode noch durch das Betriebssystem (Kernel) laufen, um ausgeführt zu werden?

Ich habe eine ähnliche Frage gelesen . Es erklärte nicht, ob der Maschinencode, der nach der Kompilierung generiert wird, eine Anweisung an die CPU direkt ist oder ob er erneut durch den Kernel gehen muss, um die korrekte Anweisung für die CPU zu erstellen. Dh was passiert, nachdem der Maschinencode in den Speicher geladen wurde? Wird es durch den Kernel gehen oder direkt mit dem Prozessor sprechen?

52
Wenn Sie Code für ein Arduino schreiben, benötigen Sie kein Betriebssystem. stib vor 5 Jahren 29
`printf` ist kein gutes Beispiel. Sie wird von der C-Spezifikation explizit als Funktion definiert, die nur in "gehosteten" Implementierungen verfügbar ist (dh, sie werden auf einem Kernel ausgeführt und nicht als "freestanding", was möglicherweise keine erfordert). Auf den meisten Plattformen ist `printf 'nur eine Funktion, die von Ihrer` libc` zur Verfügung gestellt wird und für Sie eine Menge Dinge erledigt (was schließlich einen syscall zum Drucken an stdout beinhaltet). Es unterscheidet sich nicht wirklich vom Aufruf von `libvlc_media_list_add_media` oder` PyObject_GetAttr`, nur dass einige `printf`-Implementierungen garantiert linkbar sind, ohne dass zusätzliche nicht-standardmäßige` -l`s hinzugefügt werden. abarnert vor 5 Jahren 12
Das existiert! (nicht angeschlossen, dachte nur, es sei cool) http://www.erikyyy.de/invaders/ Nonny Moose vor 5 Jahren 1
Dies hängt wirklich von Ihrer genauen Definition der Begriffe "ausführbar", "Kernel", "Ausführen", "Bedarf", "Sprechen mit" und "Durchlaufen" ab. Ohne eine genaue Definition dieser Begriffe ist die Frage nicht zu beantworten. Jörg W Mittag vor 5 Jahren 9
@ JörgWMittag - Wenn du pedantisch bist, warum untersuchst du dann nur diese Begriffe und nur diese Frage? Der wirklich herausragende Begriff, der definiert werden muss, ist "Betriebssystem", der fragwürdig auf MS-DOS (und ähnliche Single-Task-Laufzeitumgebungen) angewendet wird. Wenn es ein paar (falsch informierte) Leute gibt, die glauben, dass das [PC BIOS ein Betriebssystem] ist (https://superuser.com/questions/424892/is-bios-considered-an-os), dann steht Ihnen alles zur Verfügung? Ich denke nicht. Das OP verwendet diese Wörter in einem Kontext, der entweder vernünftig (insbesondere wenn nicht englischer Muttersprachler) oder nicht-technischer erscheint. sawdust vor 5 Jahren 3
"Mit nur einer" printf () "- Funktion" - Sie unterschätzen genau, wie viel Komplexität sich hinter "einer Funktion, die die Ausgabe ausführt" verbirgt. Es ist wahrscheinlich durch Verknüpfen mit einer Bibliothek verfügbar - und eine Bibliotheks-ABI und -Links sind etwas, das das Betriebssystem beim Laden einer ausführbaren Datei angibt - und zur Implementierung einer Implementierung der C-Standardbibliothek werden möglicherweise Syscalls verwendet, mit denen der Betriebssystemkern aufgefordert wird, die Daten zu schreiben zu Geräten. millimoose vor 5 Jahren 0
Natürlich muss dies alles nicht passieren, da die Implementierung der C-Standardbibliothek für ein eingebettetes Gerät Code enthalten könnte, der den letzten Teil direkt ausführt, und der Compiler für ein eingebettetes System alles statisch verknüpft, sodass es sich eigentlich nur um einen Stream handelt von Anweisungen, die direkt auf der CPU ausgeführt werden. Dies ist jedoch ein Sonderfall für Hardware, die normalerweise ohne Betriebssystem ausgeführt wird, und Sie benötigen dazu eine Toolchain. millimoose vor 5 Jahren 1
Wenn Sie dies beim Retro-Computing-Stack gefragt hätten, hätten Sie viele Antworten erhalten, wie Computer verwendet wurden, bevor Festplattenlaufwerke üblich waren. Viele (die meisten?) Programme liefen ohne Betriebssystem. Sie haben die Programmdiskette eingelegt und den Computer eingeschaltet, der direkt in das Programm gebootet wurde. Es gab keine Ausfahrt zu einem Betriebssystem. Als Sie fertig waren, haben Sie den Computer ausgeschaltet. Sie können auch die Laufwerke wechseln und den IPL-Interrupt (Initial Program Load) manuell senden, der auf IBM PCs und kompatiblen Computern mit STRG-ALT-DEL ausgeführt wurde. Dies würde das System kurz starten und die neue Festplatte booten. Todd Wilcox vor 5 Jahren 1

11 Antworten auf die Frage

85
sawdust

Als jemand, der Programme geschrieben hat, die ohne Betriebssystem laufen, gebe ich eine definitive Antwort.

Braucht eine ausführbare Datei einen Betriebssystemkern, um ausgeführt zu werden?

Das hängt davon ab, wie das Programm geschrieben und gebaut wurde.
Sie könnten ein Programm schreiben (vorausgesetzt, Sie verfügen über das Wissen), das überhaupt kein Betriebssystem erfordert.
Ein solches Programm wird als eigenständig bezeichnet .
Bootloader und Diagnoseprogramme sind typische Anwendungen für eigenständige Programme.

Ein typisches Programm, das in einer Host-Betriebssystemumgebung geschrieben und eingebaut wurde, würde jedoch standardmäßig in derselben Host-Betriebssystemumgebung ausgeführt.
Es sind sehr explizite Entscheidungen und Aktionen erforderlich, um ein eigenständiges Programm zu schreiben und zu erstellen.


... die Ausgabe des Compilers ist der Maschinencode (ausführbar), von dem ich dachte, dass er Anweisungen an die CPU direkt waren.

Richtig.

Vor kurzem las ich über Kernel nach und fand heraus, dass Programme nicht direkt auf die Hardware zugreifen können, sondern den Kernel durchlaufen müssen.

Diese Einschränkung wird durch einen CPU-Modus auferlegt, den das Betriebssystem zum Ausführen von Programmen verwendet, und wird durch bestimmte Build-Tools wie Compiler und Bibliotheken erleichtert.
Es ist keine intrinsische Einschränkung für jedes Programm, das jemals geschrieben wurde.


Wenn wir also einfachen Quellcode kompilieren, beispielsweise mit einer printf () - Funktion, und die Kompilierung den ausführbaren Maschinencode erzeugt, wird jeder Befehl in diesem Maschinencode direkt aus dem Speicher ausgeführt (sobald der Code vom Betriebssystem in den Speicher geladen wird) ) oder muss jeder Befehl im Maschinencode noch durch das Betriebssystem (Kernel) laufen, um ausgeführt zu werden?

Jede Anweisung wird von der CPU ausgeführt.
Eine Anweisung, die nicht unterstützt oder unzulässig ist (z. B. hat der Prozess keine ausreichenden Berechtigungen), führt zu einer sofortigen Ausnahme und die CPU führt stattdessen eine Routine aus, um diesen ungewöhnlichen Zustand zu behandeln.

Eine printf () - Funktion sollte nicht als Beispiel für "einfachen Quellcode" verwendet werden .
Die Übersetzung von einer objektorientierten übergeordneten Programmiersprache in Maschinencode ist möglicherweise nicht so unbedeutend, wie Sie meinen.
Und dann wählen Sie eine der komplexesten Funktionen aus einer Laufzeitbibliothek, die Datenkonvertierungen und E / A durchführt.

Beachten Sie, dass Ihre Frage eine Umgebung mit einem Betriebssystem (und einer Laufzeitbibliothek) festlegt.
Sobald das System hochgefahren ist und das Betriebssystem die Kontrolle über den Computer hat, sind die Möglichkeiten für ein Programm eingeschränkt (zB E / A muss vom Betriebssystem ausgeführt werden).
Wenn Sie davon ausgehen, ein eigenständiges Programm auszuführen (dh ohne Betriebssystem), müssen Sie den Computer nicht starten, um das Betriebssystem auszuführen.


... was passiert, nachdem der Maschinencode in den Speicher geladen wurde?

Das hängt von der Umgebung ab.

Bei einem Standalone-Programm kann es ausgeführt werden, dh die Steuerung wird durch Springen an die Startadresse des Programms übergeben.

Für ein vom Betriebssystem geladenes Programm muss das Programm dynamisch mit den gemeinsam genutzten Bibliotheken verknüpft sein, von denen es abhängig ist. Das Betriebssystem muss einen Ausführungsbereich für den Prozess erstellen, der das Programm ausführen soll.

Wird es durch den Kernel gehen oder direkt mit dem Prozessor sprechen?

Maschinencode wird ausgeführt durch die CPU.
Sie "gehen nicht durch den Kernel", aber sie sprechen auch nicht mit dem Prozessor .
Der Maschinencode (bestehend aus Operationscode und Operanden) ist eine Anweisung an die CPU, die dekodiert wird und die Operation ausgeführt wird.

Das nächste Thema, das Sie untersuchen sollten, sind die CPU-Modi .

"Wenn Sie davon ausgehen, ein eigenständiges Programm (dh ohne Betriebssystem) auszuführen, müssen Sie den Computer nicht starten, um das Betriebssystem auszuführen." ist nicht ganz richtig. Viele DOS-Programme wurden nach DOS geladen und dann vollständig von DOS-Diensten ignoriert (durch direktes Bit-Banging oder vielleicht direktes Aufrufen des BIOS). Win3.x ist ein hervorragendes Beispiel, das (außer in einigen interessanten Eckfällen) ignorierte, dass DOS vorhanden war. Win95 / 98 / Me hat das auch gemacht. Es gibt viele Beispiele für Betriebssysteme, die Standalone-Programme unterstützen, viele aus der 8- / 16-Bit-Ära. Eric Towers vor 5 Jahren 2
@EricTowers - Mit * "DOS" * meinen Sie vermutlich MS-DOS (da ich DOS verwendet habe, die nicht mit MS oder Intel verwandt sind)? Sie zitieren ein "OS", das nicht einmal den Kriterien meiner College-Lehrbücher der 1970er Jahre zu Betriebssystemkonzepten und -design entspricht. Die Ursprünge von MS-DOS gehen (durch Seattle Computer Products) auf CP / M zurück, das von seinem Autor Gary Kildall explizit nicht als Betriebssystem bezeichnet wird. FWIW ein Betriebssystem, das einem Programm die Übernahme des Systems ermöglicht, ist in seiner grundlegenden Funktion der Verwaltung der Systemressourcen ausgefallen. * "Es gibt viele Beispiele für Betriebssysteme, die Standalone-Programme unterstützen" * - * "Support" * oder nicht verhindern können? sawdust vor 5 Jahren 8
... oder [ProDOS] (https://en.wikipedia.org/wiki/Apple_ProDOS) oder [PC-DOS] (https://en.wikipedia.org/wiki/IBM_PC_DOS) oder [DR-DOS] ( https://en.wikipedia.org/wiki/DR-DOS) oder [CBM DOS] (https://en.wikipedia.org/wiki/Commodore_DOS) oder [TRS DOS] (https: //en.wikipedia). org / wiki / TRSDOS) oder [FLEX] (https://en.wikipedia.org/wiki/FLEX_ (Betriebssystem)) ... Eric Towers vor 5 Jahren 5
Ich mag die "freistehende" Terminologie von GCC. Das englische Wort hat alle richtigen Konnotationen für Code, der ohne Betriebssystem läuft, vielleicht sogar besser als "Standalone". Sie können zum Beispiel `gcc -O2 -ffreestanding my_kernel.c special_sauce.S` kompilieren, um eine ausführbare Datei zu erstellen, die nicht von normalen Bibliotheken oder Betriebssystemen ausgeht. (Natürlich benötigen Sie normalerweise ein Linker-Skript, um eine Verknüpfung zu einem Dateiformat herzustellen, das ein Bootloader laden soll!) Peter Cordes vor 5 Jahren 3
@EricTowers - Warum sollten Sie archaische Single-Task-Laufzeitumgebungen auflisten, wenn jedes Betriebssystem, das keine MMU verwendet (z. B. uClinux, auch "Linux ohne MMU"), das System nicht vor einem Schurkenprogramm schützen kann? Aber das OP hat eindeutig ein sicheres Betriebssystem im Sinn, das geschützte CPU-Modi und MMU verwendet, so dass Ihr Exkurs pedantisch ist. sawdust vor 5 Jahren 1
@ PeterCordes - Das sind interessante Informationen zu GCC, aber ich teile Ihre Begeisterung für diese Terminologie nicht. Da die Konnotation eines Wortes das beinhaltet, was es nicht impliziert, betrachten Sie die Antonyme jedes Wortes .powerthesaurus.org / standalone / antonyms). Das (was ist oder nicht) Adjektiv / Substantiv "standalone" scheint viel kürzer als "freistehend" zu sein. sawdust vor 5 Jahren 0
Ich finde, dass "Standalone Executable" so aussieht, als könnte es auf etwas zutreffen, das nicht auf Bibliotheken oder andere Programme angewiesen ist (z. B. eine statische Binärdatei oder einfach das Einfügen einer Funktion eines größeren Programms in eine ausführbare Datei). Dies bedeutet nicht zwangsläufig, dass es nicht auf Betriebssystemaufrufen des Betriebssystems angewiesen ist, es sei denn, der Kontext oder die Definition des Kontextes sagt Ihnen dies. Ich denke, dass das Freistehende das gleiche Problem haben könnte. Ich behaupte nicht, dass "freistehend" korrekter oder weit verbreiteter ist, aber ich mag es. Es ist ein weniger gebräuchliches Wort, daher gibt es im Computer nicht so viele Anwendungen. Jedem das Seine! Peter Cordes vor 5 Jahren 1
@sawdust: Ich bin nicht sicher, ob es wirklich fair ist, eine Wortwahl anhand eines beschissenen Thesaurus-Eintrags zu beurteilen? "Freistehend" und "Mitten" sind keine Antonyme in einem sinnvollen Sinn (sie sind nicht einmal derselbe Teil der Sprache) und in ähnlicher Weise für viele der anderen Einträge auf dieser Seite. psmears vor 5 Jahren 2
@PeterCordes "Standalone" ist der im C-Standard verwendete Begriff, den IMO als etwas autoritär betrachten kann. Alternativ ist ein guter Begriff auch "nicht gehostet" (wie vom Betriebssystem gehostet). Jan Dorniak vor 5 Jahren 4
Ich bin mir nicht sicher, ich denke, der Großteil davon hängt davon ab, wie Sie ein "OS" definieren. Wenn Sie zum Beispiel einen Bootloader schreiben, ist das nur ein Programm oder schreiben Sie tatsächlich das Betriebssystem selbst? Am Ende ist sogar das BIOS ein Programm, aber es ist eigentlich auch ein Betriebssystem für sich. ChatterOne vor 5 Jahren 0
38
Mokubai

Der Kernel ist "nur" mehr Code. Es ist nur so, dass dieser Code eine Schicht ist, die sich zwischen den untersten Teilen Ihres Systems und der tatsächlichen Hardware befindet.

Alles läuft direkt auf der CPU, Sie wechseln einfach durch mehrere Ebenen, um alles zu tun.

Ihr Programm "benötigt" den Kernel genauso, wie er die Standard-C-Bibliotheken benötigt, um den Befehl überhaupt zu verwenden printf.

Der eigentliche Code Ihres Programms wird auf der CPU ausgeführt, aber die Verzweigungen, die der Code für den Ausdruck auf dem Bildschirm benötigt, durchlaufen den Code für die C- printfFunktion, durch verschiedene andere Systeme und Interpreter, die jeweils ihre eigene Verarbeitung durchführen, um genau zu erfahren, wie hello world! wird tatsächlich auf Ihrem Bildschirm gedruckt.

Angenommen, Sie haben ein Terminalprogramm, das auf einem Desktop-Fenstermanager ausgeführt wird, der auf Ihrem Kernel ausgeführt wird, der wiederum auf Ihrer Hardware ausgeführt wird.

Es gibt noch viel mehr, aber es bleibt einfach ...

  1. In Ihrem Terminalprogramm führen Sie Ihr Programm zum Drucken aus hello world!
  2. Das Terminal sieht, dass das Programm (über die C-Ausgaberoutinen) hello world!an die Konsole geschrieben hat
  3. Das Terminalprogramm geht auf den Desktop Window - Manager auf und sagt : „Ich habe hello world!mich geschrieben, können Sie es an Position setzen x, ybitte?“
  4. Der Desktop-Fenstermanager geht mit dem Kernel zum Kernel über: "Eines meiner Programme möchte, dass Ihr Grafikgerät an dieser Position etwas Text einfügt.
  5. Der Kernel leitet die Anforderung an den Treiber für Grafikgeräte weiter, der sie so formatiert, dass sie von der Grafikkarte verstanden werden kann
  6. Abhängig davon, wie die Grafikkarte angeschlossen ist, müssen andere Kernel-Gerätetreiber aufgerufen werden, um die Daten auf physischen Gerätebussen wie PCIe auszutauschen. So kann beispielsweise sichergestellt werden, dass das richtige Gerät ausgewählt ist und die Daten durch die entsprechende Bridge oder durchlaufen werden Konverter
  7. Die Hardware zeigt Sachen an.

Dies ist eine massive Vereinfachung nur zur Beschreibung. Hier sei Drachen.

Alles, was Sie tun, das Hardware-Zugriff erfordert, sei es Anzeige, Speicherblöcke, Dateibits oder ähnliches, muss durch einen Gerätetreiber im Kernel geführt werden, um genau zu wissen, wie Sie mit dem entsprechenden Gerät sprechen. Sei es ein Dateisystemtreiber auf einem SATA-Festplattencontrollertreiber, der sich selbst auf einem PCIe-Bridge-Gerät befindet.

Der Kernel weiß, wie man all diese Geräte miteinander verbindet, und stellt eine relativ einfache Schnittstelle für Programme bereit, die Dinge erledigen können, ohne dass sie wissen müssen, wie sie all diese Dinge selbst erledigen.

Desktop-Fenstermanager bieten eine Ebene, die bedeutet, dass Programme nicht wissen müssen, wie sie Fenster zeichnen und gut mit anderen Programmen spielen, die versuchen, Dinge gleichzeitig anzuzeigen.

Schließlich bedeutet das Terminalprogramm, dass Ihr Programm nicht wissen muss, wie ein Fenster zu zeichnen ist, wie es mit dem Kernel-Grafiktreiber zu sprechen ist, und wie kompliziert es ist, mit Bildschirmpuffern und Anzeige-Timing umzugehen und tatsächlich zu wackeln Datenzeilen zur Anzeige.

Es wird alles von Schichten auf Codeebenen gehandhabt.

Nicht nur * Hardware * -Zugang, die meiste Kommunikation * zwischen * Programmen läuft auch über den Kernel; Das, an dem der Kernel normalerweise nicht beteiligt ist, richtet einen direkteren Kanal ein. Für die Zwecke der Frage ist es jedoch auch möglich und praktiziert, in viel einfacheren Fällen den gesamten Code in einem einzigen Programm zu verdichten. Chris Stratton vor 5 Jahren 0
Tatsächlich muss Ihr Terminalprogramm nicht einmal auf demselben Computer ausgeführt werden wie das Programm, mit dem Daten geschrieben werden. jamesqf vor 5 Jahren 0
Da dies in dieser Frage möglicherweise explizit angegeben werden muss, beachten Sie, dass es metaphorisch ist, wenn wir über Programme sprechen, die miteinander "sprechen". user20574 vor 5 Jahren 0
21
Jamie Hanrahan

Das hängt von der Umgebung ab. Bei vielen älteren (und einfacheren!) Computern wie dem IBM 1401 lautet die Antwort "Nein". Ihr Compiler und Linker sendeten eine eigenständige "Binärdatei", die überhaupt ohne Betriebssystem lief. Wenn Ihr Programm nicht mehr lief, haben Sie ein anderes geladen, das auch ohne Betriebssystem lief.

In modernen Umgebungen ist ein Betriebssystem erforderlich, da Sie nicht jeweils nur ein Programm ausführen. Die gemeinsame Nutzung des CPU-Kerns, des Arbeitsspeichers, des Massenspeichergeräts, der Tastatur, der Maus und der Anzeige unter mehreren Programmen gleichzeitig erfordert Koordination. Das OS bietet das. In einer modernen Umgebung kann Ihr Programm also nicht einfach die Festplatte oder SSD lesen und schreiben, sondern muss das Betriebssystem dazu auffordern. Das Betriebssystem erhält solche Anforderungen von allen Programmen, die auf das Speichergerät zugreifen möchten, implementiert etwa Zugriffssteuerungen (kann nicht zulassen, dass normale Benutzer in die Dateien des Betriebssystems schreiben), stellt sie auf das Gerät in eine Warteschlange und sortiert die zurückgegebenen Informationen aus zu den richtigen Programmen (Prozessen).

Darüber hinaus unterstützen moderne Computer (im Gegensatz zum Beispiel 1401) die Anbindung unterschiedlichster E / A-Geräte, nicht nur derer, die IBM Ihnen früher verkaufen würde. Ihr Compiler und Linker können nicht alle Möglichkeiten kennen. Beispielsweise kann Ihre Tastatur über PS / 2 oder USB angeschlossen werden. Mit dem Betriebssystem können Sie gerätespezifische "Gerätetreiber" installieren, die wissen, wie sie mit diesen Geräten kommunizieren, dem Betriebssystem jedoch eine gemeinsame Schnittstelle für die Geräteklasse bieten. Ihr Programm und sogar das Betriebssystem müssen also nichts anderes tun, um Tastatureingaben von einer USB-Tastatur über eine PS / 2-Tastatur zu erhalten, oder um beispielsweise auf eine lokale SATA-Festplatte oder ein USB-Speichergerät zuzugreifen und Speicherplatz abzuspeichern auf einem NAS oder SAN. Diese Details werden von Gerätetreibern für die verschiedenen Gerätesteuerungen verarbeitet.

Für Massenspeichergeräte bietet das Betriebssystem auf allen einen Dateisystemtreiber an, der für Verzeichnisse und Dateien die gleiche Schnittstelle bietet, unabhängig davon, wo und wie der Speicher implementiert wird. Und wieder macht sich das Betriebssystem Sorgen um Zugriffskontrollen und Serialisierung. Im Allgemeinen sollte zum Beispiel dieselbe Datei nicht zum Schreiben von mehr als einem Programm gleichzeitig geöffnet werden, ohne durch einige Blöcke zu springen (aber gleichzeitiges Lesen ist im Allgemeinen in Ordnung).

Ja, in einer modernen, universellen Umgebung benötigen Sie ein Betriebssystem. Aber auch heute gibt es Computer wie Echtzeit-Controller, die nicht kompliziert genug sind, um einen zu benötigen.

In der Arduino-Umgebung gibt es beispielsweise kein Betriebssystem. Sicher, es gibt eine Reihe von Bibliothekscode, den die Build-Umgebung in jede "Binärdatei" integriert, die sie erstellt. Da dieser Code jedoch nicht von einem Programm zum anderen persistent ist, handelt es sich nicht um ein Betriebssystem.

10
Artelius

Ich denke, viele Antworten missverstehen die Frage, die darauf hinausläuft:

Ein Compiler gibt Maschinencode aus. Wird dieser Maschinencode direkt von einer CPU ausgeführt oder vom Kernel "interpretiert"?

Grundsätzlich führt die CPU den Maschinencode direkt aus . Es wäre wesentlich langsamer, wenn der Kernel alle Anwendungen ausführen würde. Es gibt jedoch einige Vorbehalte.

  1. Wenn ein Betriebssystem vorhanden ist, dürfen Anwendungsprogramme normalerweise keine Anweisungen ausführen oder auf bestimmte Ressourcen zugreifen. Wenn zum Beispiel eine Anwendung eine Anweisung ausführt, die die System-Interrupt-Tabelle modifiziert, springt die CPU stattdessen zu einem OS-Ausnahmebehandler, so dass die störende Anwendung beendet wird. Außerdem dürfen Anwendungen normalerweise nicht in den Gerätespeicher lesen / schreiben. (Dh "mit der Hardware sprechen".) Beim Zugriff auf diese speziellen Speicherbereiche kommuniziert das Betriebssystem mit Geräten wie Grafikkarte, Netzwerkschnittstelle, Systemuhr usw.

  2. Die Einschränkungen, die ein Betriebssystem für Anwendungen auferlegt, werden durch spezielle Funktionen der CPU wie Privilegienmodi, Speicherschutz und Interrupts erreicht. Jede CPU, die Sie in einem Smartphone oder PC finden würden, verfügt zwar über diese Funktionen, bestimmte CPUs jedoch nicht. Diese CPUs benötigen in der Tat spezielle Kernel, die Anwendungscode "interpretieren", um die gewünschten Funktionen zu erreichen. Ein sehr interessantes Beispiel ist der Gigatron, ein Computer mit 8 Anweisungen, den Sie aus Chips bauen können, der einen Computer mit 34 Anweisungen emuliert.

  3. Einige Sprachen wie Java "kompilieren" zu etwas namens Bytecode, bei dem es sich nicht wirklich um Maschinencode handelt. Obwohl sie früher für die Ausführung der Programme interpretiert wurden, wird in der Regel eine so genannte Just-in-Time-Kompilierung verwendet, sodass sie als Maschinencode direkt auf der CPU ausgeführt werden.

  4. Das Ausführen von Software in einer virtuellen Maschine erforderte früher, dass der Maschinencode von einem Programm namens Hypervisor "interpretiert" wird . Aufgrund der großen Nachfrage der Industrie nach VMs haben CPU-Hersteller ihre CPUs um Funktionen wie VTx erweitert, sodass die meisten Anweisungen eines Gastsystems direkt von der CPU ausgeführt werden können. Wenn Sie jedoch Software ausführen, die für eine inkompatible CPU in einer virtuellen Maschine entwickelt wurde (z. B. eine NES-Emulation), muss der Maschinencode interpretiert werden.

Obwohl der Bytecode von Java normalerweise nicht der Maschinencode ist, gibt es immer noch [Java-Prozessoren] (https://en.wikipedia.org/wiki/Java_processor). Ruslan vor 5 Jahren 1
Hypervisoren waren nie immer Dolmetscher. Eine Interpretation ist natürlich erforderlich, wenn die virtuelle Maschine als mit ihrem Host inkompatibler Befehlssatz ausgeführt wird. Bei der Ausführung derselben Architektur führen jedoch auch frühe Hypervisoren Code direkt auf der CPU aus (Sie können verwirrt sein, wenn paravirtualisierte Kernel für CPUs ohne verwendet werden die notwendige Hypervisor-Unterstützung). Toby Speight vor 5 Jahren 0
5
Alex

Wenn Sie Ihren Code kompilieren, erstellen Sie einen sogenannten "Objekt" -Code, der (in den meisten Fällen) von Systembibliotheken abhängt ( printfz. B.). Anschließend wird Ihr Code von einem Linker umschlossen, der eine Art Programmladeprogramm hinzufügt, das Ihr Betriebssystem verwenden kann erkennen (deshalb können Sie beispielsweise kein Programm ausführen, das für Windows unter Linux kompiliert wurde) und wissen, wie Sie Ihren Code auspacken und ausführen. Ihr Programm ist also wie ein Fleisch in einem Sandwich und kann nur als Bündel insgesamt gegessen werden.

Vor kurzem las ich über Kernels und fand heraus, dass Programme nicht direkt auf die Hardware zugreifen können, sondern den Kernel durchlaufen müssen.

Nun, es ist halbwegs wahr; Wenn Ihr Programm ein Kernelmodustreiber ist, können Sie tatsächlich direkt auf die Hardware zugreifen, wenn Sie wissen, wie Sie mit der Hardware "sprechen". In der Regel (vor allem bei nicht dokumentierter oder komplizierter Hardware) wird jedoch ein Treiber verwendet, bei dem es sich um Kernel-Bibliotheken handelt. Auf diese Weise können Sie API-Funktionen finden, die wissen, wie sie mit der Hardware auf nahezu lesbare Weise kommunizieren können, ohne Adressen, Register, Timing und viele andere Dinge zu kennen.

wird jede Anweisung in diesem Maschinencode direkt aus dem Speicher ausgeführt (sobald der Code vom Betriebssystem in den Speicher geladen wurde) oder muss jeder Befehl im Maschinencode noch durch das Betriebssystem (Kernel) laufen, um ausgeführt zu werden

Nun, der Kernel ist eine Kellnerin, deren Aufgabe es ist, Sie an einen Tisch zu bringen und Ihnen zu dienen. Das einzige, was es nicht kann - es ist für Sie zu essen, das sollten Sie selbst tun. Das gleiche gilt für Ihren Code: Der Kernel entpackt Ihr Programm in einen Speicher und startet Ihren Code, den Maschinencode, der direkt von der CPU ausgeführt wird. Ein Kernel muss Sie nur überwachen - was Ihnen erlaubt ist und was Sie nicht dürfen.

es nicht erklären, ob der Maschinencode, der nach der Kompilierung generiert wird, eine Anweisung an die CPU direkt ist, oder muss er erneut durch den Kernel gehen, um die korrekte Anweisung für die CPU zu erstellen?

Maschinencode, der nach der Kompilierung generiert wird, ist eine Anweisung an die CPU direkt. Daran besteht kein Zweifel. Das einzige, was Sie beachten müssen, ist nicht der gesamte Code in der kompilierten Datei der tatsächliche Maschinen- / CPU-Code. Linker hat Ihr Programm mit einigen Metadaten versehen, die nur der Kernel als Hinweis interpretieren kann, was mit Ihrem Programm zu tun ist.

Was passiert, nachdem der Maschinencode in den Speicher geladen wurde? Wird es durch den Kernel gehen oder direkt mit dem Prozessor sprechen.

Handelt es sich bei Ihrem Code lediglich um einfache Opcodes wie das Hinzufügen von zwei Registern, wird er direkt von der CPU ohne Kernelunterstützung ausgeführt. Wenn Ihr Code jedoch Funktionen aus Bibliotheken verwendet, werden solche Aufrufe durch den Kernel unterstützt, wie in der Kellnerin beispielsweise, wenn Sie möchten In einem Restaurant zu essen, gaben sie Ihnen ein Werkzeug - Gabel, Löffel (und es bleibt ihr Vermögen), aber was Sie damit machen werden, ist - bis zu Ihrem "Code".

Nun, nur um Flammen in Kommentaren zu vermeiden - es ist wirklich ein stark vereinfachtes Modell, von dem ich hoffe, dass es der OP hilft, grundlegende Dinge zu verstehen, aber gute Vorschläge zur Verbesserung dieser Antwort sind willkommen.

3
LawrenceC

Wenn wir also einen einfachen Quellcode kompilieren, beispielsweise mit einer Funktion printf (), und die Kompilierung den ausführbaren Maschinencode erzeugt, wird jeder Befehl in diesem Maschinencode direkt aus dem Speicher ausgeführt (sobald der Code in den Speicher geladen ist) von OS) oder muss jeder Befehl im Maschinencode noch durch das Betriebssystem (Kernel) laufen, um ausgeführt zu werden?

Im Wesentlichen gehen nur Systemaufrufe an den Kernel. Alles, was mit E / A oder Speicherzuweisung / -freigabe zu tun hat, führt in der Regel zu einem Systemaufruf. Einige Anweisungen können nur im Kernelmodus ausgeführt werden und bewirken, dass die CPU eine Ausnahme auslöst. Ausnahmen bewirken einen Wechsel in den Kernel-Modus und einen Sprung in den Kernel-Code.

Der Kernel verarbeitet nicht alle Anweisungen in einem Programm. Das System ruft einfach das System auf und wechselt zwischen laufenden Programmen, um die CPU gemeinsam zu nutzen.

Eine Speicherzuweisung im Benutzermodus (ohne Kernel) ist nicht möglich. Wenn Sie auf den Speicher zugreifen, für den Sie keine Zugriffsberechtigung haben, gibt die zuvor vom Kernel programmierte MMU eine Ausnahme auf CPU-Ebene "Segmentierungsfehler" aus, der den Kernel auslöst und der Kernel das Programm beendet.

E / A im Benutzermodus (ohne Kernel) ist nicht möglich. Wenn Sie auf E / A-Ports oder Register für Geräte zugreifen oder Adressen, die mit Geräten verbunden sind (eines oder beide für die E / A-Ausführung erforderlich), lösen diese aus Ausnahme auf die gleiche Weise.


Braucht eine ausführbare Datei einen Betriebssystemkern, um ausgeführt zu werden?

Abhängig von der Art der ausführbaren Datei.

Kernels führen neben dem gemeinsamen Zugriff auf RAM und Hardware auch eine Loader-Funktion aus.

Viele "ausführbare Formate", wie ELF oder PE, enthalten zusätzlich zum Code Metadaten in der ausführbaren Datei und müssen vom Loader verarbeitet werden. Lesen Sie die blutigen Details über Microsofts PE - Format für weitere Informationen.

Diese ausführbaren Dateien verweisen auch auf Bibliotheken ( .dllgemeinsam genutzte Windows- oder Linux-Objektdateien .so) - ihr Code muss enthalten sein.

Wenn Ihr Compiler eine Datei erzeugt, die von einem Betriebssystemlader verarbeitet werden soll, und dieser Lader nicht vorhanden ist, funktioniert er nicht.

  • Können Sie Code einfügen, der die Arbeit des Laders übernimmt?

Sicher. Sie müssen das Betriebssystem dazu bringen, Ihren Rohcode irgendwie auszuführen, ohne Metadaten zu verarbeiten. Wenn Ihr Code Kernel-APIs aufruft, funktioniert es trotzdem nicht.

  • Was ist, wenn Kernel-APIs nicht aufgerufen werden?

Wenn Sie diese ausführbare Datei auf irgendeine Weise von einem Betriebssystem laden (dh wenn Rohcode geladen und ausgeführt werden kann), befindet sich die Anwendung weiterhin im Benutzermodus. Wenn Ihr Code auf Dinge zugreift, die im Benutzermodus im Gegensatz zum Kernelmodus verboten sind, z. B. nicht zugewiesener Speicher oder E / A-Geräteadressen / -register, stürzt er mit Privilegien oder Segmentverletzungen ab (wiederum gehen Ausnahmen in den Kernelmodus über und werden behandelt dort) und funktioniert immer noch nicht.

  • Was ist, wenn Sie es aus dem Kernel-Modus ausführen.

Dann wird es klappen.


Das ist nicht ganz richtig. Das Erfordernis, dass Hardwarezugriff durch den Kernel geht oder dass es sogar einen Kernel gibt, ist eine Entwurfsentscheidung, die heutzutage bei vielen Systemen bejaht wird, aber auch bei vielen einfachen Systemen (bis heute) negativ ist. Chris Stratton vor 5 Jahren 0
Ich erkläre, wie die Dinge aussehen, wenn A) ein Kernel ist und B) wenn Sie Code auf einer CPU mit Benutzer- / Supervisor-Modus und einer MMU ausführen, um dies zu erzwingen. Ja, es gibt CPUs und Mikrocontroller ohne MMUs oder Benutzer- / Supervisor-Modus. Ja, manche Systeme laufen ohne die gesamte Benutzer- / Supervisor-Infrastruktur. Microsofts erste Xbox war so - auch wenn eine Standard-x86-CPU mit Benutzer- / Supervisor-Modus den Kernelmodus verlassen hat, so wie ich es verstehe, konnte das geladene Spiel tun, was es wollte. LawrenceC vor 5 Jahren 0
Das Macintosh-System vor MacOS X war ein Betriebssystem eines * Universalcomputers *, der auf einer Universal-CPU (68000-Familie, PowerPC) mit Unterstützung für Speicherschutz seit Jahrzehnten (mit Ausnahme der ersten 68000-basierten Computer, die meines Erachtens nicht verwendet werden) läuft Speicherschutz: Jedes Programm kann auf alles im Speicher zugreifen. curiousguy vor 5 Jahren 1
3
dgnuff

TL; DR-Nr.

Arduino-Entwicklung ist eine aktuelle Umgebung, in der es kein Betriebssystem gibt. Vertrauen Sie mir, bei einem dieser Babys haben Sie keinen Platz für ein Betriebssystem.

Ebenso hatten Spiele für den Sega Genesis kein Betriebssystem, das von Sega zur Verfügung gestellt wurde. Sie haben Ihr Spiel gerade in 68K Assembler erstellt und direkt auf das blanke Metall geschrieben.

Oder wo ich meine Zähne schneide und Embedded-Arbeiten mit dem Intel 8051 erledige. Wenn Sie nur einen 2716-Eprom mit 2k * 8-Fußabdruck haben, haben Sie keinen Platz für ein Betriebssystem.

Dies setzt natürlich eine sehr breite Verwendung der Wortanwendung voraus. Als rhetorische Frage lohnt es sich zu fragen, ob eine Arduino-Skizze tatsächlich eine Anwendung ist.

3
Gábor

Ich möchte nicht darauf hinweisen, dass die anderen Antworten nicht für sich allein richtig sind, sie liefern jedoch zu viele Details, die Sie, fürchte ich, immer noch sehr undeutlich erscheinen.

Die grundlegende Antwort ist, dass der Code direkt auf dem Prozessor ausgeführt wird. Und nein, der Maschinencode wird mit niemandem "sprechen", er ist umgekehrt. Der Prozessor ist die aktive Komponente und alles, was Sie in Ihrem Computer tun, wird von diesem Prozessor erledigt (ich vereinfache die Dinge hier ein bisschen, aber das ist jetzt in Ordnung). Der Prozessor liest den Code und führt ihn aus und spuckt die Ergebnisse aus. Der Maschinencode ist nur eine Nahrung für den Prozessor.

Ihre Verwirrung beruht auf der Verwendung des Wortes Hardware. Obwohl die Division nicht mehr so ​​eindeutig ist wie früher, ist es besser, wenn Sie in Bezug auf Peripheriegeräte denken, anstatt einfach alles als Hardware zu bezeichnen. Wenn sich auf Ihrem Computer ein Betriebssystem oder ein ähnliches Betriebssystem befindet, muss Ihr Programm seine Dienste für den Zugriff auf die Peripheriegeräte verwenden. Der Prozessor selbst ist jedoch kein Peripheriegerät, sondern die Hauptverarbeitungseinheit, auf der Ihr Programm direkt ausgeführt wird.

Kernel, Betriebssysteme und ähnliche dazwischenliegende Schichten werden normalerweise nur in größeren Systemen verwendet, bei denen zu erwarten ist, dass mehrere Programme ausgeführt werden, und das System muss verwalten können, wie diese Programme die Peripheriegeräte des Computers nutzen können (häufig am Computer) gleiche Zeit). In diesen Fällen können laufende Programme nur über das System auf diese Peripheriegeräte zugreifen, über das sie freigegeben werden, und es wird sichergestellt, dass keine Konflikte auftreten. Kleine Systeme, bei denen keine Verwaltung unter konkurrierenden Programmen erforderlich ist, da keines vorhanden ist, haben sie oft überhaupt kein zugrunde liegendes System, und das einzelne Programm, das normalerweise auf diesen Systemen ausgeführt wird, kann mehr oder weniger frei mit den Peripheriegeräten arbeiten.

2
Walter Mitty

Das BIOS, das beim Einschalten auf Ihrem Computer ausgeführt wird, ist im ROM gespeicherter ausführbarer Code. Es besteht aus Maschinenanweisungen plus Daten. Es gibt einen Compiler (oder Assembler), der dieses BIOS aus Quellcode zusammenstellt. Dies ist ein Sonderfall.

Andere Sonderfälle umfassen das Bootstrap-Programm, das den Kernel und den Kernel selbst lädt. Diese Sonderfälle werden im Allgemeinen in einer anderen Sprache als C ++ codiert.

Im Allgemeinen ist es viel praktischer, wenn der Compiler einige Anweisungen erzeugt, die Systemdienste aufrufen, die von einem Kernel oder von Bibliotheksroutinen bereitgestellt werden. Dadurch wird der Compiler wesentlich leichter. Dadurch wird der kompilierte Code auch leichter.

Am anderen Ende des Spektrums steht Java. In Java übersetzt der Compiler den Quellcode nicht in Maschinenanweisungen, da dieser Begriff normalerweise verstanden wird. Stattdessen wird der Quellcode in "Maschinenanweisungen" für eine imaginäre Maschine, die Java Virtual Machine, übersetzt. Bevor ein Java-Programm ausgeführt werden kann, muss es mit der Java-Laufzeitumgebung kombiniert werden, die einen Interpreter für die Java Virtual Machine enthält.

2
Thorbjørn Ravn Andersen

In den guten alten Tagen war Ihr Programm dafür verantwortlich, alles zu tun, was während der Ausführung Ihres Programms getan werden musste. Entweder indem Sie es selbst tun oder indem Sie Bibliothekscode hinzufügen, den andere zu Ihrem Programm geschrieben haben. Das einzige, was im Computer daneben lief, war der Code, den Sie in Ihrem kompilierten Programm lesen sollten - wenn Sie Glück hatten. Bei einigen Computern musste der Code über Switches eingegeben werden, bevor mehr ausgeführt werden konnte (der ursprüngliche "Bootstrap" -Prozess) oder sogar das gesamte Programm, das auf diese Weise eingegeben wurde.

Es stellte sich schnell heraus, dass es schön war, wenn Code zum Laden und Ausführen von Programmen ausgeführt werden konnte. Später stellte sich heraus, dass Computer so leistungsfähig waren, dass sie die gleichzeitige Ausführung mehrerer Programme unterstützen, indem sie die CPU zwischen ihnen wechseln ließen, insbesondere wenn die Hardware helfen könnte, jedoch mit der zusätzlichen Komplexität der Programme nicht auf die jeweils anderen Zehen (z. B.), wie Sie mit mehreren Programmen umgehen, die versuchen, Daten gleichzeitig an den Drucker zu senden?).

All dies führte dazu, dass eine große Menge von Hilfscode aus den einzelnen Programmen in das "Betriebssystem" verschoben wurde, wobei der Hilfscode auf standardisierte Weise aus Benutzerprogrammen aufgerufen wurde.

Und hier sind wir heute. Ihre Programme laufen mit voller Geschwindigkeit, aber wenn sie etwas benötigen, das vom Betriebssystem verwaltet wird, rufen sie Hilfsroutinen auf, die vom Betriebssystem bereitgestellt werden. Dieser Code wird nicht benötigt und ist nicht in den Benutzerprogrammen selbst enthalten. Dies beinhaltete das Schreiben auf die Anzeige, das Speichern von Dateien, den Zugriff auf das Netzwerk usw.

Es wurden Mikrokerne geschrieben, die genau das bieten, was ein bestimmtes Programm ohne ein vollständiges Betriebssystem ausführen kann. Dies hat einige Vorteile für die erfahrenen Benutzer, während die meisten anderen verschenkt werden. Vielleicht möchten Sie die Wikipedia-Seite dazu lesen - https://en.wikipedia.org/wiki/Microkernel - wenn Sie mehr erfahren möchten.

Ich habe mit einem Microkernel experimentiert, der eine Java Virtual Machine ausführen kann. Später stellte sich jedoch heraus, dass dies der beste Punkt für Docker ist.