Würde eine ausführbare Datei einen Betriebssystemkern benötigen, um ausgeführt zu werden?

53

Ich weiß, dass die Ausgabe des Compilers, wenn der Quellcode in C ++ kompiliert wird, der Maschinencode (ausführbar) ist, von dem ich dachte, dass er Anweisungen direkt an die CPU enthält. Kürzlich las ich über Kernel und fand heraus, dass Programme nicht direkt auf die Hardware zugreifen können, sondern den Kernel durchlaufen müssen.

Wenn wir also einen einfachen Quellcode kompilieren, beispielsweise mit nur 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 wurde) oder wird ausgeführt muss jeder befehl im maschinencode noch über das betriebssystem (kernel) ausgeführt werden?

Ich habe eine ähnliche Frage gelesen . Es wurde nicht erklärt, ob der nach dem Kompilieren generierte Maschinencode eine Anweisung an die CPU ist oder ob der Kernel erneut durchlaufen werden muss, um die richtige Anweisung für die CPU zu erstellen. Was passiert also, nachdem der Maschinencode in den Speicher geladen wurde? Wird es durch den Kernel gehen oder direkt mit dem Prozessor sprechen?

GRANZER
quelle
29
Wenn Sie Code für ein Arduino schreiben, benötigen Sie kein Betriebssystem.
Stib
12
printfist kein gutes Beispiel. Es wird in der C-Spezifikation explizit als eine Funktion definiert, die nur in "gehosteten" Implementierungen verfügbar ist (dh auf einem Kernel ausgeführt werden, im Gegensatz zu "freistehenden", für die möglicherweise keine erforderlich ist). Und auf den meisten Plattformen printfist dies nur eine von Ihnen bereitgestellte Funktion libc, die eine Reihe von Aufgaben für Sie erledigt (einschließlich eines Systemaufrufs zum Drucken auf stdout). Es ist wirklich nicht anders als das Aufrufen von libvlc_media_list_add_mediaoder PyObject_GetAttr, mit der Ausnahme, dass einige printfImplementierungen garantiert verknüpft werden können, ohne dass zusätzliche nicht standardmäßige -ls hinzugefügt werden .
Abarnert
1
Das gibt es! (nicht verbunden, fand es nur cool) erikyyy.de/invaders
Nonny Moose
9
Dies hängt wirklich von Ihrer genauen Definition der Begriffe "ausführbar", "Kernel", "ausführen", "benötigen", "ansprechen" und "durchgehen" ab. Ohne eine genaue Definition dieser Begriffe ist die Frage nicht zu beantworten.
Jörg W Mittag
3
@ JörgWMittag - Wenn Sie pedantisch sein wollen, warum hinterfragen Sie dann nur diese Begriffe und nur diese Frage? Der wichtigste Begriff, der definiert werden muss, ist "Betriebssystem", das fraglich auf MS-DOS (und ähnliche Single-Task-Laufzeitumgebungen) angewendet wird. Wenn es ein paar (falsch informierte) Leute gibt, die denken, dass das PC-BIOS ein Betriebssystem ist , ist dann alles zu haben? Ich denke nicht. Das OP verwendet diese Wörter in einem Kontext, der entweder vernünftig (insbesondere wenn kein englischer Muttersprachler ist) oder nicht technisch erscheint.
Sägemehl

Antworten:

86

Als jemand, der Programme geschrieben hat, die ohne Betriebssystem ausgeführt werden, biete ich eine endgültige Antwort.

Würde eine ausführbare Datei einen Betriebssystemkern benötigen, um ausgeführt zu werden?

Das hängt davon ab, wie das Programm geschrieben und erstellt wurde.
Sie könnten ein Programm schreiben (vorausgesetzt, Sie haben 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.

Das typische Programm, das in einer Host-Betriebssystemumgebung geschrieben und erstellt wird, wird standardmäßig in derselben Host-Betriebssystemumgebung ausgeführt.
Sehr explizite Entscheidungen und Aktionen sind 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 direkt an die CPU enthält.

Richtig.

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

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


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 vom Betriebssystem in den Speicher geladen wurde) ) oder muss jeder Befehl im Maschinencode noch das Betriebssystem (den Kernel) durchlaufen, 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. ein Prozess hat nicht genügend Berechtigungen), löst eine sofortige Ausnahme aus, 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 Programmiersprache auf hoher Ebene in Maschinencode ist möglicherweise nicht so trivial, wie Sie vermuten.
Anschließend wählen Sie eine der komplexesten Funktionen aus einer Laufzeitbibliothek aus, die Datenkonvertierungen und E / A durchführt.

Beachten Sie, dass Ihre Frage eine Umgebung mit einem Betriebssystem (und einer Laufzeitbibliothek) vorsieht.
Sobald das System hochgefahren ist und das Betriebssystem die Kontrolle über den Computer hat, werden Einschränkungen für die Funktionen eines Programms auferlegt (z. B. muss E / A vom Betriebssystem ausgeführt werden).
Wenn Sie ein eigenständiges Programm ausführen möchten (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.

Für ein eigenständiges Programm kann es ausgeführt werden, dh die Steuerung wird durch Springen zur Startadresse des Programms übergeben.

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

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" , sondern "sprechen mit dem Prozessor" .
Der Maschinencode (bestehend aus Operationscode und Operanden) ist eine Anweisung an die CPU, die decodiert und die Operation ausgeführt wird.

Vielleicht sollten Sie sich als nächstes mit den CPU-Modi befassen .

Sägespäne
quelle
2
"Wenn Sie ein eigenständiges Programm ausführen möchten (dh ohne Betriebssystem), dürfen Sie den Computer nicht starten, um das Betriebssystem auszuführen." ist nicht ganz richtig. Viele DOS-Programme wurden nach DOS geladen und dann von DOS-Diensten vollständig ignoriert (durch direktes Bit-Banging oder möglicherweise direkten Aufruf des BIOS). Win3.x ist ein hervorragendes Beispiel dafür, dass (mit Ausnahme einiger interessanter Eckfälle) ignoriert wurde, dass DOS vorhanden war. Win95 / 98 / Me hat das auch getan. Es gibt viele Beispiele für Betriebssysteme, die eigenständige Programme unterstützen, viele davon aus der 8- / 16-Bit-Ära.
Eric Towers
8
@EricTowers - Mit "DOS" meinen Sie vermutlich MS-DOS (da ich DOSs verwendet habe, die nicht mit MS oder Intel zusammenhängen)? Sie zitieren ein "OS", das nicht einmal den Kriterien meiner College-Lehrbücher über OS-Konzepte und -Design aus den 1970er Jahren entspricht. Die Ursprünge von MS-DOS gehen (über Seattle Computer Products) auf CP / M zurück, das von seinem Autor Gary Kildall ausdrücklich nicht als Betriebssystem bezeichnet wird. FWIW ein Betriebssystem, mit dem ein Programm das System übernehmen kann, ist in seiner Grundfunktion zur Verwaltung der Systemressourcen gescheitert. "Es gibt viele Beispiele für Betriebssysteme, die eigenständige Programme unterstützen" - "Unterstützen" oder nicht verhindern können?
Sägemehl
5
... oder ProDOS oder PC-DOS oder DR-DOS oder CBM DOS oder TRS DOS oder FLEX ...
Eric Towers
3
Ich mag die "freistehende" Terminologie von GCC. Das englische Wort hat die richtigen Konnotationen für Code, der ohne Betriebssystem ausgeführt wird, vielleicht sogar besser als "Standalone". Sie können z. B. kompilieren gcc -O2 -ffreestanding my_kernel.c special_sauce.S, um eine ausführbare Datei zu erstellen , bei der keine der normalen Bibliotheken oder Betriebssysteme vorhanden sind. (Natürlich benötigen Sie normalerweise ein Linker-Skript, um es in ein Dateiformat zu verlinken, das ein Bootloader laden möchte!)
Peter Cordes
4
@PeterCordes "Standalone" ist der im C-Standard verwendete Begriff, den IMO als etwas maßgebend betrachten kann. Alternativ ist ein guter Begriff auch "nicht gehostet" (wie in von der OS gehostet)
Jan Dorniak
38

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 Ebenen, um etwas zu tun.

Ihr Programm "benötigt" den Kernel genauso wie die Standard-C-Bibliotheken, um den printfBefehl überhaupt verwenden zu können.

Der eigentliche Code Ihres Programms läuft auf der CPU, aber die Verzweigungen, die der Code zum Ausdrucken auf dem Bildschirm erzeugt, durchlaufen den Code für die C- printfFunktion sowie verschiedene andere Systeme und Interpreter, von denen jedes seine eigene Verarbeitung vornimmt , um herauszufinden, wie hello world! wird tatsächlich auf Ihrem Bildschirm gedruckt.

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

Es gibt noch viel mehr, aber lassen Sie es uns einfach halten ...

  1. In Ihrem Terminal-Programm führen Sie Ihr Programm zum Drucken aus hello world!
  2. Das Terminal sieht, dass das Programm (über die C-Ausgaberoutinen) hello world!auf 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 auf den Kernel zu und sagt: "Eines meiner Programme möchte, dass Ihr Grafikgerät an dieser Stelle Text anzeigt, und los geht's, Alter!"
  5. Der Kernel leitet die Anforderung an den Grafikgerätetreiber weiter, der sie so formatiert, dass die Grafikkarte sie verstehen kann
  6. Je nachdem, wie die Grafikkarte angeschlossen ist, müssen andere Kernel-Gerätetreiber aufgerufen werden, um die Daten auf physische Gerätebusse wie PCIe zu übertragen. Dabei muss beispielsweise sichergestellt werden, dass das richtige Gerät ausgewählt ist und die Daten über die entsprechende Bridge oder übertragen werden können Konverter
  7. Die Hardware zeigt Sachen an.

Dies ist eine massive Vereinfachung, die nur der Beschreibung dient. Hier seid Drachen.

Effektiv alles , was Sie tun , dass Hardware-Zugriff benötigt, sei es angezeigt, Speicherblöcke, die Bits von Dateien oder so etwas hat durch einige Gerätetreiber im Kernel genau arbeiten gehen , wie zu dem jeweiligen Gerät zu sprechen. Sei es ein Dateisystemtreiber über einem SATA-Festplatten-Controller-Treiber, der sich selbst auf einem PCIe-Bridge-Gerät befindet.

Der Kernel versteht es, all diese Geräte miteinander zu verbinden, und bietet eine relativ einfache Schnittstelle, über die Programme Dinge erledigen können, ohne wissen zu müssen, wie all diese Dinge selbst zu erledigen sind.

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

Schließlich bedeutet das Terminal-Programm, dass Ihr Programm nicht wissen muss, wie man ein Fenster zeichnet, wie man mit dem Kernel-Grafikkartentreiber spricht oder wie kompliziert es ist, mit Bildschirmpuffern und dem Timing der Anzeige umzugehen und tatsächlich zu wackeln Datenleitungen zum Display.

Es wird alles von Schichten auf Schichten von Code gehandhabt.

Mokubai
quelle
Nicht nur der Hardware- Zugriff, die meiste Kommunikation zwischen Programmen erfolgt auch über den Kernel. Das, was normalerweise nicht den Kernel betrifft, baut einen direkteren Kanal auf. Für die Zwecke der Frage ist es jedoch auch möglich und in weitaus einfacheren Fällen üblich, den gesamten Code in einem einzigen Programm zu komprimieren.
Chris Stratton
In der Tat muss Ihr Terminal-Programm nicht einmal auf demselben Computer ausgeführt werden wie das Programm, mit dem Sie Ihre Daten schreiben.
Jamesqf
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".
user253751
21

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 haben eine eigenständige "Binärdatei" ausgegeben, die überhaupt ohne Betriebssystem ausgeführt wurde. Als Ihr Programm aufhörte zu laufen, haben Sie ein anderes geladen, das auch ohne Betriebssystem lief.

In modernen Umgebungen ist ein Betriebssystem erforderlich, da nicht immer nur ein Programm gleichzeitig ausgeführt wird. Die gleichzeitige Verteilung von CPU-Kern (en), RAM, Massenspeichergerät, Tastatur, Maus und Bildschirm auf mehrere Programme erfordert eine Koordinierung. Das Betriebssystem bietet das. In einer modernen Umgebung kann Ihr Programm nicht nur die Festplatte oder SSD lesen und schreiben, sondern muss das Betriebssystem bitten, dies in seinem Namen zu tun. Das Betriebssystem empfängt solche Anforderungen von allen Programmen, die auf das Speichergerät zugreifen möchten, implementiert beispielsweise Zugriffssteuerungen (normale Benutzer können nicht in die Dateien des Betriebssystems schreiben), stellt sie in die Warteschlange und sortiert die zurückgegebenen Informationen zu den richtigen Programmen (Prozessen).

Darüber hinaus unterstützen moderne Computer (im Gegensatz zum 1401) den Anschluss einer Vielzahl von E / A-Geräten, nicht nur die, die IBM früher verkaufte. Ihr Compiler und Linker kann möglicherweise nicht alle Möglichkeiten kennen. Beispielsweise kann Ihre Tastatur über PS / 2 oder USB angeschlossen sein. Mit dem Betriebssystem können Sie gerätespezifische "Gerätetreiber" installieren, die mit diesen Geräten kommunizieren können, 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 einem USB-Gerät gegenüber einer PS / 2-Tastatur abzurufen oder beispielsweise auf eine lokale SATA-Festplatte gegenüber einem USB-Speichergerät zuzugreifen auf einem NAS oder SAN. Diese Details werden von Gerätetreibern für die verschiedenen Gerätecontroller verarbeitet.

Für Massenspeichergeräte bietet das Betriebssystem auf allen einen Dateisystemtreiber, der für Verzeichnisse und Dateien dieselbe Schnittstelle bietet, unabhängig davon, wo und wie der Speicher implementiert ist. Auch hier macht sich das Betriebssystem Sorgen um die Zugriffskontrolle und die Serialisierung. Im Allgemeinen sollte zum Beispiel dieselbe Datei nicht von mehr als einem Programm gleichzeitig zum Schreiben geöffnet werden, ohne durch einige Rahmen zu springen (gleichzeitige Lesevorgänge sind jedoch im Allgemeinen in Ordnung).

Ja, in einer modernen Universalumgebung brauchen Sie wirklich 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 zum Beispiel kein wirkliches Betriebssystem. Klar, es gibt eine Menge Bibliothekscode, den die Build-Umgebung in jede "Binärdatei" einbindet, die sie erstellt. Da dieser Code jedoch von Programm zu Programm nicht permanent vorhanden ist, handelt es sich nicht um ein Betriebssystem.

Jamie Hanrahan
quelle
10

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 wird er 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 Einschränkungen.

  1. Wenn ein Betriebssystem vorhanden ist, ist es Anwendungsprogrammen normalerweise untersagt, bestimmte Anweisungen auszuführen oder auf bestimmte Ressourcen zuzugreifen. Wenn beispielsweise eine Anwendung einen Befehl ausführt, der die Systeminterrupt-Tabelle ändert, springt die CPU stattdessen zu einem OS-Ausnahmebehandler, sodass die fehlerhafte Anwendung beendet wird. Außerdem dürfen Anwendungen normalerweise nicht in den Gerätespeicher lesen / schreiben. Der Zugriff auf diese speziellen Speicherbereiche erfolgt über die Kommunikation des Betriebssystems mit Geräten wie Grafikkarte, Netzwerkschnittstelle, Systemuhr usw.

  2. Die Einschränkungen, die ein Betriebssystem Anwendungen auferlegt, werden durch spezielle Funktionen der CPU wie Privilegierungsmodi, Speicherschutz und Interrupts erreicht. Obwohl jede CPU, die Sie in einem Smartphone oder PC finden würden, über diese Funktionen verfügt, ist dies bei bestimmten CPUs nicht der Fall. Diese CPUs benötigen in der Tat spezielle Kernel, die den Anwendungscode "interpretieren", um die gewünschten Funktionen zu erreichen. Ein sehr interessantes Beispiel ist der Gigatron , ein Computer mit 8 Befehlen, der aus Chips aufgebaut werden kann und einen Computer mit 34 Befehlen emuliert.

  3. Einige Sprachen wie Java "kompilieren" zu etwas, das als Bytecode bezeichnet wird und eigentlich kein Maschinencode ist. Obwohl sie in der Vergangenheit zum Ausführen der Programme interpretiert wurden, wird heutzutage in der Regel die sogenannte Just-in-Time-Kompilierung verwendet, sodass sie als Maschinencode direkt auf der CPU ausgeführt werden.

  4. Ausführen von Software auf einer virtuellen Maschine, bei der der Maschinencode von einem Programm namens Hypervisor "interpretiert" werden musste . Aufgrund der enormen Nachfrage der Industrie nach VMs haben die CPU-Hersteller Funktionen wie VTx zu ihren CPUs hinzugefügt, damit 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. die Emulation eines NES), muss der Maschinencode interpretiert werden.

Artelius
quelle
1
Obwohl der Bytecode von Java normalerweise nicht der Maschinencode ist, gibt es immer noch Java-Prozessoren .
Ruslan
Hypervisoren waren noch nie Dolmetscher. Eine Interpretation ist natürlich erforderlich, wenn die virtuelle Maschine ein Befehlssatz ist, der nicht mit ihrem Host kompatibel ist. Für die Ausführung derselben Architektur führen jedoch auch frühe Hypervisoren Code direkt auf der CPU aus (möglicherweise sind paravirtualisierte Kernel für CPUs ohne erforderlich) die notwendige Hypervisor-Unterstützung).
Toby Speight
5

Wenn Sie Ihren Code kompilieren, erstellen Sie so genannten "Objekt" -Code, der (in den meisten Fällen) ( printfbeispielsweise ) von Systembibliotheken abhängt. Anschließend wird Ihr Code von einem Linker umschlossen, der eine Art Programmladeprogramm hinzufügt, das Ihr bestimmtes Betriebssystem unterstützt Erkennen Sie, warum Sie ein für Windows kompiliertes Programm nicht unter Linux ausführen können, und wissen Sie, wie Sie Ihren Code entpacken und ausführen können. So ist Ihr Programm wie ein Fleisch in einem Sandwich und kann nur als ganzes Bündel gegessen werden.

Kürzlich las ich über Kernel 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 es sich bei Ihrem Programm um einen Kernelmodustreiber handelt, können Sie direkt auf Hardware zugreifen, wenn Sie wissen, wie man mit Hardware "spricht". In der Regel (insbesondere bei nicht dokumentierter oder komplizierter Hardware) verwenden die Benutzer jedoch Treiber, die Kernelbibliotheken sind. Auf diese Weise können Sie API-Funktionen finden, die wissen, wie man auf fast menschenlesbare Weise mit Hardware kommuniziert, ohne dass Adressen, Register, Timing und viele andere Dinge bekannt sein müssen.

Wird jeder Befehl 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 das auszuführende Betriebssystem (Kernel) durchlaufen

Nun, der Kernel ist wie eine Kellnerin, deren Aufgabe es ist, Sie zu einem Tisch zu führen und Ihnen zu dienen. Das einzige, was es nicht kann - es ist Essen für dich, das solltest du selbst tun. Ebenso wie Ihr Code entpackt der Kernel Ihr Programm in einen Speicher und startet Ihren Code, der Maschinencode, der direkt von der CPU ausgeführt wird. Ein Kernel muss Sie nur beaufsichtigen - was Sie dürfen und was Sie nicht dürfen.

Es wird nicht erklärt, ob der nach dem Kompilieren generierte Maschinencode eine Anweisung an die CPU ist oder muss er erneut den Kernel durchlaufen, um die richtige Anweisung für die CPU zu erstellen.

Maschinencode, der nach dem Übersetzen generiert wird, ist eine Anweisung an die CPU direkt. Daran besteht kein Zweifel. Das Einzige, was Sie beachten müssen, ist, dass nicht der gesamte Code in der kompilierten Datei der tatsächliche Maschinen- / CPU-Code ist. Linker hat Ihr Programm mit einigen Metadaten umhüllt, die nur der Kernel interpretieren kann, als Hinweis darauf, was mit Ihrem Programm geschehen soll.

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 nur um einfache Opcodes wie das Hinzufügen von zwei Registern, wird er direkt von der CPU ohne Unterstützung des Kernels ausgeführt. Wenn Ihr Code jedoch Funktionen aus Bibliotheken verwendet, werden solche Aufrufe vom Kernel unterstützt, wie zum Beispiel von der Kellnerin, wenn Sie dies wünschen in einem Restaurant zu essen, würde man einem Werkzeug geben - Gabel, Löffel (und immer noch ihr Vermögen), aber was man damit machen wird - es hängt von seinem "Code" ab.

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

Alex
quelle
3

Wenn wir also einen 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 in den Speicher geladen wurde) von OS) oder muss jeder Befehl im Maschinencode noch das Betriebssystem (Kernel) durchlaufen, um ausgeführt zu werden?

Grundsätzlich gehen nur Systemaufrufe an den Kernel. Alles, was mit E / A oder Speicherzuweisung / Freigabe zu tun hat, führt normalerweise zu einem Systemaufruf. Einige Anweisungen können nur im Kernel-Modus ausgeführt werden und führen dazu, dass die CPU eine Ausnahme auslöst. Ausnahmen führen zu einem Wechsel in den Kernel-Modus und einem Sprung in den Kernel-Code.

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

Eine Speicherzuweisung im Benutzermodus (ohne Kernel) ist nicht möglich. Wenn Sie auf Speicher zugreifen, auf den Sie nicht zugreifen dürfen, bemerkt die zuvor vom Kernel programmierte MMU eine Ausnahme auf CPU-Ebene (Segmentierungsfehler) , was den Kernel auslöst und der Kernel das Programm beendet.

Das Ausführen von E / A im Benutzermodus (ohne den Kernel) ist nicht möglich. Wenn Sie auf E / A-Ports oder -Register für Geräte oder Adressen zugreifen, die mit Geräten verbunden sind (eines oder beide werden für die Ausführung von E / A benötigt), lösen diese ein aus Ausnahme in gleicher Weise.


Würde eine ausführbare Datei einen Betriebssystemkern benötigen, um ausgeführt zu werden?

Hängt vom Typ der ausführbaren Datei ab.

Kernel vermitteln nicht nur den gemeinsamen Zugriff auf RAM und Hardware, sondern führen auch eine Loader-Funktion aus.

Viele "ausführbare Formate", wie ELF oder PE, enthalten zusätzlich zum Code Metadaten in der ausführbaren Datei, die 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 (Windows- .dlloder Linux-Shared-Object- .soDateien) - ihr Code muss enthalten sein.

Wenn Ihr Compiler eine Datei erstellt, die von einem Betriebssystem-Loader verarbeitet werden soll, und dieser Loader nicht vorhanden ist, funktioniert er nicht.

  • Können Sie Code einfügen, der die Arbeit des Loaders erledigt?

Sicher. Sie müssen das Betriebssystem davon überzeugen, Ihren Rohcode auszuführen, ohne Metadaten zu verarbeiten. Wenn Ihr Code Kernel-APIs aufruft, funktioniert er immer noch nicht.

  • Was ist, wenn keine Kernel-APIs 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 sie sich weiterhin im Benutzermodus. Wenn Ihr Code auf Dinge zugreift, die im Benutzermodus verboten sind, im Gegensatz zum Kernelmodus, wie nicht zugeteilter Speicher oder E / A-Geräteadressen / -register, stürzt er mit Berechtigungen oder Segmentverletzungen ab (Ausnahmen gehen wiederum in den Kernelmodus und werden behandelt) dort) und wird immer noch nicht funktionieren.

  • Was ist, wenn Sie es im Kernel-Modus ausführen?

Dann wird es funktionieren.


LawrenceC
quelle
Das ist nicht ganz richtig. Die Anforderung, die den Zugriff Hardware durch den Kernel zu gehen, oder dass es sogar sein , ein Kern, ist eine Design - Entscheidung auf vielen Systemen heute in der affirmative gemacht, sondern auch in der negativen (auch heute) auf vielen einfachen Systemen.
Chris Stratton
Ich erkläre den Stand der Dinge, wenn A) ein Kernel vorhanden ist und B) 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, und ja, einige Systeme laufen ohne die gesamte Benutzer- / Supervisor-Infrastruktur. Microsofts erste Xbox war so - obwohl eine Standard-x86-CPU mit Benutzer- / Supervisor-Modus, soweit ich weiß, den Kernel-Modus nie verlassen hat, konnte das geladene Spiel tun, was es wollte.
LawrenceC
1
Das Macintosh-System vor MacOS X war ein Betriebssystem eines Universalcomputers , der auf einer Universal-CPU (68000-Familie, PowerPC) mit jahrzehntelanger Unterstützung für den Speicherschutz lief (mit Ausnahme der ersten 68000-basierten Computer, von denen ich glaube, dass sie keinen Speicherschutz verwendeten) : Jedes Programm kann auf alles im Speicher zugreifen.
neugierig
3

TL; DR-Nr.

Die 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 das Sega Genesis kein Betriebssystem, auf das Sega zurückgreifen konnte. Sie haben gerade Ihr Spiel in 68K Assembler erstellt und direkt auf das Bare Metal geschrieben.

Oder wo ich mir die Zähne geschnitten habe, um Embedded-Arbeit am Intel 8051 zu leisten. Wenn Sie wieder nur ein 2716-Eprom mit einer Grundfläche von 2k * 8 haben, haben Sie keinen Platz für ein Betriebssystem.

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

dgnuff
quelle
3

Ich möchte nicht andeuten, dass die anderen Antworten nicht für sich genommen stimmen, aber sie enthalten viel zu viele Details, die für Sie leider immer noch sehr undurchsichtig sind.

Die grundlegende Antwort ist, dass der Code direkt auf dem Prozessor ausgeführt wird. Und nein, der Maschinencode "spricht" niemanden an, es 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 wenig, aber das ist im Moment in Ordnung). Der Prozessor liest den Code, führt ihn aus und spuckt die Ergebnisse aus. Der Maschinencode ist nur Nahrung für den Prozessor.

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

Kernel, Betriebssysteme und ähnliche dazwischen liegende Schichten werden normalerweise nur in größeren Systemen verwendet, in denen erwartet wird, dass mehrere Programme ausgeführt werden und das System verwalten muss, wie diese Programme die Peripheriegeräte des Computers verwenden können (recht häufig auf dem Computer) gleiche Zeit). In diesen Fällen können laufende Programme nur mit dem System auf diese Peripheriegeräte zugreifen, das über die Freigabe entscheidet und sicherstellt, dass keine Konflikte vorliegen. Kleine Systeme, bei denen keine Verwaltung zwischen konkurrierenden Programmen erforderlich ist, weil es keine gibt, haben häufig ü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 tun, was es will.

Gábor
quelle
2

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

Weitere Sonderfälle sind das Bootstrap-Programm, mit dem der Kernel und der Kernel selbst geladen werden. Diese Sonderfälle werden in der Regel in einer anderen Sprache als C ++ codiert.

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

Am anderen Ende des Spektrums befindet sich 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 übersetzt, die als Java Virtual Machine bezeichnet wird. 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.

Walter Mitty
quelle
2

In der guten alten Zeit 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 in Ihr Programm geschrieben haben. Das Einzige, was im Computer daneben lief, war der Code, den Sie in Ihrem kompilierten Programm lesen konnten - wenn Sie Glück hatten. Auf einigen Computern musste Code über Schalter eingegeben werden, bevor mehr ausgeführt werden konnte (der ursprüngliche "Bootstrap" -Prozess), oder sogar Ihr gesamtes Programm wurde auf diese Weise eingegeben.

Es stellte sich schnell heraus, dass es nett war, Code zum Laden und Ausführen von Programmen laufen zu lassen. Später stellte sich heraus, dass Computer leistungsfähig genug waren, um das gleichzeitige Ausführen mehrerer Programme zu unterstützen, indem die CPU zwischen ihnen umgeschaltet wurde, insbesondere wenn die Hardware helfen konnte, aber die zusätzliche Komplexität der Programme sich nicht gegenseitig auf die Füße stellte (zum Beispiel Wie gehe ich mit mehreren Programmen um, die versuchen, Daten gleichzeitig an den Drucker zu senden?

All dies führte dazu, dass eine große Menge von Hilfecode aus den einzelnen Programmen in das "Betriebssystem" verschoben wurde, mit einer standardisierten Methode, den Hilfecode aus Benutzerprogrammen aufzurufen.

Und dort sind wir heute. Ihre Programme laufen auf Hochtouren, aber wenn sie etwas benötigen, das vom Betriebssystem verwaltet wird, rufen sie Hilfsroutinen auf, die vom Betriebssystem bereitgestellt werden, und dieser Code wird nicht benötigt und ist nicht in den Benutzerprogrammen selbst vorhanden. Dies beinhaltete das Schreiben auf das Display, das Speichern von Dateien, den Zugriff auf das Netzwerk usw.

Es wurden Mikrokerne geschrieben, die genau das bereitstellen, was für ein bestimmtes Programm benötigt wird, um ohne ein vollständiges Betriebssystem ausgeführt zu werden. Dies hat einige Vorteile für die erfahrenen Benutzer, während die meisten anderen verschenkt werden. Vielleicht möchten Sie die Wikipedia-Seite darüber lesen - https://en.wikipedia.org/wiki/Microkernel - wenn Sie mehr wissen möchten.

Ich habe mit einem Mikrokernel experimentiert, auf dem eine Java Virtual Machine ausgeführt werden kann, habe aber später festgestellt, dass Docker der ideale Ort dafür ist.

Thorbjørn Ravn Andersen
quelle
1

In typischen Desktop-Betriebssystemen ist der Kernel selbst eine ausführbare Datei. (Windows hat ntoskrnl.exe; Linux hat vmlinuxusw.) Wenn Sie einen Kernel benötigen, damit eine ausführbare Datei ausgeführt werden kann, können diese Betriebssysteme nicht existieren.

Was Sie für einen Kernel brauchen, ist, die Dinge zu tun, die ein Kernel tut. Lassen Sie zu, dass mehrere ausführbare Dateien gleichzeitig ausgeführt werden, fechten Sie zwischen ihnen, abstrahieren Sie die Hardware usw. Die meisten Programme sind nicht in der Lage, diese Aufgaben selbst zu erledigen, und Sie möchten nicht, dass sie dies tun, selbst wenn sie könnten. In den Tagen von DOS - das selbst kaum als Betriebssystem zu bezeichnen war - verwendeten Spiele das Betriebssystem oft nur so wenig wie ein Loader und griffen direkt auf die Hardware zu, wie es ein Kernel tun würde. Aber Sie mussten oft wissen, welche Marken und Modelle von Hardware auf Ihrem Computer vorhanden waren, bevor Sie ein Spiel kauften. Viele Spiele unterstützten nur bestimmte Familien von Video- und Soundkarten und liefen bei konkurrierenden Marken sehr schlecht, wenn sie überhaupt funktionierten. Das'

cHao
quelle